diff --git a/docs/rh-log.txt b/docs/rh-log.txt index a778feae..72765813 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,80 @@ +September 22, 2008 (Changes by Graf Zahl) +- Used the one unused byte in the state structure as a flag to tell what type + the NextState parameter is. The code did some rather unsafe checks with it + to determine its type. +- moved all state related code into a new file: p_states.cpp. +- merged all FindState functions. All the different variations are now inlined + and call the same function to do the real work. + +September 21, 2008 (Changes by Graf Zahl) +- did some code cleanup and reorganization in thingdef.cpp. +- Replaced the translation parser for TEXTURES with FRemapTable::AddToTranslation. +- To get the game name the screenshot code might as well use the globally + available GameNames array instead of creating its own list. +- Moved backpack names for cheat into gameinfo. +- Fixed: SNDINFO must be loaded before the textures. However, this required + some changes to the MAPINFO parser which tried to access the texture manager + to check if the level name patches exist. That check had to be moved to + where the intermission screen is set up. +- Fixed: 'bloodcolor' ignored the first parameter value when given a list + of integers. + Please note that this creates an incompatibility between old and new + versions so if you want to create something that works with both 2.2.0 + and current versions better use the string format version for the color + parameter! +- Rewrote the DECORATE property parser so that the parser is completely + separated from the property handlers. This should allow reuse of all + the handler code for a new format if Doomscript requires one. +- Fixed: PClass::InitializeActorInfo copied too many bytes if a subclass's + defaults were larger than the parent's. +- Moved A_ChangeFlag to thingdef_codeptr.cpp. +- Moved translation related code from thingdef_properties.cpp to r_translate.cpp + and rewrote the translation parser to use FScanner instead of strtol. +- replaced DECORATE's 'alpha default' by 'defaultalpha' for consistency. + Since this was never used outside zdoom.pk3 it's not critical. +- Removed support for game specific pickup messages because the only thing + this was ever used for - Raven's invulnerability item - has already been + split up into a Heretic and Hexen version. + +September 20, 2008 +- Fixed: The Timidity config parser always tried to process the note number, + even if it wasn't specified. + +September 19, 2008 +- Fixed: When UpdateJoystickMenu() modifies the menu items for different + controllers, the joystick axis selectors need to NULL the d.graycheck + field, since this is shared by the axis sensitivity sliders' step values. + +September 19, 2008 (Changes by Graf Zahl) +- Fixed: The crosshair must be initialized after the texture manager because + on the fly texture creation for graphics patches is no longer supported. +- Fixed a few Linux compile errors. + +September 16, 2008 (Changes by Graf Zahl) +- Changed: Replaced weapons should not be given by generic cheats, only + when explicitly giving them. +- Changed 'give weapon' cheat so that in single player it only gives weapons + belonging to the current game or are placed in a weapon slot to avoid + giving the Chex Quest weapons in Doom and vice versa. +- Fixed: The texture manager must be the first thing to be initialized + because MAPINFO and DECORATE both can reference textures and letting them + create their own textures is not safe. + +September 15, 2008 (Changes by Graf Zahl) +- Separated low level sound code from all high level dependencies. +- Separated low level sound channel class from high level class which now + is just a subclass of the low level class. +- Moved some more high level sound logic out of FMODSoundRenderer: + The rolloff and channel ended callbacks now call functions in s_sound.cpp + instead of working on the data itself and GSnd->StopSound has been replaced + with S_StopChannel. +- Changed compilation for g_doom, g_heretic, g_hexen and g_strife folders so + that all files are included by a central one instead of compiling each one + separately. This speeds up the compilation process by 25% when doing a + complete rebuild in Visual C. + September 14, 2008 (Changes by Graf Zahl) +- Cleaned up some include dependencies. - fixed: For Chex Quest some CVars were initialized to Heretic's default. - fixed pickup message for LargeZorchPack. diff --git a/gzdoom.vcproj b/gzdoom.vcproj index be880673..1690763c 100644 --- a/gzdoom.vcproj +++ b/gzdoom.vcproj @@ -845,6 +845,10 @@ RelativePath=".\src\p_spec.cpp" > + + @@ -1072,6 +1076,10 @@ RelativePath=".\src\thingdef\thingdef_main.cpp" > + + @@ -1563,6 +1571,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -1805,14 +1821,6 @@ Outputs="$(IntDir)/$(InputName).obj" /> - - - @@ -1986,14 +1994,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -2004,6 +2004,14 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ +public: + ~FDropItemPtrArray(); +}; + +extern FDropItemPtrArray DropItemList; + +void FreeDropItemChain(FDropItem *chain); +int StoreDropItemChain(FDropItem *chain); + + + // Map Object definition. class AActor : public DThinker { @@ -451,6 +472,7 @@ public: return (AActor *)(RUNTIME_TYPE(this)->Defaults); } + FDropItem *GetDropItems(); // Return true if the monster should use a missile attack, false for melee bool SuggestMissileAttack (fixed_t dist); @@ -766,14 +788,20 @@ public: bool isFast(); void SetIdle(); - FState *FindState (FName label) const; - FState *FindState (FName label, FName sublabel, bool exact = false) const; + FState *FindState (FName label) const + { + return GetClass()->ActorInfo->FindState(1, &label); + } + + FState *FindState (FName label, FName sublabel, bool exact = false) const + { + FName names[]={label, sublabel}; + return GetClass()->ActorInfo->FindState(2, &label, exact); + } + + bool HasSpecialDeathStates () const; - static FState States[]; - - enum { S_NULL = 2, S_GENERICFREEZEDEATH = 3 }; - TArray > dynamiclights; void * lightassociations; bool hasmodel; diff --git a/src/autosegs.h b/src/autosegs.h index 0f5fd0c0..c4b9c896 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -50,7 +50,7 @@ #define REGMARKER(x) (x) typedef void *REGINFO; -// List of ActorInfos and the TypeInfos they belong to +// List of Action functons extern REGINFO ARegHead; extern REGINFO ARegTail; @@ -58,6 +58,10 @@ extern REGINFO ARegTail; extern REGINFO CRegHead; extern REGINFO CRegTail; +// List of properties +extern REGINFO GRegHead; +extern REGINFO GRegTail; + template class TAutoSegIteratorNoArrow { diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 3d23baf0..4a857219 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -682,6 +682,7 @@ static int PatchThing (int thingy) bool hadHeight = false; bool hadTranslucency = false; bool hadStyle = false; + FStateDefinitions statedef; bool patchedStates = false; int oldflags; const PClass *type; @@ -813,36 +814,36 @@ static int PatchThing (int thingy) if (type != NULL && !patchedStates) { - MakeStateDefines(type->ActorInfo->StateList); + statedef.MakeStateDefines(type); patchedStates = true; } if (!strnicmp (Line1, "Initial", 7)) - AddState("Spawn", state ? state : GetDefault()->SpawnState); + statedef.AddState("Spawn", state ? state : GetDefault()->SpawnState); else if (!strnicmp (Line1, "First moving", 12)) - AddState("See", state); + statedef.AddState("See", state); else if (!strnicmp (Line1, "Injury", 6)) - AddState("Pain", state); + statedef.AddState("Pain", state); else if (!strnicmp (Line1, "Close attack", 12)) { if (thingy != 1) // Not for players! { - AddState("Melee", state); + statedef.AddState("Melee", state); } } else if (!strnicmp (Line1, "Far attack", 10)) { if (thingy != 1) // Not for players! { - AddState("Missile", state); + statedef.AddState("Missile", state); } } else if (!strnicmp (Line1, "Death", 5)) - AddState("Death", state); + statedef.AddState("Death", state); else if (!strnicmp (Line1, "Exploding", 9)) - AddState("XDeath", state); + statedef.AddState("XDeath", state); else if (!strnicmp (Line1, "Respawn", 7)) - AddState("Raise", state); + statedef.AddState("Raise", state); } else if (stricmp (Line1 + linelen - 6, " sound") == 0) { @@ -1048,7 +1049,7 @@ static int PatchThing (int thingy) } if (patchedStates) { - InstallStates(type->ActorInfo, info); + statedef.InstallStates(type->ActorInfo, info); } } @@ -1359,6 +1360,7 @@ static int PatchWeapon (int weapNum) AWeapon *info; BYTE dummy[sizeof(AWeapon)]; bool patchedStates = false; + FStateDefinitions statedef; if (weapNum >= 0 && weapNum < 9) { @@ -1385,20 +1387,20 @@ static int PatchWeapon (int weapNum) if (type != NULL && !patchedStates) { - MakeStateDefines(type->ActorInfo->StateList); + statedef.MakeStateDefines(type); patchedStates = true; } if (strnicmp (Line1, "Deselect", 8) == 0) - AddState("Select", state); + statedef.AddState("Select", state); else if (strnicmp (Line1, "Select", 6) == 0) - AddState("Deselect", state); + statedef.AddState("Deselect", state); else if (strnicmp (Line1, "Bobbing", 7) == 0) - AddState("Ready", state); + statedef.AddState("Ready", state); else if (strnicmp (Line1, "Shooting", 8) == 0) - AddState("Fire", state); + statedef.AddState("Fire", state); else if (strnicmp (Line1, "Firing", 6) == 0) - AddState("Flash", state); + statedef.AddState("Flash", state); } else if (stricmp (Line1, "Ammo type") == 0) { @@ -1455,7 +1457,7 @@ static int PatchWeapon (int weapNum) if (patchedStates) { - InstallStates(type->ActorInfo, info); + statedef.InstallStates(type->ActorInfo, info); } return result; @@ -1697,18 +1699,22 @@ static int PatchMisc (int dummy) { player->health = deh.StartHealth; - FDropItem * di = GetDropItems(PClass::FindClass(NAME_DoomPlayer)); - while (di != NULL) + // Hm... I'm not sure that this is the right way to change this info... + unsigned int index = PClass::FindClass(NAME_DoomPlayer)->Meta.GetMetaInt (ACMETA_DropItems) - 1; + if (index >= 0 && index < DropItemList.Size()) { - if (di->Name == NAME_Clip) + FDropItem * di = DropItemList[index]; + while (di != NULL) { - di->amount = deh.StartBullets; + if (di->Name == NAME_Clip) + { + di->amount = deh.StartBullets; + } + di = di->Next; } - di = di->Next; } } - // 0xDD means "enable infighting" if (infighting == 0xDD) { @@ -2195,14 +2201,6 @@ void DoDehPatch (const char *patchfile, bool autoloading, int lump) PatchFile[filelen] = 0; dversion = pversion = -1; -/* - if (gameinfo.gametype != GAME_Doom) - { - Printf ("DeHackEd/BEX patches are only supported for DOOM mode\n"); - delete[] PatchFile; - return; - } -*/ cont = 0; if (0 == strncmp (PatchFile, "Patch File for DeHackEd v", 25)) { @@ -2586,13 +2584,14 @@ void FinishDehPatch () memcpy (defaults2, defaults1, sizeof(AActor)); // Make a copy the state labels - MakeStateDefines(type->ActorInfo->StateList); if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory))) { // If this is a hacked non-inventory item we must also copy AInventory's special states - AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList); + FStateDefinitions statedef; + statedef.MakeStateDefines(type); + statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList); + statedef.InstallStates(subclass->ActorInfo, defaults2); } - InstallStates(subclass->ActorInfo, defaults2); // Use the DECORATE replacement feature to redirect all spawns // of the original class to the new one. diff --git a/src/d_main.cpp b/src/d_main.cpp index 257650d6..ce8aef51 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2489,6 +2489,13 @@ void D_DoomMain (void) Printf ("S_InitData: Load sound definitions.\n"); S_InitData (); + + Printf ("Texman.Init: Init texture manager.\n"); + TexMan.Init(); + + // Now that all textues have been loaded the crosshair can be initialized. + crosshair.Callback (); + // [CW] Parse any TEAMINFO lumps Printf ("TEAMINFO_Init: Load team definitions.\n"); TEAMINFO_Init (); diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 73c66da9..2bd670b0 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -297,7 +297,7 @@ void PClass::InitializeActorInfo () Defaults = new BYTE[Size]; if (ParentClass->Defaults != NULL) { - memcpy (Defaults, ParentClass->Defaults, Size); + memcpy (Defaults, ParentClass->Defaults, ParentClass->Size); if (Size > ParentClass->Size) { memset (Defaults + ParentClass->Size, 0, Size - ParentClass->Size); diff --git a/src/doomtype.h b/src/doomtype.h index d7ea6ec7..72feddbc 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -170,6 +170,14 @@ struct PalEntry #endif }; +// Screenshot buffer image data types +enum ESSType +{ + SS_PAL, + SS_RGB, + SS_BGRA +}; + #ifndef M_PI #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h #endif diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp index 6cf9146c..2c7e3e86 100644 --- a/src/g_doom/a_bossbrain.cpp +++ b/src/g_doom/a_bossbrain.cpp @@ -165,7 +165,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) FDropItem *drop; // while drop stays as the reference point. int n=0; - drop = di = GetDropItems(self->master->GetClass()); + drop = di = self->master->GetDropItems(); if (di != NULL) { while (di != NULL) diff --git a/src/g_level.cpp b/src/g_level.cpp index 005b741d..b00a9a36 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -848,13 +848,15 @@ static void G_DoParseMapInfo (int lump) strcpy (levelinfo->skypic2, levelinfo->skypic1); } SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps. + /* can't do this here. if (levelinfo->pname[0] != 0) { - if (!TexMan.AddPatch(levelinfo->pname).Exists()) + if (!TexMan.CheckForTexture(levelinfo->pname, FTexture::TEX_MiscPatch).Exists()) { levelinfo->pname[0] = 0; } } + */ break; } @@ -1722,7 +1724,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) { int cstype = SBarInfoScript->GetGameType(); - if(cstype == GAME_Doom || cstype == GAME_Chex) //Did the user specify a "base" + if(cstype & GAME_DoomChex) //Did the user specify a "base" { StatusBar = CreateDoomStatusBar (); } @@ -1854,7 +1856,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) // // G_DoCompleted // -static char nextlevel[9]; +static FString nextlevel; static int startpos; // [RH] Support for multiple starts per level extern int NoWipe; // [RH] Don't wipe when travelling in hubs static bool startkeepfacing; // [RH] Support for keeping your facing angle @@ -1866,7 +1868,7 @@ static bool g_nomonsters; // match the first parameter of the single player start spots // that should appear in the next map. -void G_ChangeLevel(const char * levelname, int position, bool keepFacing, int nextSkill, +void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nextSkill, bool nointermission, bool resetinv, bool nomonsters) { if (unloading) @@ -1875,15 +1877,14 @@ void G_ChangeLevel(const char * levelname, int position, bool keepFacing, int ne return; } - strncpy (nextlevel, levelname, 8); - nextlevel[8] = 0; + nextlevel = levelname; - if (strncmp(nextlevel, "enDSeQ", 6)) + if (strncmp(levelname, "enDSeQ", 6)) { level_info_t *nextinfo = CheckLevelRedirect (FindLevelInfo (nextlevel)); if (nextinfo) { - strncpy(nextlevel, nextinfo->mapname, 8); + nextlevel = nextinfo->mapname; } } @@ -1983,7 +1984,7 @@ void G_DoCompleted (void) if (gamestate == GS_TITLELEVEL) { - strncpy (level.mapname, nextlevel, 8); + strncpy (level.mapname, nextlevel, 255); G_DoLoadLevel (startpos, false); startpos = 0; viewactive = true; @@ -1998,7 +1999,7 @@ void G_DoCompleted (void) AM_Stop (); wminfo.finished_ep = level.cluster - 1; - wminfo.lname0 = level.info->pname; + wminfo.LName0 = TexMan[TexMan.CheckForTexture(level.info->pname, FTexture::TEX_MiscPatch)]; wminfo.current = level.mapname; if (deathmatch && @@ -2006,26 +2007,27 @@ void G_DoCompleted (void) !(level.flags & LEVEL_CHANGEMAPCHEAT)) { wminfo.next = level.mapname; - wminfo.lname1 = level.info->pname; + wminfo.LName1 = wminfo.LName0; } else { if (strncmp (nextlevel, "enDSeQ", 6) == 0) { wminfo.next = FString(nextlevel, 8); - wminfo.lname1 = ""; + wminfo.LName1 = NULL; } else { level_info_t *nextinfo = FindLevelInfo (nextlevel); wminfo.next = nextinfo->mapname; - wminfo.lname1 = nextinfo->pname; + wminfo.LName1 = TexMan[TexMan.CheckForTexture(nextinfo->pname, FTexture::TEX_MiscPatch)]; } } CheckWarpTransMap (wminfo.next, true); + nextlevel = wminfo.next; - wminfo.next_ep = FindLevelInfo (nextlevel)->cluster - 1; + wminfo.next_ep = FindLevelInfo (wminfo.next)->cluster - 1; wminfo.maxkills = level.total_monsters; wminfo.maxitems = level.total_items; wminfo.maxsecret = level.total_secrets; @@ -2357,7 +2359,7 @@ void G_DoWorldDone (void) } else { - strncpy (level.mapname, nextlevel, 8); + strncpy (level.mapname, nextlevel, 255); } G_StartTravel (); G_DoLoadLevel (startpos, true); diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index d38a1b06..399a3d14 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -81,7 +81,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) // If the self has attached metadata for items to drop, drop those. if (!self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB] { - FDropItem *di = GetDropItems(RUNTIME_TYPE(self)); + FDropItem *di = self->GetDropItems(); if (di != NULL) { diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index 33988bec..e9298e8f 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -394,6 +394,7 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) const char *failtext = NULL; FSoundID failsound; + if (owner == NULL) return false; if (keynum<=0 || keynum>255) return true; // Just a safety precaution. The messages should have been initialized upon game start. if (!keysdone) P_InitKeyMessages(); diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 4581b9c9..e54f3175 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -23,14 +23,14 @@ class ARandomSpawner : public AActor void PostBeginPlay() { - AActor *newmobj; + AActor *newmobj = NULL; FDropItem *di; // di will be our drop item list iterator FDropItem *drop; // while drop stays as the reference point. int n=0; Super::PostBeginPlay(); - drop = di = GetDropItems(RUNTIME_TYPE(this)); + drop = di = GetDropItems(); if (di != NULL) { while (di != NULL) diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index a9b49024..33f27930 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -587,7 +587,7 @@ IMPLEMENT_CLASS(AWeaponGiver) bool AWeaponGiver::TryPickup(AActor *&toucher) { - FDropItem *di = GetDropItems(GetClass()); + FDropItem *di = GetDropItems(); if (di != NULL) { @@ -737,8 +737,8 @@ bool FWeaponSlots::LocateWeapon (const PClass *type, int *const slot, int *const { if (Slots[i].Weapons[j] == type) { - *slot = i; - *index = j; + if (slot != NULL) *slot = i; + if (index != NULL) *index = j; return true; } else if (Slots[i].Weapons[j] == NULL) diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index f72ef095..133dd011 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -94,7 +94,7 @@ CUSTOM_CVAR (Bool, st_scale, true, CVAR_ARCHIVE) } } -CUSTOM_CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { int num = self; char name[16], size; @@ -123,7 +123,7 @@ CUSTOM_CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) strcpy (name, "XHAIRS1"); } } - CrosshairImage = TexMan[TexMan.AddPatch (name)]; + CrosshairImage = TexMan[TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch)]; } CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); diff --git a/src/gi.cpp b/src/gi.cpp index 088c1a69..d26733e2 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -100,6 +100,7 @@ gameinfo_t HexenGameInfo = { "mapinfo/hexen.txt", NULL }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "BagOfHolding", // Hexen doesn't have a backpack so use Heretic's. }; gameinfo_t HexenDKGameInfo = @@ -132,6 +133,7 @@ gameinfo_t HexenDKGameInfo = { "mapinfo/hexen.txt", NULL }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "BagOfHolding", }; gameinfo_t HereticGameInfo = @@ -164,6 +166,7 @@ gameinfo_t HereticGameInfo = { "mapinfo/heretic.txt", NULL }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "BagOfHolding", }; gameinfo_t HereticSWGameInfo = @@ -196,6 +199,7 @@ gameinfo_t HereticSWGameInfo = { "mapinfo/heretic.txt", NULL }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "BagOfHolding", }; gameinfo_t SharewareGameInfo = @@ -228,6 +232,7 @@ gameinfo_t SharewareGameInfo = { "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "Backpack", }; gameinfo_t RegisteredGameInfo = @@ -260,6 +265,7 @@ gameinfo_t RegisteredGameInfo = { "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "Backpack", }; gameinfo_t ChexGameInfo = @@ -292,6 +298,7 @@ gameinfo_t ChexGameInfo = { "mapinfo/chex.txt", NULL }, MAKERGB(63,125,57), MAKERGB(95,175,87), + "ZorchPack", }; gameinfo_t Chex3GameInfo = @@ -324,6 +331,7 @@ gameinfo_t Chex3GameInfo = { "mapinfo/chex.txt", NULL }, MAKERGB(63,125,57), MAKERGB(95,175,87), + "ZorchPack", }; gameinfo_t RetailGameInfo = @@ -356,6 +364,7 @@ gameinfo_t RetailGameInfo = { "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "Backpack", }; gameinfo_t CommercialGameInfo = @@ -388,6 +397,7 @@ gameinfo_t CommercialGameInfo = { "mapinfo/doomcommon.txt", "mapinfo/doom2.txt" }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "Backpack", }; gameinfo_t PlutoniaGameInfo = @@ -420,6 +430,7 @@ gameinfo_t PlutoniaGameInfo = { "mapinfo/doomcommon.txt", "mapinfo/plutonia.txt" }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "Backpack", }; gameinfo_t TNTGameInfo = @@ -452,6 +463,7 @@ gameinfo_t TNTGameInfo = { "mapinfo/doomcommon.txt", "mapinfo/tnt.txt" }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "Backpack", }; gameinfo_t StrifeGameInfo = @@ -484,6 +496,7 @@ gameinfo_t StrifeGameInfo = { "mapinfo/strife.txt", NULL }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "AmmoSatchel", }; gameinfo_t StrifeTeaserGameInfo = @@ -516,6 +529,7 @@ gameinfo_t StrifeTeaserGameInfo = { "mapinfo/strife.txt", NULL }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "AmmoSatchel", }; gameinfo_t StrifeTeaser2GameInfo = @@ -548,4 +562,5 @@ gameinfo_t StrifeTeaser2GameInfo = { "mapinfo/strife.txt", NULL }, MAKERGB(104,0,0), MAKERGB(255,0,0), + "AmmoSatchel", }; diff --git a/src/gi.h b/src/gi.h index 26514d2c..9ef71f8a 100644 --- a/src/gi.h +++ b/src/gi.h @@ -121,6 +121,7 @@ typedef struct const char *mapinfo[2]; DWORD defaultbloodcolor; DWORD defaultbloodparticlecolor; + const char *backpacktype; } gameinfo_t; extern gameinfo_t gameinfo; diff --git a/src/info.cpp b/src/info.cpp index 61eb767f..4487d7ac 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -51,122 +51,6 @@ extern void LoadDecorations (); -// Each state is owned by an actor. Actors can own any number of -// states, but a single state cannot be owned by more than one -// actor. States are archived by recording the actor they belong -// to and the index into that actor's list of states. - -// For NULL states, which aren't owned by any actor, the owner -// is recorded as AActor with the following state. AActor should -// never actually have this many states of its own, so this -// is (relatively) safe. - -#define NULL_STATE_INDEX 127 - -//========================================================================== -// -// -//========================================================================== - -FArchive &operator<< (FArchive &arc, FState *&state) -{ - const PClass *info; - - if (arc.IsStoring ()) - { - if (state == NULL) - { - arc.UserWriteClass (RUNTIME_CLASS(AActor)); - arc.WriteCount (NULL_STATE_INDEX); - return arc; - } - - info = FState::StaticFindStateOwner (state); - - if (info != NULL) - { - arc.UserWriteClass (info); - arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates)); - } - else - { - /* this was never working as intended. - I_Error ("Cannot find owner for state %p:\n" - "%s %c%c %3d [%p] -> %p", state, - sprites[state->sprite].name, - state->GetFrame() + 'A', - state->GetFullbright() ? '*' : ' ', - state->GetTics(), - state->GetAction(), - state->GetNextState()); - */ - } - } - else - { - const PClass *info; - DWORD ofs; - - arc.UserReadClass (info); - ofs = arc.ReadCount (); - if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor)) - { - state = NULL; - } - else if (info->ActorInfo != NULL) - { - state = info->ActorInfo->OwnedStates + ofs; - } - else - { - state = NULL; - } - } - return arc; -} - -//========================================================================== -// -// Find the actor that a state belongs to. -// -//========================================================================== - -const PClass *FState::StaticFindStateOwner (const FState *state) -{ - for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) - { - FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo; - if (state >= info->OwnedStates && - state < info->OwnedStates + info->NumOwnedStates) - { - return info->Class; - } - } - - return NULL; -} - -//========================================================================== -// -// Find the actor that a state belongs to, but restrict the search to -// the specified type and its ancestors. -// -//========================================================================== - -const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info) -{ - while (info != NULL) - { - if (state >= info->OwnedStates && - state < info->OwnedStates + info->NumOwnedStates) - { - return info->Class; - } - info = info->Class->ParentClass->ActorInfo; - } - return NULL; -} - //========================================================================== // // @@ -174,16 +58,23 @@ const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInf int GetSpriteIndex(const char * spritename) { + // Make sure that the string is upper case and 4 characters long + char upper[5]; + for (int i = 0; spritename[i] != 0 && i < 4; i++) + { + upper[i] = toupper (spritename[i]); + } + upper[4] = 0; + for (unsigned i = 0; i < sprites.Size (); ++i) { - if (strncmp (sprites[i].name, spritename, 4) == 0) + if (strcmp (sprites[i].name, spritename) == 0) { return (int)i; } } spritedef_t temp; - strncpy (temp.name, spritename, 4); - temp.name[4] = 0; + strcpy (temp.name, upper); temp.numframes = 0; temp.spriteframes = 0; return (int)sprites.Push (temp); @@ -337,209 +228,6 @@ void FActorInfo::SetPainChance(FName type, int chance) } } -//========================================================================== -// -// -//========================================================================== - -FStateLabel *FStateLabels::FindLabel (FName label) -{ - return const_cast(BinarySearch (Labels, NumLabels, &FStateLabel::Label, label)); -} - -void FStateLabels::Destroy () -{ - for(int i=0; iDestroy(); - free (Labels[i].Children); // These are malloc'd, not new'd! - Labels[i].Children=NULL; - } - } -} - - -//=========================================================================== -// -// HasStates -// -// Checks whether the actor has special death states. -// -//=========================================================================== - -bool AActor::HasSpecialDeathStates () const -{ - const FActorInfo *info = GetClass()->ActorInfo; - - if (info->StateList != NULL) - { - FStateLabel *slabel = info->StateList->FindLabel (NAME_Death); - if (slabel != NULL && slabel->Children != NULL) - { - for(int i=0;iChildren->NumLabels;i++) - { - if (slabel->Children->Labels[i].State != NULL) return true; - } - } - } - return false; -} - -//=========================================================================== -// -// FindState (one name version) -// -// Finds a state with the exact specified name. -// -//=========================================================================== - -FState *AActor::FindState (FName label) const -{ - const FActorInfo *info = GetClass()->ActorInfo; - - if (info->StateList != NULL) - { - FStateLabel *slabel = info->StateList->FindLabel (label); - if (slabel != NULL) - { - return slabel->State; - } - } - return NULL; -} - -//=========================================================================== -// -// FindState (two name version) -// -//=========================================================================== - -FState *AActor::FindState (FName label, FName sublabel, bool exact) const -{ - const FActorInfo *info = GetClass()->ActorInfo; - - if (info->StateList != NULL) - { - FStateLabel *slabel = info->StateList->FindLabel (label); - if (slabel != NULL) - { - if (slabel->Children != NULL) - { - FStateLabel *slabel2 = slabel->Children->FindLabel(sublabel); - if (slabel2 != NULL) - { - return slabel2->State; - } - } - if (!exact) return slabel->State; - } - } - return NULL; -} - -//=========================================================================== -// -// FindState (multiple names version) -// -// Finds a state that matches as many of the supplied names as possible. -// A state with more names than those provided does not match. -// A state with fewer names can match if there are no states with the exact -// same number of names. -// -// The search proceeds like this. For the current class, keeping matching -// names until there are no more. If both the argument list and the state -// are out of names, it's an exact match, so return it. If the state still -// has names, ignore it. If the argument list still has names, remember it. -// -//=========================================================================== -FState *FActorInfo::FindState (FName name) const -{ - return FindState(1, &name); -} - -FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const -{ - FStateLabels *labels = StateList; - FState *best = NULL; - - if (labels != NULL) - { - int count = 0; - FStateLabel *slabel = NULL; - FName label; - - // Find the best-matching label for this class. - while (labels != NULL && count < numnames) - { - label = *names++; - slabel = labels->FindLabel (label); - - if (slabel != NULL) - { - count++; - labels = slabel->Children; - best = slabel->State; - } - else - { - break; - } - } - if (count < numnames && exact) return NULL; - } - return best; -} - -//========================================================================== -// -// Creates a list of names from a string. Dots are used as separator -// -//========================================================================== - -void MakeStateNameList(const char * fname, TArray * out) -{ - FName firstpart, secondpart; - char * c; - - // Handle the old names for the existing death states - char * name = copystring(fname); - firstpart = strtok(name, "."); - switch (firstpart) - { - case NAME_Burn: - firstpart = NAME_Death; - secondpart = NAME_Fire; - break; - case NAME_Ice: - firstpart = NAME_Death; - secondpart = NAME_Ice; - break; - case NAME_Disintegrate: - firstpart = NAME_Death; - secondpart = NAME_Disintegrate; - break; - case NAME_XDeath: - firstpart = NAME_Death; - secondpart = NAME_Extreme; - break; - } - - out->Clear(); - out->Push(firstpart); - if (secondpart!=NAME_None) out->Push(secondpart); - - while ((c = strtok(NULL, "."))!=NULL) - { - FName cc = c; - out->Push(cc); - } - delete [] name; -} - - - //========================================================================== // // diff --git a/src/info.h b/src/info.h index f7e9212d..07b6650d 100644 --- a/src/info.h +++ b/src/info.h @@ -89,6 +89,7 @@ struct FState SBYTE Misc1; BYTE Misc2; BYTE Frame; + BYTE DefineFlags; // Unused byte so let's use it during state creation. FState *NextState; actionf_p ActionFunc; int ParameterIndex; @@ -204,8 +205,12 @@ struct FActorInfo void SetDamageFactor(FName type, fixed_t factor); void SetPainChance(FName type, int chance); - FState *FindState (FName name) const; FState *FindState (int numnames, FName *names, bool exact=false) const; + FState *FindStateByString(const char *name, bool exact=false); + FState *FindState (FName name) const + { + return FindState(1, &name); + } FActorInfo *GetReplacement (); FActorInfo *GetReplacee (); @@ -252,6 +257,6 @@ private: extern FDoomEdMap DoomEdMap; int GetSpriteIndex(const char * spritename); -void MakeStateNameList(const char * fname, TArray * out); +TArray &MakeStateNameList(const char * fname); #endif // __INFO_H__ diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 10ae08d5..1a276216 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -43,6 +43,8 @@ #include "r_translate.h" #include "g_level.h" #include "d_net.h" +#include "d_dehacked.h" +#include "gi.h" // [RH] Actually handle the cheat. The cheat code in st_stuff.c now just // writes some bytes to the network data stream, and the network code @@ -629,26 +631,7 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "backpack") == 0) { // Select the correct type of backpack based on the game - if (gameinfo.gametype == GAME_Heretic) - { - type = PClass::FindClass ("BagOfHolding"); - } - else if (gameinfo.gametype == GAME_Strife) - { - type = PClass::FindClass ("AmmoSatchel"); - } - else if (gameinfo.gametype == GAME_Doom) - { - type = PClass::FindClass ("Backpack"); - } - else if (gameinfo.gametype == GAME_Chex) - { - type = PClass::FindClass ("Zorchpack"); - } - else - { // Hexen doesn't have a backpack, foo! - type = NULL; - } + type = PClass::FindClass(gameinfo.backpacktype); if (type != NULL) { GiveSpawner (player, type, 1); @@ -743,13 +726,26 @@ void cht_Give (player_t *player, const char *name, int amount) for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { type = PClass::m_Types[i]; + // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && - type->IsDescendantOf (RUNTIME_CLASS(AWeapon))) + type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && + (type->ActorInfo->GetReplacement() == type->ActorInfo || + type->ActorInfo->GetReplacement()->Class->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) + { - AWeapon *def = (AWeapon*)GetDefaultByType (type); - if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON)) + // Give the weapon only if it belongs to the current game or + // is in a weapon slot. Unfortunately this check only works in + // singleplayer games because the weapon slots are stored locally. + // In multiplayer games all weapons must be given. + if (multiplayer || type->ActorInfo->GameFilter == GAME_Any || + (type->ActorInfo->GameFilter & gameinfo.gametype) || + LocalWeapons.LocateWeapon(type, NULL, NULL)) { - GiveSpawner (player, type, 1); + AWeapon *def = (AWeapon*)GetDefaultByType (type); + if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON)) + { + GiveSpawner (player, type, 1); + } } } } @@ -860,33 +856,17 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "backpack") == 0) { - // Select the correct type of backpack based on the game - if (gameinfo.gametype == GAME_Heretic) + // Take away all types of backpacks the player might own. + for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { - type = PClass::FindClass ("BagOfHolding"); - } - else if (gameinfo.gametype == GAME_Strife) - { - type = PClass::FindClass ("AmmoSatchel"); - } - else if (gameinfo.gametype == GAME_Doom) - { - type = PClass::FindClass ("Backpack"); - } - else if (gameinfo.gametype == GAME_Chex) - { - type = PClass::FindClass ("Zorchpack"); - } - else - { // Hexen doesn't have a backpack, foo! - type = NULL; - } - if (type != NULL) - { - AActor *backpack = player->mo->FindInventory (type); + const PClass *type = PClass::m_Types[i]; - if (backpack) - backpack->Destroy (); + if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) + { + AInventory *pack = player->mo->FindInventory (type); + + if (pack) pack->Destroy(); + } } if (!takeall) diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 381656e0..a7ef11e3 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -596,17 +596,7 @@ static bool FindFreeName (FString &fullname, const char *extension) for (i = 0; i <= 9999; i++) { - const char *gamename; - - switch (gameinfo.gametype) - { - case GAME_Doom: gamename = "Doom_"; break; - case GAME_Heretic: gamename = "Heretic_"; break; - case GAME_Hexen: gamename = "Hexen_"; break; - case GAME_Strife: gamename = "Strife_"; break; - case GAME_Chex: gamename = "Chex_"; break; - default: gamename = ""; break; - } + const char *gamename = GameNames[gameinfo.gametype]; time_t now; tm *tm; @@ -616,18 +606,18 @@ static bool FindFreeName (FString &fullname, const char *extension) if (tm == NULL) { - lbmname.Format ("%sScreenshot_%s%04d.%s", fullname.GetChars(), gamename, i, extension); + lbmname.Format ("%sScreenshot_%s_%04d.%s", fullname.GetChars(), gamename, i, extension); } else if (i == 0) { - lbmname.Format ("%sScreenshot_%s%04d%02d%02d_%02d%02d%02d.%s", fullname.GetChars(), gamename, + lbmname.Format ("%sScreenshot_%s_%04d%02d%02d_%02d%02d%02d.%s", fullname.GetChars(), gamename, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, extension); } else { - lbmname.Format ("%sScreenshot_%s%04d%02d%02d_%02d%02d%02d_%02d.%s", fullname.GetChars(), gamename, + lbmname.Format ("%sScreenshot_%s_%04d%02d%02d_%02d%02d%02d_%02d.%s", fullname.GetChars(), gamename, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, i, extension); diff --git a/src/m_options.cpp b/src/m_options.cpp index c4201947..78a336e1 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1392,7 +1392,7 @@ static BYTE BitTranslate[32]; void M_OptInit (void) { - if (gameinfo.gametype == GAME_Doom) + if (gameinfo.gametype & GAME_DoomChex) { LabelColor = CR_UNTRANSLATED; ValueColor = CR_GRAY; @@ -2999,6 +2999,7 @@ void UpdateJoystickMenu () JoystickItems[line].type = discrete; JoystickItems[line].a.intcvar = cvars[i]; JoystickItems[line].b.numvalues = 6.f; + JoystickItems[line].d.graycheck = NULL; JoystickItems[line].e.values = JoyAxisMapNames; line++; } diff --git a/src/m_png.h b/src/m_png.h index 8dd7c01a..7815369c 100644 --- a/src/m_png.h +++ b/src/m_png.h @@ -35,8 +35,7 @@ #include #include "doomtype.h" - -enum ESSType; +#include "v_video.h" // PNG Writing -------------------------------------------------------------- @@ -116,4 +115,4 @@ class FTexture; FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename); -#endif \ No newline at end of file +#endif diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b64ce92a..9949f7a4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -5230,16 +5230,13 @@ int DLevelScript::RunScript () case PCD_SETACTORSTATE: { const char *statename = FBehavior::StaticLookupString (STACK(2)); - TArray statelist; FState *state; - MakeStateNameList(statename, &statelist); - if (STACK(3) == 0) { if (activator != NULL) { - state = activator->GetClass()->ActorInfo->FindState (statelist.Size(), &statelist[0], !!STACK(1)); + state = activator->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1)); if (state != NULL) { activator->SetState (state); @@ -5259,7 +5256,7 @@ int DLevelScript::RunScript () while ( (actor = iterator.Next ()) ) { - state = actor->GetClass()->ActorInfo->FindState (statelist.Size(), &statelist[0], !!STACK(1)); + state = actor->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1)); if (state != NULL) { actor->SetState (state); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e7d88183..e053efe7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4968,10 +4968,6 @@ int AActor::DoSpecialDamage (AActor *target, int damage) int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype) { - // If the actor does not have a corresponding death state, then it does not take damage. - // Note that DeathState matches every kind of damagetype, so if an actor has that, it can - // be hurt with any type of damage. Exception: Massacre damage always succeeds, because - // it needs to work. FState *death; if (flags5 & MF5_NODAMAGE) @@ -4985,7 +4981,7 @@ int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FN // it needs to work. // Always kill if there is a regular death state or no death states at all. - if (FindState (NAME_Death) != NULL || !HasSpecialDeathStates()) + if (FindState (NAME_Death) != NULL || !HasSpecialDeathStates() || damagetype == NAME_Massacre) { return damage; } @@ -5044,3 +5040,45 @@ void AActor::SetIdle() if (idle == NULL) idle = SpawnState; SetState(idle); } + +FDropItem *AActor::GetDropItems() +{ + unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1; + + if (index >= 0 && index < DropItemList.Size()) + { + return DropItemList[index]; + } + return NULL; +} + +//---------------------------------------------------------------------------- +// +// DropItem handling +// +//---------------------------------------------------------------------------- +FDropItemPtrArray DropItemList; + +void FreeDropItemChain(FDropItem *chain) +{ + while (chain != NULL) + { + FDropItem *next = chain->Next; + delete chain; + chain = next; + } +} + +FDropItemPtrArray::~FDropItemPtrArray() +{ + for (unsigned int i = 0; i < Size(); ++i) + { + FreeDropItemChain ((*this)[i]); + } +} + +int StoreDropItemChain(FDropItem *chain) +{ + return DropItemList.Push (chain) + 1; +} + diff --git a/src/p_states.cpp b/src/p_states.cpp new file mode 100644 index 00000000..0bda6dca --- /dev/null +++ b/src/p_states.cpp @@ -0,0 +1,814 @@ +/* +** p_states.cpp +** state management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** Copyright 2006-2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ +#include "actor.h" +#include "farchive.h" +#include "templates.h" +#include "cmdlib.h" +#include "i_system.h" +#include "thingdef/thingdef.h" + +// Each state is owned by an actor. Actors can own any number of +// states, but a single state cannot be owned by more than one +// actor. States are archived by recording the actor they belong +// to and the index into that actor's list of states. + +// For NULL states, which aren't owned by any actor, the owner +// is recorded as AActor with the following state. AActor should +// never actually have this many states of its own, so this +// is (relatively) safe. + +#define NULL_STATE_INDEX 127 + +TArray JumpParameters; + +//========================================================================== +// +// +//========================================================================== + +FArchive &operator<< (FArchive &arc, FState *&state) +{ + const PClass *info; + + if (arc.IsStoring ()) + { + if (state == NULL) + { + arc.UserWriteClass (RUNTIME_CLASS(AActor)); + arc.WriteCount (NULL_STATE_INDEX); + return arc; + } + + info = FState::StaticFindStateOwner (state); + + if (info != NULL) + { + arc.UserWriteClass (info); + arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates)); + } + else + { + /* this was never working as intended. + I_Error ("Cannot find owner for state %p:\n" + "%s %c%c %3d [%p] -> %p", state, + sprites[state->sprite].name, + state->GetFrame() + 'A', + state->GetFullbright() ? '*' : ' ', + state->GetTics(), + state->GetAction(), + state->GetNextState()); + */ + } + } + else + { + const PClass *info; + DWORD ofs; + + arc.UserReadClass (info); + ofs = arc.ReadCount (); + if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor)) + { + state = NULL; + } + else if (info->ActorInfo != NULL) + { + state = info->ActorInfo->OwnedStates + ofs; + } + else + { + state = NULL; + } + } + return arc; +} + +//========================================================================== +// +// Find the actor that a state belongs to. +// +//========================================================================== + +const PClass *FState::StaticFindStateOwner (const FState *state) +{ + for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i) + { + FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo; + if (state >= info->OwnedStates && + state < info->OwnedStates + info->NumOwnedStates) + { + return info->Class; + } + } + + return NULL; +} + +//========================================================================== +// +// Find the actor that a state belongs to, but restrict the search to +// the specified type and its ancestors. +// +//========================================================================== + +const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info) +{ + while (info != NULL) + { + if (state >= info->OwnedStates && + state < info->OwnedStates + info->NumOwnedStates) + { + return info->Class; + } + info = info->Class->ParentClass->ActorInfo; + } + return NULL; +} + + +//========================================================================== +// +// +//========================================================================== + +FStateLabel *FStateLabels::FindLabel (FName label) +{ + return const_cast(BinarySearch (Labels, NumLabels, &FStateLabel::Label, label)); +} + +void FStateLabels::Destroy () +{ + for(int i=0; iDestroy(); + free (Labels[i].Children); // These are malloc'd, not new'd! + Labels[i].Children=NULL; + } + } +} + + +//=========================================================================== +// +// HasStates +// +// Checks whether the actor has special death states. +// +//=========================================================================== + +bool AActor::HasSpecialDeathStates () const +{ + const FActorInfo *info = GetClass()->ActorInfo; + + if (info->StateList != NULL) + { + FStateLabel *slabel = info->StateList->FindLabel (NAME_Death); + if (slabel != NULL && slabel->Children != NULL) + { + for(int i=0;iChildren->NumLabels;i++) + { + if (slabel->Children->Labels[i].State != NULL) return true; + } + } + } + return false; +} + +//========================================================================== +// +// Resolves a label parameter +// +//========================================================================== + +FState *P_GetState(AActor *self, FState *CallingState, int offset) +{ + if (offset == 0 || offset == INT_MIN) + { + return NULL; // 0 means 'no state' + } + else if (offset>0) + { + if (CallingState == NULL) return NULL; + return CallingState + offset; + } + else if (self != NULL) + { + FName *params = &JumpParameters[-offset]; + + FName classname = params[0]; + const PClass *cls; + cls = classname==NAME_None? RUNTIME_TYPE(self) : PClass::FindClass(classname); + if (cls==NULL || cls->ActorInfo==NULL) return NULL; // shouldn't happen + + int numnames = (int)params[1]; + FState *jumpto = cls->ActorInfo->FindState(numnames, ¶ms[2]); + if (jumpto == NULL) + { + const char *dot=""; + Printf("Jump target '"); + if (classname != NAME_None) Printf("%s::", classname.GetChars()); + for (int i=0;iGetClass()->TypeName.GetChars()); + } + return jumpto; + } + else return NULL; +} + +//========================================================================== +// +// Creates a list of names from a string. Dots are used as separator +// +//========================================================================== + +TArray &MakeStateNameList(const char * fname) +{ + static TArray namelist(3); + FName firstpart, secondpart; + char * c; + + // Handle the old names for the existing death states + char * name = copystring(fname); + firstpart = strtok(name, "."); + switch (firstpart) + { + case NAME_Burn: + firstpart = NAME_Death; + secondpart = NAME_Fire; + break; + case NAME_Ice: + firstpart = NAME_Death; + secondpart = NAME_Ice; + break; + case NAME_Disintegrate: + firstpart = NAME_Death; + secondpart = NAME_Disintegrate; + break; + case NAME_XDeath: + firstpart = NAME_Death; + secondpart = NAME_Extreme; + break; + } + + namelist.Clear(); + namelist.Push(firstpart); + if (secondpart!=NAME_None) namelist.Push(secondpart); + + while ((c = strtok(NULL, "."))!=NULL) + { + FName cc = c; + namelist.Push(cc); + } + delete [] name; + return namelist; +} + +//=========================================================================== +// +// FindState (multiple names version) +// +// Finds a state that matches as many of the supplied names as possible. +// A state with more names than those provided does not match. +// A state with fewer names can match if there are no states with the exact +// same number of names. +// +// The search proceeds like this. For the current class, keeping matching +// names until there are no more. If both the argument list and the state +// are out of names, it's an exact match, so return it. If the state still +// has names, ignore it. If the argument list still has names, remember it. +// +//=========================================================================== +FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const +{ + FStateLabels *labels = StateList; + FState *best = NULL; + + if (labels != NULL) + { + int count = 0; + FStateLabel *slabel = NULL; + FName label; + + // Find the best-matching label for this class. + while (labels != NULL && count < numnames) + { + label = *names++; + slabel = labels->FindLabel (label); + + if (slabel != NULL) + { + count++; + labels = slabel->Children; + best = slabel->State; + } + else + { + break; + } + } + if (count < numnames && exact) return NULL; + } + return best; +} + +//========================================================================== +// +// Finds the state associated with the given string +// +//========================================================================== + +FState *FActorInfo::FindStateByString(const char *name, bool exact) +{ + TArray &namelist = MakeStateNameList(name); + return FindState(namelist.Size(), &namelist[0], exact); +} + + + + +//========================================================================== +// +// Search one list of state definitions for the given name +// +//========================================================================== + +FStateDefine *FStateDefinitions::FindStateLabelInList(TArray & list, FName name, bool create) +{ + for(unsigned i = 0; i &namelist = MakeStateNameList(name); + + TArray * statelist = &StateLabels; + for(unsigned i=0;iChildren; + } + return statedef; +} + +//========================================================================== +// +// Adds a new state tp the curremt list +// +//========================================================================== + +void FStateDefinitions::AddState (const char *statename, FState *state, BYTE defflags) +{ + FStateDefine *std = FindStateAddress(statename); + std->State = state; + std->DefineFlags = defflags; +} + +//========================================================================== +// +// Finds the state associated with the given name +// returns NULL if none found +// +//========================================================================== + +FState * FStateDefinitions::FindState(const char * name) +{ + FStateDefine * statedef=NULL; + + TArray &namelist = MakeStateNameList(name); + + TArray * statelist = &StateLabels; + for(unsigned i=0;iChildren; + } + return statedef? statedef->State : NULL; +} + +//========================================================================== +// +// Creates the final list of states from the state definitions +// +//========================================================================== + +static int STACK_ARGS labelcmp(const void * a, const void * b) +{ + FStateLabel * A = (FStateLabel *)a; + FStateLabel * B = (FStateLabel *)b; + return ((int)A->Label - (int)B->Label); +} + +FStateLabels * FStateDefinitions::CreateStateLabelList(TArray & statelist) +{ + // First delete all empty labels from the list + for (int i=statelist.Size()-1;i>=0;i--) + { + if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0)) + { + statelist.Delete(i); + } + } + + int count=statelist.Size(); + + if (count == 0) return NULL; + + FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); + list->NumLabels = count; + + for (int i=0;iLabels[i].Label = statelist[i].Label; + list->Labels[i].State = statelist[i].State; + list->Labels[i].Children = CreateStateLabelList(statelist[i].Children); + } + qsort(list->Labels, count, sizeof(FStateLabel), labelcmp); + return list; +} + +//=========================================================================== +// +// InstallStates +// +// Creates the actor's state list from the current definition +// +//=========================================================================== + +void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults) +{ + // First ensure we have a valid spawn state. + FState *state = FindState("Spawn"); + + if (state == NULL) + { + // A NULL spawn state will crash the engine so set it to something valid. + AddState("Spawn", GetDefault()->SpawnState); + } + + if (info->StateList != NULL) + { + info->StateList->Destroy(); + M_Free(info->StateList); + } + info->StateList = CreateStateLabelList(StateLabels); + + // Cache these states as member veriables. + defaults->SpawnState = info->FindState(NAME_Spawn); + defaults->SeeState = info->FindState(NAME_See); + // Melee and Missile states are manipulated by the scripted marines so they + // have to be stored locally + defaults->MeleeState = info->FindState(NAME_Melee); + defaults->MissileState = info->FindState(NAME_Missile); +} + +//=========================================================================== +// +// MakeStateDefines +// +// Creates a list of state definitions from an existing actor +// Used by Dehacked to modify an actor's state list +// +//=========================================================================== + +void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray &dest) +{ + dest.Clear(); + if (list != NULL) for(int i=0;iNumLabels;i++) + { + FStateDefine def; + + def.Label = list->Labels[i].Label; + def.State = list->Labels[i].State; + dest.Push(def); + if (list->Labels[i].Children != NULL) + { + MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children); + } + } +} + +void FStateDefinitions::MakeStateDefines(const PClass *cls) +{ + if (cls->ActorInfo && cls->ActorInfo->StateList) + { + MakeStateList(cls->ActorInfo->StateList, StateLabels); + } + else + { + ClearStateLabels(); + } +} + +//=========================================================================== +// +// AddStateDefines +// +// Adds a list of states to the current definitions +// +//=========================================================================== + +void FStateDefinitions::AddStateDefines(const FStateLabels *list) +{ + if (list != NULL) for(int i=0;iNumLabels;i++) + { + if (list->Labels[i].Children == NULL) + { + if (!FindStateLabelInList(StateLabels, list->Labels[i].Label, false)) + { + FStateDefine def; + + def.Label = list->Labels[i].Label; + def.State = list->Labels[i].State; + StateLabels.Push(def); + } + } + } +} + +//========================================================================== +// +// RetargetState(Pointer)s +// +// These functions are used when a goto follows one or more labels. +// Because multiple labels are permitted to occur consecutively with no +// intervening states, it is not enough to remember the last label defined +// and adjust it. So these functions search for all labels that point to +// the current position in the state array and give them a copy of the +// target string instead. +// +//========================================================================== + +void FStateDefinitions::RetargetStatePointers (intptr_t count, const char *target, TArray & statelist) +{ + for(unsigned i = 0;i 0) + { + RetargetStatePointers(count, target, statelist[i].Children); + } + } +} + +void FStateDefinitions::RetargetStates (intptr_t count, const char *target) +{ + RetargetStatePointers(count, target, StateLabels); +} + + +//========================================================================== +// +// ResolveGotoLabel +// +// Resolves any strings being stored in a state's NextState field +// +//========================================================================== + +FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name) +{ + const PClass *type=mytype; + FState *state; + char *namestart = name; + char *label, *offset, *pt; + int v; + + // Check for classname + if ((pt = strstr (name, "::")) != NULL) + { + const char *classname = name; + *pt = '\0'; + name = pt + 2; + + // The classname may either be "Super" to identify this class's immediate + // superclass, or it may be the name of any class that this one derives from. + if (stricmp (classname, "Super") == 0) + { + type = type->ParentClass; + actor = GetDefaultByType (type); + } + else + { + // first check whether a state of the desired name exists + const PClass *stype = PClass::FindClass (classname); + if (stype == NULL) + { + I_Error ("%s is an unknown class.", classname); + } + if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor))) + { + I_Error ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars()); + } + if (!stype->IsAncestorOf (type)) + { + I_Error ("%s is not derived from %s so cannot access its states.", + type->TypeName.GetChars(), stype->TypeName.GetChars()); + } + if (type != stype) + { + type = stype; + actor = GetDefaultByType (type); + } + } + } + label = name; + // Check for offset + offset = NULL; + if ((pt = strchr (name, '+')) != NULL) + { + *pt = '\0'; + offset = pt + 1; + } + v = offset ? strtol (offset, NULL, 0) : 0; + + // Get the state's address. + if (type==mytype) state = FindState (label); + else state = type->ActorInfo->FindStateByString(label, true); + + if (state != NULL) + { + state += v; + } + else if (v != 0) + { + I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars()); + } + delete[] namestart; // free the allocated string buffer + return state; +} + +//========================================================================== +// +// FixStatePointers +// +// Fixes an actor's default state pointers. +// +//========================================================================== + +void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray & list) +{ + for(unsigned i=0;i= 1 && v < 0x10000) + { + list[i].State = actor->OwnedStates + v - 1; + } + if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children); + } +} + +//========================================================================== +// +// ResolveGotoLabels +// +// Resolves an actor's state pointers that were specified as jumps. +// +//========================================================================== + +void FStateDefinitions::ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray & list) +{ + for(unsigned i=0;iClass, (char *)list[i].State); + list[i].DefineFlags = SDF_STATE; + } + if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, defaults, list[i].Children); + } +} + + +//========================================================================== +// +// FinishStates +// copies a state block and fixes all state links using the current list of labels +// +//========================================================================== + +int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults, TArray &StateArray) +{ + static int c=0; + int count = StateArray.Size(); + + if (count > 0) + { + FState *realstates = new FState[count]; + int i; + int currange; + + memcpy(realstates, &StateArray[0], count*sizeof(FState)); + actor->OwnedStates = realstates; + actor->NumOwnedStates = count; + + // adjust the state pointers + // In the case new states are added these must be adjusted, too! + FixStatePointers (actor, StateLabels); + + for(i = currange = 0; i < count; i++) + { + // resolve labels and jumps + switch(realstates[i].DefineFlags) + { + case SDF_STOP: // stop + realstates[i].NextState = NULL; + break; + + case SDF_WAIT: // wait + realstates[i].NextState = &realstates[i]; + break; + + case SDF_NEXT: // next + realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]); + break; + + case SDF_INDEX: // loop + realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1]; + break; + + case SDF_LABEL: + realstates[i].NextState = ResolveGotoLabel (defaults, actor->Class, (char *)realstates[i].NextState); + break; + } + } + } + + // Fix state pointers that are gotos + ResolveGotoLabels (actor, defaults, StateLabels); + + return count; +} + diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index c1b3bb35..b60fe0bd 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -80,47 +80,15 @@ void P_SpawnTeleportFog(fixed_t x, fixed_t y, fixed_t z, int spawnid) { fog = SpawnableThings[spawnid]; } - /* if (fog != NULL && level.info->teleportfog != NAME_None) - { - fog = PClass::FindClass(level.info->teleportfog); - } - */ if (fog == NULL) { AActor *mo = Spawn ("TeleportFog", x, y, z + TELEFOGHEIGHT, ALLOW_REPLACE); - if (mo != NULL) - { - FState * state = NULL; - - switch(gameinfo.gametype) - { - default: - case GAME_Doom: - state = mo->FindState(NAME_Doom); - break; - - case GAME_Heretic: - state = mo->FindState(NAME_Heretic); - break; - - case GAME_Hexen: - state = mo->FindState(NAME_Hexen); - break; - - case GAME_Strife: - state = mo->FindState(NAME_Strife); - break; - } - if (state == NULL) state = mo->SpawnState; // allow execution of code pointers in the spawn state - - mo->SetState(state); - } } else { AActor *mo = Spawn (fog, x, y, z, ALLOW_REPLACE); - if (mo != NULL) mo->SetState(mo->SpawnState); + if (mo != NULL) S_Sound(mo, CHAN_BODY, mo->SeeSound, 1.f, ATTN_NORM); } } diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 7cfc8ddc..da34393b 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1124,6 +1124,7 @@ struct UDMFParser { default: // Shh, GCC case GAME_Doom: + case GAME_Chex: namespace_bits = Dm; P_LoadTranslator("xlat/doom_base.txt"); break; diff --git a/src/p_user.cpp b/src/p_user.cpp index 1ed9270a..49a2e716 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -227,8 +227,8 @@ player_t::player_t() momy(0), centering(0), turnticks(0), - oldbuttons(0), attackdown(0), + oldbuttons(0), health(0), inventorytics(0), CurrentPlayerClass(0), @@ -988,7 +988,7 @@ void APlayerPawn::GiveDefaultInventory () AddInventory (barmor); // Now add the items from the DECORATE definition - FDropItem *di = GetDropItems(RUNTIME_TYPE(this)); + FDropItem *di = GetDropItems(); while (di) { diff --git a/src/r_data.cpp b/src/r_data.cpp index f382b9a2..b999b641 100644 --- a/src/r_data.cpp +++ b/src/r_data.cpp @@ -265,9 +265,7 @@ DWORD R_BlendForColormap (DWORD map) void R_InitData () { - FTexture::InitGrayMap(); StartScreen->Progress(); - TexMan.Init(); V_InitFonts(); StartScreen->Progress(); diff --git a/src/r_main.h b/src/r_main.h index 049f1213..515f7717 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -54,8 +54,8 @@ extern bool LocalKeyboardTurner; // [RH] The local player used the keyboard t extern float WallTMapScale; extern float WallTMapScale2; -extern int viewwidth; -extern int viewheight; +extern "C" int viewwidth; +extern "C" int viewheight; extern int viewwindowx; extern int viewwindowy; diff --git a/src/r_translate.cpp b/src/r_translate.cpp index f6ec46c2..4a048128 100644 --- a/src/r_translate.cpp +++ b/src/r_translate.cpp @@ -43,6 +43,9 @@ #include "colormatcher.h" #include "d_netinf.h" #include "v_palette.h" +#include "sc_man.h" +#include "doomerrors.h" +#include "i_system.h" #include "gi.h" #include "stats.h" @@ -82,11 +85,23 @@ FRemapTable::FRemapTable(int count) // the caller will do that next, if only by calling MakeIdentity(). } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + FRemapTable::~FRemapTable() { Free(); } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void FRemapTable::Alloc(int count) { Remap = (BYTE *)M_Malloc(count*sizeof(*Remap) + count*sizeof(*Palette)); @@ -96,6 +111,12 @@ void FRemapTable::Alloc(int count) NumEntries = count; } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void FRemapTable::Free() { KillNative(); @@ -108,6 +129,12 @@ void FRemapTable::Free() } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + FRemapTable::FRemapTable(const FRemapTable &o) { Remap = NULL; @@ -116,6 +143,12 @@ FRemapTable::FRemapTable(const FRemapTable &o) operator= (o); } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + FRemapTable &FRemapTable::operator=(const FRemapTable &o) { if (&o == this) @@ -134,6 +167,12 @@ FRemapTable &FRemapTable::operator=(const FRemapTable &o) return *this; } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + bool FRemapTable::operator==(const FRemapTable &o) { // Two translations are identical when they have the same amount of colors @@ -143,6 +182,12 @@ bool FRemapTable::operator==(const FRemapTable &o) return !memcmp(o.Palette, Palette, NumEntries * sizeof(*Palette)); } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void FRemapTable::Serialize(FArchive &arc) { int n = NumEntries; @@ -167,6 +212,11 @@ void FRemapTable::Serialize(FArchive &arc) } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- void FRemapTable::MakeIdentity() { @@ -186,6 +236,12 @@ void FRemapTable::MakeIdentity() } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + bool FRemapTable::IsIdentity() const { for (int j = 0; j < 256; ++j) @@ -198,6 +254,12 @@ bool FRemapTable::IsIdentity() const return true; } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void FRemapTable::KillNative() { if (Native != NULL) @@ -207,6 +269,12 @@ void FRemapTable::KillNative() } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void FRemapTable::UpdateNative() { if (Native != NULL) @@ -215,6 +283,12 @@ void FRemapTable::UpdateNative() } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + FNativePalette *FRemapTable::GetNative() { if (Native == NULL) @@ -224,6 +298,12 @@ FNativePalette *FRemapTable::GetNative() return Native; } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) { fixed_t palcol, palstep; @@ -250,6 +330,12 @@ void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2) } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, int _r2, int _g2, int _b2) { fixed_t r1 = _r1 << FRACBITS; @@ -304,6 +390,160 @@ void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, in } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void FRemapTable::AddToTranslation(const char * range) +{ + int start,end; + FScanner sc; + + sc.OpenMem("translation", range, int(strlen(range))); + sc.SetCMode(true); + + try + { + sc.MustGetToken(TK_IntConst); + start = sc.Number; + sc.MustGetToken(':'); + sc.MustGetToken(TK_IntConst); + end = sc.Number; + sc.MustGetToken('='); + if (!sc.CheckToken('[')) + { + int pal1,pal2; + + sc.MustGetToken(TK_IntConst); + pal1 = sc.Number; + sc.MustGetToken(':'); + sc.MustGetToken(TK_IntConst); + pal2 = sc.Number; + AddIndexRange(start, end, pal1, pal2); + } + else + { + // translation using RGB values + int r1,g1,b1,r2,g2,b2; + + sc.MustGetToken(TK_IntConst); + r1 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + g1 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + b1 = sc.Number; + sc.MustGetToken(']'); + sc.MustGetToken(':'); + sc.MustGetToken('['); + + sc.MustGetToken(TK_IntConst); + r2 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + g2 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + b2 = sc.Number; + sc.MustGetToken(']'); + + AddColorRange(start, end, r1, g1, b1, r2, g2, b2); + } + } + catch (CRecoverableError &err) + { + Printf("Error in translation '%s':\n%s\n", err.GetMessage()); + } +} + +//---------------------------------------------------------------------------- +// +// Stores a copy of this translation in the DECORATE translation table +// +//---------------------------------------------------------------------------- + +int FRemapTable::StoreTranslation() +{ + unsigned int i; + + for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++) + { + if (*this == *translationtables[TRANSLATION_Decorate][i]) + { + // A duplicate of this translation already exists + return TRANSLATION(TRANSLATION_Decorate, i); + } + } + if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS) + { + I_Error("Too many DECORATE translations"); + } + FRemapTable *newtrans = new FRemapTable; + *newtrans = *this; + i = translationtables[TRANSLATION_Decorate].Push(newtrans); + return TRANSLATION(TRANSLATION_Decorate, i); +} + + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +TArray BloodTranslationColors; + +int CreateBloodTranslation(PalEntry color) +{ + unsigned int i; + + if (BloodTranslationColors.Size() == 0) + { + // Don't use the first slot. + translationtables[TRANSLATION_Blood].Push(NULL); + BloodTranslationColors.Push(0); + } + + for (i = 1; i < BloodTranslationColors.Size(); i++) + { + if (color.r == BloodTranslationColors[i].r && + color.g == BloodTranslationColors[i].g && + color.b == BloodTranslationColors[i].b) + { + // A duplicate of this translation already exists + return i; + } + } + if (BloodTranslationColors.Size() >= MAX_DECORATE_TRANSLATIONS) + { + I_Error("Too many blood colors"); + } + FRemapTable *trans = new FRemapTable; + for (i = 0; i < 256; i++) + { + int bright = MAX(MAX(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b); + PalEntry pe = PalEntry(color.r*bright/255, color.g*bright/255, color.b*bright/255); + int entry = ColorMatcher.Pick(pe.r, pe.g, pe.b); + + trans->Palette[i] = pe; + trans->Remap[i] = entry; + } + translationtables[TRANSLATION_Blood].Push(trans); + return BloodTranslationColors.Push(color); +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- FRemapTable *TranslationToTable(int translation) { @@ -323,6 +563,12 @@ FRemapTable *TranslationToTable(int translation) return slots->operator[](index); } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + static void PushIdentityTable(int slot) { FRemapTable *table = new FRemapTable; @@ -330,11 +576,14 @@ static void PushIdentityTable(int slot) translationtables[slot].Push(table); } +//---------------------------------------------------------------------------- // // R_InitTranslationTables // Creates the translation tables to map the green color ramp to gray, // brown, red. Assumes a given structure of the PLAYPAL. // +//---------------------------------------------------------------------------- + void R_InitTranslationTables () { int i, j; @@ -508,6 +757,12 @@ void R_InitTranslationTables () } } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void R_DeinitTranslationTables() { for (int i = 0; i < NUM_TRANSLATION_TABLES; ++i) @@ -523,8 +778,13 @@ void R_DeinitTranslationTables() } } +//---------------------------------------------------------------------------- +// // [RH] Create a player's translation table based on a given mid-range color. // [GRB] Split to 2 functions (because of player setup menu) +// +//---------------------------------------------------------------------------- + static void SetRemap(FRemapTable *table, int i, float r, float g, float b) { int ir = clamp (int(r * 255.f), 0, 255); @@ -534,6 +794,12 @@ static void SetRemap(FRemapTable *table, int i, float r, float g, float b) table->Palette[i] = PalEntry(255, ir, ig, ib); } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable) { int i; @@ -675,6 +941,12 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s table->UpdateNative(); } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void R_BuildPlayerTranslation (int player) { float h, s, v; @@ -687,6 +959,12 @@ void R_BuildPlayerTranslation (int player) translationtables[TRANSLATION_PlayersExtra][player]); } +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table) { float h, s, v; @@ -696,3 +974,4 @@ void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table) R_CreatePlayerTranslation (h, s, v, skin, table, NULL); } + diff --git a/src/r_translate.h b/src/r_translate.h index 84e481b0..098edb69 100644 --- a/src/r_translate.h +++ b/src/r_translate.h @@ -38,6 +38,8 @@ struct FRemapTable void Serialize(FArchive &ar); void AddIndexRange(int start, int end, int pal1, int pal2); void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2); + void AddToTranslation(const char * range); + int StoreTranslation(); BYTE *Remap; // For the software renderer PalEntry *Palette; // The ideal palette this maps to @@ -99,6 +101,10 @@ void R_BuildPlayerTranslation (int player); extern const BYTE IcePalette[16][3]; +extern TArray BloodTranslationColors; + +int CreateBloodTranslation(PalEntry color); + #endif // __R_TRANSLATE_H diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 3bc4e993..4117930b 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -342,7 +342,10 @@ int S_PickReplacement (int refid) unsigned int S_GetMSLength(FSoundID sound) { - if (sound < 0 || sound >= S_sfx.Size()) return 0; + if ((unsigned int)sound >= S_sfx.Size()) + { + return 0; + } sfxinfo_t *sfx = &S_sfx[sound]; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 31f2ca25..96f5e807 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1478,6 +1478,7 @@ void S_RelinkSound (AActor *from, AActor *to) } else { + chan->Actor = NULL; S_StopChannel(chan); } } @@ -1778,7 +1779,7 @@ static void S_SetListener(SoundListener &listener, AActor *listenactor) // //========================================================================== -float S_GetRolloff(FRolloffInfo *rolloff, float distance) +float S_GetRolloff(FRolloffInfo *rolloff, float distance, bool logarithmic) { if (rolloff == NULL) { @@ -1803,13 +1804,27 @@ float S_GetRolloff(FRolloffInfo *rolloff, float distance) { volume = S_SoundCurve[int(S_SoundCurveSize * (1 - volume))] / 127.f; } - if (rolloff->RolloffType == ROLLOFF_Linear) + if (logarithmic) { - return volume; + if (rolloff->RolloffType == ROLLOFF_Linear) + { + return volume; + } + else + { + return float((powf(10.f, volume) - 1.) / 9.); + } } else { - return (powf(10.f, volume) - 1.f) / 9.f; + if (rolloff->RolloffType == ROLLOFF_Linear) + { + return float(log10(9. * volume + 1.)); + } + else + { + return volume; + } } } diff --git a/src/sc_man.cpp b/src/sc_man.cpp index cf0622a7..6a228cf8 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -192,7 +192,7 @@ void FScanner::OpenFile (const char *name) // //========================================================================== -void FScanner::OpenMem (const char *name, char *buffer, int size) +void FScanner::OpenMem (const char *name, const char *buffer, int size) { Close (); ScriptBuffer = FString(buffer, size); diff --git a/src/sc_man.h b/src/sc_man.h index 81061b9c..fba8275f 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -20,7 +20,7 @@ public: void Open(const char *lumpname); void OpenFile(const char *filename); - void OpenMem(const char *name, char *buffer, int size); + void OpenMem(const char *name, const char *buffer, int size); void OpenLumpNum(int lump); void Close(); diff --git a/src/sdl/i_input.cpp b/src/sdl/i_input.cpp index a22adafc..2f8ba9c6 100644 --- a/src/sdl/i_input.cpp +++ b/src/sdl/i_input.cpp @@ -9,6 +9,7 @@ #include "v_video.h" #include "d_main.h" +#include "d_event.h" #include "d_gui.h" #include "c_console.h" #include "c_cvars.h" diff --git a/src/sdl/i_main.cpp b/src/sdl/i_main.cpp index f49c9bbd..5650c078 100644 --- a/src/sdl/i_main.cpp +++ b/src/sdl/i_main.cpp @@ -54,6 +54,11 @@ #include "errors.h" #include "version.h" #include "w_wad.h" +#include "g_level.h" +#include "r_state.h" +#include "cmdlib.h" +#include "r_main.h" +#include "doomstat.h" // MACROS ------------------------------------------------------------------ @@ -180,7 +185,7 @@ static int DoomSpecificInfo (char *buffer, char *end) if (!viewactive) { - buffer += snprintf (buffer+p, size-p, "\n\nView not active."); + p += snprintf (buffer+p, size-p, "\n\nView not active."); } else { diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 9fb86414..78318b10 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -40,6 +40,7 @@ #include "SDL.h" #include "doomtype.h" +#include "doomstat.h" #include "version.h" #include "doomdef.h" #include "cmdlib.h" @@ -61,6 +62,9 @@ #include "hardware.h" #include "gameconfigfile.h" +#include "m_fixed.h" +#include "g_level.h" + EXTERN_CVAR (String, language) extern "C" diff --git a/src/sdl/sdlvideo.cpp b/src/sdl/sdlvideo.cpp index 7227ccef..b028aafa 100644 --- a/src/sdl/sdlvideo.cpp +++ b/src/sdl/sdlvideo.cpp @@ -9,7 +9,7 @@ #include "v_video.h" #include "v_pfx.h" #include "stats.h" - +#include "v_palette.h" #include "sdlvideo.h" #include diff --git a/src/sdl/st_start.cpp b/src/sdl/st_start.cpp index 7cb64ca9..81e50d23 100644 --- a/src/sdl/st_start.cpp +++ b/src/sdl/st_start.cpp @@ -42,6 +42,7 @@ #include "st_start.h" #include "doomdef.h" #include "i_system.h" +#include "c_cvars.h" // MACROS ------------------------------------------------------------------ diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index dc29295e..9946edaf 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -44,6 +44,7 @@ extern HWND Window; #define FALSE 0 #define TRUE 1 #endif +#include #include "templates.h" #include "fmodsound.h" @@ -2039,11 +2040,11 @@ float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNEL *channel, float if (GRolloff != NULL) { - return S_GetRolloff(GRolloff, distance * GDistScale); + return S_GetRolloff(GRolloff, distance * GDistScale, true); } else if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL) { - return S_GetRolloff(&schan->Rolloff, distance * schan->DistanceScale); + return S_GetRolloff(&schan->Rolloff, distance * schan->DistanceScale, true); } else { diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index d7c07129..6844a754 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -141,7 +141,7 @@ void I_InitSound (); void I_ShutdownSound (); void S_ChannelEnded(FISoundChannel *schan); -float S_GetRolloff(FRolloffInfo *rolloff, float distance); +float S_GetRolloff(FRolloffInfo *rolloff, float distance, bool logarithmic); FISoundChannel *S_GetChannel(void *syschan); extern ReverbContainer *DefaultEnvironments[26]; diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index d3872932..fd46dcdf 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -33,6 +33,7 @@ // HEADER FILES ------------------------------------------------------------ +#include #include "i_musicinterns.h" #include "templates.h" #include "doomdef.h" diff --git a/src/st_stuff.cpp b/src/st_stuff.cpp index af728787..f0ee5ba8 100644 --- a/src/st_stuff.cpp +++ b/src/st_stuff.cpp @@ -346,7 +346,7 @@ bool ST_Responder (event_t *ev) static int counts[] = { countof(DoomCheats), countof(HereticCheats), countof(HexenCheats), countof(StrifeCheats), countof(ChexCheats), countof(SpecialCheats) }; - for (int i=0; iAddIndexRange(start, end, pal1, pal2); - } - else - { - // translation using RGB values - int r1,g1,b1,r2,g2,b2; - - r1=strtol(range, &range, 10); - if (!Check(range, ',')) return; - g1=strtol(range, &range, 10); - if (!Check(range, ',')) return; - b1=strtol(range, &range, 10); - if (!Check(range, ']')) return; - if (!Check(range, ':')) return; - if (!Check(range, '[')) return; - r2=strtol(range, &range, 10); - if (!Check(range, ',')) return; - g2=strtol(range, &range, 10); - if (!Check(range, ',')) return; - b2=strtol(range, &range, 10); - if (!Check(range, ']')) return; - - part.Translation->AddColorRange(start, end, r1, g1, b1, r2, g2, b2); - } + part.Translation->AddToTranslation(sc.String); } while (sc.CheckString(",")); } @@ -1161,6 +1117,11 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part) } } +//========================================================================== +// +// Constructor for text based multipatch definitions +// +//========================================================================== FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype) : Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false) diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 69828593..6ea67e54 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -330,33 +330,6 @@ void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, b } } -//========================================================================== -// -// FTextureManager :: AddPatch -// -//========================================================================== - -FTextureID FTextureManager::AddPatch (const char *patchname, int namespc, bool tryany) -{ - if (patchname == NULL) - { - return FTextureID(-1); - } - FTextureID texnum = CheckForTexture (patchname, FTexture::TEX_MiscPatch, tryany); - - if (texnum.Exists()) - { - return texnum; - } - int lumpnum = Wads.CheckNumForName (patchname, namespc==ns_global? ns_graphics:namespc); - if (lumpnum < 0) - { - return FTextureID(-1); - } - - return CreateTexture (lumpnum, FTexture::TEX_MiscPatch); -} - //========================================================================== // // FTextureManager :: AddGroup @@ -440,11 +413,6 @@ void FTextureManager::AddHiresTextures (int wadnum) { int amount = ListTextures(name, tlist); if (amount == 0) - { - FTextureID oldtex = AddPatch(name); - if (oldtex.Exists()) tlist.Push(oldtex); - } - if (tlist.Size() == 0) { // A texture with this name does not yet exist FTexture * newtex = FTexture::CreateTexture (firsttx, FTexture::TEX_Any); @@ -519,11 +487,6 @@ void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) tlist.Clear(); int amount = ListTextures(sc.String, tlist); - if (amount == 0) - { - FTextureID oldtex = AddPatch(sc.String); - if (oldtex.Exists()) tlist.Push(FTextureID(oldtex)); - } FName texname = sc.String; sc.MustGetString(); @@ -624,6 +587,10 @@ void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) { ParseXTexture(sc, FTexture::TEX_Flat); } + else if (sc.Compare("graphic")) + { + ParseXTexture(sc, FTexture::TEX_MiscPatch); + } } } } @@ -843,6 +810,8 @@ void FTextureManager::SortTexturesByType(int start, int end) void FTextureManager::Init() { + FTexture::InitGrayMap(); + int wadcnt = Wads.GetNumWads(); for(int i = 0; i< wadcnt; i++) { diff --git a/src/textures/warptexture.cpp b/src/textures/warptexture.cpp index 82ad00d3..6e30e036 100644 --- a/src/textures/warptexture.cpp +++ b/src/textures/warptexture.cpp @@ -41,7 +41,7 @@ FWarpTexture::FWarpTexture (FTexture *source) -: SourcePic (source), Pixels (0), Spans (0), GenTime (0), Speed (1.f) +: GenTime (0), SourcePic (source), Pixels (0), Spans (0), Speed (1.f) { CopySize(source); bNoDecals = source->bNoDecals; diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 8e25f764..6772e291 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -103,8 +103,8 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- -static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, - TArray &states, FExtraInfo &extra, EDefinitionType def, FScanner &sc); +static void ParseInsideDecoration (Baggage &bag, AActor *defaults, + FExtraInfo &extra, EDefinitionType def, FScanner &sc); static void ParseSpriteFrames (FActorInfo *info, TArray &states, FScanner &sc); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -123,97 +123,6 @@ static const char *RenderStyles[] = NULL }; -static const char *FlagNames1[] = -{ - "*", - "Solid", - "*", - "NoSector", - - "NoBlockmap", - "*", - "*", - "*", - - "SpawnCeiling", - "NoGravity", - "*", - "*", - - "*", - "*", - "*", - "*", - - "*", - "*", - "Shadow", - "NoBlood", - - "*", - "*", - "*", - "CountItem", - NULL -}; - -static const char *FlagNames2[] = -{ - "LowGravity", - "WindThrust", - "*", - "*", - - "*", - "FloorClip", - "SpawnFloat", - "NoTeleport", - - "Ripper", - "Pushable", - "SlidesOnWalls", - "*", - - "CanPass", - "CannotPush", - "ThruGhost", - "*", - - "FireDamage", - "NoDamageThrust", - "Telestomp", - "FloatBob", - - "*", - "ActivateImpact", - "CanPushWalls", - "ActivateMCross", - - "ActivatePCross", - "*", - "*", - "*", - - "*", - "*", - "*", - "Reflective", - NULL -}; - -static const char *FlagNames3[] = -{ - "FloorHugger", - "CeilingHugger", - "*", - "*", - - "*", - "*", - "DontSplash", - NULL -}; - // CODE -------------------------------------------------------------------- //========================================================================== @@ -226,11 +135,11 @@ static const char *FlagNames3[] = void ParseOldDecoration(FScanner &sc, EDefinitionType def) { - TArray states; + Baggage bag; FExtraInfo extra; + FActorInfo *info; PClass *type; PClass *parent; - FActorInfo *info; FName typeName; if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory); @@ -239,76 +148,17 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) sc.MustGetString(); typeName = FName(sc.String); type = parent->CreateDerivedClass (typeName, parent->Size); - info = type->ActorInfo; - info->GameFilter = 0x80; - MakeStateDefines(parent->ActorInfo->StateList); + ResetBaggage(&bag, parent); + info = bag.Info = type->ActorInfo; - // There isn't a single WAD out there which uses game filters with old style - // decorations so this may as well be disabled. Without this option is is much - // easier to detect incorrect declarations -#if 0 - sc.MustGetString (); - while (!sc.Compare ("{")) - { - if (sc.Compare ("Doom")) - { - info->GameFilter |= GAME_Doom; - } - else if (sc.Compare ("Heretic")) - { - info->GameFilter |= GAME_Heretic; - } - else if (sc.Compare ("Hexen")) - { - info->GameFilter |= GAME_Hexen; - } - else if (sc.Compare ("Raven")) - { - info->GameFilter |= GAME_Raven; - } - else if (sc.Compare ("Strife")) - { - info->GameFilter |= GAME_Strife; - } - else if (sc.Compare ("Any")) - { - info->GameFilter = GAME_Any; - } - else - { - if (def != DEF_Decoration || info->GameFilter != 0x80) - { - sc.ScriptError ("Unknown game type %s in %s", sc.String, typeName.GetChars()); - } - else - { - // If this is a regular decoration (without preceding keyword) and no game - // filters defined this is more likely a general syntax error so output a - // more meaningful message. - sc.ScriptError ("Syntax error: Unknown identifier '%s'", typeName.GetChars()); - } - } - sc.MustGetString (); - } - if (info->GameFilter == 0x80) - { - info->GameFilter = GAME_Any; - } - else - { - info->GameFilter &= ~0x80; - } -#else info->GameFilter = GAME_Any; sc.MustGetStringName("{"); -#endif - states.Clear (); memset (&extra, 0, sizeof(extra)); - ParseInsideDecoration (info, (AActor *)(type->Defaults), states, extra, def, sc); + ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc); - info->NumOwnedStates = states.Size(); - if (info->NumOwnedStates == 0) + bag.Info->NumOwnedStates = bag.StateArray.Size(); + if (bag.Info->NumOwnedStates == 0) { sc.ScriptError ("%s does not define any animation frames", typeName.GetChars() ); } @@ -328,13 +178,13 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) if (extra.IceDeathEnd != 0) { // Make a copy of the final frozen frame for A_FreezeDeathChunks - FState icecopy = states[extra.IceDeathEnd-1]; - states.Push (icecopy); + FState icecopy = bag.StateArray[extra.IceDeathEnd-1]; + bag.StateArray.Push (icecopy); info->NumOwnedStates += 1; } info->OwnedStates = new FState[info->NumOwnedStates]; - memcpy (info->OwnedStates, &states[0], info->NumOwnedStates * sizeof(info->OwnedStates[0])); + memcpy (info->OwnedStates, &bag.StateArray[0], info->NumOwnedStates * sizeof(info->OwnedStates[0])); if (info->NumOwnedStates == 1) { info->OwnedStates->Tics = -1; @@ -395,7 +245,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height; info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight); } - AddState("Death", &info->OwnedStates[extra.DeathStart]); + bag.statedef.AddState("Death", &info->OwnedStates[extra.DeathStart]); } // Burn states are the same as death states, except they can optionally terminate @@ -433,7 +283,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight); - AddState("Burn", &info->OwnedStates[extra.FireDeathStart]); + bag.statedef.AddState("Burn", &info->OwnedStates[extra.FireDeathStart]); } // Ice states are similar to burn and death, except their final frame enters @@ -454,11 +304,11 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) info->OwnedStates[i].Tics = 1; info->OwnedStates[i].Misc1 = 0; info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")); - AddState("Ice", &info->OwnedStates[extra.IceDeathStart]); + bag.statedef.AddState("Ice", &info->OwnedStates[extra.IceDeathStart]); } else if (extra.bGenericIceDeath) { - AddState("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath)); + bag.statedef.AddState("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath)); } } if (def == DEF_BreakableDecoration) @@ -469,8 +319,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) { ((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE; } - AddState("Spawn", &info->OwnedStates[extra.SpawnStart]); - InstallStates (info, ((AActor *)(type->Defaults))); + bag.statedef.AddState("Spawn", &info->OwnedStates[extra.SpawnStart]); + bag.statedef.InstallStates (info, ((AActor *)(type->Defaults))); } //========================================================================== @@ -481,8 +331,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) // //========================================================================== -static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, - TArray &states, FExtraInfo &extra, EDefinitionType def, FScanner &sc) +static void ParseInsideDecoration (Baggage &bag, AActor *defaults, + FExtraInfo &extra, EDefinitionType def, FScanner &sc) { AFakeInventory *const inv = static_cast(defaults); char sprite[5] = "TNT1"; @@ -497,7 +347,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, { sc.ScriptError ("DoomEdNum must be in the range [-1,32767]"); } - info->DoomEdNum = (SWORD)sc.Number; + bag.Info->DoomEdNum = (SWORD)sc.Number; } else if (sc.Compare ("SpawnNum")) { @@ -506,7 +356,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, { sc.ScriptError ("SpawnNum must be in the range [0,255]"); } - info->SpawnID = (BYTE)sc.Number; + bag.Info->SpawnID = (BYTE)sc.Number; } else if (sc.Compare ("Sprite") || ( (def == DEF_BreakableDecoration || def == DEF_Projectile) && @@ -531,31 +381,31 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, else if (sc.Compare ("Frames")) { sc.MustGetString (); - extra.SpawnStart = states.Size(); - ParseSpriteFrames (info, states, sc); - extra.SpawnEnd = states.Size(); + extra.SpawnStart = bag.StateArray.Size(); + ParseSpriteFrames (bag.Info, bag.StateArray, sc); + extra.SpawnEnd = bag.StateArray.Size(); } else if ((def == DEF_BreakableDecoration || def == DEF_Projectile) && sc.Compare ("DeathFrames")) { sc.MustGetString (); - extra.DeathStart = states.Size(); - ParseSpriteFrames (info, states, sc); - extra.DeathEnd = states.Size(); + extra.DeathStart = bag.StateArray.Size(); + ParseSpriteFrames (bag.Info, bag.StateArray, sc); + extra.DeathEnd = bag.StateArray.Size(); } else if (def == DEF_BreakableDecoration && sc.Compare ("IceDeathFrames")) { sc.MustGetString (); - extra.IceDeathStart = states.Size(); - ParseSpriteFrames (info, states, sc); - extra.IceDeathEnd = states.Size(); + extra.IceDeathStart = bag.StateArray.Size(); + ParseSpriteFrames (bag.Info, bag.StateArray, sc); + extra.IceDeathEnd = bag.StateArray.Size(); } else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathFrames")) { sc.MustGetString (); - extra.FireDeathStart = states.Size(); - ParseSpriteFrames (info, states, sc); - extra.FireDeathEnd = states.Size(); + extra.FireDeathStart = bag.StateArray.Size(); + ParseSpriteFrames (bag.Info, bag.StateArray, sc); + extra.FireDeathEnd = bag.StateArray.Size(); } else if (def == DEF_BreakableDecoration && sc.Compare ("GenericIceDeath")) { @@ -612,18 +462,18 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius")) { sc.MustGetNumber (); - info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number); + bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number); extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage")) { sc.MustGetNumber (); - info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number); + bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number); extra.bExplosive = true; } else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter")) { - info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true); + bag.Info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true); } else if (def == DEF_Projectile && sc.Compare ("Damage")) { @@ -708,7 +558,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, else if (def == DEF_Pickup && sc.Compare ("PickupMessage")) { sc.MustGetString (); - info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String); + bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String); } else if (def == DEF_Pickup && sc.Compare ("Respawns")) { @@ -724,23 +574,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, } else if (sc.String[0] != '*') { - int bit = sc.MatchString (FlagNames1); - if (bit != -1) - { - defaults->flags |= 1 << bit; - } - else if ((bit = sc.MatchString (FlagNames2)) != -1) - { - defaults->flags2 |= 1 << bit; - } - else if ((bit = sc.MatchString (FlagNames3)) != -1) - { - defaults->flags3 |= 1 << bit; - } - else - { - sc.ScriptError (NULL); - } + HandleActorFlag(sc, bag, sc.String, NULL, '+'); } else { @@ -752,16 +586,16 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, unsigned int i; int spr = GetSpriteIndex(sprite); - for (i = 0; i < states.Size(); ++i) + for (i = 0; i < bag.StateArray.Size(); ++i) { - states[i].sprite = spr; + bag.StateArray[i].sprite = spr; } if (extra.DeathSprite[0] && extra.DeathEnd != 0) { int spr = GetSpriteIndex(extra.DeathSprite); for (i = extra.DeathStart; i < extra.DeathEnd; ++i) { - states[i].sprite = spr; + bag.StateArray[i].sprite = spr; } } } diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 42b82c10..3a634b9b 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -68,82 +68,6 @@ const PClass *QuestItemClasses[31]; - - -//========================================================================== -// -// ActorConstDef -// -// Parses a constant definition. -// -//========================================================================== - -void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) -{ - // Read the type and make sure it's int. - // (Maybe there will be other types later.) - sc.MustGetToken(TK_Int); - sc.MustGetToken(TK_Identifier); - FName symname = sc.String; - sc.MustGetToken('='); - int expr = ParseExpression (sc, false, cls); - sc.MustGetToken(';'); - - int val = EvalExpressionI (expr, NULL, cls); - PSymbolConst *sym = new PSymbolConst; - sym->SymbolName = symname; - sym->SymbolType = SYM_Const; - sym->Value = val; - if (symt->AddSymbol (sym) == NULL) - { - delete sym; - sc.ScriptError ("'%s' is already defined in class '%s'.", - symname.GetChars(), cls->TypeName.GetChars()); - } -} - -//========================================================================== -// -// ActorEnumDef -// -// Parses an enum definition. -// -//========================================================================== - -void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) -{ - int currvalue = 0; - - sc.MustGetToken('{'); - while (!sc.CheckToken('}')) - { - sc.MustGetToken(TK_Identifier); - FName symname = sc.String; - if (sc.CheckToken('=')) - { - int expr = ParseExpression(sc, false, cls); - currvalue = EvalExpressionI(expr, NULL, cls); - } - PSymbolConst *sym = new PSymbolConst; - sym->SymbolName = symname; - sym->SymbolType = SYM_Const; - sym->Value = currvalue; - if (symt->AddSymbol (sym) == NULL) - { - delete sym; - sc.ScriptError ("'%s' is already defined in class '%s'.", - symname.GetChars(), cls->TypeName.GetChars()); - } - // This allows a comma after the last value but doesn't enforce it. - if (sc.CheckToken('}')) break; - sc.MustGetToken(','); - currvalue++; - } - sc.MustGetToken(';'); -} - - - //========================================================================== // // ParseParameter @@ -245,8 +169,8 @@ int ParseParameter(FScanner &sc, PClass *cls, char type, bool constant) // be checked here. JumpParameters.Push(NAME_None); } - TArray names; - MakeStateNameList(statestring, &names); + + TArray &names = MakeStateNameList(statestring); if (stype != NULL) { @@ -409,7 +333,8 @@ static void ParseActionDef (FScanner &sc, PClass *cls) if (hasdefaults) { sym->defaultparameterindex = StateParameters.Size(); - for(int i = 0; i < DefaultParams.Size(); i++) StateParameters.Push(DefaultParams[i]); + for(unsigned int i = 0; i < DefaultParams.Size(); i++) + StateParameters.Push(DefaultParams[i]); } else { @@ -428,123 +353,63 @@ static void ParseActionDef (FScanner &sc, PClass *cls) // Starts a new actor definition // //========================================================================== -static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *bag) +static FActorInfo *CreateNewActor(FName typeName, FName parentName, FName replaceName, + int DoomEdNum, bool native) { - FName typeName; const PClass *replacee = NULL; - int DoomEdNum = -1; PClass *ti = NULL; FActorInfo *info = NULL; - // Get actor name - sc.MustGetString(); - - char *colon = strchr(sc.String, ':'); - if (colon != NULL) - { - *colon++ = 0; - } - - /* - if (PClass::FindClass (sc.String) != NULL) - { - sc.ScriptError ("Actor %s is already defined.", sc.String); - } - */ - - typeName = sc.String; - PClass *parent = RUNTIME_CLASS(AActor); - if (parentc) - { - *parentc = NULL; - - // Do some tweaking so that a definition like 'Actor:Parent' which is read as a single token is recognized as well - // without having resort to C-mode (which disallows periods in actor names.) - if (colon == NULL) - { - sc.MustGetString (); - if (sc.String[0]==':') - { - colon = sc.String + 1; - } - } - - if (colon != NULL) - { - if (colon[0] == 0) - { - sc.MustGetString (); - colon = sc.String; - } - } - - if (colon != NULL) - { - parent = const_cast (PClass::FindClass (colon)); - if (parent == NULL) - { - sc.ScriptError ("Parent type '%s' not found", colon); - } - else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor))) - { - sc.ScriptError ("Parent type '%s' is not an actor", colon); - } - else if (parent->ActorInfo == NULL) - { - sc.ScriptError ("uninitialized parent type '%s'", colon); - } - else - { - *parentc = parent->ActorInfo; - } + if (parentName != NAME_None) + { + parent = const_cast (PClass::FindClass (parentName)); + + if (parent == NULL) + { + I_Error ("Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars()); + } + else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor))) + { + I_Error ("Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); + } + else if (parent->ActorInfo == NULL) + { + I_Error ("uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars()); } - else sc.UnGet(); } // Check for "replaces" - if (sc.CheckString ("replaces")) + if (replaceName != NAME_None) { - // Get actor name - sc.MustGetString (); - replacee = PClass::FindClass (sc.String); + replacee = PClass::FindClass (replaceName); if (replacee == NULL) { - sc.ScriptError ("Replaced type '%s' not found", sc.String); + I_Error ("Replaced type '%s' not found in %s", replaceName.GetChars(), typeName.GetChars()); } else if (replacee->ActorInfo == NULL) { - sc.ScriptError ("Replaced type '%s' is not an actor", sc.String); + I_Error ("Replaced type '%s' is not an actor in %s", replaceName.GetChars(), typeName.GetChars()); } } - // Now, after the actor names have been parsed, it is time to switch to C-mode - // for the rest of the actor definition. - sc.SetCMode (true); - if (sc.CheckNumber()) - { - if (sc.Number>=-1 && sc.Number<32768) DoomEdNum = sc.Number; - else sc.ScriptError ("DoomEdNum must be in the range [-1,32767]"); - } - - if (sc.CheckString("native")) + if (native) { ti = (PClass*)PClass::FindClass(typeName); if (ti == NULL) { - sc.ScriptError("Unknown native class '%s'", typeName.GetChars()); + I_Error("Unknown native class '%s'", typeName.GetChars()); } else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass()) { - sc.ScriptError("Native class '%s' does not inherit from '%s'", - typeName.GetChars(),parent->TypeName.GetChars()); + I_Error("Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars()); } else if (ti->ActorInfo != NULL) { - sc.ScriptMessage("Redefinition of internal class '%s'", typeName.GetChars()); + I_Error("Redefinition of internal class '%s'", typeName.GetChars()); } ti->InitializeActorInfo(); info = ti->ActorInfo; @@ -555,11 +420,6 @@ static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *b info = ti->ActorInfo; } - MakeStateDefines(parent->ActorInfo->StateList); - - ResetBaggage (bag); - bag->Info = info; - info->DoomEdNum = -1; if (parent->ActorInfo->DamageFactors != NULL) { @@ -580,10 +440,98 @@ static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *b ti->ActorInfo->Replacee = replacee->ActorInfo; } - info->DoomEdNum = DoomEdNum; + if (DoomEdNum > 0) info->DoomEdNum = DoomEdNum; return info; } +//========================================================================== +// +// Starts a new actor definition +// +//========================================================================== +static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag) +{ + FName typeName; + FName parentName; + FName replaceName; + bool native = false; + int DoomEdNum = -1; + + // Get actor name + sc.MustGetString(); + + char *colon = strchr(sc.String, ':'); + if (colon != NULL) + { + *colon++ = 0; + } + + typeName = sc.String; + + // Do some tweaking so that a definition like 'Actor:Parent' which is read as a single token is recognized as well + // without having resort to C-mode (which disallows periods in actor names.) + if (colon == NULL) + { + sc.MustGetString (); + if (sc.String[0]==':') + { + colon = sc.String + 1; + } + } + + if (colon != NULL) + { + if (colon[0] == 0) + { + sc.MustGetString (); + colon = sc.String; + } + } + + if (colon == NULL) + { + sc.UnGet(); + } + + parentName = colon; + + // Check for "replaces" + if (sc.CheckString ("replaces")) + { + // Get actor name + sc.MustGetString (); + replaceName = sc.String; + } + + // Now, after the actor names have been parsed, it is time to switch to C-mode + // for the rest of the actor definition. + sc.SetCMode (true); + if (sc.CheckNumber()) + { + if (sc.Number>=-1 && sc.Number<32768) DoomEdNum = sc.Number; + else sc.ScriptError ("DoomEdNum must be in the range [-1,32767]"); + } + + if (sc.CheckString("native")) + { + native = true; + } + + try + { + FActorInfo *info = CreateNewActor(typeName, parentName, replaceName, DoomEdNum, native); + ResetBaggage (bag, info->Class->ParentClass); + bag->Info = info; + bag->Lumpnum = sc.LumpNum; + return info; + } + catch (CRecoverableError &err) + { + sc.ScriptError("%s", err.GetMessage()); + return NULL; + } +} + //========================================================================== // // Reads an actor definition @@ -594,64 +542,41 @@ void ParseActor(FScanner &sc) FActorInfo * info=NULL; Baggage bag; - try + info = ParseActorHeader(sc, &bag); + sc.MustGetToken('{'); + while (sc.MustGetAnyToken(), sc.TokenType != '}') { - FActorInfo * parent; - - info = CreateNewActor(sc, &parent, &bag); - sc.MustGetToken('{'); - while (sc.MustGetAnyToken(), sc.TokenType != '}') + switch (sc.TokenType) { - switch (sc.TokenType) - { - case TK_Action: - ParseActionDef (sc, info->Class); - break; + case TK_Action: + ParseActionDef (sc, info->Class); + break; - case TK_Const: - ParseConstant (sc, &info->Class->Symbols, info->Class); - break; + case TK_Const: + ParseConstant (sc, &info->Class->Symbols, info->Class); + break; - case TK_Enum: - ParseEnum (sc, &info->Class->Symbols, info->Class); - break; + case TK_Enum: + ParseEnum (sc, &info->Class->Symbols, info->Class); + break; - case TK_Identifier: - // other identifier related checks here - case TK_Projectile: // special case: both keyword and property name - ParseActorProperty(sc, bag); - break; + case TK_Identifier: + // other identifier related checks here + case TK_Projectile: // special case: both keyword and property name + ParseActorProperty(sc, bag); + break; - case '+': - case '-': - ParseActorFlag(sc, bag, sc.TokenType); - break; - - default: - sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars()); - break; - } + case '+': + case '-': + ParseActorFlag(sc, bag, sc.TokenType); + break; + default: + sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars()); + break; } - - FinishActor(sc, info, bag); } - - catch(CRecoverableError & e) - { - throw e; - } - // I think this is better than a crash log. -#ifndef _DEBUG - catch (...) - { - if (info) - sc.ScriptError("Unexpected error during parsing of actor %s", info->Class->TypeName.GetChars()); - else - sc.ScriptError("Unexpected error during parsing of actor definitions"); - } -#endif - + FinishActor(sc, info, bag); sc.SetCMode (false); } @@ -663,10 +588,33 @@ void ParseActor(FScanner &sc) // //========================================================================== +static int ResolvePointer(const PClass **pPtr, const PClass *owner, const PClass *destclass, const char *description) +{ + fuglyname v; + + v = *pPtr; + if (v != NAME_None && v.IsValidName()) + { + *pPtr = PClass::FindClass(v); + if (!*pPtr) + { + Printf("Unknown %s '%s' in '%s'\n", description, v.GetChars(), owner->TypeName.GetChars()); + return 1; + } + else if (!(*pPtr)->IsDescendantOf(destclass)) + { + *pPtr = NULL; + Printf("Invalid %s '%s' in '%s'\n", description, v.GetChars(), owner->TypeName.GetChars()); + return 1; + } + } + return 0; +} + + void FinishThingdef() { unsigned int i; - bool isRuntimeActor=false; int errorcount=0; for (i = 0;i < PClass::m_Types.Size(); i++) @@ -676,13 +624,6 @@ void FinishThingdef() // Skip non-actors if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue; - // Everything coming after the first runtime actor is also a runtime actor - // so this check is sufficient - if (ti == PClass::m_RuntimeActors[0]) - { - isRuntimeActor=true; - } - AActor *def = GetDefaultByType(ti); if (!def) @@ -701,21 +642,7 @@ void FinishThingdef() if (ti->IsDescendantOf(RUNTIME_CLASS(AInventory))) { AInventory * defaults=(AInventory *)def; - fuglyname v; - - v = defaults->PickupFlash; - if (v != NAME_None && v.IsValidName()) - { - defaults->PickupFlash = PClass::FindClass(v); - if (isRuntimeActor) - { - if (!defaults->PickupFlash) - { - Printf("Unknown pickup flash '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - } - } + errorcount += ResolvePointer(&defaults->PickupFlash, ti, RUNTIME_CLASS(AActor), "pickup flash"); } if (ti->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)) && ti != RUNTIME_CLASS(APowerupGiver)) @@ -757,122 +684,47 @@ void FinishThingdef() if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { AWeapon * defaults=(AWeapon *)def; - fuglyname v; + errorcount += ResolvePointer(&defaults->AmmoType1, ti, RUNTIME_CLASS(AAmmo), "ammo type"); + errorcount += ResolvePointer(&defaults->AmmoType2, ti, RUNTIME_CLASS(AAmmo), "ammo type"); + errorcount += ResolvePointer(&defaults->SisterWeaponType, ti, RUNTIME_CLASS(AWeapon), "sister weapon type"); - v = defaults->AmmoType1; - if (v != NAME_None && v.IsValidName()) + FState * ready = ti->ActorInfo->FindState(NAME_Ready); + FState * select = ti->ActorInfo->FindState(NAME_Select); + FState * deselect = ti->ActorInfo->FindState(NAME_Deselect); + FState * fire = ti->ActorInfo->FindState(NAME_Fire); + + // Consider any weapon without any valid state abstract and don't output a warning + // This is for creating base classes for weapon groups that only set up some properties. + if (ready || select || deselect || fire) { - defaults->AmmoType1 = PClass::FindClass(v); - if (isRuntimeActor) + // Do some consistency checks. If these states are undefined the weapon cannot work! + if (!ready) { - if (!defaults->AmmoType1) - { - Printf("Unknown ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - else if (defaults->AmmoType1->ParentClass != RUNTIME_CLASS(AAmmo)) - { - Printf("Invalid ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } + Printf("Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars()); + errorcount++; + } + if (!select) + { + Printf("Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars()); + errorcount++; + } + if (!deselect) + { + Printf("Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars()); + errorcount++; + } + if (!fire) + { + Printf("Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars()); + errorcount++; } } - - v = defaults->AmmoType2; - if (v != NAME_None && v.IsValidName()) - { - defaults->AmmoType2 = PClass::FindClass(v); - if (isRuntimeActor) - { - if (!defaults->AmmoType2) - { - Printf("Unknown ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - else if (defaults->AmmoType2->ParentClass != RUNTIME_CLASS(AAmmo)) - { - Printf("Invalid ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - } - } - - v = defaults->SisterWeaponType; - if (v != NAME_None && v.IsValidName()) - { - defaults->SisterWeaponType = PClass::FindClass(v); - if (isRuntimeActor) - { - if (!defaults->SisterWeaponType) - { - Printf("Unknown sister weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - else if (!defaults->SisterWeaponType->IsDescendantOf(RUNTIME_CLASS(AWeapon))) - { - Printf("Invalid sister weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - } - } - - if (isRuntimeActor) - { - FState * ready = ti->ActorInfo->FindState(NAME_Ready); - FState * select = ti->ActorInfo->FindState(NAME_Select); - FState * deselect = ti->ActorInfo->FindState(NAME_Deselect); - FState * fire = ti->ActorInfo->FindState(NAME_Fire); - - // Consider any weapon without any valid state abstract and don't output a warning - // This is for creating base classes for weapon groups that only set up some properties. - if (ready || select || deselect || fire) - { - // Do some consistency checks. If these states are undefined the weapon cannot work! - if (!ready) - { - Printf("Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars()); - errorcount++; - } - if (!select) - { - Printf("Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars()); - errorcount++; - } - if (!deselect) - { - Printf("Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars()); - errorcount++; - } - if (!fire) - { - Printf("Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars()); - errorcount++; - } - } - } - } // same for the weapon type of weapon pieces. else if (ti->IsDescendantOf(RUNTIME_CLASS(AWeaponPiece))) { AWeaponPiece * defaults=(AWeaponPiece *)def; - fuglyname v; - - v = defaults->WeaponClass; - if (v != NAME_None && v.IsValidName()) - { - defaults->WeaponClass = PClass::FindClass(v); - if (!defaults->WeaponClass) - { - Printf("Unknown weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - else if (!defaults->WeaponClass->IsDescendantOf(RUNTIME_CLASS(AWeapon))) - { - Printf("Invalid weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars()); - errorcount++; - } - } + errorcount += ResolvePointer(&defaults->WeaponClass, ti, RUNTIME_CLASS(AWeapon), "weapon type"); } } if (errorcount > 0) diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index fc14386c..958f1419 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -5,6 +5,24 @@ class FScanner; + +//========================================================================== +// +// A flag descriptor +// +//========================================================================== + +struct FFlagDef +{ + int flagbit; + const char *name; + int structoffset; +}; + +FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2); +void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index); + + //========================================================================== // // This class is for storing a name inside a const PClass* field without @@ -32,25 +50,72 @@ public: //========================================================================== // -// Dropitem list +// State parser // //========================================================================== -struct FDropItem +extern TArray StateParameters; +extern TArray JumpParameters; + +struct FStateLabels; + +enum EStateDefineFlags { - FName Name; - int probability; - int amount; - FDropItem * Next; + SDF_NEXT = 0, + SDF_STATE = 1, + SDF_STOP = 2, + SDF_WAIT = 3, + SDF_LABEL = 4, + SDF_INDEX = 5, }; -FDropItem *GetDropItems(const PClass * cls); +struct FStateDefine +{ + FName Label; + TArray Children; + FState *State; + BYTE DefineFlags; +}; + +class FStateDefinitions +{ + TArray StateLabels; + + static FStateDefine *FindStateLabelInList(TArray &list, FName name, bool create); + static FStateLabels *CreateStateLabelList(TArray &statelist); + static void MakeStateList(const FStateLabels *list, TArray &dest); + static void RetargetStatePointers (intptr_t count, const char *target, TArray & statelist); + FStateDefine *FindStateAddress(const char *name); + FState *FindState(const char *name); + + FState *ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name); + static void FixStatePointers (FActorInfo *actor, TArray & list); + void ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray & list); + +public: + + + void ClearStateLabels() + { + StateLabels.Clear(); + } + + void AddState (const char * statename, FState * state, BYTE defflags = SDF_STATE); + void InstallStates(FActorInfo *info, AActor *defaults); + int FinishStates (FActorInfo *actor, AActor *defaults, TArray &StateArray); + + void MakeStateDefines(const PClass *cls); + void AddStateDefines(const FStateLabels *list); + void RetargetStates (intptr_t count, const char *target); + +}; //========================================================================== // // Extra info maintained while defining an actor. // //========================================================================== +struct FDropItem; struct Baggage { @@ -58,19 +123,23 @@ struct Baggage bool DropItemSet; bool StateSet; int CurrentState; + int Lumpnum; + FStateDefinitions statedef; + TArray StateArray; FDropItem *DropItemList; }; -inline void ResetBaggage (Baggage *bag) +inline void ResetBaggage (Baggage *bag, const PClass *stateclass) { bag->DropItemList = NULL; bag->DropItemSet = false; bag->CurrentState = 0; bag->StateSet = false; + bag->StateArray.Clear(); + bag->statedef.MakeStateDefines(stateclass); } - //========================================================================== // // Action function lookup @@ -87,25 +156,8 @@ AFuncDesc * FindFunction(const char * string); -//========================================================================== -// -// State parser -// -//========================================================================== - -extern TArray StateParameters; -extern TArray JumpParameters; - -void ClearStateLabels(); -void AddState (const char * statename, FState * state); -FState * FindState(AActor * actor, const PClass * type, const char * name); -void InstallStates(FActorInfo *info, AActor *defaults); -void MakeStateDefines(const FStateLabels *list); -void AddStateDefines(const FStateLabels *list); FState *P_GetState(AActor *self, FState *CallingState, int offset); -int FinishStates (FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag); int ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag); -FState *CheckState(FScanner &sc, PClass *type); //========================================================================== @@ -115,6 +167,7 @@ FState *CheckState(FScanner &sc, PClass *type); //========================================================================== void ParseActorProperty(FScanner &sc, Baggage &bag); +void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); void ParseActorFlag (FScanner &sc, Baggage &bag, int mod); void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag); @@ -156,20 +209,91 @@ enum EDefinitionType #if defined(_MSC_VER) #pragma data_seg(".areg$u") +#pragma data_seg(".greg$u") #pragma data_seg() #define MSVC_ASEG __declspec(allocate(".areg$u")) #define GCC_ASEG +#define MSVC_PSEG __declspec(allocate(".greg$u")) +#define GCC_PSEG #else #define MSVC_ASEG #define GCC_ASEG __attribute__((section(AREG_SECTION))) +#define MSVC_PSEG +#define GCC_PSEG __attribute__((section(GREG_SECTION))) #endif +union FPropParam +{ + int i; + float f; + const char *s; +}; + +typedef void (*PropHandler)(AActor *defaults, Baggage &bag, FPropParam *params); + +enum ECategory +{ + CAT_PROPERTY, // Inheritable property + CAT_INFO // non-inheritable info (spawn ID, Doomednum, game filter, conversation ID) +}; + +struct FPropertyInfo +{ + const char *name; + const char *params; + const PClass *cls; + PropHandler Handler; + int category; +}; + +FPropertyInfo *FindProperty(const char * string); +int MatchString (const char *in, const char **strings); + + +#define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \ + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \ + static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ + { #name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ + MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \ + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params) + +#define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \ + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \ + static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ +{ #prefix"."#name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ + MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \ + static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params) + + +#define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY) +#define DEFINE_INFO_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_INFO) + +#define DEFINE_CLASS_PROPERTY(name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(clas, name, paramlist, clas, CAT_PROPERTY) +#define DEFINE_CLASS_PROPERTY_PREFIX(prefix, name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, CAT_PROPERTY) + +#define PROP_PARM_COUNT (params[0].i) + +#define PROP_STRING_PARM(var, no) \ + const char *var = params[(no)+1].s; + +#define PROP_INT_PARM(var, no) \ + int var = params[(no)+1].i; + +#define PROP_FLOAT_PARM(var, no) \ + float var = params[(no)+1].f; + +#define PROP_FIXED_PARM(var, no) \ + fixed_t var = fixed_t(params[(no)+1].f * FRACUNIT); + +#define PROP_COLOR_PARM(var, no) \ + int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s); + struct StateCallData { - FState * State; - AActor * Item; + FState *State; + AActor *Item; bool Result; }; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 7a9799d1..85bd5c8a 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -354,51 +354,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack) } -//========================================================================== -// -// Resolves a label parameter -// -//========================================================================== - -FState *P_GetState(AActor *self, FState *CallingState, int offset) -{ - if (offset == 0 || offset == INT_MIN) - { - return NULL; // 0 means 'no state' - } - else if (offset>0) - { - if (CallingState == NULL) return NULL; - return CallingState + offset; - } - else if (self != NULL) - { - offset = -offset; - - FName classname = JumpParameters[offset]; - const PClass *cls; - cls = classname==NAME_None? RUNTIME_TYPE(self) : PClass::FindClass(classname); - if (cls==NULL || cls->ActorInfo==NULL) return NULL; // shouldn't happen - - int numnames = (int)JumpParameters[offset+1]; - FState *jumpto = cls->ActorInfo->FindState(numnames, &JumpParameters[offset+2]); - if (jumpto == NULL) - { - const char *dot=""; - Printf("Jump target '"); - if (classname != NAME_None) Printf("%s::", classname.GetChars()); - for (int i=0;iGetClass()->TypeName.GetChars()); - } - return jumpto; - } - else return NULL; -} - //========================================================================== // // Do the state jump @@ -2236,3 +2191,49 @@ DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter) AWeapon *weapon = self->player->ReadyWeapon; weapon->ReloadCounter = 0; } + +//=========================================================================== +// +// A_ChangeFlag +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_STRING(flagname, 0); + ACTION_PARAM_BOOL(expression, 1); + + const char *dot = strchr (flagname, '.'); + FFlagDef *fd; + const PClass *cls = self->GetClass(); + + if (dot != NULL) + { + FString part1(flagname, dot-flagname); + fd = FindFlag (cls, part1, dot+1); + } + else + { + fd = FindFlag (cls, flagname, NULL); + } + + if (fd != NULL) + { + if (fd->structoffset == -1) + { + HandleDeprecatedFlags(self, cls->ActorInfo, expression, fd->flagbit); + } + else + { + int * flagp = (int*) (((char*)self) + fd->structoffset); + + if (expression) *flagp |= fd->flagbit; + else *flagp &= ~fd->flagbit; + } + } + else + { + Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars()); + } +} + diff --git a/src/thingdef/thingdef_main.cpp b/src/thingdef/thingdef_main.cpp index 4525ff73..85513e15 100644 --- a/src/thingdef/thingdef_main.cpp +++ b/src/thingdef/thingdef_main.cpp @@ -47,9 +47,6 @@ // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void ParseActor(FScanner &sc); -void ParseClass(FScanner &sc); -void ParseGlobalConst(FScanner &sc); -void ParseGlobalEnum(FScanner &sc); void FinishThingdef(); void ParseOldDecoration(FScanner &sc, EDefinitionType def); diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp new file mode 100644 index 00000000..f06b8d80 --- /dev/null +++ b/src/thingdef/thingdef_parse.cpp @@ -0,0 +1,559 @@ +/* +** thingdef-parse.cpp +** +** Actor definitions - all parser related code +** +**--------------------------------------------------------------------------- +** Copyright 2002-2007 Christoph Oelckers +** Copyright 2004-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be +** covered by the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "doomtype.h" +#include "actor.h" +#include "a_pickups.h" +#include "sc_man.h" +#include "thingdef.h" +#include "a_morph.h" +#include "cmdlib.h" +#include "templates.h" +#include "v_palette.h" +#include "doomerrors.h" +#include "autosegs.h" +#include "i_system.h" + + +//========================================================================== +// +// ActorConstDef +// +// Parses a constant definition. +// +//========================================================================== + +void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls) +{ + // Read the type and make sure it's int. + // (Maybe there will be other types later.) + sc.MustGetToken(TK_Int); + sc.MustGetToken(TK_Identifier); + FName symname = sc.String; + sc.MustGetToken('='); + int expr = ParseExpression (sc, false, cls); + sc.MustGetToken(';'); + + int val = EvalExpressionI (expr, NULL, cls); + PSymbolConst *sym = new PSymbolConst; + sym->SymbolName = symname; + sym->SymbolType = SYM_Const; + sym->Value = val; + if (symt->AddSymbol (sym) == NULL) + { + delete sym; + sc.ScriptError ("'%s' is already defined in class '%s'.", + symname.GetChars(), cls->TypeName.GetChars()); + } +} + +//========================================================================== +// +// ActorEnumDef +// +// Parses an enum definition. +// +//========================================================================== + +void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls) +{ + int currvalue = 0; + + sc.MustGetToken('{'); + while (!sc.CheckToken('}')) + { + sc.MustGetToken(TK_Identifier); + FName symname = sc.String; + if (sc.CheckToken('=')) + { + int expr = ParseExpression(sc, false, cls); + currvalue = EvalExpressionI(expr, NULL, cls); + } + PSymbolConst *sym = new PSymbolConst; + sym->SymbolName = symname; + sym->SymbolType = SYM_Const; + sym->Value = currvalue; + if (symt->AddSymbol (sym) == NULL) + { + delete sym; + sc.ScriptError ("'%s' is already defined in class '%s'.", + symname.GetChars(), cls->TypeName.GetChars()); + } + // This allows a comma after the last value but doesn't enforce it. + if (sc.CheckToken('}')) break; + sc.MustGetToken(','); + currvalue++; + } + sc.MustGetToken(';'); +} + +//========================================================================== +// +// Parses a flag name +// +//========================================================================== +void ParseActorFlag (FScanner &sc, Baggage &bag, int mod) +{ + sc.MustGetString (); + + FString part1 = sc.String; + const char *part2 = NULL; + if (sc.CheckString (".")) + { + sc.MustGetString (); + part2 = sc.String; + } + HandleActorFlag(sc, bag, part1, part2, mod); +} + +//========================================================================== +// +// Processes a flag. Also used by olddecorations.cpp +// +//========================================================================== +void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod) +{ + FFlagDef *fd; + + if ( (fd = FindFlag (bag.Info->Class, part1, part2)) ) + { + AActor *defaults = (AActor*)bag.Info->Class->Defaults; + if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property + { + HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit); + } + else + { + DWORD * flagvar = (DWORD*) ((char*)defaults + fd->structoffset); + if (mod == '+') + { + *flagvar |= fd->flagbit; + } + else + { + *flagvar &= ~fd->flagbit; + } + } + } + else + { + if (part2 == NULL) + { + sc.ScriptError("\"%s\" is an unknown flag\n", part1); + } + else + { + sc.ScriptError("\"%s.%s\" is an unknown flag\n", part1, part2); + } + } +} + +//========================================================================== +// +// [MH] parses a morph style expression +// +//========================================================================== + +static int ParseMorphStyle (FScanner &sc) +{ + static const char * morphstyles[]={ + "MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE", + "MRF_FAILNOTELEFRAG", "MRF_FAILNOLAUGH", "MRF_WHENINVULNERABLE", "MRF_LOSEACTUALWEAPON", + "MRF_NEWTIDBEHAVIOUR", "MRF_UNDOBYDEATH", "MRF_UNDOBYDEATHFORCED", "MRF_UNDOBYDEATHSAVES", NULL}; + + static const int morphstyle_values[]={ + MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE, + MORPH_FAILNOTELEFRAG, MORPH_FAILNOLAUGH, MORPH_WHENINVULNERABLE, MORPH_LOSEACTUALWEAPON, + MORPH_NEWTIDBEHAVIOUR, MORPH_UNDOBYDEATH, MORPH_UNDOBYDEATHFORCED, MORPH_UNDOBYDEATHSAVES}; + + // May be given flags by number... + if (sc.CheckNumber()) + { + sc.MustGetNumber(); + return sc.Number; + } + + // ... else should be flags by name. + // NOTE: Later this should be removed and a normal expression used. + // The current DECORATE parser can't handle this though. + bool gotparen = sc.CheckString("("); + int style = 0; + do + { + sc.MustGetString(); + style |= morphstyle_values[sc.MustMatchString(morphstyles)]; + } + while (sc.CheckString("|")); + if (gotparen) + { + sc.MustGetStringName(")"); + } + + return style; +} + +//========================================================================== +// +// For getting a state address from the parent +// No attempts have been made to add new functionality here +// This is strictly for keeping compatibility with old WADs! +// +//========================================================================== + +FState *CheckState(FScanner &sc, PClass *type) +{ + int v=0; + + if (sc.GetString() && !sc.Crossed) + { + if (sc.Compare("0")) return NULL; + else if (sc.Compare("PARENT")) + { + FState * state = NULL; + sc.MustGetString(); + + FActorInfo * info = type->ParentClass->ActorInfo; + + if (info != NULL) + { + state = info->FindState(FName(sc.String)); + } + + if (sc.GetString ()) + { + if (sc.Compare ("+")) + { + sc.MustGetNumber (); + v = sc.Number; + } + else + { + sc.UnGet (); + } + } + + if (state == NULL && v==0) return NULL; + + if (v!=0 && state==NULL) + { + sc.ScriptError("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars()); + return NULL; + } + state+=v; + return state; + } + else sc.ScriptError("Invalid state assignment"); + } + return NULL; +} + +//========================================================================== +// +// Parses an actor property's parameters and calls the handler +// +//========================================================================== + +bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defaults, Baggage &bag) +{ + static TArray params; + static TArray strings; + + params.Clear(); + strings.Clear(); + params.Reserve(1); + params[0].i = 0; + if (prop->params[0] != '0') + { + const char * p = prop->params; + bool nocomma; + bool optcomma; + while (*p) + { + FPropParam conv; + FPropParam pref; + + nocomma = false; + conv.s = NULL; + pref.i = -1; + switch ((*p) & 223) + { + case 'X': // Expression in parentheses or number. + + if (sc.CheckString ("(")) + { + conv.i = 0x40000000 | ParseExpression (sc, false, bag.Info->Class); + params.Push(conv); + sc.MustGetStringName(")"); + break; + } + // fall through + + case 'I': + sc.MustGetNumber(); + conv.i = sc.Number; + break; + + case 'F': + sc.MustGetFloat(); + conv.f = sc.Float; + break; + + case 'Z': // an optional string. Does not allow any numerical value. + if (sc.CheckFloat()) + { + nocomma = true; + sc.UnGet(); + break; + } + // fall through + + case 'S': + case 'T': + sc.MustGetString(); + conv.s = strings[strings.Reserve(1)] = sc.String; + break; + + case 'C': + if (sc.CheckNumber ()) + { + int R, G, B; + R = clamp (sc.Number, 0, 255); + sc.CheckString (","); + sc.MustGetNumber (); + G = clamp (sc.Number, 0, 255); + sc.CheckString (","); + sc.MustGetNumber (); + B = clamp (sc.Number, 0, 255); + conv.i = MAKERGB(R, G, B); + pref.i = 0; + } + else + { + sc.MustGetString (); + conv.s = strings[strings.Reserve(1)] = sc.String; + pref.i = 1; + } + break; + + case 'M': // special case. An expression-aware parser will not need this. + conv.i = ParseMorphStyle(sc); + break; + + case 'L': // Either a number or a list of strings + if (sc.CheckNumber()) + { + pref.i = 0; + conv.i = sc.Number; + } + else + { + pref.i = 1; + params.Push(pref); + params[0].i++; + + do + { + sc.MustGetString (); + conv.s = strings[strings.Reserve(1)] = sc.String; + params.Push(conv); + params[0].i++; + } + while (sc.CheckString(",")); + goto endofparm; + } + break; + + default: + assert(false); + break; + + } + if (pref.i != -1) + { + params.Push(pref); + params[0].i++; + } + params.Push(conv); + params[0].i++; + endofparm: + p++; + // Hack for some properties that have to allow comma less + // parameter lists for compatibility. + if ((optcomma = (*p == '_'))) + p++; + + if (nocomma) + { + continue; + } + else if (*p == 0) + { + break; + } + else if (*p >= 'a') + { + if (!sc.CheckString(",")) + { + if (optcomma) + { + if (!sc.CheckFloat()) break; + else sc.UnGet(); + } + else break; + } + } + else + { + if (!optcomma) sc.MustGetStringName(","); + else sc.CheckString(","); + } + } + } + // call the handler + try + { + prop->Handler(defaults, bag, ¶ms[0]); + } + catch (CRecoverableError &error) + { + sc.ScriptError("%s", error.GetMessage()); + } + + return true; +} + +//========================================================================== +// +// Parses an actor property +// +//========================================================================== + +void ParseActorProperty(FScanner &sc, Baggage &bag) +{ + static const char *statenames[] = { + "Spawn", "See", "Melee", "Missile", "Pain", "Death", "XDeath", "Burn", + "Ice", "Raise", "Crash", "Crush", "Wound", "Disintegrate", "Heal", NULL }; + + strlwr (sc.String); + + FString propname = sc.String; + + if (sc.CheckString (".")) + { + sc.MustGetString (); + propname += '.'; + strlwr (sc.String); + propname += sc.String; + } + else + { + sc.UnGet (); + } + + FPropertyInfo *prop = FindProperty(propname); + + if (prop != NULL) + { + if (bag.Info->Class->IsDescendantOf(prop->cls)) + { + ParsePropertyParams(sc, prop, (AActor *)bag.Info->Class->Defaults, bag); + } + else + { + sc.ScriptError("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->cls->TypeName.GetChars()); + } + } + else if (!propname.CompareNoCase("States")) + { + if (!bag.StateSet) ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag); + else sc.ScriptError("Multiple state declarations not allowed"); + bag.StateSet=true; + } + else if (MatchString(propname, statenames) != -1) + { + bag.statedef.AddState(propname, CheckState (sc, bag.Info->Class)); + } + else + { + sc.ScriptError("\"%s\" is an unknown actor property\n", propname.GetChars()); + } +} + + +//========================================================================== +// +// Finalizes an actor definition +// +//========================================================================== + +void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag) +{ + AActor *defaults = (AActor*)info->Class->Defaults; + + try + { + bag.statedef.FinishStates (info, defaults, bag.StateArray); + } + catch (CRecoverableError &err) + { + sc.ScriptError(err.GetMessage()); + } + bag.statedef.InstallStates (info, defaults); + bag.StateArray.Clear (); + if (bag.DropItemSet) + { + if (bag.DropItemList == NULL) + { + if (info->Class->Meta.GetMetaInt (ACMETA_DropItems) != 0) + { + info->Class->Meta.SetMetaInt (ACMETA_DropItems, 0); + } + } + else + { + info->Class->Meta.SetMetaInt (ACMETA_DropItems, + StoreDropItemChain(bag.DropItemList)); + } + } + if (info->Class->IsDescendantOf (RUNTIME_CLASS(AInventory))) + { + defaults->flags |= MF_SPECIAL; + } +} diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 5c355f80..ea12c553 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1,7 +1,7 @@ /* ** thingdef-properties.cpp ** -** Actor definitions - properties and flags parser +** Actor definitions - properties and flags handling ** **--------------------------------------------------------------------------- ** Copyright 2002-2007 Christoph Oelckers @@ -41,7 +41,6 @@ #include "gi.h" #include "actor.h" #include "info.h" -#include "sc_man.h" #include "tarray.h" #include "w_wad.h" #include "templates.h" @@ -68,6 +67,7 @@ #include "r_translate.h" #include "a_morph.h" #include "colormatcher.h" +#include "autosegs.h" //========================================================================== // @@ -81,13 +81,6 @@ #define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1 } #define DEFINE_DUMMY_FLAG(name) { DEPF_UNUSED, #name, -1 } -struct flagdef -{ - int flagbit; - const char *name; - int structoffset; -}; - enum { DEPF_UNUSED, @@ -101,7 +94,7 @@ enum DEPF_FIRERESIST, }; -static flagdef ActorFlags[]= +static FFlagDef ActorFlags[]= { DEFINE_FLAG(MF, PICKUP, APlayerPawn, flags), DEFINE_FLAG(MF, SPECIAL, APlayerPawn, flags), @@ -267,7 +260,7 @@ static flagdef ActorFlags[]= DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN), }; -static flagdef InventoryFlags[] = +static FFlagDef InventoryFlags[] = { // Inventory flags DEFINE_FLAG(IF, QUIET, AInventory, ItemFlags), @@ -288,7 +281,7 @@ static flagdef InventoryFlags[] = }; -static flagdef WeaponFlags[] = +static FFlagDef WeaponFlags[] = { // Weapon flags DEFINE_FLAG(WIF, NOAUTOFIRE, AWeapon, WeaponFlags), @@ -311,11 +304,11 @@ static flagdef WeaponFlags[] = DEFINE_DUMMY_FLAG(NOLMS), }; -static const struct { const PClass *Type; flagdef *Defs; int NumDefs; } FlagLists[] = +static const struct { const PClass *Type; FFlagDef *Defs; int NumDefs; } FlagLists[] = { - { RUNTIME_CLASS(AActor), ActorFlags, sizeof(ActorFlags)/sizeof(flagdef) }, - { RUNTIME_CLASS(AInventory), InventoryFlags, sizeof(InventoryFlags)/sizeof(flagdef) }, - { RUNTIME_CLASS(AWeapon), WeaponFlags, sizeof(WeaponFlags)/sizeof(flagdef) } + { RUNTIME_CLASS(AActor), ActorFlags, sizeof(ActorFlags)/sizeof(FFlagDef) }, + { RUNTIME_CLASS(AInventory), InventoryFlags, sizeof(InventoryFlags)/sizeof(FFlagDef) }, + { RUNTIME_CLASS(AWeapon), WeaponFlags, sizeof(WeaponFlags)/sizeof(FFlagDef) } }; #define NUM_FLAG_LISTS 3 @@ -326,10 +319,10 @@ static const struct { const PClass *Type; flagdef *Defs; int NumDefs; } FlagList //========================================================================== static int STACK_ARGS flagcmp (const void * a, const void * b) { - return stricmp( ((flagdef*)a)->name, ((flagdef*)b)->name); + return stricmp( ((FFlagDef*)a)->name, ((FFlagDef*)b)->name); } -static flagdef *FindFlag (flagdef *flags, int numflags, const char *flag) +static FFlagDef *FindFlag (FFlagDef *flags, int numflags, const char *flag) { int min = 0, max = numflags - 1; @@ -353,17 +346,17 @@ static flagdef *FindFlag (flagdef *flags, int numflags, const char *flag) return NULL; } -static flagdef *FindFlag (const PClass *type, const char *part1, const char *part2) +FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2) { static bool flagsorted = false; - flagdef *def; + FFlagDef *def; int i; if (!flagsorted) { for (i = 0; i < NUM_FLAG_LISTS; ++i) { - qsort (FlagLists[i].Defs, FlagLists[i].NumDefs, sizeof(flagdef), flagcmp); + qsort (FlagLists[i].Defs, FlagLists[i].NumDefs, sizeof(FFlagDef), flagcmp); } flagsorted = true; } @@ -412,7 +405,7 @@ static flagdef *FindFlag (const PClass *type, const char *part1, const char *par // properties is not recommended // //=========================================================================== -static void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index) +void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index) { switch (index) { @@ -452,372 +445,126 @@ static void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, } } -//=========================================================================== -// -// A_ChangeFlag -// -// This cannot be placed in thingdef_codeptr because it needs the flag table -// -//=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag) -{ - ACTION_PARAM_START(2); - ACTION_PARAM_STRING(flagname, 0); - ACTION_PARAM_BOOL(expression, 1); - - const char *dot = strchr (flagname, '.'); - flagdef *fd; - const PClass *cls = self->GetClass(); - - if (dot != NULL) - { - FString part1(flagname, dot-flagname); - fd = FindFlag (cls, part1, dot+1); - } - else - { - fd = FindFlag (cls, flagname, NULL); - } - - if (fd != NULL) - { - if (fd->structoffset == -1) - { - HandleDeprecatedFlags(self, cls->ActorInfo, expression, fd->flagbit); - } - else - { - int * flagp = (int*) (((char*)self) + fd->structoffset); - - if (expression) *flagp |= fd->flagbit; - else *flagp &= ~fd->flagbit; - } - } - else - { - Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars()); - } -} - //========================================================================== // +// +// //========================================================================== -void ParseActorFlag (FScanner &sc, Baggage &bag, int mod) +int MatchString (const char *in, const char **strings) { - flagdef *fd; + int i; - sc.MustGetString (); - - FString part1 = sc.String; - const char *part2 = NULL; - if (sc.CheckString (".")) + for (i = 0; *strings != NULL; i++) { - sc.MustGetString (); - part2 = sc.String; - } - if ( (fd = FindFlag (bag.Info->Class, part1.GetChars(), part2)) ) - { - AActor *defaults = (AActor*)bag.Info->Class->Defaults; - if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property + if (!stricmp(in, *strings++)) { - HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit); - } - else - { - DWORD * flagvar = (DWORD*) ((char*)defaults + fd->structoffset); - if (mod == '+') - { - *flagvar |= fd->flagbit; - } - else - { - *flagvar &= ~fd->flagbit; - } - } - } - else - { - if (part2 == NULL) - { - sc.ScriptError("\"%s\" is an unknown flag\n", part1.GetChars()); - } - else - { - sc.ScriptError("\"%s.%s\" is an unknown flag\n", part1.GetChars(), part2); - } - } -} - - - -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- -// -// Translation parsing -// -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- -FRemapTable CurrentTranslation; -TArray BloodTranslationColors; - -PalEntry BloodTranslations[256]; - -static bool Check(char *& range, char c, bool error=true) -{ - while (isspace(*range)) range++; - if (*range==c) - { - range++; - return true; - } - if (error) - { - //sc.ScriptError("Invalid syntax in translation specification: '%c' expected", c); - } - return false; -} - - -static void AddToTranslation(char * range) -{ - int start,end; - - start=strtol(range, &range, 10); - if (!Check(range, ':')) return; - end=strtol(range, &range, 10); - if (!Check(range, '=')) return; - if (!Check(range, '[', false)) - { - int pal1,pal2; - - pal1=strtol(range, &range, 10); - if (!Check(range, ':')) return; - pal2=strtol(range, &range, 10); - - CurrentTranslation.AddIndexRange(start, end, pal1, pal2); - } - else - { - // translation using RGB values - int r1,g1,b1,r2,g2,b2; - - r1=strtol(range, &range, 10); - if (!Check(range, ',')) return; - g1=strtol(range, &range, 10); - if (!Check(range, ',')) return; - b1=strtol(range, &range, 10); - if (!Check(range, ']')) return; - if (!Check(range, ':')) return; - if (!Check(range, '[')) return; - r2=strtol(range, &range, 10); - if (!Check(range, ',')) return; - g2=strtol(range, &range, 10); - if (!Check(range, ',')) return; - b2=strtol(range, &range, 10); - if (!Check(range, ']')) return; - - CurrentTranslation.AddColorRange(start, end, r1, g1, b1, r2, g2, b2); - } -} - -static int StoreTranslation(FScanner &sc) -{ - unsigned int i; - - for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++) - { - if (CurrentTranslation == *translationtables[TRANSLATION_Decorate][i]) - { - // A duplicate of this translation already exists - return TRANSLATION(TRANSLATION_Decorate, i); - } - } - if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS) - { - sc.ScriptError("Too many translations in DECORATE"); - } - FRemapTable *newtrans = new FRemapTable; - *newtrans = CurrentTranslation; - i = translationtables[TRANSLATION_Decorate].Push(newtrans); - return TRANSLATION(TRANSLATION_Decorate, i); -} - -static int CreateBloodTranslation(FScanner &sc, PalEntry color) -{ - unsigned int i; - - for (i = 0; i < BloodTranslationColors.Size(); i++) - { - if (color.r == BloodTranslationColors[i].r && - color.g == BloodTranslationColors[i].g && - color.b == BloodTranslationColors[i].b) - { - // A duplicate of this translation already exists return i; } } - if (BloodTranslationColors.Size() >= MAX_DECORATE_TRANSLATIONS) - { - sc.ScriptError("Too many blood colors in DECORATE"); - } - FRemapTable *trans = new FRemapTable; - for (i = 0; i < 256; i++) - { - int bright = MAX(MAX(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b); - PalEntry pe = PalEntry(color.r*bright/255, color.g*bright/255, color.b*bright/255); - int entry = ColorMatcher.Pick(pe.r, pe.g, pe.b); - - trans->Palette[i] = pe; - trans->Remap[i] = entry; - } - translationtables[TRANSLATION_Blood].Push(trans); - return BloodTranslationColors.Push(color); -} - -//---------------------------------------------------------------------------- -// -// DropItem handling -// -//---------------------------------------------------------------------------- - -static void FreeDropItemChain(FDropItem *chain) -{ - while (chain != NULL) - { - FDropItem *next = chain->Next; - delete chain; - chain = next; - } -} - -class FDropItemPtrArray : public TArray -{ -public: - ~FDropItemPtrArray() - { - for (unsigned int i = 0; i < Size(); ++i) - { - FreeDropItemChain ((*this)[i]); - } - } -}; - -static FDropItemPtrArray DropItemList; - -FDropItem *GetDropItems(const PClass *cls) -{ - unsigned int index = cls->Meta.GetMetaInt (ACMETA_DropItems) - 1; - - if (index >= 0 && index < DropItemList.Size()) - { - return DropItemList[index]; - } - return NULL; + return -1; } //========================================================================== // +// Info Property handlers // //========================================================================== -typedef void (*ActorPropFunction) (FScanner &sc, AActor *defaults, Baggage &bag); - -struct ActorProps -{ - const char *name; - ActorPropFunction Handler; - const PClass * type; -}; - -typedef ActorProps (*ActorPropHandler) (const char *str, unsigned int len); - -static const ActorProps *is_actorprop (const char *str); - - //========================================================================== // -// Checks for a numeric parameter which may or may not be preceded by a comma -// //========================================================================== -static bool CheckNumParm(FScanner &sc) +DEFINE_INFO_PROPERTY(game, T, Actor) { - if (sc.CheckString(",")) + PROP_STRING_PARM(str, 0); + if (!stricmp(str, "Doom")) { - sc.MustGetNumber(); - return true; + bag.Info->GameFilter |= GAME_Doom; + } + else if (!stricmp(str, "Heretic")) + { + bag.Info->GameFilter |= GAME_Heretic; + } + else if (!stricmp(str, "Hexen")) + { + bag.Info->GameFilter |= GAME_Hexen; + } + else if (!stricmp(str, "Raven")) + { + bag.Info->GameFilter |= GAME_Raven; + } + else if (!stricmp(str, "Strife")) + { + bag.Info->GameFilter |= GAME_Strife; + } + else if (!stricmp(str, "Chex")) + { + bag.Info->GameFilter |= GAME_Chex; + } + else if (!stricmp(str, "Any")) + { + bag.Info->GameFilter = GAME_Any; } else { - return sc.CheckNumber(); + I_Error ("Unknown game type %s", str); } } -static bool CheckFloatParm(FScanner &sc) +//========================================================================== +// +//========================================================================== +DEFINE_INFO_PROPERTY(spawnid, I, Actor) { - if (sc.CheckString(",")) + PROP_INT_PARM(id, 0); + if (id<0 || id>255) { - sc.MustGetFloat(); - return true; - } - else - { - return sc.CheckFloat(); + I_Error ("SpawnID must be in the range [0,255]"); } + else bag.Info->SpawnID=(BYTE)id; } -// [MH] -static int ParseMorphStyle (FScanner &sc) +//========================================================================== +// +//========================================================================== +DEFINE_INFO_PROPERTY(conversationid, IiI, Actor) { - static const char * morphstyles[]={ - "MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE", - "MRF_FAILNOTELEFRAG", "MRF_FAILNOLAUGH", "MRF_WHENINVULNERABLE", "MRF_LOSEACTUALWEAPON", - "MRF_NEWTIDBEHAVIOUR", "MRF_UNDOBYDEATH", "MRF_UNDOBYDEATHFORCED", "MRF_UNDOBYDEATHSAVES", NULL}; + PROP_INT_PARM(convid, 0); + PROP_INT_PARM(id1, 1); + PROP_INT_PARM(id2, 2); - static const int morphstyle_values[]={ - MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE, - MORPH_FAILNOTELEFRAG, MORPH_FAILNOLAUGH, MORPH_WHENINVULNERABLE, MORPH_LOSEACTUALWEAPON, - MORPH_NEWTIDBEHAVIOUR, MORPH_UNDOBYDEATH, MORPH_UNDOBYDEATHFORCED, MORPH_UNDOBYDEATHSAVES}; - - // May be given flags by number... - if (sc.CheckNumber()) + // Handling for Strife teaser IDs - only of meaning for the standard items + // as PWADs cannot be loaded with the teasers. + if (PROP_PARM_COUNT > 1) { - sc.MustGetNumber(); - return sc.Number; - } + if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE)) + convid=id1; - // ... else should be flags by name. - // NOTE: Later this should be removed and a normal expression used. - // The current DECORATE parser can't handle this though. - bool gotparen = sc.CheckString("("); - int style = 0; - do - { - sc.MustGetString(); - style |= morphstyle_values[sc.MustMatchString(morphstyles)]; - } - while (sc.CheckString("|")); - if (gotparen) - { - sc.MustGetStringName(")"); - } + if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE|GI_TEASER2)) + convid=id2; - return style; + if (convid==-1) return; + } + if (convid<0 || convid>1000) + { + I_Error ("ConversationID must be in the range [0,1000]"); + } + else StrifeTypes[convid] = bag.Info->Class; } //========================================================================== // -// Property parsers +// Property handlers // //========================================================================== //========================================================================== // //========================================================================== -static void ActorSkipSuper (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(skip_super, 0, Actor) { if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(AInventory))) { - sc.ScriptMessage("'skip_super' in definition of inventory item igmored.\n"); + Printf("'skip_super' in definition of inventory item '%s' ignored.", bag.Info->Class->TypeName.GetChars() ); return; } @@ -826,264 +573,173 @@ static void ActorSkipSuper (FScanner &sc, AActor *defaults, Baggage &bag) { FreeDropItemChain (bag.DropItemList); } - ResetBaggage (&bag); - MakeStateDefines(NULL); + ResetBaggage (&bag, RUNTIME_CLASS(AActor)); } //========================================================================== // //========================================================================== -static void ActorGame (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(tag, S, Actor) { - sc.MustGetString (); - if (sc.Compare ("Doom")) + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaString(AMETA_StrifeName, str); +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(health, I, Actor) +{ + PROP_INT_PARM(id, 0); + defaults->health=id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(gibhealth, I, Actor) +{ + PROP_INT_PARM(id, 0); + bag.Info->Class->Meta.SetMetaInt (AMETA_GibHealth, id); +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(woundhealth, I, Actor) +{ + PROP_INT_PARM(id, 0); + bag.Info->Class->Meta.SetMetaInt (AMETA_WoundHealth, id); +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(reactiontime, I, Actor) +{ + PROP_INT_PARM(id, 0); + defaults->reactiontime=id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(painchance, ZI, Actor) +{ + PROP_STRING_PARM(str, 0); + PROP_INT_PARM(id, 1); + if (str == NULL) { - bag.Info->GameFilter |= GAME_Doom; - } - else if (sc.Compare ("Heretic")) - { - bag.Info->GameFilter |= GAME_Heretic; - } - else if (sc.Compare ("Hexen")) - { - bag.Info->GameFilter |= GAME_Hexen; - } - else if (sc.Compare ("Raven")) - { - bag.Info->GameFilter |= GAME_Raven; - } - else if (sc.Compare ("Strife")) - { - bag.Info->GameFilter |= GAME_Strife; - } - else if (sc.Compare ("Chex")) - { - bag.Info->GameFilter |= GAME_Chex; - } - else if (sc.Compare ("Any")) - { - bag.Info->GameFilter = GAME_Any; + defaults->PainChance=id; } else - { - sc.ScriptError ("Unknown game type %s", sc.String); - } -} - -//========================================================================== -// -//========================================================================== -static void ActorSpawnID (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetNumber(); - if (sc.Number<0 || sc.Number>255) - { - sc.ScriptError ("SpawnID must be in the range [0,255]"); - } - else bag.Info->SpawnID=(BYTE)sc.Number; -} - -//========================================================================== -// -//========================================================================== -static void ActorConversationID (FScanner &sc, AActor *defaults, Baggage &bag) -{ - int convid; - - sc.MustGetNumber(); - convid = sc.Number; - - // Handling for Strife teaser IDs - only of meaning for the standard items - // as PWADs cannot be loaded with the teasers. - if (sc.CheckString(",")) - { - sc.MustGetNumber(); - if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE)) - convid=sc.Number; - - sc.MustGetStringName(","); - sc.MustGetNumber(); - if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE|GI_TEASER2)) - convid=sc.Number; - - if (convid==-1) return; - } - if (convid<0 || convid>1000) - { - sc.ScriptError ("ConversationID must be in the range [0,1000]"); - } - else StrifeTypes[convid] = bag.Info->Class; -} - -//========================================================================== -// -//========================================================================== -static void ActorTag (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaString(AMETA_StrifeName, sc.String); -} - -//========================================================================== -// -//========================================================================== -static void ActorHealth (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetNumber(); - defaults->health=sc.Number; -} - -//========================================================================== -// -//========================================================================== -static void ActorGibHealth (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt (AMETA_GibHealth, sc.Number); -} - -//========================================================================== -// -//========================================================================== -static void ActorWoundHealth (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt (AMETA_WoundHealth, sc.Number); -} - -//========================================================================== -// -//========================================================================== -static void ActorReactionTime (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetNumber(); - defaults->reactiontime=sc.Number; -} - -//========================================================================== -// -//========================================================================== -static void ActorPainChance (FScanner &sc, AActor *defaults, Baggage &bag) -{ - if (!sc.CheckNumber()) { FName painType; - sc.MustGetString(); - if (sc.Compare("Normal")) painType = NAME_None; - else painType=sc.String; - sc.MustGetToken(','); - sc.MustGetNumber(); - bag.Info->SetPainChance(painType, sc.Number); - return; + if (!stricmp(str, "Normal")) painType = NAME_None; + else painType=str; + + if (bag.Info->PainChances == NULL) bag.Info->PainChances=new PainChanceList; + (*bag.Info->PainChances)[painType] = (BYTE)id; } - defaults->PainChance=sc.Number; } //========================================================================== // //========================================================================== -static void ActorDamage (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(damage, X, Actor) { + PROP_INT_PARM(id, 0); + // Damage can either be a single number, in which case it is subject // to the original damage calculation rules. Or, it can be an expression // and will be calculated as-is, ignoring the original rules. For // compatibility reasons, expressions must be enclosed within // parentheses. - if (sc.CheckString ("(")) + defaults->Damage = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(speed, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + defaults->Speed = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(floatspeed, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + defaults->FloatSpeed=id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(radius, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + defaults->radius=id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(height, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + defaults->height=id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(mass, I, Actor) +{ + PROP_INT_PARM(id, 0); + defaults->Mass=id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(xscale, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + defaults->scaleX = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(yscale, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + defaults->scaleY = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(scale, F, Actor) +{ + PROP_FIXED_PARM(id, 0); + defaults->scaleX = defaults->scaleY = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(args, Iiiii, Actor) +{ + for (int i = 0; i < PROP_PARM_COUNT; i++) { - defaults->Damage = 0x40000000 | ParseExpression (sc, false, bag.Info->Class); - sc.MustGetStringName(")"); - } - else - { - sc.MustGetNumber (); - defaults->Damage = sc.Number; - } -} - -//========================================================================== -// -//========================================================================== -static void ActorSpeed (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetFloat(); - defaults->Speed=fixed_t(sc.Float*FRACUNIT); -} - -//========================================================================== -// -//========================================================================== -static void ActorFloatSpeed (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetFloat(); - defaults->FloatSpeed=fixed_t(sc.Float*FRACUNIT); -} - -//========================================================================== -// -//========================================================================== -static void ActorRadius (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetFloat(); - defaults->radius=fixed_t(sc.Float*FRACUNIT); -} - -//========================================================================== -// -//========================================================================== -static void ActorHeight (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetFloat(); - defaults->height=fixed_t(sc.Float*FRACUNIT); -} - -//========================================================================== -// -//========================================================================== -static void ActorMass (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetNumber(); - defaults->Mass=sc.Number; -} - -//========================================================================== -// -//========================================================================== -static void ActorXScale (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetFloat(); - defaults->scaleX = FLOAT2FIXED(sc.Float); -} - -//========================================================================== -// -//========================================================================== -static void ActorYScale (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetFloat(); - defaults->scaleY = FLOAT2FIXED(sc.Float); -} - -//========================================================================== -// -//========================================================================== -static void ActorScale (FScanner &sc, AActor *defaults, Baggage &bag) -{ - sc.MustGetFloat(); - defaults->scaleX= defaults->scaleY = FLOAT2FIXED(sc.Float); -} - -//========================================================================== -// -//========================================================================== -static void ActorArgs (FScanner &sc, AActor *defaults, Baggage &bag) -{ - for (int i = 0; i < 5; i++) - { - sc.MustGetNumber(); - defaults->args[i] = sc.Number; - if (i < 4 && !sc.CheckToken(',')) break; + PROP_INT_PARM(id, i); + defaults->args[i] = id; } defaults->flags2|=MF2_ARGSDEFINED; } @@ -1091,62 +747,64 @@ static void ActorArgs (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorSeeSound (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(seesound, S, Actor) { - sc.MustGetString(); - defaults->SeeSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->SeeSound = str; } //========================================================================== // //========================================================================== -static void ActorAttackSound (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(attacksound, S, Actor) { - sc.MustGetString(); - defaults->AttackSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->AttackSound = str; } //========================================================================== // //========================================================================== -static void ActorPainSound (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(painsound, S, Actor) { - sc.MustGetString(); - defaults->PainSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->PainSound = str; } //========================================================================== // //========================================================================== -static void ActorDeathSound (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(deathsound, S, Actor) { - sc.MustGetString(); - defaults->DeathSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->DeathSound = str; } //========================================================================== // //========================================================================== -static void ActorActiveSound (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(activesound, S, Actor) { - sc.MustGetString(); - defaults->ActiveSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->ActiveSound = str; } //========================================================================== // //========================================================================== -static void ActorHowlSound (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(howlsound, S, Actor) { - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(sc.String)); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str)); } //========================================================================== // //========================================================================== -static void ActorDropItem (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(dropitem, S_i_i, Actor) { + PROP_STRING_PARM(type, 0); + // create a linked list of dropitems if (!bag.DropItemSet) { @@ -1156,17 +814,18 @@ static void ActorDropItem (FScanner &sc, AActor *defaults, Baggage &bag) FDropItem *di = new FDropItem; - sc.MustGetString(); - di->Name=sc.String; + di->Name =type; di->probability=255; di->amount=-1; - if (CheckNumParm(sc)) + if (PROP_PARM_COUNT > 1) { - di->probability = sc.Number; - if (CheckNumParm(sc)) + PROP_INT_PARM(prob, 1); + di->probability = prob; + if (PROP_PARM_COUNT > 2) { - di->amount = sc.Number; + PROP_INT_PARM(amt, 1); + di->amount = amt; } } di->Next = bag.DropItemList; @@ -1176,138 +835,9 @@ static void ActorDropItem (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorSpawnState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Spawn", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorSeeState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("See", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorMeleeState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Melee", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorMissileState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Missile", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorPainState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Pain", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorDeathState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Death", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorXDeathState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("XDeath", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorBurnState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Burn", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorIceState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Ice", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorRaiseState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Raise", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorCrashState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Crash", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorCrushState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Crush", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorWoundState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Wound", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorDisintegrateState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Disintegrate", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorHealState (FScanner &sc, AActor *defaults, Baggage &bag) -{ - AddState("Heal", CheckState (sc, bag.Info->Class)); -} - -//========================================================================== -// -//========================================================================== -static void ActorStates (FScanner &sc, AActor *defaults, Baggage &bag) -{ - if (!bag.StateSet) ParseStates(sc, bag.Info, defaults, bag); - else sc.ScriptError("Multiple state declarations not allowed"); - bag.StateSet=true; -} - -//========================================================================== -// -//========================================================================== -static void ActorRenderStyle (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(renderstyle, S, Actor) { + PROP_STRING_PARM(str, 0); static const char * renderstyles[]={ "NONE","NORMAL","FUZZY","SOULTRANS","OPTFUZZY","STENCIL","TRANSLUCENT", "ADD","SHADED", NULL}; @@ -1315,48 +845,53 @@ static void ActorRenderStyle (FScanner &sc, AActor *defaults, Baggage &bag) STYLE_None, STYLE_Normal, STYLE_Fuzzy, STYLE_SoulTrans, STYLE_OptFuzzy, STYLE_TranslucentStencil, STYLE_Translucent, STYLE_Add, STYLE_Shaded}; - sc.MustGetString(); - defaults->RenderStyle = LegacyRenderStyles[renderstyle_values[sc.MustMatchString(renderstyles)]]; + // make this work for old style decorations, too. + if (!strnicmp(str, "style_", 6)) str+=6; + + int style = MatchString(str, renderstyles); + if (style < 0) I_Error("Unknown render style '%s'"); + defaults->RenderStyle = LegacyRenderStyles[renderstyle_values[style]]; } //========================================================================== // //========================================================================== -static void ActorAlpha (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(defaultalpha, 0, Actor) { - if (sc.CheckString("DEFAULT")) - { - defaults->alpha = gameinfo.gametype == GAME_Heretic ? HR_SHADOW : HX_SHADOW; - } - else - { - sc.MustGetFloat(); - defaults->alpha=fixed_t(sc.Float*FRACUNIT); - } + defaults->alpha = gameinfo.gametype == GAME_Heretic ? HR_SHADOW : HX_SHADOW; } //========================================================================== // //========================================================================== -static void ActorObituary (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(alpha, F, Actor) { - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaString (AMETA_Obituary, sc.String); + PROP_FIXED_PARM(id, 0); + defaults->alpha = id; } //========================================================================== // //========================================================================== -static void ActorHitObituary (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(obituary, S, Actor) { - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaString (AMETA_HitObituary, sc.String); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaString (AMETA_Obituary, str); } //========================================================================== // //========================================================================== -static void ActorDontHurtShooter (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(hitobituary, S, Actor) +{ + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaString (AMETA_HitObituary, str); +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(donthurtshooter, 0, Actor) { bag.Info->Class->Meta.SetMetaInt (ACMETA_DontHurtShooter, true); } @@ -1364,28 +899,27 @@ static void ActorDontHurtShooter (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorExplosionRadius (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(explosionradius, I, Actor) { - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, sc.Number); + PROP_INT_PARM(id, 0); + bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, id); } //========================================================================== // //========================================================================== -static void ActorExplosionDamage (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(explosiondamage, I, Actor) { - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, sc.Number); + PROP_INT_PARM(id, 0); + bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, id); } //========================================================================== // //========================================================================== -static void ActorDeathHeight (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(deathheight, F, Actor) { - sc.MustGetFloat(); - fixed_t h = fixed_t(sc.Float * FRACUNIT); + PROP_FIXED_PARM(h, 0); // AActor::Die() uses a height of 0 to mean "cut the height to 1/4", // so if a height of 0 is desired, store it as -1. bag.Info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h); @@ -1394,10 +928,9 @@ static void ActorDeathHeight (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorBurnHeight (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(burnheight, F, Actor) { - sc.MustGetFloat(); - fixed_t h = fixed_t(sc.Float * FRACUNIT); + PROP_FIXED_PARM(h, 0); // The note above for AMETA_DeathHeight also applies here. bag.Info->Class->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h); } @@ -1405,162 +938,124 @@ static void ActorBurnHeight (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorMaxTargetRange (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(maxtargetrange, F, Actor) { - sc.MustGetFloat(); - defaults->maxtargetrange = fixed_t(sc.Float*FRACUNIT); + PROP_FIXED_PARM(id, 0); + defaults->maxtargetrange = id; } //========================================================================== // //========================================================================== -static void ActorMeleeThreshold (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(meleethreshold, F, Actor) { - sc.MustGetFloat(); - defaults->meleethreshold = fixed_t(sc.Float*FRACUNIT); + PROP_FIXED_PARM(id, 0); + defaults->meleethreshold = id; } //========================================================================== // //========================================================================== -static void ActorMeleeDamage (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(meleedamage, I, Actor) { - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt (ACMETA_MeleeDamage, sc.Number); + PROP_INT_PARM(id, 0); + bag.Info->Class->Meta.SetMetaInt (ACMETA_MeleeDamage, id); } //========================================================================== // //========================================================================== -static void ActorMeleeRange (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(meleerange, F, Actor) { - sc.MustGetFloat(); - defaults->meleerange = fixed_t(sc.Float*FRACUNIT); + PROP_FIXED_PARM(id, 0); + defaults->meleerange = id; } //========================================================================== // //========================================================================== -static void ActorMeleeSound (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(meleesound, S, Actor) { - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(sc.String)); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str)); } //========================================================================== // //========================================================================== -static void ActorMissileType (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(missiletype, S, Actor) { - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaInt (ACMETA_MissileName, FName(sc.String)); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaInt (ACMETA_MissileName, FName(str)); } //========================================================================== // //========================================================================== -static void ActorMissileHeight (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(missileheight, F, Actor) { - sc.MustGetFloat(); - bag.Info->Class->Meta.SetMetaFixed (ACMETA_MissileHeight, fixed_t(sc.Float*FRACUNIT)); + PROP_FIXED_PARM(id, 0); + bag.Info->Class->Meta.SetMetaFixed (ACMETA_MissileHeight, id); } //========================================================================== // //========================================================================== -static void ActorTranslation (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(translation, L, Actor) { - if (sc.CheckNumber()) + PROP_INT_PARM(type, 0); + + if (type == 0) { + PROP_INT_PARM(trans, 1); int max = (gameinfo.gametype==GAME_Strife || (bag.Info->GameFilter&GAME_Strife)) ? 6:2; - if (sc.Number < 0 || sc.Number > max) + if (trans < 0 || trans > max) { - sc.ScriptError ("Translation must be in the range [0,%d]", max); + I_Error ("Translation must be in the range [0,%d]", max); } - defaults->Translation = TRANSLATION(TRANSLATION_Standard, sc.Number); + defaults->Translation = TRANSLATION(TRANSLATION_Standard, trans); } - else if (sc.CheckString("Ice")) - { - defaults->Translation = TRANSLATION(TRANSLATION_Standard, 7); - } - else + else { + FRemapTable CurrentTranslation; + CurrentTranslation.MakeIdentity(); - do + for(int i = 1; i < PROP_PARM_COUNT; i++) { - sc.GetString(); - AddToTranslation(sc.String); + PROP_STRING_PARM(str, i); + if (i== 1 && PROP_PARM_COUNT == 2 && !stricmp(str, "Ice")) + { + defaults->Translation = TRANSLATION(TRANSLATION_Standard, 7); + return; + } + else + { + CurrentTranslation.AddToTranslation(str); + } } - while (sc.CheckString(",")); - defaults->Translation = StoreTranslation (sc); + defaults->Translation = CurrentTranslation.StoreTranslation (); } } //========================================================================== // //========================================================================== -static void ActorStencilColor (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(stencilcolor, C, Actor) { - int r,g,b; + PROP_COLOR_PARM(color, 0); - if (sc.CheckNumber()) - { - sc.MustGetNumber(); - r=clamp(sc.Number, 0, 255); - sc.CheckString(","); - sc.MustGetNumber(); - g=clamp(sc.Number, 0, 255); - sc.CheckString(","); - sc.MustGetNumber(); - b=clamp(sc.Number, 0, 255); - } - else - { - sc.MustGetString(); - int c = V_GetColor(NULL, sc.String); - r=RPART(c); - g=GPART(c); - b=BPART(c); - } - defaults->fillcolor = MAKERGB(r,g,b) | (ColorMatcher.Pick (r, g, b) << 24); + defaults->fillcolor = color | (ColorMatcher.Pick (RPART(color), GPART(color), BPART(color)) << 24); } - //========================================================================== // //========================================================================== -static void ActorBloodColor (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(bloodcolor, C, Actor) { - int r,g,b; + PROP_COLOR_PARM(color, 0); - if (sc.CheckNumber()) - { - sc.MustGetNumber(); - r = clamp(sc.Number, 0, 255); - sc.CheckString(","); - sc.MustGetNumber(); - g = clamp(sc.Number, 0, 255); - sc.CheckString(","); - sc.MustGetNumber(); - b = clamp(sc.Number, 0, 255); - } - else - { - sc.MustGetString(); - int c = V_GetColor(NULL, sc.String); - r = RPART(c); - g = GPART(c); - b = BPART(c); - } - PalEntry pe = MAKERGB(r,g,b); - pe.a = CreateBloodTranslation(sc, pe); - if (DWORD(pe) == 0) - { - // If black is the first color being created it will create a value of 0 - // which stands for 'no translation' - // Using (1,1,1) instead of (0,0,0) won't be noticable. - pe = MAKERGB(1,1,1); - } + PalEntry pe = color; + pe.a = CreateBloodTranslation(pe); bag.Info->Class->Meta.SetMetaInt (AMETA_BloodColor, pe); } @@ -1568,25 +1063,26 @@ static void ActorBloodColor (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorBloodType (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(bloodtype, Sss, Actor) { - sc.MustGetString(); - FName blood = sc.String; + PROP_STRING_PARM(str, 0) + PROP_STRING_PARM(str1, 1) + PROP_STRING_PARM(str2, 2) + + FName blood = str; // normal blood bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType, blood); - if (sc.CheckString(",")) + if (PROP_PARM_COUNT > 1) { - sc.MustGetString(); - blood = sc.String; + blood = str1; } // blood splatter bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType2, blood); - if (sc.CheckString(",")) + if (PROP_PARM_COUNT > 2) { - sc.MustGetString(); - blood = sc.String; + blood = str2; } // axe blood bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType3, blood); @@ -1595,157 +1091,154 @@ static void ActorBloodType (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorBounceFactor (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(bouncefactor, F, Actor) { - sc.MustGetFloat (); - defaults->bouncefactor = clamp(fixed_t(sc.Float * FRACUNIT), 0, FRACUNIT); + PROP_FIXED_PARM(id, 0); + defaults->bouncefactor = clamp(id, 0, FRACUNIT); } //========================================================================== // //========================================================================== -static void ActorWallBounceFactor (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(wallbouncefactor, F, Actor) { - sc.MustGetFloat (); - defaults->wallbouncefactor = clamp(fixed_t(sc.Float * FRACUNIT), 0, FRACUNIT); + PROP_FIXED_PARM(id, 0); + defaults->wallbouncefactor = clamp(id, 0, FRACUNIT); } //========================================================================== // //========================================================================== -static void ActorBounceCount (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(bouncecount, I, Actor) { - sc.MustGetNumber (); - defaults->bouncecount = sc.Number; + PROP_INT_PARM(id, 0); + defaults->bouncecount = id; } //========================================================================== // //========================================================================== -static void ActorMinMissileChance (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(minmissilechance, I, Actor) { - sc.MustGetNumber (); - defaults->MinMissileChance=sc.Number; + PROP_INT_PARM(id, 0); + defaults->MinMissileChance=id; } //========================================================================== // //========================================================================== -static void ActorDamageType (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(damagetype, S, Actor) { - sc.MustGetString (); - if (sc.Compare("Normal")) defaults->DamageType = NAME_None; - else defaults->DamageType=sc.String; + PROP_STRING_PARM(str, 0); + if (!stricmp(str, "Normal")) defaults->DamageType = NAME_None; + else defaults->DamageType=str; } //========================================================================== // //========================================================================== -static void ActorDamageFactor (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(damagefactor, SF, Actor) { - sc.MustGetString (); + PROP_STRING_PARM(str, 0); + PROP_FIXED_PARM(id, 0); + + if (bag.Info->DamageFactors == NULL) bag.Info->DamageFactors=new DmgFactors; FName dmgType; - if (sc.Compare("Normal")) dmgType = NAME_None; - else dmgType=sc.String; + if (!stricmp(str, "Normal")) dmgType = NAME_None; + else dmgType=str; - sc.MustGetToken(','); - sc.MustGetFloat(); - bag.Info->SetDamageFactor(dmgType, FLOAT2FIXED(sc.Float)); + (*bag.Info->DamageFactors)[dmgType]=id; } //========================================================================== // //========================================================================== -static void ActorDecal (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(decal, S, Actor) { - sc.MustGetString(); - defaults->DecalGenerator = (FDecalBase *)intptr_t(int(FName(sc.String))); + PROP_STRING_PARM(str, 0); + defaults->DecalGenerator = (FDecalBase *)intptr_t(int(FName(str))); } //========================================================================== // //========================================================================== -static void ActorMaxStepHeight (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(maxstepheight, F, Actor) { - sc.MustGetNumber (); - defaults->MaxStepHeight=sc.Number * FRACUNIT; + PROP_FIXED_PARM(i, 0); + defaults->MaxStepHeight = i; } //========================================================================== // //========================================================================== -static void ActorMaxDropoffHeight (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(maxdropoffheight, F, Actor) { - sc.MustGetNumber (); - defaults->MaxDropOffHeight=sc.Number * FRACUNIT; + PROP_FIXED_PARM(i, 0); + defaults->MaxDropOffHeight = i; } //========================================================================== // //========================================================================== -static void ActorPoisonDamage (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(poisondamage, I, Actor) { - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt (AMETA_PoisonDamage, sc.Number); + PROP_INT_PARM(i, 0); + bag.Info->Class->Meta.SetMetaInt (AMETA_PoisonDamage, i); } //========================================================================== // //========================================================================== -static void ActorFastSpeed (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(fastspeed, F, Actor) { - sc.MustGetFloat(); - bag.Info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, fixed_t(sc.Float*FRACUNIT)); + PROP_FIXED_PARM(i, 0); + bag.Info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, i); } //========================================================================== // //========================================================================== -static void ActorRadiusDamageFactor (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(radiusdamagefactor, F, Actor) { - sc.MustGetFloat(); - bag.Info->Class->Meta.SetMetaFixed (AMETA_RDFactor, fixed_t(sc.Float*FRACUNIT)); + PROP_FIXED_PARM(i, 0); + bag.Info->Class->Meta.SetMetaFixed (AMETA_RDFactor, i); } //========================================================================== // //========================================================================== -static void ActorCameraheight (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(cameraheight, F, Actor) { - sc.MustGetFloat(); - bag.Info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, fixed_t(sc.Float*FRACUNIT)); + PROP_FIXED_PARM(i, 0); + bag.Info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, i); } //========================================================================== // //========================================================================== -static void ActorVSpeed (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(vspeed, F, Actor) { - sc.MustGetFloat(); - defaults->momz = fixed_t(sc.Float*FRACUNIT); + PROP_FIXED_PARM(i, 0); + defaults->momz = i; } //========================================================================== // //========================================================================== -static void ActorGravity (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(gravity, F, Actor) { - sc.MustGetFloat (); + PROP_FIXED_PARM(i, 0); - if (sc.Float < 0.f) - sc.ScriptError ("Gravity must not be negative."); - - defaults->gravity = FLOAT2FIXED (sc.Float); - - if (sc.Float == 0.f) - defaults->flags |= MF_NOGRAVITY; + if (i < 0) I_Error ("Gravity must not be negative."); + defaults->gravity = i; + if (i == 0) defaults->flags |= MF_NOGRAVITY; } //========================================================================== // //========================================================================== -static void ActorClearFlags (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(clearflags, 0, Actor) { defaults->flags=defaults->flags3=defaults->flags4=defaults->flags5=0; defaults->flags2&=MF2_ARGSDEFINED; // this flag must not be cleared @@ -1754,9 +1247,9 @@ static void ActorClearFlags (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorMonster (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(monster, 0, Actor) { - // sets the standard flag for a monster + // sets the standard flags for a monster defaults->flags|=MF_SHOOTABLE|MF_COUNTKILL|MF_SOLID; defaults->flags2|=MF2_PUSHWALL|MF2_MCROSS|MF2_PASSMOBJ; defaults->flags3|=MF3_ISMONSTER; @@ -1766,7 +1259,7 @@ static void ActorMonster (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void ActorProjectile (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_PROPERTY(projectile, 0, Actor) { // sets the standard flags for a projectile defaults->flags|=MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE; @@ -1783,129 +1276,127 @@ static void ActorProjectile (FScanner &sc, AActor *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void AmmoBackpackAmount (FScanner &sc, AAmmo *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(backpackamount, I, Ammo) { - sc.MustGetNumber(); - defaults->BackpackAmount=sc.Number; + PROP_INT_PARM(i, 0); + defaults->BackpackAmount = i; } //========================================================================== // //========================================================================== -static void AmmoBackpackMaxAmount (FScanner &sc, AAmmo *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(backpackmaxamount, I, Ammo) { - sc.MustGetNumber(); - defaults->BackpackMaxAmount=sc.Number; + PROP_INT_PARM(i, 0); + defaults->BackpackMaxAmount = i; } //========================================================================== // //========================================================================== -static void AmmoDropAmount (FScanner &sc, AAmmo *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(dropamount, I, Ammo) { - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt (AIMETA_DropAmount, sc.Number); + PROP_INT_PARM(i, 0); + bag.Info->Class->Meta.SetMetaInt (AIMETA_DropAmount, i); } //========================================================================== // //========================================================================== -static void ArmorMaxSaveAmount (FScanner &sc, ABasicArmorBonus *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(armor, maxsaveamount, I, BasicArmorBonus) { - sc.MustGetNumber(); - defaults->MaxSaveAmount = sc.Number; + PROP_INT_PARM(i, 0); + defaults->MaxSaveAmount = i; } //========================================================================== // //========================================================================== -static void ArmorMaxBonus (FScanner &sc, ABasicArmorBonus *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(armor, maxbonus, I, BasicArmorBonus) { - sc.MustGetNumber(); - defaults->BonusCount = sc.Number; + PROP_INT_PARM(i, 0); + defaults->BonusCount = i; } //========================================================================== // //========================================================================== -static void ArmorMaxBonusMax (FScanner &sc, ABasicArmorBonus *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(armor, maxbonusmax, I, BasicArmorBonus) { - sc.MustGetNumber(); - defaults->BonusMax = sc.Number; + PROP_INT_PARM(i, 0); + defaults->BonusMax = i; } //========================================================================== // //========================================================================== -static void ArmorSaveAmount (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(saveamount, I, Armor) { - sc.MustGetNumber(); + PROP_INT_PARM(i, 0); + // Special case here because this property has to work for 2 unrelated classes if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { - ((ABasicArmorPickup*)defaults)->SaveAmount=sc.Number; + ((ABasicArmorPickup*)defaults)->SaveAmount=i; } else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { - ((ABasicArmorBonus*)defaults)->SaveAmount=sc.Number; + ((ABasicArmorBonus*)defaults)->SaveAmount=i; } else { - sc.ScriptError("\"%s\" requires an actor of type \"Armor\"\n", sc.String); + I_Error("\"Armor.SaveAmount\" requires an actor of type \"Armor\""); } } //========================================================================== // //========================================================================== -static void ArmorSavePercent (FScanner &sc, AActor *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(savepercent, F, Armor) { - sc.MustGetFloat(); - if (sc.Float<0.0f) sc.Float=0.0f; - if (sc.Float>100.0f) sc.Float=100.0f; + PROP_FIXED_PARM(i, 0); + + i = clamp(i, 0, 100*FRACUNIT)/100; // Special case here because this property has to work for 2 unrelated classes if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) { - ((ABasicArmorPickup*)defaults)->SavePercent=fixed_t(sc.Float*FRACUNIT/100.0f); + ((ABasicArmorPickup*)defaults)->SavePercent = i; } else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) { - ((ABasicArmorBonus*)defaults)->SavePercent=fixed_t(sc.Float*FRACUNIT/100.0f); + ((ABasicArmorBonus*)defaults)->SavePercent = i; } else { - sc.ScriptError("\"%s\" requires an actor of type \"Armor\"\n", sc.String); + I_Error("\"Armor.SavePercent\" requires an actor of type \"Armor\"\n"); } } //========================================================================== // //========================================================================== -static void InventoryAmount (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(amount, I, Inventory) { - sc.MustGetNumber(); - defaults->Amount=sc.Number; + PROP_INT_PARM(i, 0); + defaults->Amount = i; } //========================================================================== // //========================================================================== -static void InventoryIcon (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(icon, S, Inventory) { - sc.MustGetString(); - defaults->Icon = TexMan.AddPatch (sc.String); + PROP_STRING_PARM(i, 0); + + defaults->Icon = TexMan.CheckForTexture(i, FTexture::TEX_MiscPatch); if (!defaults->Icon.isValid()) { - defaults->Icon = TexMan.AddPatch (sc.String, ns_sprites); - if (!defaults->Icon.isValid()) + // Don't print warnings if the item is for another game or if this is a shareware IWAD. + // Strife's teaser doesn't contain all the icon graphics of the full game. + if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) && + !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) { - // Don't print warnings if the item is for another game or if this is a shareware IWAD. - // Strife's teaser doesn't contain all the icon graphics of the full game. - if ((bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype) && - !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(sc.LumpNum) != 0) - { - Printf("Icon '%s' for '%s' not found\n", sc.String, bag.Info->Class->TypeName.GetChars()); - } + Printf("Icon '%s' for '%s' not found\n", i, bag.Info->Class->TypeName.GetChars()); } } } @@ -1913,16 +1404,16 @@ static void InventoryIcon (FScanner &sc, AInventory *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void InventoryMaxAmount (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(maxamount, I, Inventory) { - sc.MustGetNumber(); - defaults->MaxAmount=sc.Number; + PROP_INT_PARM(i, 0); + defaults->MaxAmount = i; } //========================================================================== // //========================================================================== -static void InventoryDefMaxAmount (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(defmaxamount, 0, Inventory) { defaults->MaxAmount = gameinfo.gametype == GAME_Heretic ? 16 : 25; } @@ -1931,170 +1422,180 @@ static void InventoryDefMaxAmount (FScanner &sc, AInventory *defaults, Baggage & //========================================================================== // //========================================================================== -static void InventoryPickupflash (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) { - sc.MustGetString(); - defaults->PickupFlash = fuglyname(sc.String); + PROP_STRING_PARM(str, 0); + defaults->PickupFlash = fuglyname(str); } //========================================================================== // //========================================================================== -static void InventoryPickupmsg (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(pickupmessage, S, Inventory) { - // allow game specific pickup messages - const char * games[] = {"Doom", "Heretic", "Hexen", "Raven", "Strife", "Chex", NULL}; - int gamemode[]={GAME_Doom, GAME_Heretic, GAME_Hexen, GAME_Raven, GAME_Strife, GAME_Chex}; - - sc.MustGetString(); - int game = sc.MatchString(games); - - if (game!=-1 && sc.CheckString(",")) - { - sc.MustGetString(); - if (!(gameinfo.gametype&gamemode[game])) return; - } - bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, str); } //========================================================================== // //========================================================================== -static void InventoryPickupsound (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(pickupsound, S, Inventory) { - sc.MustGetString(); - defaults->PickupSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->PickupSound = str; } //========================================================================== // //========================================================================== -static void InventoryRespawntics (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(respawntics, I, Inventory) { - sc.MustGetNumber(); - defaults->RespawnTics=sc.Number; + PROP_INT_PARM(i, 0); + defaults->RespawnTics = i; } //========================================================================== // //========================================================================== -static void InventoryUsesound (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(usesound, S, Inventory) { - sc.MustGetString(); - defaults->UseSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->UseSound = str; } //========================================================================== // //========================================================================== -static void InventoryGiveQuest (FScanner &sc, AInventory *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(givequest, I, Inventory) { - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, sc.Number); + PROP_INT_PARM(i, 0); + bag.Info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, i); } //========================================================================== // //========================================================================== -static void HealthLowMessage (FScanner &sc, AHealth *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(lowmessage, IS, Health) { - sc.MustGetNumber(); - bag.Info->Class->Meta.SetMetaInt(AIMETA_LowHealth, sc.Number); - sc.MustGetStringName(","); - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, sc.String); + PROP_INT_PARM(i, 0); + PROP_STRING_PARM(str, 1); + bag.Info->Class->Meta.SetMetaInt(AIMETA_LowHealth, i); + bag.Info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, str); } //========================================================================== // //========================================================================== -static void PuzzleitemNumber (FScanner &sc, APuzzleItem *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(number, I, PuzzleItem) { - sc.MustGetNumber(); - defaults->PuzzleItemNumber=sc.Number; + PROP_INT_PARM(i, 0); + defaults->PuzzleItemNumber = i; } //========================================================================== // //========================================================================== -static void PuzzleitemFailMsg (FScanner &sc, APuzzleItem *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(failmessage, S, PuzzleItem) { - sc.MustGetString(); - bag.Info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, sc.String); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, str); } //========================================================================== // //========================================================================== -static void WeaponAmmoGive1 (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(ammogive, I, Weapon) { - sc.MustGetNumber(); - defaults->AmmoGive1=sc.Number; + PROP_INT_PARM(i, 0); + defaults->AmmoGive1 = i; } //========================================================================== // //========================================================================== -static void WeaponAmmoGive2 (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(ammogive1, I, Weapon) { - sc.MustGetNumber(); - defaults->AmmoGive2=sc.Number; -} - -//========================================================================== -// -// Passing these parameters is really tricky to allow proper inheritance -// and forward declarations. Here only a name is -// stored which must be resolved after everything has been declared -// -//========================================================================== - -static void WeaponAmmoType1 (FScanner &sc, AWeapon *defaults, Baggage &bag) -{ - sc.MustGetString(); - defaults->AmmoType1 = fuglyname(sc.String); + PROP_INT_PARM(i, 0); + defaults->AmmoGive1 = i; } //========================================================================== // //========================================================================== -static void WeaponAmmoType2 (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(ammogive2, I, Weapon) { - sc.MustGetString(); - defaults->AmmoType2 = fuglyname(sc.String); + PROP_INT_PARM(i, 0); + defaults->AmmoGive2 = 2; } //========================================================================== // //========================================================================== -static void WeaponAmmoUse1 (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(ammotype, S, Weapon) { - sc.MustGetNumber(); - defaults->AmmoUse1=sc.Number; + PROP_STRING_PARM(str, 0); + defaults->AmmoType1 = fuglyname(str); } //========================================================================== // //========================================================================== -static void WeaponAmmoUse2 (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(ammotype1, S, Weapon) { - sc.MustGetNumber(); - defaults->AmmoUse2=sc.Number; + PROP_STRING_PARM(str, 0); + defaults->AmmoType1 = fuglyname(str); } //========================================================================== // //========================================================================== -static void WeaponKickback (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(ammotype2, S, Weapon) { - sc.MustGetNumber(); - defaults->Kickback=sc.Number; + PROP_STRING_PARM(str, 0); + defaults->AmmoType2 = fuglyname(str); } //========================================================================== // //========================================================================== -static void WeaponDefKickback (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(ammouse, I, Weapon) +{ + PROP_INT_PARM(i, 0); + defaults->AmmoUse1 = i; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(ammouse1, I, Weapon) +{ + PROP_INT_PARM(i, 0); + defaults->AmmoUse1 = i; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(ammouse2, I, Weapon) +{ + PROP_INT_PARM(i, 0); + defaults->AmmoUse2 = i; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(kickback, I, Weapon) +{ + PROP_INT_PARM(i, 0); + defaults->Kickback = i; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(defaultkickback, 0, Weapon) { defaults->Kickback = gameinfo.defKickback; } @@ -2102,74 +1603,73 @@ static void WeaponDefKickback (FScanner &sc, AWeapon *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void WeaponReadySound (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(readysound, S, Weapon) { - sc.MustGetString(); - defaults->ReadySound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->ReadySound = str; } //========================================================================== // //========================================================================== -static void WeaponSelectionOrder (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(selectionorder, I, Weapon) { - sc.MustGetNumber(); - defaults->SelectionOrder=sc.Number; + PROP_INT_PARM(i, 0); + defaults->SelectionOrder = i; } //========================================================================== // //========================================================================== -static void WeaponSisterWeapon (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(sisterweapon, S, Weapon) { - sc.MustGetString(); - defaults->SisterWeaponType=fuglyname(sc.String); + PROP_STRING_PARM(str, 0); + defaults->SisterWeaponType = fuglyname(str); } //========================================================================== // //========================================================================== -static void WeaponUpSound (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(upsound, S, Weapon) { - sc.MustGetString(); - defaults->UpSound = sc.String; + PROP_STRING_PARM(str, 0); + defaults->UpSound = str; } //========================================================================== // //========================================================================== -static void WeaponYAdjust (FScanner &sc, AWeapon *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(yadjust, F, Weapon) { - sc.MustGetFloat(); - defaults->YAdjust=fixed_t(sc.Float * FRACUNIT); + PROP_FIXED_PARM(i, 0); + defaults->YAdjust = i; } //========================================================================== // //========================================================================== -static void WPieceValue (FScanner &sc, AWeaponPiece *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(number, I, WeaponPiece) { - sc.MustGetNumber(); - defaults->PieceValue = 1 << (sc.Number-1); + PROP_INT_PARM(i, 0); + defaults->PieceValue = 1 << (i-1); } //========================================================================== // //========================================================================== -static void WPieceWeapon (FScanner &sc, AWeaponPiece *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece) { - sc.MustGetString(); - defaults->WeaponClass = fuglyname(sc.String); + PROP_STRING_PARM(str, 0); + defaults->WeaponClass = fuglyname(str); } //========================================================================== // //========================================================================== -static void PowerupColor (FScanner &sc, APowerupGiver *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory) { - int r; - int g; - int b; + PROP_INT_PARM(i, 0); + int alpha; PalEntry * pBlendColor; @@ -2183,67 +1683,60 @@ static void PowerupColor (FScanner &sc, APowerupGiver *defaults, Baggage &bag) } else { - sc.ScriptError("\"%s\" requires an actor of type \"Powerup\"\n", sc.String); + I_Error("\"powerup.color\" requires an actor of type \"Powerup\"\n"); return; } - if (sc.CheckNumber()) - { - r=clamp(sc.Number, 0, 255); - sc.CheckString(","); - sc.MustGetNumber(); - g=clamp(sc.Number, 0, 255); - sc.CheckString(","); - sc.MustGetNumber(); - b=clamp(sc.Number, 0, 255); - } - else - { - sc.MustGetString(); + PROP_INT_PARM(mode, 0); + PROP_INT_PARM(color, 1); - if (sc.Compare("INVERSEMAP")) + if (mode == 1) + { + PROP_STRING_PARM(name, 1); + + if (!stricmp(name, "INVERSEMAP")) { - defaults->BlendColor = INVERSECOLOR; + *pBlendColor = INVERSECOLOR; return; } - else if (sc.Compare("GOLDMAP")) + else if (!stricmp(name, "GOLDMAP")) { - defaults->BlendColor = GOLDCOLOR; + *pBlendColor = GOLDCOLOR; return; } // [BC] Yay, more hacks. - else if ( sc.Compare( "REDMAP" )) + else if (!stricmp(name, "REDMAP" )) { - defaults->BlendColor = REDCOLOR; + *pBlendColor = REDCOLOR; return; } - else if ( sc.Compare( "GREENMAP" )) + else if (!stricmp(name, "GREENMAP" )) { - defaults->BlendColor = GREENCOLOR; + *pBlendColor = GREENCOLOR; return; } - int c = V_GetColor(NULL, sc.String); - r=RPART(c); - g=GPART(c); - b=BPART(c); + color = V_GetColor(NULL, name); } - sc.CheckString(","); - sc.MustGetFloat(); - alpha=int(sc.Float*255); + else if (PROP_PARM_COUNT > 1) + { + PROP_FLOAT_PARM(falpha, 2); + alpha=int(falpha*255); + } + else alpha = 255/3; + alpha=clamp(alpha, 0, 255); - if (alpha!=0) *pBlendColor = MAKEARGB(alpha, r, g, b); + if (alpha!=0) *pBlendColor = MAKEARGB(alpha, 0, 0, 0) | color; else *pBlendColor = 0; } //========================================================================== // //========================================================================== -static void PowerupDuration (FScanner &sc, APowerupGiver *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory) { int *pEffectTics; - if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) { pEffectTics = &((APowerup*)defaults)->EffectTics; @@ -2254,30 +1747,30 @@ static void PowerupDuration (FScanner &sc, APowerupGiver *defaults, Baggage &bag } else { - sc.ScriptError("\"%s\" requires an actor of type \"Powerup\"\n", sc.String); + I_Error("\"powerup.color\" requires an actor of type \"Powerup\"\n"); return; } - sc.MustGetNumber(); - *pEffectTics = (sc.Number >= 0) ? sc.Number : -sc.Number * TICRATE; + PROP_INT_PARM(i, 0); + *pEffectTics = (i >= 0) ? i : -i * TICRATE; } //========================================================================== // //========================================================================== -static void PowerupMode (FScanner &sc, APowerupGiver *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, PowerupGiver) { - sc.MustGetString(); - defaults->mode = (FName)sc.String; + PROP_STRING_PARM(str, 0); + defaults->mode = (FName)str; } //========================================================================== // //========================================================================== -static void PowerupType (FScanner &sc, APowerupGiver *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) { - sc.MustGetString(); - defaults->PowerupType = fuglyname(sc.String); + PROP_STRING_PARM(str, 0); + defaults->PowerupType = fuglyname(str); } //========================================================================== @@ -2289,21 +1782,20 @@ static void PowerupType (FScanner &sc, APowerupGiver *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void PlayerDisplayName (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) { - sc.MustGetString (); - bag.Info->Class->Meta.SetMetaString (APMETA_DisplayName, sc.String); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaString (APMETA_DisplayName, str); } //========================================================================== // //========================================================================== -static void PlayerSoundClass (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn) { - FString tmp; + PROP_STRING_PARM(str, 0); - sc.MustGetString (); - tmp = sc.String; + FString tmp = str; tmp.ReplaceChars (' ', '_'); bag.Info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp); } @@ -2311,19 +1803,18 @@ static void PlayerSoundClass (FScanner &sc, APlayerPawn *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void PlayerFace (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn) { - FString tmp; + PROP_STRING_PARM(str, 0); + FString tmp = str; - sc.MustGetString (); - tmp = sc.String; + tmp.ToUpper(); if (tmp.Len() != 3) { Printf("Invalid face '%s' for '%s';\nSTF replacement codes must be 3 characters.\n", - sc.String, bag.Info->Class->TypeName.GetChars ()); + tmp.GetChars(), bag.Info->Class->TypeName.GetChars ()); } - tmp.ToUpper(); bool valid = ( (((tmp[0] >= 'A') && (tmp[0] <= 'Z')) || ((tmp[0] >= '0') && (tmp[0] <= '9'))) && (((tmp[1] >= 'A') && (tmp[1] <= 'Z')) || ((tmp[1] >= '0') && (tmp[1] <= '9'))) && @@ -2332,7 +1823,7 @@ static void PlayerFace (FScanner &sc, APlayerPawn *defaults, Baggage &bag) if (!valid) { Printf("Invalid face '%s' for '%s';\nSTF replacement codes must be alphanumeric.\n", - sc.String, bag.Info->Class->TypeName.GetChars ()); + tmp.GetChars(), bag.Info->Class->TypeName.GetChars ()); } bag.Info->Class->Meta.SetMetaString (APMETA_Face, tmp); @@ -2341,15 +1832,10 @@ static void PlayerFace (FScanner &sc, APlayerPawn *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void PlayerColorRange (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) { - int start, end; - - sc.MustGetNumber (); - start = sc.Number; - sc.CheckString(","); - sc.MustGetNumber (); - end = sc.Number; + PROP_INT_PARM(start, 0); + PROP_INT_PARM(end, 0); if (start > end) swap (start, end); @@ -2360,113 +1846,48 @@ static void PlayerColorRange (FScanner &sc, APlayerPawn *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void PlayerAttackZOffset (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, attackzoffset, F, PlayerPawn) { - sc.MustGetFloat (); - defaults->AttackZOffset = FLOAT2FIXED (sc.Float); + PROP_FIXED_PARM(z, 0); + defaults->AttackZOffset = z; } //========================================================================== // //========================================================================== -static void PlayerJumpZ (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, jumpz, F, PlayerPawn) { - sc.MustGetFloat (); - defaults->JumpZ = FLOAT2FIXED (sc.Float); + PROP_FIXED_PARM(z, 0); + defaults->JumpZ = z; } //========================================================================== // //========================================================================== -static void PlayerSpawnClass (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, spawnclass, L, PlayerPawn) { - sc.MustGetString (); - if (sc.Compare ("Any")) - defaults->SpawnMask = 0; - else if (sc.Compare ("Fighter")) - defaults->SpawnMask |= 1; - else if (sc.Compare ("Cleric")) - defaults->SpawnMask |= 2; - else if (sc.Compare ("Mage")) - defaults->SpawnMask |= 4; - else if (IsNum(sc.String)) + PROP_INT_PARM(type, 0); + + if (type == 0) { - int val = strtol(sc.String, NULL, 0); + PROP_INT_PARM(val, 1); if (val > 0) defaults->SpawnMask |= 1<<(val-1); } -} - -//========================================================================== -// -//========================================================================== -static void PlayerViewHeight (FScanner &sc, APlayerPawn *defaults, Baggage &bag) -{ - sc.MustGetFloat (); - defaults->ViewHeight = FLOAT2FIXED (sc.Float); -} - -//========================================================================== -// -//========================================================================== -static void PlayerForwardMove (FScanner &sc, APlayerPawn *defaults, Baggage &bag) -{ - sc.MustGetFloat (); - defaults->ForwardMove1 = defaults->ForwardMove2 = FLOAT2FIXED (sc.Float); - if (CheckFloatParm (sc)) - defaults->ForwardMove2 = FLOAT2FIXED (sc.Float); -} - -//========================================================================== -// -//========================================================================== -static void PlayerSideMove (FScanner &sc, APlayerPawn *defaults, Baggage &bag) -{ - sc.MustGetFloat (); - defaults->SideMove1 = defaults->SideMove2 = FLOAT2FIXED (sc.Float); - if (CheckFloatParm (sc)) - defaults->SideMove2 = FLOAT2FIXED (sc.Float); -} - -//========================================================================== -// -//========================================================================== -static void PlayerMaxHealth (FScanner &sc, APlayerPawn *defaults, Baggage &bag) -{ - sc.MustGetNumber (); - defaults->MaxHealth = sc.Number; -} - -//========================================================================== -// -//========================================================================== -static void PlayerRunHealth (FScanner &sc, APlayerPawn *defaults, Baggage &bag) -{ - sc.MustGetNumber (); - defaults->RunHealth = sc.Number; -} - -//========================================================================== -// -//========================================================================== -static void PlayerMorphWeapon (FScanner &sc, APlayerPawn *defaults, Baggage &bag) -{ - sc.MustGetString (); - defaults->MorphWeapon = FName(sc.String); -} - -//========================================================================== -// -//========================================================================== -static void PlayerScoreIcon (FScanner &sc, APlayerPawn *defaults, Baggage &bag) -{ - sc.MustGetString (); - defaults->ScoreIcon = TexMan.AddPatch (sc.String); - if (!defaults->ScoreIcon.isValid()) + else { - defaults->ScoreIcon = TexMan.AddPatch (sc.String, ns_sprites); - if (!defaults->ScoreIcon.isValid()) + for(int i=1; iClass->TypeName.GetChars ()); + PROP_STRING_PARM(str, i); + + if (!stricmp(str, "Any")) + defaults->SpawnMask = 0; + else if (!stricmp(str, "Fighter")) + defaults->SpawnMask |= 1; + else if (!stricmp(str, "Cleric")) + defaults->SpawnMask |= 2; + else if (!stricmp(str, "Mage")) + defaults->SpawnMask |= 4; + } } } @@ -2474,50 +1895,110 @@ static void PlayerScoreIcon (FScanner &sc, APlayerPawn *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void PlayerCrouchSprite (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, viewheight, F, PlayerPawn) { - sc.MustGetString (); - for (int i = 0; i < sc.StringLen; i++) - { - sc.String[i] = toupper (sc.String[i]); - } - defaults->crouchsprite = GetSpriteIndex (sc.String); + PROP_FIXED_PARM(z, 0); + defaults->ViewHeight = z; } //========================================================================== // //========================================================================== -static void PlayerDmgScreenColor (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, forwardmove, F_f, PlayerPawn) { - if (sc.CheckNumber ()) + PROP_FIXED_PARM(m, 0); + defaults->ForwardMove1 = defaults->ForwardMove2 = m; + if (PROP_PARM_COUNT > 1) { - sc.MustGetNumber (); - defaults->RedDamageFade = clamp (sc.Number, 0, 255); - sc.CheckString (","); - sc.MustGetNumber (); - defaults->GreenDamageFade = clamp (sc.Number, 0, 255); - sc.CheckString (","); - sc.MustGetNumber (); - defaults->BlueDamageFade = clamp (sc.Number, 0, 255); + PROP_FIXED_PARM(m2, 1); + defaults->ForwardMove2 = m2; } - else +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, sidemove, F_f, PlayerPawn) +{ + PROP_FIXED_PARM(m, 0); + defaults->SideMove1 = defaults->SideMove2 = m; + if (PROP_PARM_COUNT > 1) { - sc.MustGetString (); - int c = V_GetColor (NULL, sc.String); - defaults->RedDamageFade = RPART (c); - defaults->GreenDamageFade = GPART (c); - defaults->BlueDamageFade = BPART (c); + PROP_FIXED_PARM(m2, 1); + defaults->SideMove2 = m2; } } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, maxhealth, I, PlayerPawn) +{ + PROP_INT_PARM(z, 0); + defaults->MaxHealth = z; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, runhealth, I, PlayerPawn) +{ + PROP_INT_PARM(z, 0); + defaults->RunHealth = z; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, morphweapon, S, PlayerPawn) +{ + PROP_STRING_PARM(z, 0); + defaults->MorphWeapon = FName(z); +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, scoreicon, S, PlayerPawn) +{ + PROP_STRING_PARM(z, 0); + defaults->ScoreIcon = TexMan.CheckForTexture(z, FTexture::TEX_MiscPatch); + if (!defaults->ScoreIcon.isValid()) + { + Printf("Icon '%s' for '%s' not found\n", z, bag.Info->Class->TypeName.GetChars ()); + } +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, crouchsprite, S, PlayerPawn) +{ + PROP_STRING_PARM(z, 0); + defaults->crouchsprite = GetSpriteIndex (z); +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, damagescreencolor, C, PlayerPawn) +{ + PROP_COLOR_PARM(c, 0); + defaults->RedDamageFade = RPART (c); + defaults->GreenDamageFade = GPART (c); + defaults->BlueDamageFade = BPART (c); +} + //========================================================================== // // [GRB] Store start items in drop item list // //========================================================================== -static void PlayerStartItem (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn) { - // create a linked list of dropitems + PROP_STRING_PARM(str, 0); + + // create a linked list of startitems if (!bag.DropItemSet) { bag.DropItemSet = true; @@ -2526,13 +2007,13 @@ static void PlayerStartItem (FScanner &sc, APlayerPawn *defaults, Baggage &bag) FDropItem * di=new FDropItem; - sc.MustGetString(); - di->Name = sc.String; + di->Name = str; di->probability = 255; di->amount = 1; - if (CheckNumParm(sc)) + if (PROP_PARM_COUNT > 1) { - di->amount = sc.Number; + PROP_INT_PARM(amt, 1); + di->amount = amt; } di->Next = bag.DropItemList; bag.DropItemList = di; @@ -2541,136 +2022,162 @@ static void PlayerStartItem (FScanner &sc, APlayerPawn *defaults, Baggage &bag) //========================================================================== // //========================================================================== -static void PlayerInvulMode (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) { - sc.MustGetString (); - bag.Info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)sc.String); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)str); } //========================================================================== // //========================================================================== -static void PlayerHealRadius (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) { - sc.MustGetString (); - bag.Info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)sc.String); + PROP_STRING_PARM(str, 0); + bag.Info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str); } //========================================================================== // //========================================================================== -static void PlayerHexenArmor (FScanner &sc, APlayerPawn *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn) { for (int i=0;i<5;i++) { - sc.MustGetFloat (); - bag.Info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, FLOAT2FIXED (sc.Float)); - if (i!=4) sc.MustGetStringName(","); + PROP_FIXED_PARM(val, i); + bag.Info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val); } } //========================================================================== // //========================================================================== -static void EggFXPlayerClass (FScanner &sc, AMorphProjectile *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile) { - sc.MustGetString (); - defaults->PlayerClass = FName(sc.String); + PROP_STRING_PARM(str, 0); + defaults->PlayerClass = FName(str); } //========================================================================== // //========================================================================== -static void EggFXMonsterClass (FScanner &sc, AMorphProjectile *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile) { - sc.MustGetString (); - defaults->MonsterClass = FName(sc.String); + PROP_STRING_PARM(str, 0); + defaults->MonsterClass = FName(str); } //========================================================================== // //========================================================================== -static void EggFXDuration (FScanner &sc, AMorphProjectile *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(duration, I, MorphProjectile) { - sc.MustGetNumber (); - defaults->Duration = sc.Number; + PROP_INT_PARM(i, 0); + defaults->Duration = i >= 0 ? i : -i*TICRATE; } //========================================================================== // //========================================================================== -static void EggFXMorphStyle (FScanner &sc, AMorphProjectile *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(morphstyle, M, MorphProjectile) { - defaults->MorphStyle = ParseMorphStyle(sc); + PROP_INT_PARM(i, 0); + defaults->MorphStyle = i; } //========================================================================== // //========================================================================== -static void EggFXMorphFlash (FScanner &sc, AMorphProjectile *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile) { - sc.MustGetString (); - defaults->MorphFlash = FName(sc.String); + PROP_STRING_PARM(str, 0); + defaults->MorphFlash = FName(str); } //========================================================================== // //========================================================================== -static void EggFXUnMorphFlash (FScanner &sc, AMorphProjectile *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile) { - sc.MustGetString (); - defaults->UnMorphFlash = FName(sc.String); + PROP_STRING_PARM(str, 0); + defaults->UnMorphFlash = FName(str); } //========================================================================== // //========================================================================== -static void PowerMorphPlayerClass (FScanner &sc, APowerMorph *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph) { - sc.MustGetString (); - defaults->PlayerClass = FName(sc.String); + PROP_STRING_PARM(str, 0); + defaults->PlayerClass = FName(str); } //========================================================================== // //========================================================================== -static void PowerMorphMorphStyle (FScanner &sc, APowerMorph *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph) { - defaults->MorphStyle = ParseMorphStyle(sc); + PROP_INT_PARM(i, 0); + defaults->MorphStyle = i; } //========================================================================== // //========================================================================== -static void PowerMorphMorphFlash (FScanner &sc, APowerMorph *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph) { - sc.MustGetString (); - defaults->MorphFlash = FName(sc.String); + PROP_STRING_PARM(str, 0); + defaults->MorphFlash = FName(str); } //========================================================================== // //========================================================================== -static void PowerMorphUnMorphFlash (FScanner &sc, APowerMorph *defaults, Baggage &bag) +DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph) { - sc.MustGetString (); - defaults->UnMorphFlash = FName(sc.String); + PROP_STRING_PARM(str, 0); + defaults->UnMorphFlash = FName(str); } + //========================================================================== // +// Find a property by name using a binary search +// //========================================================================== -static const ActorProps *APropSearch (const char *str, const ActorProps *props, int numprops) +static int STACK_ARGS propcmp(const void * a, const void * b) { - int min = 0, max = numprops - 1; + return stricmp( (*(FPropertyInfo**)a)->name, (*(FPropertyInfo**)b)->name); +} + +static TArray properties; + +FPropertyInfo *FindProperty(const char * string) +{ + static bool propsorted=false; + + if (!propsorted) + { + TAutoSegIterator probe; + + while (++probe != NULL) + { + properties.Push(probe); + } + properties.ShrinkToFit(); + qsort(&properties[0], properties.Size(), sizeof(properties[0]), propcmp); + propsorted=true; + } + + int min = 0, max = properties.Size()-1; while (min <= max) { int mid = (min + max) / 2; - int lexval = strcmp (str, props[mid].name); + int lexval = stricmp (string, properties[mid]->name); if (lexval == 0) { - return &props[mid]; + return properties[mid]; } else if (lexval > 0) { @@ -2683,250 +2190,3 @@ static const ActorProps *APropSearch (const char *str, const ActorProps *props, } return NULL; } - -//========================================================================== -// -// all actor properties -// -//========================================================================== -#define apf ActorPropFunction -static const ActorProps props[] = -{ - { "activesound", ActorActiveSound, RUNTIME_CLASS(AActor) }, - { "alpha", ActorAlpha, RUNTIME_CLASS(AActor) }, - { "ammo.backpackamount", (apf)AmmoBackpackAmount, RUNTIME_CLASS(AAmmo) }, - { "ammo.backpackmaxamount", (apf)AmmoBackpackMaxAmount, RUNTIME_CLASS(AAmmo) }, - { "ammo.dropamount", (apf)AmmoDropAmount, RUNTIME_CLASS(AAmmo) }, - { "args", ActorArgs, RUNTIME_CLASS(AActor) }, - { "armor.maxbonus", (apf)ArmorMaxBonus, RUNTIME_CLASS(ABasicArmorBonus) }, - { "armor.maxbonusmax", (apf)ArmorMaxBonusMax, RUNTIME_CLASS(ABasicArmorBonus) }, - { "armor.maxsaveamount", (apf)ArmorMaxSaveAmount, RUNTIME_CLASS(ABasicArmorBonus) }, - { "armor.saveamount", (apf)ArmorSaveAmount, RUNTIME_CLASS(AActor) }, - { "armor.savepercent", (apf)ArmorSavePercent, RUNTIME_CLASS(AActor) }, - { "attacksound", ActorAttackSound, RUNTIME_CLASS(AActor) }, - { "bloodcolor", ActorBloodColor, RUNTIME_CLASS(AActor) }, - { "bloodtype", ActorBloodType, RUNTIME_CLASS(AActor) }, - { "bouncecount", ActorBounceCount, RUNTIME_CLASS(AActor) }, - { "bouncefactor", ActorBounceFactor, RUNTIME_CLASS(AActor) }, - { "burn", ActorBurnState, RUNTIME_CLASS(AActor) }, - { "burnheight", ActorBurnHeight, RUNTIME_CLASS(AActor) }, - { "cameraheight", ActorCameraheight, RUNTIME_CLASS(AActor) }, - { "clearflags", ActorClearFlags, RUNTIME_CLASS(AActor) }, - { "conversationid", ActorConversationID, RUNTIME_CLASS(AActor) }, - { "crash", ActorCrashState, RUNTIME_CLASS(AActor) }, - { "crush", ActorCrushState, RUNTIME_CLASS(AActor) }, - { "damage", ActorDamage, RUNTIME_CLASS(AActor) }, - { "damagefactor", ActorDamageFactor, RUNTIME_CLASS(AActor) }, - { "damagetype", ActorDamageType, RUNTIME_CLASS(AActor) }, - { "death", ActorDeathState, RUNTIME_CLASS(AActor) }, - { "deathheight", ActorDeathHeight, RUNTIME_CLASS(AActor) }, - { "deathsound", ActorDeathSound, RUNTIME_CLASS(AActor) }, - { "decal", ActorDecal, RUNTIME_CLASS(AActor) }, - { "disintegrate", ActorDisintegrateState, RUNTIME_CLASS(AActor) }, - { "donthurtshooter", ActorDontHurtShooter, RUNTIME_CLASS(AActor) }, - { "dropitem", ActorDropItem, RUNTIME_CLASS(AActor) }, - { "explosiondamage", ActorExplosionDamage, RUNTIME_CLASS(AActor) }, - { "explosionradius", ActorExplosionRadius, RUNTIME_CLASS(AActor) }, - { "fastspeed", ActorFastSpeed, RUNTIME_CLASS(AActor) }, - { "floatspeed", ActorFloatSpeed, RUNTIME_CLASS(AActor) }, - { "game", ActorGame, RUNTIME_CLASS(AActor) }, - { "gibhealth", ActorGibHealth, RUNTIME_CLASS(AActor) }, - { "gravity", ActorGravity, RUNTIME_CLASS(AActor) }, - { "heal", ActorHealState, RUNTIME_CLASS(AActor) }, - { "health", ActorHealth, RUNTIME_CLASS(AActor) }, - { "health.lowmessage", (apf)HealthLowMessage, RUNTIME_CLASS(AHealth) }, - { "height", ActorHeight, RUNTIME_CLASS(AActor) }, - { "hitobituary", ActorHitObituary, RUNTIME_CLASS(AActor) }, - { "howlsound", ActorHowlSound, RUNTIME_CLASS(AActor) }, - { "ice", ActorIceState, RUNTIME_CLASS(AActor) }, - { "inventory.amount", (apf)InventoryAmount, RUNTIME_CLASS(AInventory) }, - { "inventory.defmaxamount", (apf)InventoryDefMaxAmount, RUNTIME_CLASS(AInventory) }, - { "inventory.givequest", (apf)InventoryGiveQuest, RUNTIME_CLASS(AInventory) }, - { "inventory.icon", (apf)InventoryIcon, RUNTIME_CLASS(AInventory) }, - { "inventory.maxamount", (apf)InventoryMaxAmount, RUNTIME_CLASS(AInventory) }, - { "inventory.pickupflash", (apf)InventoryPickupflash, RUNTIME_CLASS(AInventory) }, - { "inventory.pickupmessage", (apf)InventoryPickupmsg, RUNTIME_CLASS(AInventory) }, - { "inventory.pickupsound", (apf)InventoryPickupsound, RUNTIME_CLASS(AInventory) }, - { "inventory.respawntics", (apf)InventoryRespawntics, RUNTIME_CLASS(AInventory) }, - { "inventory.usesound", (apf)InventoryUsesound, RUNTIME_CLASS(AInventory) }, - { "mass", ActorMass, RUNTIME_CLASS(AActor) }, - { "maxdropoffheight", ActorMaxDropoffHeight, RUNTIME_CLASS(AActor) }, - { "maxstepheight", ActorMaxStepHeight, RUNTIME_CLASS(AActor) }, - { "maxtargetrange", ActorMaxTargetRange, RUNTIME_CLASS(AActor) }, - { "melee", ActorMeleeState, RUNTIME_CLASS(AActor) }, - { "meleedamage", ActorMeleeDamage, RUNTIME_CLASS(AActor) }, - { "meleerange", ActorMeleeRange, RUNTIME_CLASS(AActor) }, - { "meleesound", ActorMeleeSound, RUNTIME_CLASS(AActor) }, - { "meleethreshold", ActorMeleeThreshold, RUNTIME_CLASS(AActor) }, - { "minmissilechance", ActorMinMissileChance, RUNTIME_CLASS(AActor) }, - { "missile", ActorMissileState, RUNTIME_CLASS(AActor) }, - { "missileheight", ActorMissileHeight, RUNTIME_CLASS(AActor) }, - { "missiletype", ActorMissileType, RUNTIME_CLASS(AActor) }, - { "monster", ActorMonster, RUNTIME_CLASS(AActor) }, - { "morphprojectile.duration", (apf)EggFXDuration, RUNTIME_CLASS(AMorphProjectile) }, - { "morphprojectile.monsterclass", (apf)EggFXMonsterClass, RUNTIME_CLASS(AMorphProjectile) }, - { "morphprojectile.morphflash", (apf)EggFXMorphFlash, RUNTIME_CLASS(AMorphProjectile) }, - { "morphprojectile.morphstyle", (apf)EggFXMorphStyle, RUNTIME_CLASS(AMorphProjectile) }, - { "morphprojectile.playerclass", (apf)EggFXPlayerClass, RUNTIME_CLASS(AMorphProjectile) }, - { "morphprojectile.unmorphflash", (apf)EggFXUnMorphFlash, RUNTIME_CLASS(AMorphProjectile) }, - { "obituary", ActorObituary, RUNTIME_CLASS(AActor) }, - { "pain", ActorPainState, RUNTIME_CLASS(AActor) }, - { "painchance", ActorPainChance, RUNTIME_CLASS(AActor) }, - { "painsound", ActorPainSound, RUNTIME_CLASS(AActor) }, - { "player.attackzoffset", (apf)PlayerAttackZOffset, RUNTIME_CLASS(APlayerPawn) }, - { "player.colorrange", (apf)PlayerColorRange, RUNTIME_CLASS(APlayerPawn) }, - { "player.crouchsprite", (apf)PlayerCrouchSprite, RUNTIME_CLASS(APlayerPawn) }, - { "player.damagescreencolor", (apf)PlayerDmgScreenColor, RUNTIME_CLASS(APlayerPawn) }, - { "player.displayname", (apf)PlayerDisplayName, RUNTIME_CLASS(APlayerPawn) }, - { "player.face", (apf)PlayerFace, RUNTIME_CLASS(APlayerPawn) }, - { "player.forwardmove", (apf)PlayerForwardMove, RUNTIME_CLASS(APlayerPawn) }, - { "player.healradiustype", (apf)PlayerHealRadius, RUNTIME_CLASS(APlayerPawn) }, - { "player.hexenarmor", (apf)PlayerHexenArmor, RUNTIME_CLASS(APlayerPawn) }, - { "player.invulnerabilitymode", (apf)PlayerInvulMode, RUNTIME_CLASS(APlayerPawn) }, - { "player.jumpz", (apf)PlayerJumpZ, RUNTIME_CLASS(APlayerPawn) }, - { "player.maxhealth", (apf)PlayerMaxHealth, RUNTIME_CLASS(APlayerPawn) }, - { "player.morphweapon", (apf)PlayerMorphWeapon, RUNTIME_CLASS(APlayerPawn) }, - { "player.runhealth", (apf)PlayerRunHealth, RUNTIME_CLASS(APlayerPawn) }, - { "player.scoreicon", (apf)PlayerScoreIcon, RUNTIME_CLASS(APlayerPawn) }, - { "player.sidemove", (apf)PlayerSideMove, RUNTIME_CLASS(APlayerPawn) }, - { "player.soundclass", (apf)PlayerSoundClass, RUNTIME_CLASS(APlayerPawn) }, - { "player.spawnclass", (apf)PlayerSpawnClass, RUNTIME_CLASS(APlayerPawn) }, - { "player.startitem", (apf)PlayerStartItem, RUNTIME_CLASS(APlayerPawn) }, - { "player.viewheight", (apf)PlayerViewHeight, RUNTIME_CLASS(APlayerPawn) }, - { "poisondamage", ActorPoisonDamage, RUNTIME_CLASS(AActor) }, - { "powermorph.morphflash", (apf)PowerMorphMorphFlash, RUNTIME_CLASS(APowerMorph) }, - { "powermorph.morphstyle", (apf)PowerMorphMorphStyle, RUNTIME_CLASS(APowerMorph) }, - { "powermorph.playerclass", (apf)PowerMorphPlayerClass, RUNTIME_CLASS(APowerMorph) }, - { "powermorph.unmorphflash", (apf)PowerMorphUnMorphFlash, RUNTIME_CLASS(APowerMorph) }, - { "powerup.color", (apf)PowerupColor, RUNTIME_CLASS(AInventory) }, - { "powerup.duration", (apf)PowerupDuration, RUNTIME_CLASS(AInventory) }, - { "powerup.mode", (apf)PowerupMode, RUNTIME_CLASS(APowerupGiver) }, - { "powerup.type", (apf)PowerupType, RUNTIME_CLASS(APowerupGiver) }, - { "projectile", ActorProjectile, RUNTIME_CLASS(AActor) }, - { "puzzleitem.failmessage", (apf)PuzzleitemFailMsg, RUNTIME_CLASS(APuzzleItem) }, - { "puzzleitem.number", (apf)PuzzleitemNumber, RUNTIME_CLASS(APuzzleItem) }, - { "radius", ActorRadius, RUNTIME_CLASS(AActor) }, - { "radiusdamagefactor", ActorRadiusDamageFactor, RUNTIME_CLASS(AActor) }, - { "raise", ActorRaiseState, RUNTIME_CLASS(AActor) }, - { "reactiontime", ActorReactionTime, RUNTIME_CLASS(AActor) }, - { "renderstyle", ActorRenderStyle, RUNTIME_CLASS(AActor) }, - { "scale", ActorScale, RUNTIME_CLASS(AActor) }, - { "see", ActorSeeState, RUNTIME_CLASS(AActor) }, - { "seesound", ActorSeeSound, RUNTIME_CLASS(AActor) }, - { "skip_super", ActorSkipSuper, RUNTIME_CLASS(AActor) }, - { "spawn", ActorSpawnState, RUNTIME_CLASS(AActor) }, - { "spawnid", ActorSpawnID, RUNTIME_CLASS(AActor) }, - { "speed", ActorSpeed, RUNTIME_CLASS(AActor) }, - { "states", ActorStates, RUNTIME_CLASS(AActor) }, - { "stencilcolor", ActorStencilColor, RUNTIME_CLASS(AActor) }, - { "tag", ActorTag, RUNTIME_CLASS(AActor) }, - { "translation", ActorTranslation, RUNTIME_CLASS(AActor) }, - { "vspeed", ActorVSpeed, RUNTIME_CLASS(AActor) }, - { "wallbouncefactor", ActorWallBounceFactor, RUNTIME_CLASS(AActor) }, - { "weapon.ammogive", (apf)WeaponAmmoGive1, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammogive1", (apf)WeaponAmmoGive1, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammogive2", (apf)WeaponAmmoGive2, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammotype", (apf)WeaponAmmoType1, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammotype1", (apf)WeaponAmmoType1, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammotype2", (apf)WeaponAmmoType2, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammouse", (apf)WeaponAmmoUse1, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammouse1", (apf)WeaponAmmoUse1, RUNTIME_CLASS(AWeapon) }, - { "weapon.ammouse2", (apf)WeaponAmmoUse2, RUNTIME_CLASS(AWeapon) }, - { "weapon.defaultkickback", (apf)WeaponDefKickback, RUNTIME_CLASS(AWeapon) }, - { "weapon.kickback", (apf)WeaponKickback, RUNTIME_CLASS(AWeapon) }, - { "weapon.readysound", (apf)WeaponReadySound, RUNTIME_CLASS(AWeapon) }, - { "weapon.selectionorder", (apf)WeaponSelectionOrder, RUNTIME_CLASS(AWeapon) }, - { "weapon.sisterweapon", (apf)WeaponSisterWeapon, RUNTIME_CLASS(AWeapon) }, - { "weapon.upsound", (apf)WeaponUpSound, RUNTIME_CLASS(AWeapon) }, - { "weapon.yadjust", (apf)WeaponYAdjust, RUNTIME_CLASS(AWeapon) }, - { "weaponpiece.number", (apf)WPieceValue, RUNTIME_CLASS(AWeaponPiece) }, - { "weaponpiece.weapon", (apf)WPieceWeapon, RUNTIME_CLASS(AWeaponPiece) }, - { "wound", ActorWoundState, RUNTIME_CLASS(AActor) }, - { "woundhealth", ActorWoundHealth, RUNTIME_CLASS(AActor) }, - { "xdeath", ActorXDeathState, RUNTIME_CLASS(AActor) }, - { "xscale", ActorXScale, RUNTIME_CLASS(AActor) }, - { "yscale", ActorYScale, RUNTIME_CLASS(AActor) }, - // AWeapon:MinAmmo1 and 2 are never used so there is no point in adding them here! -}; -static const ActorProps *is_actorprop (const char *str) -{ - return APropSearch (str, props, sizeof(props)/sizeof(ActorProps)); -} - - -//========================================================================== -// -// Parses an actor property -// -//========================================================================== - -void ParseActorProperty(FScanner &sc, Baggage &bag) -{ - strlwr (sc.String); - - FString propname = sc.String; - - if (sc.CheckString (".")) - { - sc.MustGetString (); - propname += '.'; - strlwr (sc.String); - propname += sc.String; - } - else - { - sc.UnGet (); - } - - const ActorProps *prop = is_actorprop (propname.GetChars()); - - if (prop != NULL) - { - if (!bag.Info->Class->IsDescendantOf(prop->type)) - { - sc.ScriptError("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->type->TypeName.GetChars()); - } - else - { - prop->Handler (sc, (AActor *)bag.Info->Class->Defaults, bag); - } - } - else - { - sc.ScriptError("\"%s\" is an unknown actor property\n", propname.GetChars()); - } -} - - -//========================================================================== -// -// Finalizes an actor definition -// -//========================================================================== - -void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag) -{ - AActor *defaults = (AActor*)info->Class->Defaults; - - FinishStates (sc, info, defaults, bag); - InstallStates (info, defaults); - if (bag.DropItemSet) - { - if (bag.DropItemList == NULL) - { - if (info->Class->Meta.GetMetaInt (ACMETA_DropItems) != 0) - { - info->Class->Meta.SetMetaInt (ACMETA_DropItems, 0); - } - } - else - { - info->Class->Meta.SetMetaInt (ACMETA_DropItems, - DropItemList.Push (bag.DropItemList) + 1); - } - } - if (info->Class->IsDescendantOf (RUNTIME_CLASS(AInventory))) - { - defaults->flags |= MF_SPECIAL; - } -} diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index e814afde..f315b382 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -57,9 +57,7 @@ #include "colormatcher.h" TArray StateParameters; -TArray JumpParameters; static TArray AFTable; -static TArray StateArray; //========================================================================== // @@ -132,261 +130,12 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name) return NULL; } -//========================================================================== -// -// Find a state address -// -//========================================================================== -struct FStateDefine -{ - FName Label; - TArray Children; - FState *State; -}; -static TArray StateLabels; -void ClearStateLabels() -{ - StateLabels.Clear(); -} //========================================================================== -// -// Search one list of state definitions for the given name -// -//========================================================================== - -static FStateDefine * FindStateLabelInList(TArray & list, FName name, bool create) -{ - for(unsigned i = 0; i namelist(3); - FStateDefine * statedef=NULL; - - MakeStateNameList(name, &namelist); - - TArray * statelist = &StateLabels; - for(unsigned i=0;iChildren; - } - return statedef; -} - -void AddState (const char * statename, FState * state) -{ - FStateDefine * std = FindStateAddress(statename); - std->State = state; -} - -//========================================================================== -// -// Finds the state associated with the given name -// -//========================================================================== - -FState * FindState(AActor * actor, const PClass * type, const char * name) -{ - static TArray namelist(3); - FStateDefine * statedef=NULL; - - MakeStateNameList(name, &namelist); - - TArray * statelist = &StateLabels; - for(unsigned i=0;iChildren; - } - return statedef? statedef->State : NULL; -} - -//========================================================================== -// -// Finds the state associated with the given name -// -//========================================================================== - -FState * FindStateInClass(AActor * actor, const PClass * type, const char * name) -{ - static TArray namelist(3); - - MakeStateNameList(name, &namelist); - FActorInfo * info = type->ActorInfo; - if (info) return info->FindState(namelist.Size(), &namelist[0], true); - return NULL; -} - -//========================================================================== -// -// Checks if a state list is empty -// A list is empty if it doesn't contain any states and no children -// that contain any states -// -//========================================================================== - -static bool IsStateListEmpty(TArray & statelist) -{ - for(unsigned i=0;iLabel - (int)B->Label); -} - -static FStateLabels * CreateStateLabelList(TArray & statelist) -{ - // First delete all empty labels from the list - for (int i=statelist.Size()-1;i>=0;i--) - { - if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0)) - { - statelist.Delete(i); - } - } - - int count=statelist.Size(); - - if (count == 0) return NULL; - - FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel)); - list->NumLabels = count; - - for (int i=0;iLabels[i].Label = statelist[i].Label; - list->Labels[i].State = statelist[i].State; - list->Labels[i].Children = CreateStateLabelList(statelist[i].Children); - } - qsort(list->Labels, count, sizeof(FStateLabel), labelcmp); - return list; -} - -//=========================================================================== -// -// InstallStates -// -// Creates the actor's state list from the current definition -// -//=========================================================================== - -void InstallStates(FActorInfo *info, AActor *defaults) -{ - // First ensure we have a valid spawn state. - FState * state = FindState(defaults, info->Class, "Spawn"); - - if (state == NULL) - { - // A NULL spawn state will crash the engine so set it to something valid. - AddState("Spawn", GetDefault()->SpawnState); - } - - if (info->StateList != NULL) - { - info->StateList->Destroy(); - M_Free(info->StateList); - } - info->StateList = CreateStateLabelList(StateLabels); - - // Cache these states as member veriables. - defaults->SpawnState = info->FindState(NAME_Spawn); - defaults->SeeState = info->FindState(NAME_See); - // Melee and Missile states are manipulated by the scripted marines so they - // have to be stored locally - defaults->MeleeState = info->FindState(NAME_Melee); - defaults->MissileState = info->FindState(NAME_Missile); -} - - -//=========================================================================== -// -// MakeStateDefines -// -// Creates a list of state definitions from an existing actor -// Used by Dehacked to modify an actor's state list -// -//=========================================================================== - -static void MakeStateList(const FStateLabels *list, TArray &dest) -{ - dest.Clear(); - if (list != NULL) for(int i=0;iNumLabels;i++) - { - FStateDefine def; - - def.Label = list->Labels[i].Label; - def.State = list->Labels[i].State; - dest.Push(def); - if (list->Labels[i].Children != NULL) - { - MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children); - } - } -} - -void MakeStateDefines(const FStateLabels *list) -{ - MakeStateList(list, StateLabels); -} - -void AddStateDefines(const FStateLabels *list) -{ - if (list != NULL) for(int i=0;iNumLabels;i++) - { - if (list->Labels[i].Children == NULL) - { - if (!FindStateLabelInList(StateLabels, list->Labels[i].Label, false)) - { - FStateDefine def; - - def.Label = list->Labels[i].Label; - def.State = list->Labels[i].State; - StateLabels.Push(def); - } - } - } -} - -//========================================================================== -// +//*** // PrepareStateParameters // creates an empty parameter list for a parameterized function call // @@ -403,7 +152,7 @@ int PrepareStateParameters(FState * state, int numparams) } //========================================================================== -// +//*** // DoActionSpecials // handles action specials as code pointers // @@ -457,40 +206,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, bool multistate, int * state } //========================================================================== -// -// RetargetState(Pointer)s -// -// These functions are used when a goto follows one or more labels. -// Because multiple labels are permitted to occur consecutively with no -// intervening states, it is not enough to remember the last label defined -// and adjust it. So these functions search for all labels that point to -// the current position in the state array and give them a copy of the -// target string instead. -// -//========================================================================== - -static void RetargetStatePointers (intptr_t count, const char *target, TArray & statelist) -{ - for(unsigned i = 0;i 0) - { - RetargetStatePointers(count, target, statelist[i].Children); - } - } -} - -static void RetargetStates (intptr_t count, const char *target) -{ - RetargetStatePointers(count, target, StateLabels); -} - -//========================================================================== -// +//*** // Reads a state label that may contain '.'s. // processes a state block // @@ -515,7 +231,7 @@ static FString ParseStateString(FScanner &sc) } //========================================================================== -// +//*** // ParseStates // parses a state block // @@ -551,10 +267,11 @@ do_goto: if (laststate != NULL) { // Following a state definition: Modify it. laststate->NextState = (FState*)copystring(statestring); + laststate->DefineFlags = SDF_LABEL; } else if (lastlabel >= 0) { // Following a label: Retarget it. - RetargetStates (count+1, statestring); + bag.statedef.RetargetStates (count+1, statestring); } else { @@ -566,11 +283,11 @@ do_goto: do_stop: if (laststate!=NULL) { - laststate->NextState=(FState*)-1; + laststate->DefineFlags = SDF_STOP; } else if (lastlabel >=0) { - RetargetStates (count+1, NULL); + bag.statedef.RetargetStates (count+1, NULL); } else { @@ -585,7 +302,7 @@ do_stop: sc.ScriptError("%s before first state", sc.String); continue; } - laststate->NextState=(FState*)-2; + laststate->DefineFlags = SDF_WAIT; } else if (!statestring.CompareNoCase("LOOP")) { @@ -595,6 +312,7 @@ do_stop: continue; } laststate->NextState=(FState*)(lastlabel+1); + laststate->DefineFlags = SDF_INDEX; } else { @@ -607,7 +325,7 @@ do_stop: do { lastlabel = count; - AddState(statestring, (FState *) (count+1)); + bag.statedef.AddState(statestring, (FState *) (count+1), SDF_INDEX); statestring = ParseStateString(sc); if (!statestring.CompareNoCase("GOTO")) { @@ -788,7 +506,7 @@ do_stop: } sc.UnGet(); endofstate: - StateArray.Push(state); + bag.StateArray.Push(state); while (*statestrp) { int frame=((*statestrp++)&223)-'A'; @@ -800,10 +518,10 @@ endofstate: } state.Frame=(state.Frame&(SF_FULLBRIGHT))|frame; - StateArray.Push(state); + bag.StateArray.Push(state); count++; } - laststate=&StateArray[count]; + laststate=&bag.StateArray[count]; count++; } } @@ -815,240 +533,3 @@ endofstate: return count; } -//========================================================================== -// -// ResolveGotoLabel -// -//========================================================================== - -static FState *ResolveGotoLabel (FScanner &sc, AActor *actor, const PClass *mytype, char *name) -{ - const PClass *type=mytype; - FState *state; - char *namestart = name; - char *label, *offset, *pt; - int v; - - // Check for classname - if ((pt = strstr (name, "::")) != NULL) - { - const char *classname = name; - *pt = '\0'; - name = pt + 2; - - // The classname may either be "Super" to identify this class's immediate - // superclass, or it may be the name of any class that this one derives from. - if (stricmp (classname, "Super") == 0) - { - type = type->ParentClass; - actor = GetDefaultByType (type); - } - else - { - // first check whether a state of the desired name exists - const PClass *stype = PClass::FindClass (classname); - if (stype == NULL) - { - sc.ScriptError ("%s is an unknown class.", classname); - } - if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor))) - { - sc.ScriptError ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars()); - } - if (!stype->IsAncestorOf (type)) - { - sc.ScriptError ("%s is not derived from %s so cannot access its states.", - type->TypeName.GetChars(), stype->TypeName.GetChars()); - } - if (type != stype) - { - type = stype; - actor = GetDefaultByType (type); - } - } - } - label = name; - // Check for offset - offset = NULL; - if ((pt = strchr (name, '+')) != NULL) - { - *pt = '\0'; - offset = pt + 1; - } - v = offset ? strtol (offset, NULL, 0) : 0; - - // Get the state's address. - if (type==mytype) state = FindState (actor, type, label); - else state = FindStateInClass (actor, type, label); - - if (state != NULL) - { - state += v; - } - else if (v != 0) - { - sc.ScriptError ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars()); - } - delete[] namestart; // free the allocated string buffer - return state; -} - -//========================================================================== -// -// FixStatePointers -// -// Fixes an actor's default state pointers. -// -//========================================================================== - -static void FixStatePointers (FActorInfo *actor, TArray & list) -{ - for(unsigned i=0;i= 1 && v < 0x10000) - { - list[i].State = actor->OwnedStates + v - 1; - } - if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children); - } -} - -//========================================================================== -// -// FixStatePointersAgain -// -// Resolves an actor's state pointers that were specified as jumps. -// -//========================================================================== - -static void FixStatePointersAgain (FScanner &sc, FActorInfo *actor, AActor *defaults, TArray & list) -{ - for(unsigned i=0;iClass, (char *)list[i].State); - } - if (list[i].Children.Size() > 0) FixStatePointersAgain(sc, actor, defaults, list[i].Children); - } -} - - -//========================================================================== -// -// FinishStates -// copies a state block and fixes all state links -// -//========================================================================== - -int FinishStates (FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag) -{ - static int c=0; - int count = StateArray.Size(); - - if (count > 0) - { - FState *realstates = new FState[count]; - int i; - int currange; - - memcpy(realstates, &StateArray[0], count*sizeof(FState)); - actor->OwnedStates = realstates; - actor->NumOwnedStates = count; - - // adjust the state pointers - // In the case new states are added these must be adjusted, too! - FixStatePointers (actor, StateLabels); - - for(i = currange = 0; i < count; i++) - { - // resolve labels and jumps - switch((ptrdiff_t)realstates[i].NextState) - { - case 0: // next - realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]); - break; - - case -1: // stop - realstates[i].NextState = NULL; - break; - - case -2: // wait - realstates[i].NextState = &realstates[i]; - break; - - default: // loop - if ((size_t)realstates[i].NextState < 0x10000) - { - realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1]; - } - else // goto - { - realstates[i].NextState = ResolveGotoLabel (sc, defaults, bag.Info->Class, (char *)realstates[i].NextState); - } - } - } - } - StateArray.Clear (); - - // Fix state pointers that are gotos - FixStatePointersAgain (sc, actor, defaults, StateLabels); - - return count; -} - -//========================================================================== -// -// For getting a state address from the parent -// No attempts have been made to add new functionality here -// This is strictly for keeping compatibility with old WADs! -// -//========================================================================== -FState *CheckState(FScanner &sc, PClass *type) -{ - int v=0; - - if (sc.GetString() && !sc.Crossed) - { - if (sc.Compare("0")) return NULL; - else if (sc.Compare("PARENT")) - { - FState * state = NULL; - sc.MustGetString(); - - FActorInfo * info = type->ParentClass->ActorInfo; - - if (info != NULL) - { - state = info->FindState(FName(sc.String)); - } - - if (sc.GetString ()) - { - if (sc.Compare ("+")) - { - sc.MustGetNumber (); - v = sc.Number; - } - else - { - sc.UnGet (); - } - } - - if (state == NULL && v==0) return NULL; - - if (v!=0 && state==NULL) - { - sc.ScriptError("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars()); - return NULL; - } - state+=v; - return state; - } - else sc.ScriptError("Invalid state assignment"); - } - return NULL; -} - diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 521097ef..3a4345df 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -383,7 +383,7 @@ static int read_config_file(const char *name, bool ismain) bank->tone[i].name = w[2]; bank->tone[i].fontbank = atoi(w[3]); bank->tone[i].fontpreset = atoi(w[4]); - if (bank->tone[i].fontbank == 128 || (w[5][0] >= '0' && w[5][0] <= '9')) + if (words > 5 && (bank->tone[i].fontbank == 128 || (w[5][0] >= '0' && w[5][0] <= '9'))) { bank->tone[i].fontnote = atoi(w[5]); j = 6; diff --git a/src/v_collection.cpp b/src/v_collection.cpp index 78301287..b8ee25d8 100644 --- a/src/v_collection.cpp +++ b/src/v_collection.cpp @@ -62,12 +62,7 @@ void FImageCollection::Add (const char **patchNames, int numPatches, int namespc for (int i = 0; i < numPatches; ++i) { - FTextureID picnum = TexMan.AddPatch (patchNames[i], namespc, true); - - if (!picnum.Exists() && namespc != ns_sprites) - { - picnum = TexMan.AddPatch (patchNames[i], ns_sprites); - } + FTextureID picnum = TexMan.CheckForTexture(patchNames[i], namespc); ImageMap[OldCount + i] = picnum; } } diff --git a/src/v_font.cpp b/src/v_font.cpp index 3e349031..2388e025 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -1768,7 +1768,7 @@ void V_InitCustomFonts() return; wrong: - sc.ScriptError ("Invalid combination of properties in font '%s'", namebuffer); + sc.ScriptError ("Invalid combination of properties in font '%s'", namebuffer.GetChars()); } //========================================================================== diff --git a/src/v_video.h b/src/v_video.h index b02e4ea1..788b3190 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -114,13 +114,6 @@ enum HUD_HorizCenter }; -// Screenshot buffer image data types -enum ESSType -{ - SS_PAL, - SS_RGB, - SS_BGRA -}; class FFont; struct FRemapTable; diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index d51dc042..cf49c684 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -763,7 +763,7 @@ void WI_drawLF () { int y = WI_TITLEY; - FTexture * tex = wbs->lname0[0]? TexMan[wbs->lname0] : NULL; + FTexture * tex = wbs->LName0; // draw if (tex) @@ -825,7 +825,7 @@ void WI_drawEL () } // draw - FTexture * tex = wbs->lname1[0]? TexMan[wbs->lname1] : NULL; + FTexture * tex = wbs->LName1; if (tex) { screen->DrawTexture(tex, (SCREENWIDTH - tex->GetWidth() * CleanXfac) / 2, y * CleanYfac, DTA_CleanNoMove, true, TAG_DONE); diff --git a/src/wi_stuff.h b/src/wi_stuff.h index 266fe166..dee36e73 100644 --- a/src/wi_stuff.h +++ b/src/wi_stuff.h @@ -24,6 +24,8 @@ #include "doomdef.h" +class FTexture; + // // INTERMISSION // Structure passed e.g. to WI_Start(wb) @@ -50,8 +52,8 @@ struct wbstartstruct_t FString current; // [RH] Name of map just finished FString next; // next level, [RH] actual map name - FString lname0; - FString lname1; + FTexture *LName0; + FTexture *LName1; int maxkills; int maxitems; diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 91caf723..3e7d2834 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -13,7 +13,8 @@ const int SXF_ABSOLUTEMOMENTUM=8; const int SXF_SETMASTER=16; const int SXF_NOCHECKPOSITION = 32; const int SXF_TELEFRAG=64; -const int SXF_TRANSFERAMBUSHFLAG=128; +// 128 was uses by Skulltag +const int SXF_TRANSFERAMBUSHFLAG=256; // Flags for A_Chase const int CHF_FASTCHASE = 1; @@ -28,3 +29,17 @@ const int LOF_NOSOUNDCHECK = 2; const int LOF_DONTCHASEGOAL = 4; const int LOF_NOSEESOUND = 8; const int LOF_FULLVOLSEESOUND = 16; + +// Morph constants +const int MRF_ADDSTAMINA = 1; +const int MRF_FULLHEALTH = 2; +const int MRF_UNDOBYTOMEOFPOWER = 4; +const int MRF_UNDOBYCHAOSDEVICE = 8; +const int MRF_FAILNOTELEFRAG = 16; +const int MRF_FAILNOLAUGH = 32; +const int MRF_WHENINVULNERABLE = 64; +const int MRF_LOSEACTUALWEAPON = 128; +const int MRF_NEWTIDBEHAVIOUR = 256; +const int MRF_UNDOBYDEATH = 512; +const int MRF_UNDOBYDEATHFORCED = 1024; +const int MRF_UNDOBYDEATHSAVES = 2048; diff --git a/wadsrc/static/actors/shared/splashes.txt b/wadsrc/static/actors/shared/splashes.txt index 64bb1490..56713fd1 100644 --- a/wadsrc/static/actors/shared/splashes.txt +++ b/wadsrc/static/actors/shared/splashes.txt @@ -65,7 +65,7 @@ ACTOR LavaSmoke +NOGRAVITY +DONTSPLASH RenderStyle Translucent - Alpha Default + DefaultAlpha States { Spawn: