- 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) May 27, 2007 (Changes by Graf Zahl)
- Fixed: Hirestex replacements for sprites didn't work properly due to some - Fixed: Hirestex replacements for sprites didn't work properly due to some
incorrect calculations in R_ProjectSprite. incorrect calculations in R_ProjectSprite.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -52,7 +52,7 @@
#include "templates.h" #include "templates.h"
#include "cmdlib.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 // 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 // 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; int sprite = -1;
@ -278,7 +278,7 @@ void FActorInfo::StaticInit ()
} }
Printf ("LoadDecorations: Load external actors.\n"); Printf ("LoadDecorations: Load external actors.\n");
LoadDecorations (ProcessStates); LoadDecorations ();
} }
//========================================================================== //==========================================================================

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -143,6 +143,12 @@ std2:
'evalnot' { RET(TK_EvalNot); } 'evalnot' { RET(TK_EvalNot); }
'action' { RET(TK_Action); } '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); } L (L|D)* { RET(TK_Identifier); }
("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?) ("0" [xX] H+ IS?) | ("0" D+ IS?) | (D+ IS?)

View file

@ -38,7 +38,6 @@
#include "info.h" #include "info.h"
#include "sc_man.h" #include "sc_man.h"
#include "tarray.h" #include "tarray.h"
#include "w_wad.h"
#include "templates.h" #include "templates.h"
#include "r_defs.h" #include "r_defs.h"
#include "r_draw.h" #include "r_draw.h"
@ -53,18 +52,8 @@
#include "thingdef.h" #include "thingdef.h"
#include "vectors.h" #include "vectors.h"
// MACROS ------------------------------------------------------------------
// TYPES ------------------------------------------------------------------- // TYPES -------------------------------------------------------------------
enum EDefinitionType
{
DEF_Decoration,
DEF_BreakableDecoration,
DEF_Pickup,
DEF_Projectile,
};
struct FExtraInfo struct FExtraInfo
{ {
char DeathSprite[5]; char DeathSprite[5];
@ -111,14 +100,6 @@ IMPLEMENT_STATELESS_ACTOR (AFakeInventory, Any, -1, 0)
PROP_Flags (MF_SPECIAL) PROP_Flags (MF_SPECIAL)
END_DEFAULTS END_DEFAULTS
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void ProcessActor(void (*process)(FState *, int));
void ParseClass();
void ParseGlobalConst();
void FinishThingdef();
void InitDecorateTranslations();
// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
void A_ScreamAndUnblock (AActor *); void A_ScreamAndUnblock (AActor *);
@ -127,17 +108,10 @@ void A_ActiveSound (AActor *);
// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void ParseDecorate (void (*process)(FState *, int));
static void ParseInsideDecoration (FActorInfo *info, AActor *defaults, static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
TArray<FState> &states, FExtraInfo &extra, EDefinitionType def); TArray<FState> &states, FExtraInfo &extra, EDefinitionType def);
static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states); static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
TArray<FActorInfo *> Decorations;
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
static const char *RenderStyles[] = 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)) void ParseOldDecoration(EDefinitionType def)
{
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))
{ {
TArray<FState> states; TArray<FState> states;
FExtraInfo extra; FExtraInfo extra;
PClass *type; PClass *type;
PClass *parent; PClass *parent;
EDefinitionType def;
FActorInfo *info; FActorInfo *info;
FName typeName; FName typeName;
int recursion=0;
// Get actor class name. if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory);
while (true) 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; info->GameFilter |= GAME_Doom;
SC_Close();
SC_RestoreScriptState();
recursion--;
continue;
} }
if (SC_Compare ("#include")) else if (SC_Compare ("Heretic"))
{ {
int lump; info->GameFilter |= GAME_Heretic;
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;
} }
if (SC_Compare ("Actor")) else if (SC_Compare ("Hexen"))
{ {
ProcessActor (process); info->GameFilter |= GAME_Hexen;
continue;
} }
if (SC_Compare ("Pickup")) else if (SC_Compare ("Raven"))
{ {
parent = RUNTIME_CLASS(AFakeInventory); info->GameFilter |= GAME_Raven;
def = DEF_Pickup;
SC_MustGetString ();
} }
else if (SC_Compare ("Breakable")) else if (SC_Compare ("Strife"))
{ {
parent = RUNTIME_CLASS(AActor); info->GameFilter |= GAME_Strife;
def = DEF_BreakableDecoration;
SC_MustGetString ();
} }
else if (SC_Compare ("Projectile")) else if (SC_Compare ("Any"))
{
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)
{ {
info->GameFilter = GAME_Any; info->GameFilter = GAME_Any;
} }
else 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 (); states.Clear ();
memset (&extra, 0, sizeof(extra)); memset (&extra, 0, sizeof(extra));
ParseInsideDecoration (info, (AActor *)(type->Defaults), states, extra, def); ParseInsideDecoration (info, (AActor *)(type->Defaults), states, extra, def);
info->NumOwnedStates = states.Size(); info->NumOwnedStates = states.Size();
if (info->NumOwnedStates == 0) if (info->NumOwnedStates == 0)
{ {
SC_ScriptError ("%s does not define any animation frames", typeName.GetChars() ); SC_ScriptError ("%s does not define any animation frames", typeName.GetChars() );
} }
else if (extra.SpawnEnd == 0) else if (extra.SpawnEnd == 0)
{ {
SC_ScriptError ("%s does not have a Frames definition", typeName.GetChars() ); SC_ScriptError ("%s does not have a Frames definition", typeName.GetChars() );
} }
else if (def == DEF_BreakableDecoration && extra.DeathEnd == 0) else if (def == DEF_BreakableDecoration && extra.DeathEnd == 0)
{ {
SC_ScriptError ("%s does not have a DeathFrames definition", typeName.GetChars() ); SC_ScriptError ("%s does not have a DeathFrames definition", typeName.GetChars() );
} }
else if (extra.IceDeathEnd != 0 && extra.bGenericIceDeath) else if (extra.IceDeathEnd != 0 && extra.bGenericIceDeath)
{ {
SC_ScriptError ("You cannot use IceDeathFrames and GenericIceDeath together"); SC_ScriptError ("You cannot use IceDeathFrames and GenericIceDeath together");
} }
if (extra.IceDeathEnd != 0) if (extra.IceDeathEnd != 0)
{ {
// Make a copy of the final frozen frame for A_FreezeDeathChunks // Make a copy of the final frozen frame for A_FreezeDeathChunks
FState icecopy = states[extra.IceDeathEnd-1]; FState icecopy = states[extra.IceDeathEnd-1];
states.Push (icecopy); states.Push (icecopy);
info->NumOwnedStates += 1; info->NumOwnedStates += 1;
} }
info->OwnedStates = new FState[info->NumOwnedStates]; info->OwnedStates = new FState[info->NumOwnedStates];
memcpy (info->OwnedStates, &states[0], info->NumOwnedStates * sizeof(info->OwnedStates[0])); memcpy (info->OwnedStates, &states[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
if (info->NumOwnedStates == 1) if (info->NumOwnedStates == 1)
{ {
info->OwnedStates->Tics = 0; info->OwnedStates->Tics = 0;
info->OwnedStates->Misc1 = 0; info->OwnedStates->Misc1 = 0;
info->OwnedStates->Frame &= ~SF_BIGTIC; info->OwnedStates->Frame &= ~SF_BIGTIC;
} }
else else
{ {
size_t i; size_t i;
// Spawn states loop endlessly // Spawn states loop endlessly
for (i = extra.SpawnStart; i < extra.SpawnEnd-1; ++i) 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[i+1];
} }
info->OwnedStates[i].NextState = &info->OwnedStates[extra.SpawnStart]; if (extra.bDiesAway || def == DEF_Projectile)
// 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 = NULL;
{ }
info->OwnedStates[i].NextState = &info->OwnedStates[i+1]; else
} {
if (extra.bDiesAway || def == DEF_Projectile) info->OwnedStates[i].Tics = 0;
{ info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].NextState = NULL; info->OwnedStates[i].Frame &= ~SF_BIGTIC;
}
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]);
} }
// Burn states are the same as death states, except they can optionally terminate if (def == DEF_Projectile)
if (extra.FireDeathEnd != 0)
{ {
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) }
{ else
info->OwnedStates[i].NextState = NULL; {
} // The first frame plays the death sound and
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. // the second frame makes it nonsolid.
info->OwnedStates[extra.FireDeathStart].Action = A_ActiveSound; info->OwnedStates[extra.DeathStart].Action= A_Scream;
if (extra.bSolidOnBurn) 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 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; if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height;
type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight); info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight);
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]);
} }
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]; 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. // allow decal specifications in DECORATE. Decals are loaded after DECORATE so the names must be stored here.
TArray<char*> DecalNames; TArray<char*> DecalNames;
// all state parameters // all state parameters
@ -1169,7 +1167,6 @@ static FActorInfo * CreateNewActor(FActorInfo ** parentc, Baggage *bag)
PClass * ti = parent->CreateDerivedClass (typeName, parent->Size); PClass * ti = parent->CreateDerivedClass (typeName, parent->Size);
FActorInfo * info = ti->ActorInfo; FActorInfo * info = ti->ActorInfo;
Decorations.Push (info);
MakeStateDefines(parent->ActorInfo->StateList); MakeStateDefines(parent->ActorInfo->StateList);
ResetBaggage (bag); ResetBaggage (bag);
@ -2150,7 +2147,7 @@ void ParseActorProperties (Baggage &bag)
// Reads an actor definition // Reads an actor definition
// //
//========================================================================== //==========================================================================
void ProcessActor(void (*process)(FState *, int)) void ProcessActor()
{ {
FActorInfo * info=NULL; FActorInfo * info=NULL;
AActor * defaults; AActor * defaults;
@ -2169,8 +2166,8 @@ void ProcessActor(void (*process)(FState *, int))
ParseActorProperties (bag); ParseActorProperties (bag);
FinishStates (info, defaults, bag); FinishStates (info, defaults, bag);
InstallStates(info, defaults); InstallStates (info, defaults);
process(info->OwnedStates, info->NumOwnedStates); ProcessStates (info->OwnedStates, info->NumOwnedStates);
if (bag.DropItemSet) if (bag.DropItemSet)
{ {
if (bag.DropItemList == NULL) if (bag.DropItemList == NULL)
@ -2252,7 +2249,7 @@ static void ActorConstDef (AActor *defaults, Baggage &bag)
// (Maybe there will be other types later.) // (Maybe there will be other types later.)
SC_MustGetToken(TK_Int); SC_MustGetToken(TK_Int);
SC_MustGetToken(TK_Identifier); SC_MustGetToken(TK_Identifier);
FName symname = sc_Name; FName symname = sc_String;
SC_MustGetToken('='); SC_MustGetToken('=');
int expr = ParseExpression (false, bag.Info->Class); int expr = ParseExpression (false, bag.Info->Class);
SC_MustGetToken(';'); 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 // ParseGlobalConst
@ -2287,6 +2324,14 @@ void ParseGlobalConst()
ActorConstDef(GetDefault<AActor>(), bag); ActorConstDef(GetDefault<AActor>(), bag);
} }
void ParseGlobalEnum()
{
Baggage bag;
bag.Info = RUNTIME_CLASS(AActor)->ActorInfo;
ActorEnumDef(GetDefault<AActor>(), bag);
}
//========================================================================== //==========================================================================
// //
// ActorActionDef // ActorActionDef
@ -2309,7 +2354,7 @@ static void ActorActionDef (AActor *defaults, Baggage &bag)
SC_MustGetToken(TK_Native); SC_MustGetToken(TK_Native);
SC_MustGetToken(TK_Identifier); SC_MustGetToken(TK_Identifier);
funcname = sc_Name; funcname = sc_String;
afd = FindFunction(sc_String); afd = FindFunction(sc_String);
if (afd == NULL) if (afd == NULL)
{ {
@ -4177,6 +4222,7 @@ static const ActorProps props[] =
{ "disintegrate", ActorDisintegrateState, RUNTIME_CLASS(AActor) }, { "disintegrate", ActorDisintegrateState, RUNTIME_CLASS(AActor) },
{ "donthurtshooter", ActorDontHurtShooter, RUNTIME_CLASS(AActor) }, { "donthurtshooter", ActorDontHurtShooter, RUNTIME_CLASS(AActor) },
{ "dropitem", ActorDropItem, RUNTIME_CLASS(AActor) }, { "dropitem", ActorDropItem, RUNTIME_CLASS(AActor) },
{ "enum", ActorEnumDef, RUNTIME_CLASS(AActor) },
{ "explosiondamage", ActorExplosionDamage, RUNTIME_CLASS(AActor) }, { "explosiondamage", ActorExplosionDamage, RUNTIME_CLASS(AActor) },
{ "explosionradius", ActorExplosionRadius, RUNTIME_CLASS(AActor) }, { "explosionradius", ActorExplosionRadius, RUNTIME_CLASS(AActor) },
{ "fastspeed", ActorFastSpeed, RUNTIME_CLASS(AActor) }, { "fastspeed", ActorFastSpeed, RUNTIME_CLASS(AActor) },
@ -4449,10 +4495,10 @@ void ParseClass()
FName supername; FName supername;
SC_MustGetToken(TK_Identifier); // class name 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_Extends); // because I'm not supporting Object
SC_MustGetToken(TK_Identifier); // superclass name 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(TK_Native); // use actor definitions for your own stuff
SC_MustGetToken('{'); SC_MustGetToken('{');
@ -4478,190 +4524,15 @@ void ParseClass()
{ {
ActorConstDef (0, bag); ActorConstDef (0, bag);
} }
else if (sc_TokenType == TK_Enum)
{
ActorEnumDef (0, bag);
}
else else
{ {
FString tokname = SC_TokenName(sc_TokenType, sc_String); 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(); 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); 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 #endif

View file

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

View file

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

View file

@ -4283,15 +4283,15 @@
> >
</File> </File>
<File <File
RelativePath=".\src\decorations.cpp" RelativePath=".\src\thingdef\olddecorations.cpp"
> >
</File> </File>
<File <File
RelativePath=".\src\thingdef.cpp" RelativePath=".\src\thingdef\thingdef.cpp"
> >
</File> </File>
<File <File
RelativePath=".\src\thingdef.h" RelativePath=".\src\thingdef\thingdef.h"
> >
</File> </File>
<File <File
@ -4299,7 +4299,15 @@
> >
</File> </File>
<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> </File>
</Filter> </Filter>