- Fixed: deadthings.txt contained a superfluous ';' which created parsing errors

with my changed code.
- Cleaned up DECORATE parser a little - moved the old style parsing code into its 
  own file and rearranged a few things.
- Made ProcessStates non-static so that it doesn't need to be passed as an argument
  to all functions in the DECORATE parser.
- Moved DECORATE parser files into their own subdirectory.
- Optimization: SC_GetToken no longer sets sc_name for identifiers. In most cases
  this creates needless overhead by adding a potentially unneeded name to the name
  table and looking up the name. In almost all cases where a name is needed it's as
  easy to assign sc_String to the name variable.
- Added enum definitions to DECORATE.


SVN r537 (trunk)
This commit is contained in:
Christoph Oelckers 2007-05-28 14:46:49 +00:00
parent 91241eb96e
commit 50f75b6e8a
28 changed files with 3341 additions and 3191 deletions

View file

@ -1,3 +1,17 @@
May 28, 2007 (Changes by Graf Zahl)
- Fixed: deadthings.txt contained a superfluous ';' which created parsing errors
with my changed code.
- Cleaned up DECORATE parser a little - moved the old style parsing code into its
own file and rearranged a few things.
- Made ProcessStates non-static so that it doesn't need to be passed as an argument
to all functions in the DECORATE parser.
- Moved DECORATE parser files into their own subdirectory.
- Optimization: SC_GetToken no longer sets sc_name for identifiers. In most cases
this creates needless overhead by adding a potentially unneeded name to the name
table and looking up the name. In almost all cases where a name is needed it's as
easy to assign sc_String to the name variable.
- Added enum definitions to DECORATE.
May 27, 2007 (Changes by Graf Zahl)
- Fixed: Hirestex replacements for sprites didn't work properly due to some
incorrect calculations in R_ProjectSprite.

View file

@ -63,7 +63,7 @@
#include "r_draw.h"
#include "v_palette.h"
#include "a_sharedglobal.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
#include "vectors.h"
#include "dobject.h"

View file

@ -11,7 +11,7 @@
#include "p_effect.h"
#include "gi.h"
#include "templates.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
static FRandom pr_punch ("Punch");
static FRandom pr_saw ("Saw");

View file

@ -6,7 +6,7 @@
#include "p_enemy.h"
#include "gstrings.h"
#include "a_action.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
//
// Mancubus attack,

View file

@ -4,7 +4,7 @@
#include "p_local.h"
#include "a_doomglobal.h"
#include "a_action.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
void A_PainAttack (AActor *);
void A_PainDie (AActor *);

View file

@ -1,5 +1,5 @@
#include "actor.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
#include "p_conversation.h"
#include "p_lnspec.h"
#include "a_action.h"

View file

@ -52,7 +52,7 @@
#include "templates.h"
#include "cmdlib.h"
extern void LoadDecorations (void (*process)(FState *, int));
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
@ -215,7 +215,7 @@ int GetSpriteIndex(const char * spritename)
//
//==========================================================================
static void ProcessStates (FState *states, int numstates)
void ProcessStates (FState *states, int numstates)
{
int sprite = -1;
@ -278,7 +278,7 @@ void FActorInfo::StaticInit ()
}
Printf ("LoadDecorations: Load external actors.\n");
LoadDecorations (ProcessStates);
LoadDecorations ();
}
//==========================================================================

View file

@ -453,6 +453,7 @@ extern FDoomEdMap DoomEdMap;
int GetSpriteIndex(const char * spritename);
void MakeStateNameList(const char * fname, TArray<FName> * out);
void ProcessStates (FState *states, int numstates);
#include "infomacros.h"

View file

@ -45,7 +45,7 @@
#include "r_data.h"
#include "w_wad.h"
#include "a_strifeglobal.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
void FActorInfo::BuildDefaults ()
{

View file

@ -43,7 +43,7 @@
#include "a_sharedglobal.h"
#include "a_doomglobal.h"
#include "a_action.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
#include "gi.h"

View file

@ -52,7 +52,7 @@
#include "a_action.h"
#include "a_keys.h"
#include "p_conversation.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
#include "g_game.h"
// MACROS ------------------------------------------------------------------

View file

@ -26,7 +26,7 @@
#include "p_effect.h"
#include "a_doomglobal.h"
#include "templates.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
// MACROS ------------------------------------------------------------------

View file

@ -50,7 +50,7 @@
#include "doomdef.h"
#include "c_dispatch.h"
#include "tarray.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
static FRandom pr_skullpop ("SkullPop");

View file

@ -1193,7 +1193,7 @@ void R_ProjectSprite (AActor *thing, int fakeside)
if (thing == NULL ||
(thing->renderflags & RF_INVISIBLE) ||
thing->RenderStyle == STYLE_None ||
(thing->RenderStyle >= STYLE_Translucent && thing->alpha <= 0))
(thing->RenderStyle >= STYLE_Translucent && thing->alpha <= 0))
{
return;
}

View file

@ -390,7 +390,7 @@ bool SC_GetToken ()
{
if (SC_ScanString (true))
{
if (sc_TokenType == TK_Identifier || sc_TokenType == TK_NameConst)
if (sc_TokenType == TK_NameConst)
{
sc_Name = FName(sc_String);
}
@ -854,6 +854,10 @@ FString SC_TokenName (int token, const char *string)
"'stop'",
"'eval'",
"'evalnot'",
"'pickup'",
"'breakable'",
"'projectile'",
"'#include'",
};
FString work;

View file

@ -145,6 +145,10 @@ enum
TK_Stop,
TK_Eval,
TK_EvalNot,
TK_Pickup,
TK_Breakable,
TK_Projectile,
TK_Include,
TK_LastToken
};

File diff suppressed because it is too large Load diff

View file

@ -143,6 +143,12 @@ std2:
'evalnot' { RET(TK_EvalNot); }
'action' { RET(TK_Action); }
/* other DECORATE top level keywords */
'#include' { RET(TK_Include); }
'pickup' { RET(TK_Pickup); }
'breakable' { RET(TK_Breakable); }
'projectile' { RET(TK_Projectile); }
L (L|D)* { RET(TK_Identifier); }
("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?)

View file

@ -38,7 +38,6 @@
#include "info.h"
#include "sc_man.h"
#include "tarray.h"
#include "w_wad.h"
#include "templates.h"
#include "r_defs.h"
#include "r_draw.h"
@ -53,18 +52,8 @@
#include "thingdef.h"
#include "vectors.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
enum EDefinitionType
{
DEF_Decoration,
DEF_BreakableDecoration,
DEF_Pickup,
DEF_Projectile,
};
struct FExtraInfo
{
char DeathSprite[5];
@ -111,14 +100,6 @@ IMPLEMENT_STATELESS_ACTOR (AFakeInventory, Any, -1, 0)
PROP_Flags (MF_SPECIAL)
END_DEFAULTS
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void ProcessActor(void (*process)(FState *, int));
void ParseClass();
void ParseGlobalConst();
void FinishThingdef();
void InitDecorateTranslations();
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
void A_ScreamAndUnblock (AActor *);
@ -127,17 +108,10 @@ void A_ActiveSound (AActor *);
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void ParseDecorate (void (*process)(FState *, int));
static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
TArray<FState> &states, FExtraInfo &extra, EDefinitionType def);
static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
TArray<FActorInfo *> Decorations;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const char *RenderStyles[] =
@ -248,332 +222,255 @@ static const char *FlagNames3[] =
//==========================================================================
//
// LoadDecorations
// ParseOldDecoration
//
// Called from FActor::StaticInit()
// Reads an old style decoration object
//
//==========================================================================
void LoadDecorations (void (*process)(FState *, int))
{
int lastlump, lump;
InitDecorateTranslations();
lastlump = 0;
while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1)
{
SC_OpenLumpNum (lump, Wads.GetLumpFullName(lump));
ParseDecorate (process);
SC_Close ();
}
FinishThingdef();
}
//==========================================================================
//
// ParseDecorate
//
// Parses a single DECORATE lump
//
//==========================================================================
static void ParseDecorate (void (*process)(FState *, int))
void ParseOldDecoration(EDefinitionType def)
{
TArray<FState> states;
FExtraInfo extra;
PClass *type;
PClass *parent;
EDefinitionType def;
FActorInfo *info;
FName typeName;
int recursion=0;
// Get actor class name.
while (true)
if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory);
else parent = RUNTIME_CLASS(AActor);
SC_MustGetString();
typeName = FName(sc_String);
type = parent->CreateDerivedClass (typeName, parent->Size);
info = type->ActorInfo;
info->GameFilter = 0x80;
MakeStateDefines(parent->ActorInfo->StateList);
SC_MustGetString ();
while (!SC_Compare ("{"))
{
if (!SC_GetString ())
if (SC_Compare ("Doom"))
{
if (recursion==0) return;
SC_Close();
SC_RestoreScriptState();
recursion--;
continue;
info->GameFilter |= GAME_Doom;
}
if (SC_Compare ("#include"))
else if (SC_Compare ("Heretic"))
{
int lump;
SC_MustGetString();
// This is not using SC_Open because it can print a more useful error message when done here
lump = Wads.CheckNumForFullName(sc_String);
if (lump==-1) lump = Wads.CheckNumForName(sc_String);
if (lump==-1) SC_ScriptError("Lump '%s' not found", sc_String);
SC_SaveScriptState();
SC_OpenLumpNum(lump, sc_String);
recursion++;
continue;
info->GameFilter |= GAME_Heretic;
}
if (SC_Compare ("Actor"))
else if (SC_Compare ("Hexen"))
{
ProcessActor (process);
continue;
info->GameFilter |= GAME_Hexen;
}
if (SC_Compare ("Pickup"))
else if (SC_Compare ("Raven"))
{
parent = RUNTIME_CLASS(AFakeInventory);
def = DEF_Pickup;
SC_MustGetString ();
info->GameFilter |= GAME_Raven;
}
else if (SC_Compare ("Breakable"))
else if (SC_Compare ("Strife"))
{
parent = RUNTIME_CLASS(AActor);
def = DEF_BreakableDecoration;
SC_MustGetString ();
info->GameFilter |= GAME_Strife;
}
else if (SC_Compare ("Projectile"))
{
parent = RUNTIME_CLASS(AActor);
def = DEF_Projectile;
SC_MustGetString ();
}
else if (SC_Compare ("class"))
{
ParseClass();
continue;
}
else if (SC_Compare ("Const"))
{
ParseGlobalConst();
continue;
}
else
{
parent = RUNTIME_CLASS(AActor);
def = DEF_Decoration;
}
typeName = FName(sc_String);
type = parent->CreateDerivedClass (typeName, parent->Size);
info = type->ActorInfo;
info->GameFilter = 0x80;
Decorations.Push (info);
MakeStateDefines(parent->ActorInfo->StateList);
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
{
SC_ScriptError ("Unknown game type %s", sc_String);
}
SC_MustGetString ();
}
if (info->GameFilter == 0x80)
else if (SC_Compare ("Any"))
{
info->GameFilter = GAME_Any;
}
else
{
info->GameFilter &= ~0x80;
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;
}
states.Clear ();
memset (&extra, 0, sizeof(extra));
ParseInsideDecoration (info, (AActor *)(type->Defaults), states, extra, def);
states.Clear ();
memset (&extra, 0, sizeof(extra));
ParseInsideDecoration (info, (AActor *)(type->Defaults), states, extra, def);
info->NumOwnedStates = states.Size();
if (info->NumOwnedStates == 0)
{
SC_ScriptError ("%s does not define any animation frames", typeName.GetChars() );
}
else if (extra.SpawnEnd == 0)
{
SC_ScriptError ("%s does not have a Frames definition", typeName.GetChars() );
}
else if (def == DEF_BreakableDecoration && extra.DeathEnd == 0)
{
SC_ScriptError ("%s does not have a DeathFrames definition", typeName.GetChars() );
}
else if (extra.IceDeathEnd != 0 && extra.bGenericIceDeath)
{
SC_ScriptError ("You cannot use IceDeathFrames and GenericIceDeath together");
}
info->NumOwnedStates = states.Size();
if (info->NumOwnedStates == 0)
{
SC_ScriptError ("%s does not define any animation frames", typeName.GetChars() );
}
else if (extra.SpawnEnd == 0)
{
SC_ScriptError ("%s does not have a Frames definition", typeName.GetChars() );
}
else if (def == DEF_BreakableDecoration && extra.DeathEnd == 0)
{
SC_ScriptError ("%s does not have a DeathFrames definition", typeName.GetChars() );
}
else if (extra.IceDeathEnd != 0 && extra.bGenericIceDeath)
{
SC_ScriptError ("You cannot use IceDeathFrames and GenericIceDeath together");
}
if (extra.IceDeathEnd != 0)
{
// Make a copy of the final frozen frame for A_FreezeDeathChunks
FState icecopy = states[extra.IceDeathEnd-1];
states.Push (icecopy);
info->NumOwnedStates += 1;
}
if (extra.IceDeathEnd != 0)
{
// Make a copy of the final frozen frame for A_FreezeDeathChunks
FState icecopy = states[extra.IceDeathEnd-1];
states.Push (icecopy);
info->NumOwnedStates += 1;
}
info->OwnedStates = new FState[info->NumOwnedStates];
memcpy (info->OwnedStates, &states[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
if (info->NumOwnedStates == 1)
{
info->OwnedStates->Tics = 0;
info->OwnedStates->Misc1 = 0;
info->OwnedStates->Frame &= ~SF_BIGTIC;
}
else
{
size_t i;
info->OwnedStates = new FState[info->NumOwnedStates];
memcpy (info->OwnedStates, &states[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
if (info->NumOwnedStates == 1)
{
info->OwnedStates->Tics = 0;
info->OwnedStates->Misc1 = 0;
info->OwnedStates->Frame &= ~SF_BIGTIC;
}
else
{
size_t i;
// Spawn states loop endlessly
for (i = extra.SpawnStart; i < extra.SpawnEnd-1; ++i)
// Spawn states loop endlessly
for (i = extra.SpawnStart; i < extra.SpawnEnd-1; ++i)
{
info->OwnedStates[i].NextState = &info->OwnedStates[i+1];
}
info->OwnedStates[i].NextState = &info->OwnedStates[extra.SpawnStart];
// Death states are one-shot and freeze on the final state
if (extra.DeathEnd != 0)
{
for (i = extra.DeathStart; i < extra.DeathEnd-1; ++i)
{
info->OwnedStates[i].NextState = &info->OwnedStates[i+1];
}
info->OwnedStates[i].NextState = &info->OwnedStates[extra.SpawnStart];
// Death states are one-shot and freeze on the final state
if (extra.DeathEnd != 0)
if (extra.bDiesAway || def == DEF_Projectile)
{
for (i = extra.DeathStart; i < extra.DeathEnd-1; ++i)
{
info->OwnedStates[i].NextState = &info->OwnedStates[i+1];
}
if (extra.bDiesAway || def == DEF_Projectile)
{
info->OwnedStates[i].NextState = NULL;
}
else
{
info->OwnedStates[i].Tics = 0;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Frame &= ~SF_BIGTIC;
}
if (def == DEF_Projectile)
{
if (extra.bExplosive)
{
info->OwnedStates[extra.DeathStart].Action = A_ExplodeParms;
}
}
else
{
// The first frame plays the death sound and
// the second frame makes it nonsolid.
info->OwnedStates[extra.DeathStart].Action= A_Scream;
if (extra.bSolidOnDeath)
{
}
else if (extra.DeathStart + 1 < extra.DeathEnd)
{
info->OwnedStates[extra.DeathStart+1].Action = A_NoBlocking;
}
else
{
info->OwnedStates[extra.DeathStart].Action = A_ScreamAndUnblock;
}
if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height;
info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight);
}
AddState("Death", &info->OwnedStates[extra.DeathStart]);
info->OwnedStates[i].NextState = NULL;
}
else
{
info->OwnedStates[i].Tics = 0;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Frame &= ~SF_BIGTIC;
}
// Burn states are the same as death states, except they can optionally terminate
if (extra.FireDeathEnd != 0)
if (def == DEF_Projectile)
{
for (i = extra.FireDeathStart; i < extra.FireDeathEnd-1; ++i)
if (extra.bExplosive)
{
info->OwnedStates[i].NextState = &info->OwnedStates[i+1];
info->OwnedStates[extra.DeathStart].Action = A_ExplodeParms;
}
if (extra.bBurnAway)
{
info->OwnedStates[i].NextState = NULL;
}
else
{
info->OwnedStates[i].Tics = 0;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Frame &= ~SF_BIGTIC;
}
// The first frame plays the burn sound and
}
else
{
// The first frame plays the death sound and
// the second frame makes it nonsolid.
info->OwnedStates[extra.FireDeathStart].Action = A_ActiveSound;
if (extra.bSolidOnBurn)
info->OwnedStates[extra.DeathStart].Action= A_Scream;
if (extra.bSolidOnDeath)
{
}
else if (extra.FireDeathStart + 1 < extra.FireDeathEnd)
else if (extra.DeathStart + 1 < extra.DeathEnd)
{
info->OwnedStates[extra.FireDeathStart+1].Action = A_NoBlocking;
info->OwnedStates[extra.DeathStart+1].Action = A_NoBlocking;
}
else
{
info->OwnedStates[extra.FireDeathStart].Action = A_ActiveAndUnblock;
info->OwnedStates[extra.DeathStart].Action = A_ScreamAndUnblock;
}
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height;
type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight);
AddState("Burn", &info->OwnedStates[extra.FireDeathStart]);
}
// Ice states are similar to burn and death, except their final frame enters
// a loop that eventually causes them to bust to pieces.
if (extra.IceDeathEnd != 0)
{
for (i = extra.IceDeathStart; i < extra.IceDeathEnd-1; ++i)
{
info->OwnedStates[i].NextState = &info->OwnedStates[i+1];
}
info->OwnedStates[i].NextState = &info->OwnedStates[info->NumOwnedStates-1];
info->OwnedStates[i].Tics = 6;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Action = A_FreezeDeath;
i = info->NumOwnedStates - 1;
info->OwnedStates[i].NextState = &info->OwnedStates[i];
info->OwnedStates[i].Tics = 2;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Action = A_FreezeDeathChunks;
AddState("Ice", &info->OwnedStates[extra.IceDeathStart]);
}
else if (extra.bGenericIceDeath)
{
AddState("Ice", &AActor::States[AActor::S_GENERICFREEZEDEATH]);
if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height;
info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight);
}
AddState("Death", &info->OwnedStates[extra.DeathStart]);
}
if (def == DEF_BreakableDecoration)
// Burn states are the same as death states, except they can optionally terminate
if (extra.FireDeathEnd != 0)
{
((AActor *)(type->Defaults))->flags |= MF_SHOOTABLE;
for (i = extra.FireDeathStart; i < extra.FireDeathEnd-1; ++i)
{
info->OwnedStates[i].NextState = &info->OwnedStates[i+1];
}
if (extra.bBurnAway)
{
info->OwnedStates[i].NextState = NULL;
}
else
{
info->OwnedStates[i].Tics = 0;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Frame &= ~SF_BIGTIC;
}
// The first frame plays the burn sound and
// the second frame makes it nonsolid.
info->OwnedStates[extra.FireDeathStart].Action = A_ActiveSound;
if (extra.bSolidOnBurn)
{
}
else if (extra.FireDeathStart + 1 < extra.FireDeathEnd)
{
info->OwnedStates[extra.FireDeathStart+1].Action = A_NoBlocking;
}
else
{
info->OwnedStates[extra.FireDeathStart].Action = A_ActiveAndUnblock;
}
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height;
type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight);
AddState("Burn", &info->OwnedStates[extra.FireDeathStart]);
}
if (def == DEF_Projectile)
// Ice states are similar to burn and death, except their final frame enters
// a loop that eventually causes them to bust to pieces.
if (extra.IceDeathEnd != 0)
{
((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE;
for (i = extra.IceDeathStart; i < extra.IceDeathEnd-1; ++i)
{
info->OwnedStates[i].NextState = &info->OwnedStates[i+1];
}
info->OwnedStates[i].NextState = &info->OwnedStates[info->NumOwnedStates-1];
info->OwnedStates[i].Tics = 6;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Action = A_FreezeDeath;
i = info->NumOwnedStates - 1;
info->OwnedStates[i].NextState = &info->OwnedStates[i];
info->OwnedStates[i].Tics = 2;
info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].Action = A_FreezeDeathChunks;
AddState("Ice", &info->OwnedStates[extra.IceDeathStart]);
}
else if (extra.bGenericIceDeath)
{
AddState("Ice", &AActor::States[AActor::S_GENERICFREEZEDEATH]);
}
AddState("Spawn", &info->OwnedStates[extra.SpawnStart]);
InstallStates(info, ((AActor *)(type->Defaults)));
process (info->OwnedStates, info->NumOwnedStates);
}
if (def == DEF_BreakableDecoration)
{
((AActor *)(type->Defaults))->flags |= MF_SHOOTABLE;
}
if (def == DEF_Projectile)
{
((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE;
}
AddState("Spawn", &info->OwnedStates[extra.SpawnStart]);
InstallStates (info, ((AActor *)(type->Defaults)));
ProcessStates (info->OwnedStates, info->NumOwnedStates);
}
//==========================================================================

View file

@ -73,8 +73,6 @@
const PClass *QuestItemClasses[31];
extern TArray<FActorInfo *> Decorations;
// allow decal specifications in DECORATE. Decals are loaded after DECORATE so the names must be stored here.
TArray<char*> DecalNames;
// all state parameters
@ -1169,7 +1167,6 @@ static FActorInfo * CreateNewActor(FActorInfo ** parentc, Baggage *bag)
PClass * ti = parent->CreateDerivedClass (typeName, parent->Size);
FActorInfo * info = ti->ActorInfo;
Decorations.Push (info);
MakeStateDefines(parent->ActorInfo->StateList);
ResetBaggage (bag);
@ -2150,7 +2147,7 @@ void ParseActorProperties (Baggage &bag)
// Reads an actor definition
//
//==========================================================================
void ProcessActor(void (*process)(FState *, int))
void ProcessActor()
{
FActorInfo * info=NULL;
AActor * defaults;
@ -2169,8 +2166,8 @@ void ProcessActor(void (*process)(FState *, int))
ParseActorProperties (bag);
FinishStates (info, defaults, bag);
InstallStates(info, defaults);
process(info->OwnedStates, info->NumOwnedStates);
InstallStates (info, defaults);
ProcessStates (info->OwnedStates, info->NumOwnedStates);
if (bag.DropItemSet)
{
if (bag.DropItemList == NULL)
@ -2252,7 +2249,7 @@ static void ActorConstDef (AActor *defaults, Baggage &bag)
// (Maybe there will be other types later.)
SC_MustGetToken(TK_Int);
SC_MustGetToken(TK_Identifier);
FName symname = sc_Name;
FName symname = sc_String;
SC_MustGetToken('=');
int expr = ParseExpression (false, bag.Info->Class);
SC_MustGetToken(';');
@ -2270,6 +2267,46 @@ static void ActorConstDef (AActor *defaults, Baggage &bag)
}
}
//==========================================================================
//
// ActorEnumDef
//
// Parses an enum definition.
//
//==========================================================================
static void ActorEnumDef (AActor *defaults, Baggage &bag)
{
int currvalue = 0;
SC_MustGetToken('{');
while (!SC_CheckToken('}'))
{
SC_MustGetToken(TK_Identifier);
FName symname = sc_String;
if (SC_CheckToken('='))
{
int expr = ParseExpression(false, bag.Info->Class);
currvalue = EvalExpressionI (expr, NULL, bag.Info->Class);
}
PSymbolConst *sym = new PSymbolConst;
sym->SymbolName = symname;
sym->SymbolType = SYM_Const;
sym->Value = currvalue;
if (bag.Info->Class->Symbols.AddSymbol (sym) == NULL)
{
delete sym;
SC_ScriptError ("'%s' is already defined in class '%s'.",
symname.GetChars(), bag.Info->Class->TypeName.GetChars());
}
// This allows a comma after the last value but doesn't enforce it.
if (SC_CheckToken('}')) break;
SC_MustGetToken(',');
currvalue++;
}
SC_MustGetToken(';');
}
//==========================================================================
//
// ParseGlobalConst
@ -2287,6 +2324,14 @@ void ParseGlobalConst()
ActorConstDef(GetDefault<AActor>(), bag);
}
void ParseGlobalEnum()
{
Baggage bag;
bag.Info = RUNTIME_CLASS(AActor)->ActorInfo;
ActorEnumDef(GetDefault<AActor>(), bag);
}
//==========================================================================
//
// ActorActionDef
@ -2309,7 +2354,7 @@ static void ActorActionDef (AActor *defaults, Baggage &bag)
SC_MustGetToken(TK_Native);
SC_MustGetToken(TK_Identifier);
funcname = sc_Name;
funcname = sc_String;
afd = FindFunction(sc_String);
if (afd == NULL)
{
@ -4177,6 +4222,7 @@ static const ActorProps props[] =
{ "disintegrate", ActorDisintegrateState, RUNTIME_CLASS(AActor) },
{ "donthurtshooter", ActorDontHurtShooter, RUNTIME_CLASS(AActor) },
{ "dropitem", ActorDropItem, RUNTIME_CLASS(AActor) },
{ "enum", ActorEnumDef, RUNTIME_CLASS(AActor) },
{ "explosiondamage", ActorExplosionDamage, RUNTIME_CLASS(AActor) },
{ "explosionradius", ActorExplosionRadius, RUNTIME_CLASS(AActor) },
{ "fastspeed", ActorFastSpeed, RUNTIME_CLASS(AActor) },
@ -4449,10 +4495,10 @@ void ParseClass()
FName supername;
SC_MustGetToken(TK_Identifier); // class name
classname = sc_Name;
classname = sc_String;
SC_MustGetToken(TK_Extends); // because I'm not supporting Object
SC_MustGetToken(TK_Identifier); // superclass name
supername = sc_Name;
supername = sc_String;
SC_MustGetToken(TK_Native); // use actor definitions for your own stuff
SC_MustGetToken('{');
@ -4478,190 +4524,15 @@ void ParseClass()
{
ActorConstDef (0, bag);
}
else if (sc_TokenType == TK_Enum)
{
ActorEnumDef (0, bag);
}
else
{
FString tokname = SC_TokenName(sc_TokenType, sc_String);
SC_ScriptError ("Expected 'action' or 'const' but got %s", tokname.GetChars());
SC_ScriptError ("Expected 'action', 'const' or 'enum' but got %s", tokname.GetChars());
}
SC_MustGetAnyToken();
}
}
bool ParseFunctionCall(Baggage &bag, FState & state)
{
// Make the action name lowercase to satisfy the gperf hashers
strlwr (sc_String);
FString funcname = sc_String;
int minreq=0;
memset(&state, 0, sizeof(state));
if (DoSpecialFunctions(state, false, &minreq, bag))
{
return true;
}
PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (FName(sc_String, true), true);
if (sym != NULL && sym->SymbolType == SYM_ActionFunction)
{
PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym);
state.Action = afd->Function;
if (!afd->Arguments.IsEmpty())
{
const char *params = afd->Arguments.GetChars();
int numparams = (int)afd->Arguments.Len();
int v;
if (!islower(*params))
{
SC_MustGetToken('(');
}
else
{
if (!SC_CheckToken('('))
{
return true;
}
}
int paramindex = PrepareStateParameters(&state, numparams);
int paramstart = paramindex;
bool varargs = params[numparams - 1] == '+';
if (varargs)
{
StateParameters[paramindex++] = 0;
}
while (*params)
{
switch(*params)
{
case 'I':
case 'i': // Integer
SC_MustGetNumber();
v=sc_Number;
break;
case 'F':
case 'f': // Fixed point
SC_MustGetFloat();
v=fixed_t(sc_Float*FRACUNIT);
break;
case 'S':
case 's': // Sound name
SC_MustGetString();
v=S_FindSound(sc_String);
break;
case 'M':
case 'm': // Actor name
case 'T':
case 't': // String
SC_MustGetString();
v = (int)(sc_String[0] ? FName(sc_String) : NAME_None);
break;
case 'L':
case 'l': // Jump label
SC_ScriptError("You cannot use state jump calls in action functions (%s tries to call %s)\n",
funcname.GetChars(), afd->SymbolName.GetChars());
break;
case 'C':
case 'c': // Color
SC_MustGetString ();
if (SC_Compare("none"))
{
v = -1;
}
else
{
int c = V_GetColor (NULL, sc_String);
// 0 needs to be the default so we have to mark the color.
v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
}
break;
case 'X':
case 'x':
v = ParseExpression (false, bag.Info->Class);
break;
case 'Y':
case 'y':
v = ParseExpression (true, bag.Info->Class);
break;
default:
assert(false);
v = -1;
break;
}
StateParameters[paramindex++] = v;
params++;
if (varargs)
{
StateParameters[paramstart]++;
}
if (*params)
{
if (*params == '+')
{
if (SC_CheckString(")"))
{
return true;
}
params--;
v = 0;
StateParameters.Push(v);
}
else if ((islower(*params) || *params=='!') && SC_CheckString(")"))
{
return true;
}
SC_MustGetStringName (",");
}
}
SC_MustGetStringName(")");
}
else
{
SC_MustGetString();
if (SC_Compare("("))
{
SC_ScriptError("You cannot pass parameters to '%s'\n",funcname.GetChars());
}
SC_UnGet();
}
return true;
}
return false;
}
void ParseActionFunction()
{
FState state;
Baggage bag;
bag.Info=RUNTIME_CLASS(AActor)->ActorInfo;
// for now only void functions with no parameters
SC_MustGetToken(TK_Void);
SC_MustGetString();
FName funcname = sc_String;
SC_MustGetToken('(');
SC_MustGetToken(')');
SC_MustGetToken('{');
// All this can do for the moment is parse a list of simple function calls, nothing more
while (SC_MustGetString(), sc_TokenType != '}');
{
ParseFunctionCall(bag, state);
SC_MustGetToken(';');
// Todo: Take the state's content and make a list of it.
}
}

View file

@ -71,5 +71,15 @@ enum
int FindLineSpecialEx (const char *string, int *minargs, int *maxargs);
// Types of old style decorations
enum EDefinitionType
{
DEF_Decoration,
DEF_BreakableDecoration,
DEF_Pickup,
DEF_Projectile,
};
#endif

View file

@ -696,7 +696,7 @@ static ExpData *ParseExpressionA (const PClass *cls)
}
SC_MustGetToken('.');
SC_MustGetToken(TK_Identifier);
PSymbol *sym = cls->Symbols.FindSymbol (sc_Name, true);
PSymbol *sym = cls->Symbols.FindSymbol (sc_String, true);
if (sym != NULL && sym->SymbolType == SYM_Const)
{
ExpData *data = new ExpData;
@ -713,7 +713,7 @@ static ExpData *ParseExpressionA (const PClass *cls)
}
else if (SC_CheckToken(TK_Identifier))
{
switch (sc_Name)
switch (FName(sc_String))
{
case NAME_Random:
{
@ -842,7 +842,7 @@ static ExpData *ParseExpressionA (const PClass *cls)
// Check if this is a constant
if (cls != NULL)
{
PSymbol *sym = cls->Symbols.FindSymbol (sc_Name, true);
PSymbol *sym = cls->Symbols.FindSymbol (sc_String, true);
if (sym != NULL && sym->SymbolType == SYM_Const)
{
ExpData *data = new ExpData;
@ -855,9 +855,10 @@ static ExpData *ParseExpressionA (const PClass *cls)
// Check if it's a variable we understand
int varid = -1;
FName vname = sc_String;
for (size_t i = 0; i < countof(ExpVars); i++)
{
if (sc_Name == ExpVars[i].name)
if (vname == ExpVars[i].name)
{
varid = (int)i;
break;

View file

@ -0,0 +1,170 @@
/*
** decorations.cpp
** Loads custom actors out of DECORATE lumps.
**
**---------------------------------------------------------------------------
** Copyright 2002-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.
**
** 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.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "actor.h"
#include "info.h"
#include "sc_man.h"
#include "tarray.h"
#include "w_wad.h"
#include "templates.h"
#include "s_sound.h"
#include "cmdlib.h"
#include "thingdef.h"
#include "vectors.h"
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void ProcessActor();
void ParseClass();
void ParseGlobalConst();
void ParseGlobalEnum();
void FinishThingdef();
void InitDecorateTranslations();
void ParseOldDecoration(EDefinitionType def);
// STATIC FUNCTION PROTOTYPES --------------------------------------------
//==========================================================================
//
// ParseDecorate
//
// Parses a single DECORATE lump
//
//==========================================================================
static void ParseDecorate ()
{
int recursion=0;
int lump;
// Get actor class name.
while (true)
{
SC_SavePos();
if (!SC_GetToken ())
{
if (recursion==0) return;
SC_Close();
SC_RestoreScriptState();
recursion--;
continue;
}
switch (sc_TokenType)
{
case TK_Include:
SC_MustGetString();
// This is not using SC_Open because it can print a more useful error message when done here
lump = Wads.CheckNumForFullName(sc_String);
if (lump==-1) lump = Wads.CheckNumForName(sc_String);
if (lump==-1) SC_ScriptError("Lump '%s' not found", sc_String);
SC_SaveScriptState();
SC_OpenLumpNum(lump, sc_String);
recursion++;
break;
case TK_Class:
ParseClass();
break;
case TK_Const:
ParseGlobalConst();
break;
case TK_Enum:
ParseGlobalEnum();
break;
case TK_Pickup:
ParseOldDecoration(DEF_Pickup);
break;
case TK_Breakable:
ParseOldDecoration(DEF_BreakableDecoration);
break;
case TK_Projectile:
ParseOldDecoration(DEF_Projectile);
break;
case ';':
// ';' is the start of a comment in the non-cmode parser which
// is used to parse parts of the DECORATE lump. If we don't add
// a check here the user will only get weird non-informative
// error messages if a semicolon is found.
SC_ScriptError("Unexpected ';'");
break;
case TK_Identifier:
// 'ACTOR' cannot be a keyword because it is also needed as a class identifier
// so let's do a special case for this.
if (SC_Compare("ACTOR"))
{
ProcessActor ();
break;
}
default:
// Yuck! Too bad that there's no better way to check this properly
SC_RestorePos();
ParseOldDecoration(DEF_Decoration);
break;
}
}
}
//==========================================================================
//
// LoadDecorations
//
// Called from FActor::StaticInit()
//
//==========================================================================
void LoadDecorations ()
{
int lastlump, lump;
InitDecorateTranslations();
lastlump = 0;
while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1)
{
SC_OpenLumpNum (lump, Wads.GetLumpFullName(lump));
ParseDecorate ();
SC_Close ();
}
FinishThingdef();
}

View file

@ -63,7 +63,7 @@
#include "vectors.h"
#include "a_sharedglobal.h"
#include "a_doomglobal.h"
#include "thingdef.h"
#include "thingdef/thingdef.h"
#include "v_video.h"

View file

@ -63,7 +63,7 @@ actor DeadShotgunGuy : ShotgunGuy 19
Spawn:
Goto Super::Death+4
}
};
}
// Dead imp ----------------------------------------------------------------

View file

@ -4283,15 +4283,15 @@
>
</File>
<File
RelativePath=".\src\decorations.cpp"
RelativePath=".\src\thingdef\olddecorations.cpp"
>
</File>
<File
RelativePath=".\src\thingdef.cpp"
RelativePath=".\src\thingdef\thingdef.cpp"
>
</File>
<File
RelativePath=".\src\thingdef.h"
RelativePath=".\src\thingdef\thingdef.h"
>
</File>
<File
@ -4299,7 +4299,15 @@
>
</File>
<File
RelativePath=".\src\thingdef_exp.cpp"
RelativePath=".\src\thingdef\thingdef_exp.cpp"
>
</File>
<File
RelativePath=".\src\thingdef\thingdef_main.cpp"
>
</File>
<File
RelativePath=".\src\thingdef\thingdef_specials.h"
>
</File>
</Filter>