- Fixed: The save percentage for Doom's green armor was slightly too low

which caused roundoff errors that made it less than 1/3 effective.
- Added support for "RRGGBB" strings to V_GetColor.
- Fixed: Desaturation maps for the TEXTURES lump were calculated incorrectly.
- Changed GetSpriteIndex to cache the last used sprite name so that the code
  using this function doesn't have to do it itself.
- Moved some more code for the state parser into p_states.cpp.
- Fixed: TDeletingArray should not try to delete NULL pointers.

SVN r1312 (trunk)
This commit is contained in:
Christoph Oelckers 2008-12-07 12:11:59 +00:00
parent 238de9cda1
commit 081658d3d5
24 changed files with 2428 additions and 2351 deletions

View file

@ -1,3 +1,13 @@
December 7, 2008 (Changes by Graf Zahl)
- Fixed: The save percentage for Doom's green armor was slightly too low
which caused roundoff errors that made it less than 1/3 effective.
- Added support for "RRGGBB" strings to V_GetColor.
- Fixed: Desaturation maps for the TEXTURES lump were calculated incorrectly.
- Changed GetSpriteIndex to cache the last used sprite name so that the code
using this function doesn't have to do it itself.
- Moved some more code for the state parser into p_states.cpp.
- Fixed: TDeletingArray should not try to delete NULL pointers.
December 6, 2008 December 6, 2008
- Added binary (b) and hexadecimal (x) cast types for ACS's various print - Added binary (b) and hexadecimal (x) cast types for ACS's various print
statements. statements.

View file

@ -820,31 +820,31 @@ static int PatchThing (int thingy)
} }
if (!strnicmp (Line1, "Initial", 7)) if (!strnicmp (Line1, "Initial", 7))
statedef.AddState("Spawn", state ? state : GetDefault<AActor>()->SpawnState); statedef.SetStateLabel("Spawn", state ? state : GetDefault<AActor>()->SpawnState);
else if (!strnicmp (Line1, "First moving", 12)) else if (!strnicmp (Line1, "First moving", 12))
statedef.AddState("See", state); statedef.SetStateLabel("See", state);
else if (!strnicmp (Line1, "Injury", 6)) else if (!strnicmp (Line1, "Injury", 6))
statedef.AddState("Pain", state); statedef.SetStateLabel("Pain", state);
else if (!strnicmp (Line1, "Close attack", 12)) else if (!strnicmp (Line1, "Close attack", 12))
{ {
if (thingy != 1) // Not for players! if (thingy != 1) // Not for players!
{ {
statedef.AddState("Melee", state); statedef.SetStateLabel("Melee", state);
} }
} }
else if (!strnicmp (Line1, "Far attack", 10)) else if (!strnicmp (Line1, "Far attack", 10))
{ {
if (thingy != 1) // Not for players! if (thingy != 1) // Not for players!
{ {
statedef.AddState("Missile", state); statedef.SetStateLabel("Missile", state);
} }
} }
else if (!strnicmp (Line1, "Death", 5)) else if (!strnicmp (Line1, "Death", 5))
statedef.AddState("Death", state); statedef.SetStateLabel("Death", state);
else if (!strnicmp (Line1, "Exploding", 9)) else if (!strnicmp (Line1, "Exploding", 9))
statedef.AddState("XDeath", state); statedef.SetStateLabel("XDeath", state);
else if (!strnicmp (Line1, "Respawn", 7)) else if (!strnicmp (Line1, "Respawn", 7))
statedef.AddState("Raise", state); statedef.SetStateLabel("Raise", state);
} }
else if (stricmp (Line1 + linelen - 6, " sound") == 0) else if (stricmp (Line1 + linelen - 6, " sound") == 0)
{ {
@ -1394,15 +1394,15 @@ static int PatchWeapon (int weapNum)
} }
if (strnicmp (Line1, "Deselect", 8) == 0) if (strnicmp (Line1, "Deselect", 8) == 0)
statedef.AddState("Select", state); statedef.SetStateLabel("Select", state);
else if (strnicmp (Line1, "Select", 6) == 0) else if (strnicmp (Line1, "Select", 6) == 0)
statedef.AddState("Deselect", state); statedef.SetStateLabel("Deselect", state);
else if (strnicmp (Line1, "Bobbing", 7) == 0) else if (strnicmp (Line1, "Bobbing", 7) == 0)
statedef.AddState("Ready", state); statedef.SetStateLabel("Ready", state);
else if (strnicmp (Line1, "Shooting", 8) == 0) else if (strnicmp (Line1, "Shooting", 8) == 0)
statedef.AddState("Fire", state); statedef.SetStateLabel("Fire", state);
else if (strnicmp (Line1, "Firing", 6) == 0) else if (strnicmp (Line1, "Firing", 6) == 0)
statedef.AddState("Flash", state); statedef.SetStateLabel("Flash", state);
} }
else if (stricmp (Line1, "Ammo type") == 0) else if (stricmp (Line1, "Ammo type") == 0)
{ {

View file

@ -58,6 +58,9 @@ extern void LoadActors ();
int GetSpriteIndex(const char * spritename) int GetSpriteIndex(const char * spritename)
{ {
static char lastsprite[5];
static int lastindex;
// Make sure that the string is upper case and 4 characters long // Make sure that the string is upper case and 4 characters long
char upper[5]={0,0,0,0,0}; char upper[5]={0,0,0,0,0};
for (int i = 0; spritename[i] != 0 && i < 4; i++) for (int i = 0; spritename[i] != 0 && i < 4; i++)
@ -65,18 +68,25 @@ int GetSpriteIndex(const char * spritename)
upper[i] = toupper (spritename[i]); upper[i] = toupper (spritename[i]);
} }
// cache the name so if the next one is the same the function doesn't have to perform a search.
if (!strcmp(upper, lastsprite))
{
return lastindex;
}
strcpy(lastsprite, upper);
for (unsigned i = 0; i < sprites.Size (); ++i) for (unsigned i = 0; i < sprites.Size (); ++i)
{ {
if (strcmp (sprites[i].name, spritename) == 0) if (strcmp (sprites[i].name, upper) == 0)
{ {
return (int)i; return (lastindex = (int)i);
} }
} }
spritedef_t temp; spritedef_t temp;
strcpy (temp.name, upper); strcpy (temp.name, upper);
temp.numframes = 0; temp.numframes = 0;
temp.spriteframes = 0; temp.spriteframes = 0;
return (int)sprites.Push (temp); return (lastindex = (int)sprites.Push (temp));
} }

View file

@ -29,37 +29,6 @@
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**--------------------------------------------------------------------------- **---------------------------------------------------------------------------
** **
** Important restrictions because of the way FState is structured:
**
** The range of Frame is [0,63]. Since sprite naming conventions
** are even more restrictive than this, this isn't something to
** really worry about.
**
** The range of Tics is [-1,65534]. If Misc1 is important, then
** the range of Tics is reduced to [-1,254], because Misc1 also
** doubles as the high byte of the tic.
**
** The range of Misc1 is [-128,127] and Misc2's range is [0,255].
**
** When compiled with Visual C++, this struct is 16 bytes. With
** any other compiler (assuming a 32-bit architecture), it is 20 bytes.
** This is because with VC++, I can use the charizing operator to
** initialize the name array to exactly 4 chars. If GCC would
** compile something like char t = "PLYR"[0]; as char t = 'P'; then GCC
** could also use the 16-byte version. Unfortunately, GCC compiles it
** more like:
**
** char t;
** void initializer () {
** static const char str[]="PLYR";
** t = str[0];
** }
**
** While this does allow the use of a 16-byte FState, the additional
** code amounts to more than 4 bytes.
**
** If C++ would allow char name[4] = "PLYR"; without an error (as C does),
** I could just initialize the name as a regular string and be done with it.
*/ */
#ifndef __INFO_H__ #ifndef __INFO_H__

View file

@ -366,17 +366,33 @@ FStateDefine * FStateDefinitions::FindStateAddress(const char *name)
//========================================================================== //==========================================================================
// //
// Adds a new state tp the curremt list // Adds a new state to the curremt list
// //
//========================================================================== //==========================================================================
void FStateDefinitions::AddState (const char *statename, FState *state, BYTE defflags) void FStateDefinitions::SetStateLabel (const char *statename, FState *state, BYTE defflags)
{ {
FStateDefine *std = FindStateAddress(statename); FStateDefine *std = FindStateAddress(statename);
std->State = state; std->State = state;
std->DefineFlags = defflags; std->DefineFlags = defflags;
} }
//==========================================================================
//
// Adds a new state to the curremt list
//
//==========================================================================
void FStateDefinitions::AddStateLabel (const char *statename)
{
intptr_t index = StateArray.Size();
FStateDefine *std = FindStateAddress(statename);
std->State = (FState *)(index+1);
std->DefineFlags = SDF_INDEX;
laststate = NULL;
lastlabel = index;
}
//========================================================================== //==========================================================================
// //
// Finds the state associated with the given name // Finds the state associated with the given name
@ -457,7 +473,7 @@ void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults)
if (state == NULL) if (state == NULL)
{ {
// A NULL spawn state will crash the engine so set it to something valid. // A NULL spawn state will crash the engine so set it to something valid.
AddState("Spawn", GetDefault<AActor>()->SpawnState); SetStateLabel("Spawn", GetDefault<AActor>()->SpawnState);
} }
if (info->StateList != NULL) if (info->StateList != NULL)
@ -505,13 +521,17 @@ void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray<FStateDef
void FStateDefinitions::MakeStateDefines(const PClass *cls) void FStateDefinitions::MakeStateDefines(const PClass *cls)
{ {
if (cls->ActorInfo && cls->ActorInfo->StateList) StateArray.Clear();
laststate = NULL;
lastlabel = -1;
if (cls != NULL && cls->ActorInfo != NULL && cls->ActorInfo->StateList != NULL)
{ {
MakeStateList(cls->ActorInfo->StateList, StateLabels); MakeStateList(cls->ActorInfo->StateList, StateLabels);
} }
else else
{ {
ClearStateLabels(); StateLabels.Clear();
} }
} }
@ -559,7 +579,7 @@ void FStateDefinitions::RetargetStatePointers (intptr_t count, const char *targe
{ {
for(unsigned i = 0;i<statelist.Size(); i++) for(unsigned i = 0;i<statelist.Size(); i++)
{ {
if (statelist[i].State == (FState*)count) if (statelist[i].State == (FState*)count && statelist[i].DefineFlags == SDF_INDEX)
{ {
if (target == NULL) if (target == NULL)
{ {
@ -709,6 +729,118 @@ void FStateDefinitions::ResolveGotoLabels (FActorInfo *actor, AActor *defaults,
} }
//==========================================================================
//
// SetGotoLabel
//
// sets a jump at the current state or retargets a label
//
//==========================================================================
bool FStateDefinitions::SetGotoLabel(const char *string)
{
// copy the text - this must be resolved later!
if (laststate != NULL)
{ // Following a state definition: Modify it.
laststate->NextState = (FState*)copystring(string);
laststate->DefineFlags = SDF_LABEL;
return true;
}
else if (lastlabel >= 0)
{ // Following a label: Retarget it.
RetargetStates (lastlabel+1, string);
return true;
}
return false;
}
//==========================================================================
//
// SetStop
//
// sets a stop operation
//
//==========================================================================
bool FStateDefinitions::SetStop()
{
if (laststate != NULL)
{
laststate->DefineFlags = SDF_STOP;
return true;
}
else if (lastlabel >=0)
{
RetargetStates (lastlabel+1, NULL);
return true;
}
return false;
}
//==========================================================================
//
// SetWait
//
// sets a wait or fail operation
//
//==========================================================================
bool FStateDefinitions::SetWait()
{
if (laststate != NULL)
{
laststate->DefineFlags = SDF_WAIT;
return true;
}
return false;
}
//==========================================================================
//
// SetLoop
//
// sets a loop operation
//
//==========================================================================
bool FStateDefinitions::SetLoop()
{
if (laststate != NULL)
{
laststate->DefineFlags = SDF_INDEX;
laststate->NextState = (FState*)(lastlabel+1);
return true;
}
return false;
}
//==========================================================================
//
// AddStates
// adds some state to the current definition set
//
//==========================================================================
bool FStateDefinitions::AddStates(FState *state, const char *framechars)
{
bool error = false;
while (*framechars)
{
int frame=((*framechars++)&223)-'A';
if (frame<0 || frame>28)
{
frame = 0;
error = true;
}
state->Frame=(state->Frame&(SF_FULLBRIGHT))|frame;
StateArray.Push(*state);
}
laststate = &StateArray[StateArray.Size() - 1];
return !error;
}
//========================================================================== //==========================================================================
// //
// FinishStates // FinishStates
@ -716,7 +848,7 @@ void FStateDefinitions::ResolveGotoLabels (FActorInfo *actor, AActor *defaults,
// //
//========================================================================== //==========================================================================
int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults, TArray<FState> &StateArray) int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults)
{ {
static int c=0; static int c=0;
int count = StateArray.Size(); int count = StateArray.Size();
@ -770,6 +902,12 @@ int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults, TArray
} }
//==========================================================================
//
// Prints all state label info to the logfile
//
//==========================================================================
void DumpStateHelper(FStateLabels *StateList, const FString &prefix) void DumpStateHelper(FStateLabels *StateList, const FString &prefix)
{ {
for (int i = 0; i < StateList->NumLabels; i++) for (int i = 0; i < StateList->NumLabels; i++)

View file

@ -911,12 +911,12 @@ FString FScanner::TokenName (int token, const char *string)
"'global'", "'global'",
"'self'", "'self'",
"'stop'", "'stop'",
"'pickup'",
"'breakable'",
"'projectile'",
"'#include'", "'#include'",
"'fixed_t'", "'fixed_t'",
"'angle_t'", "'angle_t'",
"'abs'",
"'random'",
"'random2'"
}; };
FString work; FString work;

View file

@ -29,7 +29,7 @@ public:
const SavedPos SavePos(); const SavedPos SavePos();
void RestorePos(const SavedPos &pos); void RestorePos(const SavedPos &pos);
FString TokenName(int token, const char *string=NULL); static FString TokenName(int token, const char *string=NULL);
bool GetString(); bool GetString();
void MustGetString(); void MustGetString();
@ -203,14 +203,12 @@ enum
TK_Global, TK_Global,
TK_Self, TK_Self,
TK_Stop, TK_Stop,
TK_Eval,
TK_EvalNot,
TK_Pickup,
TK_Breakable,
TK_Projectile,
TK_Include, TK_Include,
TK_Fixed_t, TK_Fixed_t,
TK_Angle_t, TK_Angle_t,
TK_Abs,
TK_Random,
TK_Random2,
TK_LastToken TK_LastToken
}; };

File diff suppressed because it is too large Load diff

View file

@ -142,11 +142,11 @@ std2:
/* other DECORATE top level keywords */ /* other DECORATE top level keywords */
'#include' { RET(TK_Include); } '#include' { RET(TK_Include); }
'pickup' { RET(TK_Pickup); }
'breakable' { RET(TK_Breakable); }
'projectile' { RET(TK_Projectile); }
'fixed_t' { RET(TK_Fixed_t); } 'fixed_t' { RET(TK_Fixed_t); }
'angle_t' { RET(TK_Angle_t); } 'angle_t' { RET(TK_Angle_t); }
'abs' { RET(TK_Abs); }
'random' { RET(TK_Random); }
'random2' { RET(TK_Random2); }
L (L|D)* { RET(TK_Identifier); } L (L|D)* { RET(TK_Identifier); }

View file

@ -299,7 +299,8 @@ public:
{ {
for (unsigned int i = 0; i < TArray<T,TT>::Size(); ++i) for (unsigned int i = 0; i < TArray<T,TT>::Size(); ++i)
{ {
delete (*this)[i]; if ((*this)[i] != NULL)
delete (*this)[i];
} }
} }
}; };

View file

@ -443,7 +443,7 @@ BYTE * GetBlendMap(PalEntry blend, BYTE *blendwork)
default: default:
if (blend.r >= BLEND_DESATURATE1 && blend.r <= BLEND_DESATURATE31) if (blend.r >= BLEND_DESATURATE1 && blend.r <= BLEND_DESATURATE31)
{ {
return DesaturateColormap[blend - BLEND_DESATURATE1]; return DesaturateColormap[blend.r - BLEND_DESATURATE1];
} }
else else
{ {
@ -509,7 +509,7 @@ void FMultiPatchTexture::MakeTexture ()
trans = NullMap; trans = NullMap;
hasTranslucent = true; hasTranslucent = true;
} }
else if (Parts[i].Blend != BLEND_NONE) else if (Parts[i].Blend != 0)
{ {
trans = GetBlendMap(Parts[i].Blend, blendwork); trans = GetBlendMap(Parts[i].Blend, blendwork);
} }

View file

@ -102,7 +102,7 @@ IMPLEMENT_CLASS (AFakeInventory)
// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void ParseInsideDecoration (Baggage &bag, AActor *defaults, static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
FExtraInfo &extra, EDefinitionType def, FScanner &sc); FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray<FState> &StateArray);
static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states, FScanner &sc); static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states, FScanner &sc);
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
@ -134,6 +134,7 @@ static const char *RenderStyles[] =
void ParseOldDecoration(FScanner &sc, EDefinitionType def) void ParseOldDecoration(FScanner &sc, EDefinitionType def)
{ {
Baggage bag; Baggage bag;
TArray<FState> StateArray;
FExtraInfo extra; FExtraInfo extra;
FActorInfo *info; FActorInfo *info;
PClass *type; PClass *type;
@ -156,9 +157,9 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
sc.MustGetStringName("{"); sc.MustGetStringName("{");
memset (&extra, 0, sizeof(extra)); memset (&extra, 0, sizeof(extra));
ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc); ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc, StateArray);
bag.Info->NumOwnedStates = bag.StateArray.Size(); bag.Info->NumOwnedStates = StateArray.Size();
if (bag.Info->NumOwnedStates == 0) if (bag.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() );
@ -179,13 +180,13 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
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 = bag.StateArray[extra.IceDeathEnd-1]; FState icecopy = StateArray[extra.IceDeathEnd-1];
bag.StateArray.Push (icecopy); StateArray.Push (icecopy);
info->NumOwnedStates += 1; info->NumOwnedStates += 1;
} }
info->OwnedStates = new FState[info->NumOwnedStates]; info->OwnedStates = new FState[info->NumOwnedStates];
memcpy (info->OwnedStates, &bag.StateArray[0], info->NumOwnedStates * sizeof(info->OwnedStates[0])); memcpy (info->OwnedStates, &StateArray[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
if (info->NumOwnedStates == 1) if (info->NumOwnedStates == 1)
{ {
info->OwnedStates->Tics = -1; info->OwnedStates->Tics = -1;
@ -246,7 +247,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height; if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height;
info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight); info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight);
} }
bag.statedef.AddState("Death", &info->OwnedStates[extra.DeathStart]); bag.statedef.SetStateLabel("Death", &info->OwnedStates[extra.DeathStart]);
} }
// Burn states are the same as death states, except they can optionally terminate // Burn states are the same as death states, except they can optionally terminate
@ -284,7 +285,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height; if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height;
type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight); type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight);
bag.statedef.AddState("Burn", &info->OwnedStates[extra.FireDeathStart]); bag.statedef.SetStateLabel("Burn", &info->OwnedStates[extra.FireDeathStart]);
} }
// Ice states are similar to burn and death, except their final frame enters // Ice states are similar to burn and death, except their final frame enters
@ -305,11 +306,11 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
info->OwnedStates[i].Tics = 1; info->OwnedStates[i].Tics = 1;
info->OwnedStates[i].Misc1 = 0; info->OwnedStates[i].Misc1 = 0;
info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks")); info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks"));
bag.statedef.AddState("Ice", &info->OwnedStates[extra.IceDeathStart]); bag.statedef.SetStateLabel("Ice", &info->OwnedStates[extra.IceDeathStart]);
} }
else if (extra.bGenericIceDeath) else if (extra.bGenericIceDeath)
{ {
bag.statedef.AddState("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath)); bag.statedef.SetStateLabel("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath));
} }
} }
if (def == DEF_BreakableDecoration) if (def == DEF_BreakableDecoration)
@ -320,7 +321,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
{ {
((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE; ((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE;
} }
bag.statedef.AddState("Spawn", &info->OwnedStates[extra.SpawnStart]); bag.statedef.SetStateLabel("Spawn", &info->OwnedStates[extra.SpawnStart]);
bag.statedef.InstallStates (info, ((AActor *)(type->Defaults))); bag.statedef.InstallStates (info, ((AActor *)(type->Defaults)));
} }
@ -333,7 +334,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
//========================================================================== //==========================================================================
static void ParseInsideDecoration (Baggage &bag, AActor *defaults, static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
FExtraInfo &extra, EDefinitionType def, FScanner &sc) FExtraInfo &extra, EDefinitionType def, FScanner &sc, TArray<FState> &StateArray)
{ {
AFakeInventory *const inv = static_cast<AFakeInventory *>(defaults); AFakeInventory *const inv = static_cast<AFakeInventory *>(defaults);
char sprite[5] = "TNT1"; char sprite[5] = "TNT1";
@ -382,31 +383,31 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
else if (sc.Compare ("Frames")) else if (sc.Compare ("Frames"))
{ {
sc.MustGetString (); sc.MustGetString ();
extra.SpawnStart = bag.StateArray.Size(); extra.SpawnStart = StateArray.Size();
ParseSpriteFrames (bag.Info, bag.StateArray, sc); ParseSpriteFrames (bag.Info, StateArray, sc);
extra.SpawnEnd = bag.StateArray.Size(); extra.SpawnEnd = StateArray.Size();
} }
else if ((def == DEF_BreakableDecoration || def == DEF_Projectile) && else if ((def == DEF_BreakableDecoration || def == DEF_Projectile) &&
sc.Compare ("DeathFrames")) sc.Compare ("DeathFrames"))
{ {
sc.MustGetString (); sc.MustGetString ();
extra.DeathStart = bag.StateArray.Size(); extra.DeathStart = StateArray.Size();
ParseSpriteFrames (bag.Info, bag.StateArray, sc); ParseSpriteFrames (bag.Info, StateArray, sc);
extra.DeathEnd = bag.StateArray.Size(); extra.DeathEnd = StateArray.Size();
} }
else if (def == DEF_BreakableDecoration && sc.Compare ("IceDeathFrames")) else if (def == DEF_BreakableDecoration && sc.Compare ("IceDeathFrames"))
{ {
sc.MustGetString (); sc.MustGetString ();
extra.IceDeathStart = bag.StateArray.Size(); extra.IceDeathStart = StateArray.Size();
ParseSpriteFrames (bag.Info, bag.StateArray, sc); ParseSpriteFrames (bag.Info, StateArray, sc);
extra.IceDeathEnd = bag.StateArray.Size(); extra.IceDeathEnd = StateArray.Size();
} }
else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathFrames")) else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathFrames"))
{ {
sc.MustGetString (); sc.MustGetString ();
extra.FireDeathStart = bag.StateArray.Size(); extra.FireDeathStart = StateArray.Size();
ParseSpriteFrames (bag.Info, bag.StateArray, sc); ParseSpriteFrames (bag.Info, StateArray, sc);
extra.FireDeathEnd = bag.StateArray.Size(); extra.FireDeathEnd = StateArray.Size();
} }
else if (def == DEF_BreakableDecoration && sc.Compare ("GenericIceDeath")) else if (def == DEF_BreakableDecoration && sc.Compare ("GenericIceDeath"))
{ {
@ -587,16 +588,16 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
unsigned int i; unsigned int i;
int spr = GetSpriteIndex(sprite); int spr = GetSpriteIndex(sprite);
for (i = 0; i < bag.StateArray.Size(); ++i) for (i = 0; i < StateArray.Size(); ++i)
{ {
bag.StateArray[i].sprite = spr; StateArray[i].sprite = spr;
} }
if (extra.DeathSprite[0] && extra.DeathEnd != 0) if (extra.DeathSprite[0] && extra.DeathEnd != 0)
{ {
int spr = GetSpriteIndex(extra.DeathSprite); int spr = GetSpriteIndex(extra.DeathSprite);
for (i = extra.DeathStart; i < extra.DeathEnd; ++i) for (i = extra.DeathStart; i < extra.DeathEnd; ++i)
{ {
bag.StateArray[i].sprite = spr; StateArray[i].sprite = spr;
} }
} }
} }

View file

@ -78,8 +78,7 @@ PSymbolTable GlobalSymbols;
// Starts a new actor definition // Starts a new actor definition
// //
//========================================================================== //==========================================================================
FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, FName replaceName, FActorInfo *CreateNewActor(FName typeName, FName parentName, bool native)
int DoomEdNum, bool native)
{ {
const PClass *replacee = NULL; const PClass *replacee = NULL;
PClass *ti = NULL; PClass *ti = NULL;
@ -93,31 +92,15 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare
if (parent == NULL) if (parent == NULL)
{ {
sc.Message(MSG_FATAL, "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars()); I_Error( "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars());
} }
else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor))) else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor)))
{ {
sc.Message(MSG_FATAL, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); I_Error( "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars());
} }
else if (parent->ActorInfo == NULL) else if (parent->ActorInfo == NULL)
{ {
sc.Message(MSG_FATAL, "uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars()); I_Error( "uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars());
}
}
// Check for "replaces"
if (replaceName != NAME_None)
{
// Get actor name
replacee = PClass::FindClass (replaceName);
if (replacee == NULL)
{
sc.Message(MSG_FATAL, "Replaced type '%s' not found in %s", replaceName.GetChars(), typeName.GetChars());
}
else if (replacee->ActorInfo == NULL)
{
sc.Message(MSG_FATAL, "Replaced type '%s' is not an actor in %s", replaceName.GetChars(), typeName.GetChars());
} }
} }
@ -126,15 +109,15 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare
ti = (PClass*)PClass::FindClass(typeName); ti = (PClass*)PClass::FindClass(typeName);
if (ti == NULL) if (ti == NULL)
{ {
sc.Message(MSG_FATAL, "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()) else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass())
{ {
sc.Message(MSG_FATAL, "Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars()); I_Error( "Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars());
} }
else if (ti->ActorInfo != NULL) else if (ti->ActorInfo != NULL)
{ {
sc.Message(MSG_FATAL, "Redefinition of internal class '%s'", typeName.GetChars()); I_Error( "Redefinition of internal class '%s'", typeName.GetChars());
} }
ti->InitializeActorInfo(); ti->InitializeActorInfo();
info = ti->ActorInfo; info = ti->ActorInfo;
@ -145,7 +128,6 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare
info = ti->ActorInfo; info = ti->ActorInfo;
} }
info->DoomEdNum = -1;
if (parent->ActorInfo->DamageFactors != NULL) if (parent->ActorInfo->DamageFactors != NULL)
{ {
// copy damage factors from parent // copy damage factors from parent
@ -158,15 +140,40 @@ FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName pare
info->PainChances = new PainChanceList; info->PainChances = new PainChanceList;
*info->PainChances = *parent->ActorInfo->PainChances; *info->PainChances = *parent->ActorInfo->PainChances;
} }
info->Replacee = info->Replacement = NULL;
info->DoomEdNum = -1;
return info;
}
if (replacee != NULL) //==========================================================================
//
//
//
//==========================================================================
void SetReplacement(FActorInfo *info, FName replaceName)
{
// Check for "replaces"
if (replaceName != NAME_None)
{ {
replacee->ActorInfo->Replacement = ti->ActorInfo; // Get actor name
ti->ActorInfo->Replacee = replacee->ActorInfo; const PClass *replacee = PClass::FindClass (replaceName);
if (replacee == NULL)
{
I_Error ("Replaced type '%s' not found in %s", replaceName.GetChars(), info->Class->TypeName.GetChars());
}
else if (replacee->ActorInfo == NULL)
{
I_Error ("Replaced type '%s' is not an actor in %s", replaceName.GetChars(), info->Class->TypeName.GetChars());
}
if (replacee != NULL)
{
replacee->ActorInfo->Replacement = info;
info->Replacee = replacee->ActorInfo;
}
} }
if (DoomEdNum > 0) info->DoomEdNum = DoomEdNum;
return info;
} }
//========================================================================== //==========================================================================
@ -181,14 +188,14 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag)
try try
{ {
bag.statedef.FinishStates (info, defaults, bag.StateArray); bag.statedef.FinishStates (info, defaults);
} }
catch (CRecoverableError &err) catch (CRecoverableError &err)
{ {
sc.Message(MSG_FATAL, "%s", err.GetMessage()); sc.Message(MSG_FATAL, "%s", err.GetMessage());
} }
bag.statedef.InstallStates (info, defaults); bag.statedef.InstallStates (info, defaults);
bag.StateArray.Clear (); bag.statedef.MakeStateDefines(NULL);
if (bag.DropItemSet) if (bag.DropItemSet)
{ {
if (bag.DropItemList == NULL) if (bag.DropItemList == NULL)

View file

@ -82,6 +82,9 @@ struct FStateDefine
class FStateDefinitions class FStateDefinitions
{ {
TArray<FStateDefine> StateLabels; TArray<FStateDefine> StateLabels;
FState *laststate;
intptr_t lastlabel;
TArray<FState> StateArray;
static FStateDefine *FindStateLabelInList(TArray<FStateDefine> &list, FName name, bool create); static FStateDefine *FindStateLabelInList(TArray<FStateDefine> &list, FName name, bool create);
static FStateLabels *CreateStateLabelList(TArray<FStateDefine> &statelist); static FStateLabels *CreateStateLabelList(TArray<FStateDefine> &statelist);
@ -96,20 +99,28 @@ class FStateDefinitions
public: public:
FStateDefinitions()
void ClearStateLabels()
{ {
StateLabels.Clear(); laststate = NULL;
lastlabel = -1;
} }
void AddState (const char * statename, FState * state, BYTE defflags = SDF_STATE); void SetStateLabel (const char * statename, FState * state, BYTE defflags = SDF_STATE);
void AddStateLabel (const char * statename);
void InstallStates(FActorInfo *info, AActor *defaults); void InstallStates(FActorInfo *info, AActor *defaults);
int FinishStates (FActorInfo *actor, AActor *defaults, TArray<FState> &StateArray); int FinishStates (FActorInfo *actor, AActor *defaults);
void MakeStateDefines(const PClass *cls); void MakeStateDefines(const PClass *cls);
void AddStateDefines(const FStateLabels *list); void AddStateDefines(const FStateLabels *list);
void RetargetStates (intptr_t count, const char *target); void RetargetStates (intptr_t count, const char *target);
bool SetGotoLabel(const char *string);
bool SetStop();
bool SetWait();
bool SetLoop();
bool AddStates(FState *state, const char *framechars);
int GetStateCount() const { return StateArray.Size(); }
}; };
//========================================================================== //==========================================================================
@ -162,9 +173,10 @@ struct Baggage
int CurrentState; int CurrentState;
int Lumpnum; int Lumpnum;
FStateDefinitions statedef; FStateDefinitions statedef;
TArray<FState> StateArray;
FDropItem *DropItemList; FDropItem *DropItemList;
FScriptPosition ScriptPosition;
}; };
inline void ResetBaggage (Baggage *bag, const PClass *stateclass) inline void ResetBaggage (Baggage *bag, const PClass *stateclass)
@ -173,7 +185,6 @@ inline void ResetBaggage (Baggage *bag, const PClass *stateclass)
bag->DropItemSet = false; bag->DropItemSet = false;
bag->CurrentState = 0; bag->CurrentState = 0;
bag->StateSet = false; bag->StateSet = false;
bag->StateArray.Clear();
bag->statedef.MakeStateDefines(stateclass); bag->statedef.MakeStateDefines(stateclass);
} }
@ -193,7 +204,7 @@ AFuncDesc * FindFunction(const char * string);
int ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag); void ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag);
PSymbolActionFunction *FindGlobalActionFunction(const char *name); PSymbolActionFunction *FindGlobalActionFunction(const char *name);
@ -203,8 +214,8 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name);
// //
//========================================================================== //==========================================================================
FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, FName replaceName, FActorInfo *CreateNewActor(FName typeName, FName parentName, bool native);
int DoomEdNum, bool native); void SetReplacement(FActorInfo *info, FName replaceName);
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod); void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod);
void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag); void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag);
@ -276,7 +287,7 @@ union FPropParam
const char *s; const char *s;
}; };
typedef void (*PropHandler)(AActor *defaults, Baggage &bag, FPropParam *params); typedef void (*PropHandler)(AActor *defaults, FActorInfo *info, Baggage &bag, FPropParam *params);
enum ECategory enum ECategory
{ {
@ -307,18 +318,18 @@ int MatchString (const char *in, const char **strings);
#define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \ #define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \ static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); \
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
{ #name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ { #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; \ 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) static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params)
#define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \ #define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \ static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params); \
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \ static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
{ #prefix"."#name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \ { #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; \ 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) static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, FActorInfo *info, Baggage &bag, FPropParam *params)
#define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY) #define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY)

View file

@ -336,101 +336,92 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls)
{ {
return new FxConstant(sc.Float, scpos); return new FxConstant(sc.Float, scpos);
} }
else if (sc.CheckToken(TK_Random))
{
FRandom *rng;
if (sc.CheckToken('['))
{
sc.MustGetToken(TK_Identifier);
rng = FRandom::StaticFindRNG(sc.String);
sc.MustGetToken(']');
}
else
{
rng = &pr_exrandom;
}
sc.MustGetToken('(');
FxExpression *min = ParseExpressionM (sc, cls);
sc.MustGetToken(',');
FxExpression *max = ParseExpressionM (sc, cls);
sc.MustGetToken(')');
return new FxRandom(rng, min, max, sc);
}
else if (sc.CheckToken(TK_Random2))
{
FRandom *rng;
if (sc.CheckToken('['))
{
sc.MustGetToken(TK_Identifier);
rng = FRandom::StaticFindRNG(sc.String);
sc.MustGetToken(']');
}
else
{
rng = &pr_exrandom;
}
sc.MustGetToken('(');
FxExpression *mask = NULL;
if (!sc.CheckToken(')'))
{
mask = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
}
return new FxRandom2(rng, mask, sc);
}
else if (sc.CheckToken(TK_Abs))
{
sc.MustGetToken('(');
FxExpression *x = ParseExpressionM (sc, cls);
sc.MustGetToken(')');
return new FxAbs(x);
}
else if (sc.CheckToken(TK_Identifier)) else if (sc.CheckToken(TK_Identifier))
{ {
FName identifier = FName(sc.String); FName identifier = FName(sc.String);
switch (identifier) if (sc.CheckToken('('))
{ {
case NAME_Random: FArgumentList *args = NULL;
{ try
FRandom *rng;
if (sc.CheckToken('['))
{ {
sc.MustGetToken(TK_Identifier); if (!sc.CheckToken(')'))
rng = FRandom::StaticFindRNG(sc.String);
sc.MustGetToken(']');
}
else
{
rng = &pr_exrandom;
}
sc.MustGetToken('(');
FxExpression *min = ParseExpressionM (sc, cls);
sc.MustGetToken(',');
FxExpression *max = ParseExpressionM (sc, cls);
sc.MustGetToken(')');
return new FxRandom(rng, min, max, sc);
}
break;
case NAME_Random2:
{
FRandom *rng;
if (sc.CheckToken('['))
{
sc.MustGetToken(TK_Identifier);
rng = FRandom::StaticFindRNG(sc.String);
sc.MustGetToken(']');
}
else
{
rng = &pr_exrandom;
}
sc.MustGetToken('(');
FxExpression *mask = NULL;
if (!sc.CheckToken(')'))
{
mask = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
}
return new FxRandom2(rng, mask, sc);
}
break;
case NAME_Abs:
{
sc.MustGetToken('(');
FxExpression *x = ParseExpressionM (sc, cls);
sc.MustGetToken(')');
return new FxAbs(x);
}
default:
if (sc.CheckToken('('))
{
FArgumentList *args = NULL;
try
{ {
if (!sc.CheckToken(')')) args = new FArgumentList;
do
{ {
args = new FArgumentList; args->Push(ParseExpressionM (sc, cls));
do
{
args->Push(ParseExpressionM (sc, cls));
}
while (sc.CheckToken(','));
sc.MustGetToken(')');
} }
return new FxFunctionCall(NULL, identifier, args, sc); while (sc.CheckToken(','));
sc.MustGetToken(')');
} }
catch (...) return new FxFunctionCall(NULL, identifier, args, sc);
{
delete args;
throw;
}
}
else
{
return new FxIdentifier(identifier, sc);
} }
catch (...)
{
delete args;
throw;
}
}
else
{
return new FxIdentifier(identifier, sc);
} }
} }
else else

View file

@ -1601,9 +1601,13 @@ ExpVal FxAbs::EvalExpression (AActor *self)
FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos)
: FxExpression(pos) : FxExpression(pos)
{ {
if (mi != NULL && ma != NULL)
{
min = new FxIntCast(mi);
max = new FxIntCast(ma);
}
else min = max = NULL;
rng = r; rng = r;
min = new FxIntCast(mi);
max = new FxIntCast(ma);
ValueType = VAL_Int; ValueType = VAL_Int;
} }
@ -1646,18 +1650,26 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
ExpVal FxRandom::EvalExpression (AActor *self) ExpVal FxRandom::EvalExpression (AActor *self)
{ {
int minval = min->EvalExpression (self).GetInt();
int maxval = max->EvalExpression (self).GetInt();
ExpVal val; ExpVal val;
val.Type = VAL_Int; val.Type = VAL_Int;
if (maxval < minval) if (min != NULL && max != NULL)
{ {
swap (maxval, minval); int minval = min->EvalExpression (self).GetInt();
} int maxval = max->EvalExpression (self).GetInt();
val.Int = (*rng)(maxval - minval + 1) + minval;
if (maxval < minval)
{
swap (maxval, minval);
}
val.Int = (*rng)(maxval - minval + 1) + minval;
}
else
{
val.Int = (*rng)();
}
return val; return val;
} }

View file

@ -145,6 +145,8 @@ FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant
case 'X': case 'X':
case 'x': case 'x':
case 'Y':
case 'y':
x = ParseExpression (sc, cls); x = ParseExpression (sc, cls);
if (constant && !x->isConstant()) if (constant && !x->isConstant())
{ {
@ -190,7 +192,7 @@ static void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls)
else else
{ {
sym->ValueType = VAL_Float; sym->ValueType = VAL_Float;
sym->Value = val.GetFloat(); sym->Float = val.GetFloat();
} }
if (symt->AddSymbol (sym) == NULL) if (symt->AddSymbol (sym) == NULL)
{ {
@ -654,7 +656,7 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau
// call the handler // call the handler
try try
{ {
prop->Handler(defaults, bag, &params[0]); prop->Handler(defaults, bag.Info, bag, &params[0]);
} }
catch (CRecoverableError &error) catch (CRecoverableError &error)
{ {
@ -713,7 +715,7 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
} }
else if (MatchString(propname, statenames) != -1) else if (MatchString(propname, statenames) != -1)
{ {
bag.statedef.AddState(propname, CheckState (sc, bag.Info->Class)); bag.statedef.SetStateLabel(propname, CheckState (sc, bag.Info->Class));
} }
else else
{ {
@ -782,10 +784,13 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
{ {
case TK_Bool: case TK_Bool:
case TK_Int: case TK_Int:
case TK_Float:
type = 'x'; type = 'x';
break; break;
case TK_Float:
type = 'y';
break;
case TK_Sound: type = 's'; break; case TK_Sound: type = 's'; break;
case TK_String: type = 't'; break; case TK_String: type = 't'; break;
case TK_Name: type = 't'; break; case TK_Name: type = 't'; break;
@ -940,7 +945,10 @@ static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag)
try try
{ {
FActorInfo *info = CreateNewActor(sc, typeName, parentName, replaceName, DoomEdNum, native); FActorInfo *info = CreateNewActor(typeName, parentName, native);
info->DoomEdNum = DoomEdNum > 0? DoomEdNum : -1;
SetReplacement(info, replaceName);
ResetBaggage (bag, info->Class->ParentClass); ResetBaggage (bag, info->Class->ParentClass);
bag->Info = info; bag->Info = info;
bag->Lumpnum = sc.LumpNum; bag->Lumpnum = sc.LumpNum;
@ -989,8 +997,6 @@ static void ParseActor(FScanner &sc)
break; break;
case TK_Identifier: case TK_Identifier:
// other identifier related checks here
case TK_Projectile: // special case: both keyword and property name
ParseActorProperty(sc, bag); ParseActorProperty(sc, bag);
break; break;
@ -1047,18 +1053,6 @@ void ParseDecorate (FScanner &sc)
ParseEnum (sc, &GlobalSymbols, NULL); ParseEnum (sc, &GlobalSymbols, NULL);
break; break;
case TK_Pickup:
ParseOldDecoration (sc, DEF_Pickup);
break;
case TK_Breakable:
ParseOldDecoration (sc, DEF_BreakableDecoration);
break;
case TK_Projectile:
ParseOldDecoration (sc, DEF_Projectile);
break;
case TK_Native: case TK_Native:
ParseVariable(sc, &GlobalSymbols, NULL); ParseVariable(sc, &GlobalSymbols, NULL);
break; break;
@ -1079,7 +1073,18 @@ void ParseDecorate (FScanner &sc)
ParseActor (sc); ParseActor (sc);
break; break;
} }
else if (sc.Compare("PICKUP"))
{
ParseOldDecoration (sc, DEF_Pickup);
}
else if (sc.Compare("BREAKABLE"))
{
ParseOldDecoration (sc, DEF_BreakableDecoration);
}
else if (sc.Compare("PROJECTILE"))
{
ParseOldDecoration (sc, DEF_Projectile);
}
default: default:
// without the option of game filters following, anything but an opening brace // without the option of game filters following, anything but an opening brace
// here means a syntax error. // here means a syntax error.

View file

@ -152,31 +152,31 @@ DEFINE_INFO_PROPERTY(game, T, Actor)
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
if (!stricmp(str, "Doom")) if (!stricmp(str, "Doom"))
{ {
bag.Info->GameFilter |= GAME_Doom; info->GameFilter |= GAME_Doom;
} }
else if (!stricmp(str, "Heretic")) else if (!stricmp(str, "Heretic"))
{ {
bag.Info->GameFilter |= GAME_Heretic; info->GameFilter |= GAME_Heretic;
} }
else if (!stricmp(str, "Hexen")) else if (!stricmp(str, "Hexen"))
{ {
bag.Info->GameFilter |= GAME_Hexen; info->GameFilter |= GAME_Hexen;
} }
else if (!stricmp(str, "Raven")) else if (!stricmp(str, "Raven"))
{ {
bag.Info->GameFilter |= GAME_Raven; info->GameFilter |= GAME_Raven;
} }
else if (!stricmp(str, "Strife")) else if (!stricmp(str, "Strife"))
{ {
bag.Info->GameFilter |= GAME_Strife; info->GameFilter |= GAME_Strife;
} }
else if (!stricmp(str, "Chex")) else if (!stricmp(str, "Chex"))
{ {
bag.Info->GameFilter |= GAME_Chex; info->GameFilter |= GAME_Chex;
} }
else if (!stricmp(str, "Any")) else if (!stricmp(str, "Any"))
{ {
bag.Info->GameFilter = GAME_Any; info->GameFilter = GAME_Any;
} }
else else
{ {
@ -194,7 +194,7 @@ DEFINE_INFO_PROPERTY(spawnid, I, Actor)
{ {
I_Error ("SpawnID must be in the range [0,255]"); I_Error ("SpawnID must be in the range [0,255]");
} }
else bag.Info->SpawnID=(BYTE)id; else info->SpawnID=(BYTE)id;
} }
//========================================================================== //==========================================================================
@ -222,7 +222,7 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor)
{ {
I_Error ("ConversationID must be in the range [0,1000]"); I_Error ("ConversationID must be in the range [0,1000]");
} }
else StrifeTypes[convid] = bag.Info->Class; else StrifeTypes[convid] = info->Class;
} }
//========================================================================== //==========================================================================
@ -236,9 +236,16 @@ DEFINE_INFO_PROPERTY(conversationid, IiI, Actor)
//========================================================================== //==========================================================================
DEFINE_PROPERTY(skip_super, 0, Actor) DEFINE_PROPERTY(skip_super, 0, Actor)
{ {
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(AInventory))) if (info->Class->IsDescendantOf(RUNTIME_CLASS(AInventory)))
{ {
Printf("'skip_super' in definition of inventory item '%s' ignored.", bag.Info->Class->TypeName.GetChars() ); bag.ScriptPosition.Message(MSG_WARNING,
"'skip_super' in definition of inventory item '%s' ignored.", info->Class->TypeName.GetChars() );
return;
}
if (bag.StateSet)
{
bag.ScriptPosition.Message(MSG_WARNING,
"'skip_super' must appear before any state definitions.");
return; return;
} }
@ -256,7 +263,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor)
DEFINE_PROPERTY(tag, S, Actor) DEFINE_PROPERTY(tag, S, Actor)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaString(AMETA_StrifeName, str); info->Class->Meta.SetMetaString(AMETA_StrifeName, str);
} }
//========================================================================== //==========================================================================
@ -274,7 +281,7 @@ DEFINE_PROPERTY(health, I, Actor)
DEFINE_PROPERTY(gibhealth, I, Actor) DEFINE_PROPERTY(gibhealth, I, Actor)
{ {
PROP_INT_PARM(id, 0); PROP_INT_PARM(id, 0);
bag.Info->Class->Meta.SetMetaInt (AMETA_GibHealth, id); info->Class->Meta.SetMetaInt (AMETA_GibHealth, id);
} }
//========================================================================== //==========================================================================
@ -283,7 +290,7 @@ DEFINE_PROPERTY(gibhealth, I, Actor)
DEFINE_PROPERTY(woundhealth, I, Actor) DEFINE_PROPERTY(woundhealth, I, Actor)
{ {
PROP_INT_PARM(id, 0); PROP_INT_PARM(id, 0);
bag.Info->Class->Meta.SetMetaInt (AMETA_WoundHealth, id); info->Class->Meta.SetMetaInt (AMETA_WoundHealth, id);
} }
//========================================================================== //==========================================================================
@ -312,8 +319,8 @@ DEFINE_PROPERTY(painchance, ZI, Actor)
if (!stricmp(str, "Normal")) painType = NAME_None; if (!stricmp(str, "Normal")) painType = NAME_None;
else painType=str; else painType=str;
if (bag.Info->PainChances == NULL) bag.Info->PainChances=new PainChanceList; if (info->PainChances == NULL) info->PainChances=new PainChanceList;
(*bag.Info->PainChances)[painType] = (BYTE)id; (*info->PainChances)[painType] = (BYTE)id;
} }
} }
@ -478,7 +485,7 @@ DEFINE_PROPERTY(activesound, S, Actor)
DEFINE_PROPERTY(howlsound, S, Actor) DEFINE_PROPERTY(howlsound, S, Actor)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str)); info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(str));
} }
//========================================================================== //==========================================================================
@ -559,7 +566,7 @@ DEFINE_PROPERTY(alpha, F, Actor)
DEFINE_PROPERTY(obituary, S, Actor) DEFINE_PROPERTY(obituary, S, Actor)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaString (AMETA_Obituary, str); info->Class->Meta.SetMetaString (AMETA_Obituary, str);
} }
//========================================================================== //==========================================================================
@ -568,7 +575,7 @@ DEFINE_PROPERTY(obituary, S, Actor)
DEFINE_PROPERTY(hitobituary, S, Actor) DEFINE_PROPERTY(hitobituary, S, Actor)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaString (AMETA_HitObituary, str); info->Class->Meta.SetMetaString (AMETA_HitObituary, str);
} }
//========================================================================== //==========================================================================
@ -576,7 +583,7 @@ DEFINE_PROPERTY(hitobituary, S, Actor)
//========================================================================== //==========================================================================
DEFINE_PROPERTY(donthurtshooter, 0, Actor) DEFINE_PROPERTY(donthurtshooter, 0, Actor)
{ {
bag.Info->Class->Meta.SetMetaInt (ACMETA_DontHurtShooter, true); info->Class->Meta.SetMetaInt (ACMETA_DontHurtShooter, true);
} }
//========================================================================== //==========================================================================
@ -585,7 +592,7 @@ DEFINE_PROPERTY(donthurtshooter, 0, Actor)
DEFINE_PROPERTY(explosionradius, I, Actor) DEFINE_PROPERTY(explosionradius, I, Actor)
{ {
PROP_INT_PARM(id, 0); PROP_INT_PARM(id, 0);
bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, id); info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, id);
} }
//========================================================================== //==========================================================================
@ -594,7 +601,7 @@ DEFINE_PROPERTY(explosionradius, I, Actor)
DEFINE_PROPERTY(explosiondamage, I, Actor) DEFINE_PROPERTY(explosiondamage, I, Actor)
{ {
PROP_INT_PARM(id, 0); PROP_INT_PARM(id, 0);
bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, id); info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, id);
} }
//========================================================================== //==========================================================================
@ -605,7 +612,7 @@ DEFINE_PROPERTY(deathheight, F, Actor)
PROP_FIXED_PARM(h, 0); PROP_FIXED_PARM(h, 0);
// AActor::Die() uses a height of 0 to mean "cut the height to 1/4", // 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. // so if a height of 0 is desired, store it as -1.
bag.Info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h); info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h);
} }
//========================================================================== //==========================================================================
@ -615,7 +622,7 @@ DEFINE_PROPERTY(burnheight, F, Actor)
{ {
PROP_FIXED_PARM(h, 0); PROP_FIXED_PARM(h, 0);
// The note above for AMETA_DeathHeight also applies here. // The note above for AMETA_DeathHeight also applies here.
bag.Info->Class->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h); info->Class->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h);
} }
//========================================================================== //==========================================================================
@ -642,7 +649,7 @@ DEFINE_PROPERTY(meleethreshold, F, Actor)
DEFINE_PROPERTY(meleedamage, I, Actor) DEFINE_PROPERTY(meleedamage, I, Actor)
{ {
PROP_INT_PARM(id, 0); PROP_INT_PARM(id, 0);
bag.Info->Class->Meta.SetMetaInt (ACMETA_MeleeDamage, id); info->Class->Meta.SetMetaInt (ACMETA_MeleeDamage, id);
} }
//========================================================================== //==========================================================================
@ -660,7 +667,7 @@ DEFINE_PROPERTY(meleerange, F, Actor)
DEFINE_PROPERTY(meleesound, S, Actor) DEFINE_PROPERTY(meleesound, S, Actor)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str)); info->Class->Meta.SetMetaInt (ACMETA_MeleeSound, S_FindSound(str));
} }
//========================================================================== //==========================================================================
@ -669,7 +676,7 @@ DEFINE_PROPERTY(meleesound, S, Actor)
DEFINE_PROPERTY(missiletype, S, Actor) DEFINE_PROPERTY(missiletype, S, Actor)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaInt (ACMETA_MissileName, FName(str)); info->Class->Meta.SetMetaInt (ACMETA_MissileName, FName(str));
} }
//========================================================================== //==========================================================================
@ -678,7 +685,7 @@ DEFINE_PROPERTY(missiletype, S, Actor)
DEFINE_PROPERTY(missileheight, F, Actor) DEFINE_PROPERTY(missileheight, F, Actor)
{ {
PROP_FIXED_PARM(id, 0); PROP_FIXED_PARM(id, 0);
bag.Info->Class->Meta.SetMetaFixed (ACMETA_MissileHeight, id); info->Class->Meta.SetMetaFixed (ACMETA_MissileHeight, id);
} }
//========================================================================== //==========================================================================
@ -691,7 +698,7 @@ DEFINE_PROPERTY(translation, L, Actor)
if (type == 0) if (type == 0)
{ {
PROP_INT_PARM(trans, 1); PROP_INT_PARM(trans, 1);
int max = (gameinfo.gametype==GAME_Strife || (bag.Info->GameFilter&GAME_Strife)) ? 6:2; int max = (gameinfo.gametype==GAME_Strife || (info->GameFilter&GAME_Strife)) ? 6:2;
if (trans < 0 || trans > max) if (trans < 0 || trans > max)
{ {
I_Error ("Translation must be in the range [0,%d]", max); I_Error ("Translation must be in the range [0,%d]", max);
@ -739,7 +746,7 @@ DEFINE_PROPERTY(bloodcolor, C, Actor)
PalEntry pe = color; PalEntry pe = color;
pe.a = CreateBloodTranslation(pe); pe.a = CreateBloodTranslation(pe);
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodColor, pe); info->Class->Meta.SetMetaInt (AMETA_BloodColor, pe);
} }
@ -754,21 +761,21 @@ DEFINE_PROPERTY(bloodtype, Sss, Actor)
FName blood = str; FName blood = str;
// normal blood // normal blood
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType, blood); info->Class->Meta.SetMetaInt (AMETA_BloodType, blood);
if (PROP_PARM_COUNT > 1) if (PROP_PARM_COUNT > 1)
{ {
blood = str1; blood = str1;
} }
// blood splatter // blood splatter
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType2, blood); info->Class->Meta.SetMetaInt (AMETA_BloodType2, blood);
if (PROP_PARM_COUNT > 2) if (PROP_PARM_COUNT > 2)
{ {
blood = str2; blood = str2;
} }
// axe blood // axe blood
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType3, blood); info->Class->Meta.SetMetaInt (AMETA_BloodType3, blood);
} }
//========================================================================== //==========================================================================
@ -825,13 +832,13 @@ DEFINE_PROPERTY(damagefactor, SF, Actor)
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
PROP_FIXED_PARM(id, 1); PROP_FIXED_PARM(id, 1);
if (bag.Info->DamageFactors == NULL) bag.Info->DamageFactors=new DmgFactors; if (info->DamageFactors == NULL) info->DamageFactors=new DmgFactors;
FName dmgType; FName dmgType;
if (!stricmp(str, "Normal")) dmgType = NAME_None; if (!stricmp(str, "Normal")) dmgType = NAME_None;
else dmgType=str; else dmgType=str;
(*bag.Info->DamageFactors)[dmgType]=id; (*info->DamageFactors)[dmgType]=id;
} }
//========================================================================== //==========================================================================
@ -867,7 +874,7 @@ DEFINE_PROPERTY(maxdropoffheight, F, Actor)
DEFINE_PROPERTY(poisondamage, I, Actor) DEFINE_PROPERTY(poisondamage, I, Actor)
{ {
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
bag.Info->Class->Meta.SetMetaInt (AMETA_PoisonDamage, i); info->Class->Meta.SetMetaInt (AMETA_PoisonDamage, i);
} }
//========================================================================== //==========================================================================
@ -876,7 +883,7 @@ DEFINE_PROPERTY(poisondamage, I, Actor)
DEFINE_PROPERTY(fastspeed, F, Actor) DEFINE_PROPERTY(fastspeed, F, Actor)
{ {
PROP_FIXED_PARM(i, 0); PROP_FIXED_PARM(i, 0);
bag.Info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, i); info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, i);
} }
//========================================================================== //==========================================================================
@ -885,7 +892,7 @@ DEFINE_PROPERTY(fastspeed, F, Actor)
DEFINE_PROPERTY(radiusdamagefactor, F, Actor) DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
{ {
PROP_FIXED_PARM(i, 0); PROP_FIXED_PARM(i, 0);
bag.Info->Class->Meta.SetMetaFixed (AMETA_RDFactor, i); info->Class->Meta.SetMetaFixed (AMETA_RDFactor, i);
} }
//========================================================================== //==========================================================================
@ -894,7 +901,7 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
DEFINE_PROPERTY(cameraheight, F, Actor) DEFINE_PROPERTY(cameraheight, F, Actor)
{ {
PROP_FIXED_PARM(i, 0); PROP_FIXED_PARM(i, 0);
bag.Info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, i); info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, i);
} }
//========================================================================== //==========================================================================
@ -980,7 +987,7 @@ DEFINE_CLASS_PROPERTY(backpackmaxamount, I, Ammo)
DEFINE_CLASS_PROPERTY(dropamount, I, Ammo) DEFINE_CLASS_PROPERTY(dropamount, I, Ammo)
{ {
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
bag.Info->Class->Meta.SetMetaInt (AIMETA_DropAmount, i); info->Class->Meta.SetMetaInt (AIMETA_DropAmount, i);
} }
//========================================================================== //==========================================================================
@ -1018,11 +1025,11 @@ DEFINE_CLASS_PROPERTY(saveamount, I, Armor)
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes // Special case here because this property has to work for 2 unrelated classes
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{ {
((ABasicArmorPickup*)defaults)->SaveAmount=i; ((ABasicArmorPickup*)defaults)->SaveAmount=i;
} }
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{ {
((ABasicArmorBonus*)defaults)->SaveAmount=i; ((ABasicArmorBonus*)defaults)->SaveAmount=i;
} }
@ -1039,18 +1046,19 @@ DEFINE_CLASS_PROPERTY(savepercent, F, Armor)
{ {
PROP_FIXED_PARM(i, 0); 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 // Special case here because this property has to work for 2 unrelated classes
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{ {
((ABasicArmorPickup*)defaults)->SavePercent=i; ((ABasicArmorPickup*)defaults)->SavePercent = i;
} }
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{ {
((ABasicArmorBonus*)defaults)->SavePercent=i; ((ABasicArmorBonus*)defaults)->SavePercent = i;
} }
else else
{ {
I_Error("\"Armor.SavePercent\" requires an actor of type \"Armor\""); I_Error("\"Armor.SavePercent\" requires an actor of type \"Armor\"\n");
} }
} }
@ -1062,11 +1070,11 @@ DEFINE_CLASS_PROPERTY(maxabsorb, I, Armor)
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes // Special case here because this property has to work for 2 unrelated classes
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{ {
((ABasicArmorPickup*)defaults)->MaxAbsorb = i; ((ABasicArmorPickup*)defaults)->MaxAbsorb = i;
} }
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{ {
((ABasicArmorBonus*)defaults)->MaxAbsorb = i; ((ABasicArmorBonus*)defaults)->MaxAbsorb = i;
} }
@ -1084,11 +1092,11 @@ DEFINE_CLASS_PROPERTY(maxfullabsorb, I, Armor)
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
// Special case here because this property has to work for 2 unrelated classes // Special case here because this property has to work for 2 unrelated classes
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup))) if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
{ {
((ABasicArmorPickup*)defaults)->MaxFullAbsorb = i; ((ABasicArmorPickup*)defaults)->MaxFullAbsorb = i;
} }
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))) else if (info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
{ {
((ABasicArmorBonus*)defaults)->MaxFullAbsorb = i; ((ABasicArmorBonus*)defaults)->MaxFullAbsorb = i;
} }
@ -1119,10 +1127,11 @@ DEFINE_CLASS_PROPERTY(icon, S, Inventory)
{ {
// Don't print warnings if the item is for another game or if this is a shareware IWAD. // 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. // 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) && if ((info->GameFilter == GAME_Any || info->GameFilter & gameinfo.gametype) &&
!(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0) !(gameinfo.flags&GI_SHAREWARE) && Wads.GetLumpFile(bag.Lumpnum) != 0)
{ {
Printf("Icon '%s' for '%s' not found\n", i, bag.Info->Class->TypeName.GetChars()); bag.ScriptPosition.Message(MSG_WARNING,
"Icon '%s' for '%s' not found\n", i, info->Class->TypeName.GetChars());
} }
} }
} }
@ -1160,7 +1169,7 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
DEFINE_CLASS_PROPERTY(pickupmessage, S, Inventory) DEFINE_CLASS_PROPERTY(pickupmessage, S, Inventory)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, str); info->Class->Meta.SetMetaString(AIMETA_PickupMessage, str);
} }
//========================================================================== //==========================================================================
@ -1196,7 +1205,7 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
DEFINE_CLASS_PROPERTY(givequest, I, Inventory) DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
{ {
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
bag.Info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, i); info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, i);
} }
//========================================================================== //==========================================================================
@ -1206,8 +1215,8 @@ DEFINE_CLASS_PROPERTY(lowmessage, IS, Health)
{ {
PROP_INT_PARM(i, 0); PROP_INT_PARM(i, 0);
PROP_STRING_PARM(str, 1); PROP_STRING_PARM(str, 1);
bag.Info->Class->Meta.SetMetaInt(AIMETA_LowHealth, i); info->Class->Meta.SetMetaInt(AIMETA_LowHealth, i);
bag.Info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, str); info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, str);
} }
//========================================================================== //==========================================================================
@ -1225,7 +1234,7 @@ DEFINE_CLASS_PROPERTY(number, I, PuzzleItem)
DEFINE_CLASS_PROPERTY(failmessage, S, PuzzleItem) DEFINE_CLASS_PROPERTY(failmessage, S, PuzzleItem)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, str); info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, str);
} }
//========================================================================== //==========================================================================
@ -1399,11 +1408,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
int alpha; int alpha;
PalEntry * pBlendColor; PalEntry * pBlendColor;
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
{ {
pBlendColor = &((APowerup*)defaults)->BlendColor; pBlendColor = &((APowerup*)defaults)->BlendColor;
} }
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
{ {
pBlendColor = &((APowerupGiver*)defaults)->BlendColor; pBlendColor = &((APowerupGiver*)defaults)->BlendColor;
} }
@ -1463,11 +1472,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
{ {
int *pEffectTics; int *pEffectTics;
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup))) if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
{ {
pEffectTics = &((APowerup*)defaults)->EffectTics; pEffectTics = &((APowerup*)defaults)->EffectTics;
} }
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver))) else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
{ {
pEffectTics = &((APowerupGiver*)defaults)->EffectTics; pEffectTics = &((APowerupGiver*)defaults)->EffectTics;
} }
@ -1511,7 +1520,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, displayname, S, PlayerPawn)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaString (APMETA_DisplayName, str); info->Class->Meta.SetMetaString (APMETA_DisplayName, str);
} }
//========================================================================== //==========================================================================
@ -1523,7 +1532,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, soundclass, S, PlayerPawn)
FString tmp = str; FString tmp = str;
tmp.ReplaceChars (' ', '_'); tmp.ReplaceChars (' ', '_');
bag.Info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp); info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp);
} }
//========================================================================== //==========================================================================
@ -1537,8 +1546,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
tmp.ToUpper(); tmp.ToUpper();
if (tmp.Len() != 3) if (tmp.Len() != 3)
{ {
Printf("Invalid face '%s' for '%s';\nSTF replacement codes must be 3 characters.\n", bag.ScriptPosition.Message(MSG_WARNING,
tmp.GetChars(), bag.Info->Class->TypeName.GetChars ()); "Invalid face '%s' for '%s';\nSTF replacement codes must be 3 characters.\n",
tmp.GetChars(), info->Class->TypeName.GetChars ());
} }
bool valid = ( bool valid = (
@ -1548,11 +1558,12 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, face, S, PlayerPawn)
); );
if (!valid) if (!valid)
{ {
Printf("Invalid face '%s' for '%s';\nSTF replacement codes must be alphanumeric.\n", bag.ScriptPosition.Message(MSG_WARNING,
tmp.GetChars(), bag.Info->Class->TypeName.GetChars ()); "Invalid face '%s' for '%s';\nSTF replacement codes must be alphanumeric.\n",
tmp.GetChars(), info->Class->TypeName.GetChars ());
} }
bag.Info->Class->Meta.SetMetaString (APMETA_Face, tmp); info->Class->Meta.SetMetaString (APMETA_Face, tmp);
} }
//========================================================================== //==========================================================================
@ -1566,7 +1577,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn)
if (start > end) if (start > end)
swap (start, end); swap (start, end);
bag.Info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8)); info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8));
} }
//========================================================================== //==========================================================================
@ -1691,7 +1702,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, scoreicon, S, PlayerPawn)
defaults->ScoreIcon = TexMan.CheckForTexture(z, FTexture::TEX_MiscPatch); defaults->ScoreIcon = TexMan.CheckForTexture(z, FTexture::TEX_MiscPatch);
if (!defaults->ScoreIcon.isValid()) if (!defaults->ScoreIcon.isValid())
{ {
Printf("Icon '%s' for '%s' not found\n", z, bag.Info->Class->TypeName.GetChars ()); bag.ScriptPosition.Message(MSG_WARNING,
"Icon '%s' for '%s' not found\n", z, info->Class->TypeName.GetChars ());
} }
} }
@ -1751,7 +1763,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)str); info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)str);
} }
//========================================================================== //==========================================================================
@ -1760,7 +1772,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn) DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
bag.Info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str); info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)str);
} }
//========================================================================== //==========================================================================
@ -1771,7 +1783,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, hexenarmor, FFFFF, PlayerPawn)
for (int i=0;i<5;i++) for (int i=0;i<5;i++)
{ {
PROP_FIXED_PARM(val, i); PROP_FIXED_PARM(val, i);
bag.Info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val); info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, val);
} }
} }

View file

@ -63,7 +63,7 @@
// creates an empty parameter list for a parameterized function call // creates an empty parameter list for a parameterized function call
// //
//========================================================================== //==========================================================================
static int PrepareStateParameters(FState * state, int numparams, const PClass *cls) int PrepareStateParameters(FState * state, int numparams, const PClass *cls)
{ {
int paramindex=StateParams.Reserve(numparams, cls); int paramindex=StateParams.Reserve(numparams, cls);
state->ParameterIndex = paramindex+1; state->ParameterIndex = paramindex+1;
@ -76,7 +76,7 @@ static int PrepareStateParameters(FState * state, int numparams, const PClass *c
// handles action specials as code pointers // handles action specials as code pointers
// //
//========================================================================== //==========================================================================
bool DoActionSpecials(FScanner &sc, FState & state, bool multistate, int * statecount, Baggage &bag) bool DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
{ {
int i; int i;
int min_args, max_args; int min_args, max_args;
@ -150,15 +150,10 @@ static FString ParseStateString(FScanner &sc)
// parses a state block // parses a state block
// //
//========================================================================== //==========================================================================
int ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &bag) void ParseStates(FScanner &sc, FActorInfo * actor, AActor * defaults, Baggage &bag)
{ {
FString statestring; FString statestring;
intptr_t count = 0;
FState state; FState state;
FState * laststate = NULL;
intptr_t lastlabel = -1;
int minrequiredstate = -1;
int spriteindex = 0;
char lastsprite[5]=""; char lastsprite[5]="";
sc.MustGetStringName ("{"); sc.MustGetStringName ("{");
@ -177,17 +172,7 @@ do_goto:
statestring += '+'; statestring += '+';
statestring += sc.String; statestring += sc.String;
} }
// copy the text - this must be resolved later! if (!bag.statedef.SetGotoLabel(statestring))
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.
bag.statedef.RetargetStates (count+1, statestring);
}
else
{ {
sc.ScriptError("GOTO before first state"); sc.ScriptError("GOTO before first state");
} }
@ -195,15 +180,7 @@ do_goto:
else if (!statestring.CompareNoCase("STOP")) else if (!statestring.CompareNoCase("STOP"))
{ {
do_stop: do_stop:
if (laststate!=NULL) if (!bag.statedef.SetStop())
{
laststate->DefineFlags = SDF_STOP;
}
else if (lastlabel >=0)
{
bag.statedef.RetargetStates (count+1, NULL);
}
else
{ {
sc.ScriptError("STOP before first state"); sc.ScriptError("STOP before first state");
continue; continue;
@ -211,35 +188,28 @@ do_stop:
} }
else if (!statestring.CompareNoCase("WAIT") || !statestring.CompareNoCase("FAIL")) else if (!statestring.CompareNoCase("WAIT") || !statestring.CompareNoCase("FAIL"))
{ {
if (!laststate) if (!bag.statedef.SetWait())
{ {
sc.ScriptError("%s before first state", sc.String); sc.ScriptError("%s before first state", sc.String);
continue; continue;
} }
laststate->DefineFlags = SDF_WAIT;
} }
else if (!statestring.CompareNoCase("LOOP")) else if (!statestring.CompareNoCase("LOOP"))
{ {
if (!laststate) if (!bag.statedef.SetLoop())
{ {
sc.ScriptError("LOOP before first state"); sc.ScriptError("LOOP before first state");
continue; continue;
} }
laststate->NextState=(FState*)(lastlabel+1);
laststate->DefineFlags = SDF_INDEX;
} }
else else
{ {
const char * statestrp;
sc.MustGetString(); sc.MustGetString();
if (sc.Compare (":")) if (sc.Compare (":"))
{ {
laststate = NULL;
do do
{ {
lastlabel = count; bag.statedef.AddStateLabel(statestring);
bag.statedef.AddState(statestring, (FState *) (count+1), SDF_INDEX);
statestring = ParseStateString(sc); statestring = ParseStateString(sc);
if (!statestring.CompareNoCase("GOTO")) if (!statestring.CompareNoCase("GOTO"))
{ {
@ -261,25 +231,11 @@ do_stop:
sc.ScriptError ("Sprite names must be exactly 4 characters\n"); sc.ScriptError ("Sprite names must be exactly 4 characters\n");
} }
statestring.ToUpper(); state.sprite = GetSpriteIndex(statestring);
if (strcmp(statestring, lastsprite))
{
strcpy(lastsprite, statestring);
spriteindex = GetSpriteIndex(lastsprite);
}
state.sprite = spriteindex;
state.Misc1 = state.Misc2 = 0; state.Misc1 = state.Misc2 = 0;
state.ParameterIndex = 0; state.ParameterIndex = 0;
sc.MustGetString(); sc.MustGetString();
statestring = (sc.String+1); statestring = sc.String;
statestrp = statestring;
state.Frame = (*sc.String & 223)-'A';
if ((*sc.String & 223)<'A' || (*sc.String & 223)>']')
{
sc.ScriptError ("Frames must be A-Z, [, \\, or ]");
state.Frame=0;
}
sc.MustGetNumber(); sc.MustGetNumber();
state.Tics = clamp<int>(sc.Number, -1, 32767); state.Tics = clamp<int>(sc.Number, -1, 32767);
@ -307,10 +263,8 @@ do_stop:
// Make the action name lowercase to satisfy the gperf hashers // Make the action name lowercase to satisfy the gperf hashers
strlwr (sc.String); strlwr (sc.String);
int minreq = count; if (DoActionSpecials(sc, state, bag))
if (DoActionSpecials(sc, state, !statestring.IsEmpty(), &minreq, bag))
{ {
if (minreq>minrequiredstate) minrequiredstate=minreq;
goto endofstate; goto endofstate;
} }
@ -360,7 +314,7 @@ do_stop:
if ((*params == 'l' || *params == 'L') && sc.CheckNumber()) if ((*params == 'l' || *params == 'L') && sc.CheckNumber())
{ {
// Special case: State label as an offset // Special case: State label as an offset
if (sc.Number > 0 && strlen(statestring)>0) if (sc.Number > 0 && statestring.Len() > 1)
{ {
sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n"); sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n");
} }
@ -371,7 +325,7 @@ do_stop:
sc.ScriptError("Negative jump offsets are not allowed"); sc.ScriptError("Negative jump offsets are not allowed");
} }
x = new FxStateByIndex(count+v, sc); x = new FxStateByIndex(bag.statedef.GetStateCount() + v, sc);
} }
else else
{ {
@ -420,26 +374,12 @@ do_stop:
} }
sc.UnGet(); sc.UnGet();
endofstate: endofstate:
bag.StateArray.Push(state); if (!bag.statedef.AddStates(&state, statestring))
while (*statestrp)
{ {
int frame=((*statestrp++)&223)-'A'; sc.ScriptError ("Invalid frame character string '%s'", statestring.GetChars());
if (frame<0 || frame>28)
{
sc.ScriptError ("Frames must be A-Z, [, \\, or ]");
frame=0;
}
state.Frame=(state.Frame&(SF_FULLBRIGHT))|frame;
bag.StateArray.Push(state);
count++;
} }
laststate=&bag.StateArray[count];
count++;
} }
} }
sc.SetEscape(true); // re-enable escape sequences sc.SetEscape(true); // re-enable escape sequences
return count;
} }

View file

@ -441,9 +441,9 @@ void InitPalette ()
shade = DesaturateColormap[m]; shade = DesaturateColormap[m];
for (c = 0; c < 256; c++) for (c = 0; c < 256; c++)
{ {
intensity = GPalette.BaseColors[c].r * 77 + intensity = (GPalette.BaseColors[c].r * 77 +
GPalette.BaseColors[c].g * 143 + GPalette.BaseColors[c].g * 143 +
GPalette.BaseColors[c].b * 37; GPalette.BaseColors[c].b * 37) / 255;
int r = (GPalette.BaseColors[c].r * (31-m) + intensity *m) / 31; int r = (GPalette.BaseColors[c].r * (31-m) + intensity *m) / 31;
int g = (GPalette.BaseColors[c].g * (31-m) + intensity *m) / 31; int g = (GPalette.BaseColors[c].g * (31-m) + intensity *m) / 31;

View file

@ -34,7 +34,7 @@
#ifndef __V_PALETTE_H__ #ifndef __V_PALETTE_H__
#define __V_PALETTE_H__ #define __V_PALETTE_H__
#include "basictypes.h" #include "doomtype.h"
#define MAKERGB(r,g,b) DWORD(((r)<<16)|((g)<<8)|(b)) #define MAKERGB(r,g,b) DWORD(((r)<<16)|((g)<<8)|(b))
#define MAKEARGB(a,r,g,b) DWORD(((a)<<24)|((r)<<16)|((g)<<8)|(b)) #define MAKEARGB(a,r,g,b) DWORD(((a)<<24)|((r)<<16)|((g)<<8)|(b))

View file

@ -454,33 +454,48 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr)
} }
else else
{ {
// Treat it as a space-delemited hexadecimal string if (strlen(cstr) == 6)
for (i = 0; i < 3; ++i)
{ {
// Skip leading whitespace char *p;
while (*cstr <= ' ' && *cstr != '\0') int color = strtol(cstr, &p, 16);
if (*p == 0)
{ {
cstr++; // RRGGBB string
c[0] = (color & 0xff0000) >> 16;
c[1] = (color & 0xff00) >> 8;
c[2] = (color & 0xff);
} }
// Extract a component and convert it to eight-bit }
for (p = 0; *cstr > ' '; ++p, ++cstr) else
{
// Treat it as a space-delemited hexadecimal string
for (i = 0; i < 3; ++i)
{ {
if (p < 2) // Skip leading whitespace
while (*cstr <= ' ' && *cstr != '\0')
{ {
val[p] = *cstr; cstr++;
} }
} // Extract a component and convert it to eight-bit
if (p == 0) for (p = 0; *cstr > ' '; ++p, ++cstr)
{
c[i] = 0;
}
else
{
if (p == 1)
{ {
val[1] = val[0]; if (p < 2)
{
val[p] = *cstr;
}
}
if (p == 0)
{
c[i] = 0;
}
else
{
if (p == 1)
{
val[1] = val[0];
}
c[i] = ParseHex (val);
} }
c[i] = ParseHex (val);
} }
} }
} }

View file

@ -32,8 +32,8 @@ Actor GreenArmor : BasicArmorPickup 2018
Height 16 Height 16
Inventory.Pickupmessage "$GOTARMOR" Inventory.Pickupmessage "$GOTARMOR"
Inventory.Icon "ARM1A0" Inventory.Icon "ARM1A0"
Armor.Savepercent 33.33333 Armor.SavePercent 33.335
Armor.Saveamount 100 Armor.SaveAmount 100
States States
{ {
Spawn: Spawn:

View file

@ -37,7 +37,7 @@ ACTOR LeatherArmor : BasicArmorPickup 2018
Inventory.Icon "I_ARM2" Inventory.Icon "I_ARM2"
Inventory.PickupMessage "$TXT_LEATHERARMOR" Inventory.PickupMessage "$TXT_LEATHERARMOR"
Armor.SaveAmount 100 Armor.SaveAmount 100
Armor.SavePercent 33.33333 Armor.SavePercent 33.335
Tag "Leather_Armor" Tag "Leather_Armor"
States States
{ {