- Fixed: SNDINFO must be loaded before the textures. However, this required

some changes to the MAPINFO parser which tried to access the texture manager
  to check if the level name patches exist. That check had to be moved to
  where the intermission screen is set up.
- Fixed: 'bloodcolor' ignored the first parameter value when given a list
  of integers.
  Please note that this creates an incompatibility between old and new 
  versions so if you want to create something that works with both 2.2.0
  and current versions better use the string format version for the color
  parameter!
- Rewrote the DECORATE property parser so that the parser is completely
  separated from the property handlers. This should allow reuse of all 
  the handler code for a new format if Doomscript requires one.
- Fixed: PClass::InitializeActorInfo copied too many bytes if a subclass's
  defaults were larger than the parent's.
- Moved A_ChangeFlag to thingdef_codeptr.cpp.
- Moved translation related code from thingdef_properties.cpp to r_translate.cpp
  and rewrote the translation parser to use FScanner instead of strtol.
- replaced DECORATE's 'alpha default' by 'defaultalpha' for consistency.
  Since this was never used outside zdoom.pk3 it's not critical.
- Removed support for game specific pickup messages because the only thing
  this was ever used for - Raven's invulnerability item - has already been
  split up into a Heretic and Hexen version.

SVN r1240 (trunk)
This commit is contained in:
Christoph Oelckers 2008-09-21 18:02:38 +00:00
parent 2b16b99f4d
commit 6227906072
38 changed files with 2303 additions and 2309 deletions

View File

@ -1,3 +1,31 @@
September 21, 2008 (Changes by Graf Zahl)
- To get the game name the screenshot code might as well use the globally
available GameNames array instead of creating its own list.
- Moved backpack names for cheat into gameinfo.
- Fixed: SNDINFO must be loaded before the textures. However, this required
some changes to the MAPINFO parser which tried to access the texture manager
to check if the level name patches exist. That check had to be moved to
where the intermission screen is set up.
- Fixed: 'bloodcolor' ignored the first parameter value when given a list
of integers.
Please note that this creates an incompatibility between old and new
versions so if you want to create something that works with both 2.2.0
and current versions better use the string format version for the color
parameter!
- Rewrote the DECORATE property parser so that the parser is completely
separated from the property handlers. This should allow reuse of all
the handler code for a new format if Doomscript requires one.
- Fixed: PClass::InitializeActorInfo copied too many bytes if a subclass's
defaults were larger than the parent's.
- Moved A_ChangeFlag to thingdef_codeptr.cpp.
- Moved translation related code from thingdef_properties.cpp to r_translate.cpp
and rewrote the translation parser to use FScanner instead of strtol.
- replaced DECORATE's 'alpha default' by 'defaultalpha' for consistency.
Since this was never used outside zdoom.pk3 it's not critical.
- Removed support for game specific pickup messages because the only thing
this was ever used for - Raven's invulnerability item - has already been
split up into a Heretic and Hexen version.
September 20, 2008
- Fixed: The Timidity config parser always tried to process the note number,
even if it wasn't specified.

View File

@ -427,6 +427,27 @@ enum
AMETA_BloodType3, // AxeBlood replacement type
};
struct FDropItem
{
FName Name;
int probability;
int amount;
FDropItem * Next;
};
class FDropItemPtrArray : public TArray<FDropItem *>
{
public:
~FDropItemPtrArray();
};
extern FDropItemPtrArray DropItemList;
void FreeDropItemChain(FDropItem *chain);
int StoreDropItemChain(FDropItem *chain);
// Map Object definition.
class AActor : public DThinker
{
@ -448,6 +469,7 @@ public:
return (AActor *)(RUNTIME_TYPE(this)->Defaults);
}
FDropItem *GetDropItems();
// Return true if the monster should use a missile attack, false for melee
bool SuggestMissileAttack (fixed_t dist);

View File

@ -50,7 +50,7 @@
#define REGMARKER(x) (x)
typedef void *REGINFO;
// List of ActorInfos and the TypeInfos they belong to
// List of Action functons
extern REGINFO ARegHead;
extern REGINFO ARegTail;
@ -58,6 +58,10 @@ extern REGINFO ARegTail;
extern REGINFO CRegHead;
extern REGINFO CRegTail;
// List of properties
extern REGINFO GRegHead;
extern REGINFO GRegTail;
template<class T, REGINFO *_head, REGINFO *_tail>
class TAutoSegIteratorNoArrow
{

View File

@ -1697,18 +1697,22 @@ static int PatchMisc (int dummy)
{
player->health = deh.StartHealth;
FDropItem * di = GetDropItems(PClass::FindClass(NAME_DoomPlayer));
while (di != NULL)
// Hm... I'm not sure that this is the right way to change this info...
unsigned int index = PClass::FindClass(NAME_DoomPlayer)->Meta.GetMetaInt (ACMETA_DropItems) - 1;
if (index >= 0 && index < DropItemList.Size())
{
if (di->Name == NAME_Clip)
FDropItem * di = DropItemList[index];
while (di != NULL)
{
di->amount = deh.StartBullets;
if (di->Name == NAME_Clip)
{
di->amount = deh.StartBullets;
}
di = di->Next;
}
di = di->Next;
}
}
// 0xDD means "enable infighting"
if (infighting == 0xDD)
{
@ -2195,14 +2199,6 @@ void DoDehPatch (const char *patchfile, bool autoloading, int lump)
PatchFile[filelen] = 0;
dversion = pversion = -1;
/*
if (gameinfo.gametype != GAME_Doom)
{
Printf ("DeHackEd/BEX patches are only supported for DOOM mode\n");
delete[] PatchFile;
return;
}
*/
cont = 0;
if (0 == strncmp (PatchFile, "Patch File for DeHackEd v", 25))
{

View File

@ -2481,12 +2481,6 @@ void D_DoomMain (void)
StartScreen->AppendStatusLine(temp);
}
Printf ("Texman.Init: Init texture manager.\n");
TexMan.Init();
// Now that all textues have been loaded the crosshair can be initialized.
crosshair.Callback ();
// [RH] Parse through all loaded mapinfo lumps
Printf ("G_ParseMapInfo: Load map definitions.\n");
G_ParseMapInfo ();
@ -2495,6 +2489,13 @@ void D_DoomMain (void)
Printf ("S_InitData: Load sound definitions.\n");
S_InitData ();
Printf ("Texman.Init: Init texture manager.\n");
TexMan.Init();
// Now that all textues have been loaded the crosshair can be initialized.
crosshair.Callback ();
// [CW] Parse any TEAMINFO lumps
Printf ("TEAMINFO_Init: Load team definitions.\n");
TEAMINFO_Init ();

View File

@ -297,7 +297,7 @@ void PClass::InitializeActorInfo ()
Defaults = new BYTE[Size];
if (ParentClass->Defaults != NULL)
{
memcpy (Defaults, ParentClass->Defaults, Size);
memcpy (Defaults, ParentClass->Defaults, ParentClass->Size);
if (Size > ParentClass->Size)
{
memset (Defaults + ParentClass->Size, 0, Size - ParentClass->Size);

View File

@ -165,7 +165,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound)
FDropItem *drop; // while drop stays as the reference point.
int n=0;
drop = di = GetDropItems(self->master->GetClass());
drop = di = self->master->GetDropItems();
if (di != NULL)
{
while (di != NULL)

View File

@ -830,6 +830,7 @@ static void G_DoParseMapInfo (int lump)
strcpy (levelinfo->skypic2, levelinfo->skypic1);
}
SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
/* can't do this here.
if (levelinfo->pname[0] != 0)
{
if (!TexMan.CheckForTexture(levelinfo->pname, FTexture::TEX_MiscPatch).Exists())
@ -837,6 +838,7 @@ static void G_DoParseMapInfo (int lump)
levelinfo->pname[0] = 0;
}
}
*/
break;
}
@ -1704,7 +1706,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
{
int cstype = SBarInfoScript->GetGameType();
if(cstype == GAME_Doom || cstype == GAME_Chex) //Did the user specify a "base"
if(cstype & GAME_DoomChex) //Did the user specify a "base"
{
StatusBar = CreateDoomStatusBar ();
}
@ -1973,7 +1975,7 @@ void G_DoCompleted (void)
AM_Stop ();
wminfo.finished_ep = level.cluster - 1;
wminfo.lname0 = level.info->pname;
wminfo.LName0 = TexMan[TexMan.CheckForTexture(level.info->pname, FTexture::TEX_MiscPatch)];
wminfo.current = level.mapname;
if (deathmatch &&
@ -1981,20 +1983,20 @@ void G_DoCompleted (void)
!(level.flags & LEVEL_CHANGEMAPCHEAT))
{
wminfo.next = level.mapname;
wminfo.lname1 = level.info->pname;
wminfo.LName1 = wminfo.LName0;
}
else
{
if (strncmp (nextlevel, "enDSeQ", 6) == 0)
{
wminfo.next = FString(nextlevel, 8);
wminfo.lname1 = "";
wminfo.LName1 = NULL;
}
else
{
level_info_t *nextinfo = FindLevelInfo (nextlevel);
wminfo.next = nextinfo->mapname;
wminfo.lname1 = nextinfo->pname;
wminfo.LName1 = TexMan[TexMan.CheckForTexture(nextinfo->pname, FTexture::TEX_MiscPatch)];
}
}

View File

@ -81,7 +81,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking)
// If the self has attached metadata for items to drop, drop those.
if (!self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB]
{
FDropItem *di = GetDropItems(RUNTIME_TYPE(self));
FDropItem *di = self->GetDropItems();
if (di != NULL)
{

View File

@ -394,6 +394,7 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote)
const char *failtext = NULL;
FSoundID failsound;
if (owner == NULL) return false;
if (keynum<=0 || keynum>255) return true;
// Just a safety precaution. The messages should have been initialized upon game start.
if (!keysdone) P_InitKeyMessages();

View File

@ -30,7 +30,7 @@ class ARandomSpawner : public AActor
Super::PostBeginPlay();
drop = di = GetDropItems(RUNTIME_TYPE(this));
drop = di = GetDropItems();
if (di != NULL)
{
while (di != NULL)

View File

@ -587,7 +587,7 @@ IMPLEMENT_CLASS(AWeaponGiver)
bool AWeaponGiver::TryPickup(AActor *&toucher)
{
FDropItem *di = GetDropItems(GetClass());
FDropItem *di = GetDropItems();
if (di != NULL)
{

View File

@ -100,6 +100,7 @@ gameinfo_t HexenGameInfo =
{ "mapinfo/hexen.txt", NULL },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding", // Hexen doesn't have a backpack so use Heretic's.
};
gameinfo_t HexenDKGameInfo =
@ -132,6 +133,7 @@ gameinfo_t HexenDKGameInfo =
{ "mapinfo/hexen.txt", NULL },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding",
};
gameinfo_t HereticGameInfo =
@ -164,6 +166,7 @@ gameinfo_t HereticGameInfo =
{ "mapinfo/heretic.txt", NULL },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding",
};
gameinfo_t HereticSWGameInfo =
@ -196,6 +199,7 @@ gameinfo_t HereticSWGameInfo =
{ "mapinfo/heretic.txt", NULL },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding",
};
gameinfo_t SharewareGameInfo =
@ -228,6 +232,7 @@ gameinfo_t SharewareGameInfo =
{ "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
};
gameinfo_t RegisteredGameInfo =
@ -260,6 +265,7 @@ gameinfo_t RegisteredGameInfo =
{ "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
};
gameinfo_t ChexGameInfo =
@ -292,6 +298,7 @@ gameinfo_t ChexGameInfo =
{ "mapinfo/chex.txt", NULL },
MAKERGB(63,125,57),
MAKERGB(95,175,87),
"ZorchPack",
};
gameinfo_t Chex3GameInfo =
@ -324,6 +331,7 @@ gameinfo_t Chex3GameInfo =
{ "mapinfo/chex.txt", NULL },
MAKERGB(63,125,57),
MAKERGB(95,175,87),
"ZorchPack",
};
gameinfo_t RetailGameInfo =
@ -356,6 +364,7 @@ gameinfo_t RetailGameInfo =
{ "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
};
gameinfo_t CommercialGameInfo =
@ -388,6 +397,7 @@ gameinfo_t CommercialGameInfo =
{ "mapinfo/doomcommon.txt", "mapinfo/doom2.txt" },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
};
gameinfo_t PlutoniaGameInfo =
@ -420,6 +430,7 @@ gameinfo_t PlutoniaGameInfo =
{ "mapinfo/doomcommon.txt", "mapinfo/plutonia.txt" },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
};
gameinfo_t TNTGameInfo =
@ -452,6 +463,7 @@ gameinfo_t TNTGameInfo =
{ "mapinfo/doomcommon.txt", "mapinfo/tnt.txt" },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
};
gameinfo_t StrifeGameInfo =
@ -484,6 +496,7 @@ gameinfo_t StrifeGameInfo =
{ "mapinfo/strife.txt", NULL },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"AmmoSatchel",
};
gameinfo_t StrifeTeaserGameInfo =
@ -516,6 +529,7 @@ gameinfo_t StrifeTeaserGameInfo =
{ "mapinfo/strife.txt", NULL },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"AmmoSatchel",
};
gameinfo_t StrifeTeaser2GameInfo =
@ -548,4 +562,5 @@ gameinfo_t StrifeTeaser2GameInfo =
{ "mapinfo/strife.txt", NULL },
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"AmmoSatchel",
};

View File

@ -121,6 +121,7 @@ typedef struct
const char *mapinfo[2];
DWORD defaultbloodcolor;
DWORD defaultbloodparticlecolor;
const char *backpacktype;
} gameinfo_t;
extern gameinfo_t gameinfo;

View File

@ -174,16 +174,23 @@ const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInf
int GetSpriteIndex(const char * spritename)
{
// Make sure that the string is upper case and 4 characters long
char upper[5];
for (int i = 0; spritename[i] != 0 && i < 4; i++)
{
upper[i] = toupper (spritename[i]);
}
upper[4] = 0;
for (unsigned i = 0; i < sprites.Size (); ++i)
{
if (strncmp (sprites[i].name, spritename, 4) == 0)
if (strcmp (sprites[i].name, spritename) == 0)
{
return (int)i;
}
}
spritedef_t temp;
strncpy (temp.name, spritename, 4);
temp.name[4] = 0;
strcpy (temp.name, upper);
temp.numframes = 0;
temp.spriteframes = 0;
return (int)sprites.Push (temp);

View File

@ -44,6 +44,7 @@
#include "g_level.h"
#include "d_net.h"
#include "d_dehacked.h"
#include "gi.h"
// [RH] Actually handle the cheat. The cheat code in st_stuff.c now just
// writes some bytes to the network data stream, and the network code
@ -630,26 +631,7 @@ void cht_Give (player_t *player, const char *name, int amount)
if (giveall || stricmp (name, "backpack") == 0)
{
// Select the correct type of backpack based on the game
if (gameinfo.gametype == GAME_Heretic)
{
type = PClass::FindClass ("BagOfHolding");
}
else if (gameinfo.gametype == GAME_Strife)
{
type = PClass::FindClass ("AmmoSatchel");
}
else if (gameinfo.gametype == GAME_Doom)
{
type = PClass::FindClass ("Backpack");
}
else if (gameinfo.gametype == GAME_Chex)
{
type = PClass::FindClass ("Zorchpack");
}
else
{ // Hexen doesn't have a backpack, foo!
type = NULL;
}
type = PClass::FindClass(gameinfo.backpacktype);
if (type != NULL)
{
GiveSpawner (player, type, 1);
@ -874,33 +856,17 @@ void cht_Take (player_t *player, const char *name, int amount)
if (takeall || stricmp (name, "backpack") == 0)
{
// Select the correct type of backpack based on the game
if (gameinfo.gametype == GAME_Heretic)
// Take away all types of backpacks the player might own.
for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i)
{
type = PClass::FindClass ("BagOfHolding");
}
else if (gameinfo.gametype == GAME_Strife)
{
type = PClass::FindClass ("AmmoSatchel");
}
else if (gameinfo.gametype == GAME_Doom)
{
type = PClass::FindClass ("Backpack");
}
else if (gameinfo.gametype == GAME_Chex)
{
type = PClass::FindClass ("Zorchpack");
}
else
{ // Hexen doesn't have a backpack, foo!
type = NULL;
}
if (type != NULL)
{
AActor *backpack = player->mo->FindInventory (type);
const PClass *type = PClass::m_Types[i];
if (backpack)
backpack->Destroy ();
if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem)))
{
AInventory *pack = player->mo->FindInventory (type);
if (pack) pack->Destroy();
}
}
if (!takeall)

View File

@ -596,17 +596,7 @@ static bool FindFreeName (FString &fullname, const char *extension)
for (i = 0; i <= 9999; i++)
{
const char *gamename;
switch (gameinfo.gametype)
{
case GAME_Doom: gamename = "Doom_"; break;
case GAME_Heretic: gamename = "Heretic_"; break;
case GAME_Hexen: gamename = "Hexen_"; break;
case GAME_Strife: gamename = "Strife_"; break;
case GAME_Chex: gamename = "Chex_"; break;
default: gamename = ""; break;
}
const char *gamename = GameNames[gameinfo.gametype];
time_t now;
tm *tm;
@ -616,18 +606,18 @@ static bool FindFreeName (FString &fullname, const char *extension)
if (tm == NULL)
{
lbmname.Format ("%sScreenshot_%s%04d.%s", fullname.GetChars(), gamename, i, extension);
lbmname.Format ("%sScreenshot_%s_%04d.%s", fullname.GetChars(), gamename, i, extension);
}
else if (i == 0)
{
lbmname.Format ("%sScreenshot_%s%04d%02d%02d_%02d%02d%02d.%s", fullname.GetChars(), gamename,
lbmname.Format ("%sScreenshot_%s_%04d%02d%02d_%02d%02d%02d.%s", fullname.GetChars(), gamename,
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
extension);
}
else
{
lbmname.Format ("%sScreenshot_%s%04d%02d%02d_%02d%02d%02d_%02d.%s", fullname.GetChars(), gamename,
lbmname.Format ("%sScreenshot_%s_%04d%02d%02d_%02d%02d%02d_%02d.%s", fullname.GetChars(), gamename,
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
i, extension);

View File

@ -4887,3 +4887,45 @@ void AActor::SetIdle()
if (idle == NULL) idle = SpawnState;
SetState(idle);
}
FDropItem *AActor::GetDropItems()
{
unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1;
if (index >= 0 && index < DropItemList.Size())
{
return DropItemList[index];
}
return NULL;
}
//----------------------------------------------------------------------------
//
// DropItem handling
//
//----------------------------------------------------------------------------
FDropItemPtrArray DropItemList;
void FreeDropItemChain(FDropItem *chain)
{
while (chain != NULL)
{
FDropItem *next = chain->Next;
delete chain;
chain = next;
}
}
FDropItemPtrArray::~FDropItemPtrArray()
{
for (unsigned int i = 0; i < Size(); ++i)
{
FreeDropItemChain ((*this)[i]);
}
}
int StoreDropItemChain(FDropItem *chain)
{
return DropItemList.Push (chain) + 1;
}

View File

@ -80,47 +80,15 @@ void P_SpawnTeleportFog(fixed_t x, fixed_t y, fixed_t z, int spawnid)
{
fog = SpawnableThings[spawnid];
}
/* if (fog != NULL && level.info->teleportfog != NAME_None)
{
fog = PClass::FindClass(level.info->teleportfog);
}
*/
if (fog == NULL)
{
AActor *mo = Spawn ("TeleportFog", x, y, z + TELEFOGHEIGHT, ALLOW_REPLACE);
if (mo != NULL)
{
FState * state = NULL;
switch(gameinfo.gametype)
{
default:
case GAME_Doom:
state = mo->FindState(NAME_Doom);
break;
case GAME_Heretic:
state = mo->FindState(NAME_Heretic);
break;
case GAME_Hexen:
state = mo->FindState(NAME_Hexen);
break;
case GAME_Strife:
state = mo->FindState(NAME_Strife);
break;
}
if (state == NULL) state = mo->SpawnState; // allow execution of code pointers in the spawn state
mo->SetState(state);
}
}
else
{
AActor *mo = Spawn (fog, x, y, z, ALLOW_REPLACE);
if (mo != NULL) mo->SetState(mo->SpawnState);
if (mo != NULL) S_Sound(mo, CHAN_BODY, mo->SeeSound, 1.f, ATTN_NORM);
}
}

View File

@ -1124,6 +1124,7 @@ struct UDMFParser
{
default: // Shh, GCC
case GAME_Doom:
case GAME_Chex:
namespace_bits = Dm;
P_LoadTranslator("xlat/doom_base.txt");
break;

View File

@ -982,7 +982,7 @@ void APlayerPawn::GiveDefaultInventory ()
AddInventory (barmor);
// Now add the items from the DECORATE definition
FDropItem *di = GetDropItems(RUNTIME_TYPE(this));
FDropItem *di = GetDropItems();
while (di)
{

View File

@ -43,6 +43,9 @@
#include "colormatcher.h"
#include "d_netinf.h"
#include "v_palette.h"
#include "sc_man.h"
#include "doomerrors.h"
#include "i_system.h"
#include "gi.h"
#include "stats.h"
@ -82,11 +85,23 @@ FRemapTable::FRemapTable(int count)
// the caller will do that next, if only by calling MakeIdentity().
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
FRemapTable::~FRemapTable()
{
Free();
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::Alloc(int count)
{
Remap = (BYTE *)M_Malloc(count*sizeof(*Remap) + count*sizeof(*Palette));
@ -96,6 +111,12 @@ void FRemapTable::Alloc(int count)
NumEntries = count;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::Free()
{
KillNative();
@ -108,6 +129,12 @@ void FRemapTable::Free()
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
FRemapTable::FRemapTable(const FRemapTable &o)
{
Remap = NULL;
@ -116,6 +143,12 @@ FRemapTable::FRemapTable(const FRemapTable &o)
operator= (o);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
FRemapTable &FRemapTable::operator=(const FRemapTable &o)
{
if (&o == this)
@ -134,6 +167,12 @@ FRemapTable &FRemapTable::operator=(const FRemapTable &o)
return *this;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
bool FRemapTable::operator==(const FRemapTable &o)
{
// Two translations are identical when they have the same amount of colors
@ -143,6 +182,12 @@ bool FRemapTable::operator==(const FRemapTable &o)
return !memcmp(o.Palette, Palette, NumEntries * sizeof(*Palette));
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::Serialize(FArchive &arc)
{
int n = NumEntries;
@ -167,6 +212,11 @@ void FRemapTable::Serialize(FArchive &arc)
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::MakeIdentity()
{
@ -186,6 +236,12 @@ void FRemapTable::MakeIdentity()
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
bool FRemapTable::IsIdentity() const
{
for (int j = 0; j < 256; ++j)
@ -198,6 +254,12 @@ bool FRemapTable::IsIdentity() const
return true;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::KillNative()
{
if (Native != NULL)
@ -207,6 +269,12 @@ void FRemapTable::KillNative()
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::UpdateNative()
{
if (Native != NULL)
@ -215,6 +283,12 @@ void FRemapTable::UpdateNative()
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
FNativePalette *FRemapTable::GetNative()
{
if (Native == NULL)
@ -224,6 +298,12 @@ FNativePalette *FRemapTable::GetNative()
return Native;
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2)
{
fixed_t palcol, palstep;
@ -250,6 +330,12 @@ void FRemapTable::AddIndexRange(int start, int end, int pal1, int pal2)
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, int _r2, int _g2, int _b2)
{
fixed_t r1 = _r1 << FRACBITS;
@ -304,6 +390,160 @@ void FRemapTable::AddColorRange(int start, int end, int _r1,int _g1, int _b1, in
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::AddToTranslation(const char * range)
{
int start,end;
FScanner sc;
sc.OpenMem("translation", range, int(strlen(range)));
sc.SetCMode(true);
try
{
sc.MustGetToken(TK_IntConst);
start = sc.Number;
sc.MustGetToken(':');
sc.MustGetToken(TK_IntConst);
end = sc.Number;
sc.MustGetToken('=');
if (!sc.CheckToken('['))
{
int pal1,pal2;
sc.MustGetToken(TK_IntConst);
pal1 = sc.Number;
sc.MustGetToken(':');
sc.MustGetToken(TK_IntConst);
pal2 = sc.Number;
AddIndexRange(start, end, pal1, pal2);
}
else
{
// translation using RGB values
int r1,g1,b1,r2,g2,b2;
sc.MustGetToken(TK_IntConst);
r1 = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
g1 = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
b1 = sc.Number;
sc.MustGetToken(']');
sc.MustGetToken(':');
sc.MustGetToken('[');
sc.MustGetToken(TK_IntConst);
r2 = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
g2 = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
b2 = sc.Number;
sc.MustGetToken(']');
AddColorRange(start, end, r1, g1, b1, r2, g2, b2);
}
}
catch (CRecoverableError &err)
{
Printf("Error in translation '%s':\n%s\n", err.GetMessage());
}
}
//----------------------------------------------------------------------------
//
// Stores a copy of this translation in the DECORATE translation table
//
//----------------------------------------------------------------------------
int FRemapTable::StoreTranslation()
{
unsigned int i;
for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++)
{
if (*this == *translationtables[TRANSLATION_Decorate][i])
{
// A duplicate of this translation already exists
return TRANSLATION(TRANSLATION_Decorate, i);
}
}
if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS)
{
I_Error("Too many DECORATE translations");
}
FRemapTable *newtrans = new FRemapTable;
*newtrans = *this;
i = translationtables[TRANSLATION_Decorate].Push(newtrans);
return TRANSLATION(TRANSLATION_Decorate, i);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
TArray<PalEntry> BloodTranslationColors;
int CreateBloodTranslation(PalEntry color)
{
unsigned int i;
if (BloodTranslationColors.Size() == 0)
{
// Don't use the first slot.
translationtables[TRANSLATION_Blood].Push(NULL);
BloodTranslationColors.Push(0);
}
for (i = 1; i < BloodTranslationColors.Size(); i++)
{
if (color.r == BloodTranslationColors[i].r &&
color.g == BloodTranslationColors[i].g &&
color.b == BloodTranslationColors[i].b)
{
// A duplicate of this translation already exists
return i;
}
}
if (BloodTranslationColors.Size() >= MAX_DECORATE_TRANSLATIONS)
{
I_Error("Too many blood colors");
}
FRemapTable *trans = new FRemapTable;
for (i = 0; i < 256; i++)
{
int bright = MAX(MAX(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b);
PalEntry pe = PalEntry(color.r*bright/255, color.g*bright/255, color.b*bright/255);
int entry = ColorMatcher.Pick(pe.r, pe.g, pe.b);
trans->Palette[i] = pe;
trans->Remap[i] = entry;
}
translationtables[TRANSLATION_Blood].Push(trans);
return BloodTranslationColors.Push(color);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
FRemapTable *TranslationToTable(int translation)
{
@ -323,6 +563,12 @@ FRemapTable *TranslationToTable(int translation)
return slots->operator[](index);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static void PushIdentityTable(int slot)
{
FRemapTable *table = new FRemapTable;
@ -330,11 +576,14 @@ static void PushIdentityTable(int slot)
translationtables[slot].Push(table);
}
//----------------------------------------------------------------------------
//
// R_InitTranslationTables
// Creates the translation tables to map the green color ramp to gray,
// brown, red. Assumes a given structure of the PLAYPAL.
//
//----------------------------------------------------------------------------
void R_InitTranslationTables ()
{
int i, j;
@ -508,6 +757,12 @@ void R_InitTranslationTables ()
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void R_DeinitTranslationTables()
{
for (int i = 0; i < NUM_TRANSLATION_TABLES; ++i)
@ -523,8 +778,13 @@ void R_DeinitTranslationTables()
}
}
//----------------------------------------------------------------------------
//
// [RH] Create a player's translation table based on a given mid-range color.
// [GRB] Split to 2 functions (because of player setup menu)
//
//----------------------------------------------------------------------------
static void SetRemap(FRemapTable *table, int i, float r, float g, float b)
{
int ir = clamp (int(r * 255.f), 0, 255);
@ -534,6 +794,12 @@ static void SetRemap(FRemapTable *table, int i, float r, float g, float b)
table->Palette[i] = PalEntry(255, ir, ig, ib);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable)
{
int i;
@ -675,6 +941,12 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s
table->UpdateNative();
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void R_BuildPlayerTranslation (int player)
{
float h, s, v;
@ -687,6 +959,12 @@ void R_BuildPlayerTranslation (int player)
translationtables[TRANSLATION_PlayersExtra][player]);
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table)
{
float h, s, v;
@ -696,3 +974,4 @@ void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table)
R_CreatePlayerTranslation (h, s, v, skin, table, NULL);
}

View File

@ -38,6 +38,8 @@ struct FRemapTable
void Serialize(FArchive &ar);
void AddIndexRange(int start, int end, int pal1, int pal2);
void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2);
void AddToTranslation(const char * range);
int StoreTranslation();
BYTE *Remap; // For the software renderer
PalEntry *Palette; // The ideal palette this maps to
@ -99,6 +101,10 @@ void R_BuildPlayerTranslation (int player);
extern const BYTE IcePalette[16][3];
extern TArray<PalEntry> BloodTranslationColors;
int CreateBloodTranslation(PalEntry color);
#endif // __R_TRANSLATE_H

View File

@ -192,7 +192,7 @@ void FScanner::OpenFile (const char *name)
//
//==========================================================================
void FScanner::OpenMem (const char *name, char *buffer, int size)
void FScanner::OpenMem (const char *name, const char *buffer, int size)
{
Close ();
ScriptBuffer = FString(buffer, size);

View File

@ -20,7 +20,7 @@ public:
void Open(const char *lumpname);
void OpenFile(const char *filename);
void OpenMem(const char *name, char *buffer, int size);
void OpenMem(const char *name, const char *buffer, int size);
void OpenLumpNum(int lump);
void Close();

View File

@ -123,97 +123,6 @@ static const char *RenderStyles[] =
NULL
};
static const char *FlagNames1[] =
{
"*",
"Solid",
"*",
"NoSector",
"NoBlockmap",
"*",
"*",
"*",
"SpawnCeiling",
"NoGravity",
"*",
"*",
"*",
"*",
"*",
"*",
"*",
"*",
"Shadow",
"NoBlood",
"*",
"*",
"*",
"CountItem",
NULL
};
static const char *FlagNames2[] =
{
"LowGravity",
"WindThrust",
"*",
"*",
"*",
"FloorClip",
"SpawnFloat",
"NoTeleport",
"Ripper",
"Pushable",
"SlidesOnWalls",
"*",
"CanPass",
"CannotPush",
"ThruGhost",
"*",
"FireDamage",
"NoDamageThrust",
"Telestomp",
"FloatBob",
"*",
"ActivateImpact",
"CanPushWalls",
"ActivateMCross",
"ActivatePCross",
"*",
"*",
"*",
"*",
"*",
"*",
"Reflective",
NULL
};
static const char *FlagNames3[] =
{
"FloorHugger",
"CeilingHugger",
"*",
"*",
"*",
"*",
"DontSplash",
NULL
};
// CODE --------------------------------------------------------------------
//==========================================================================
@ -243,65 +152,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
info->GameFilter = 0x80;
MakeStateDefines(parent->ActorInfo->StateList);
// There isn't a single WAD out there which uses game filters with old style
// decorations so this may as well be disabled. Without this option is is much
// easier to detect incorrect declarations
#if 0
sc.MustGetString ();
while (!sc.Compare ("{"))
{
if (sc.Compare ("Doom"))
{
info->GameFilter |= GAME_Doom;
}
else if (sc.Compare ("Heretic"))
{
info->GameFilter |= GAME_Heretic;
}
else if (sc.Compare ("Hexen"))
{
info->GameFilter |= GAME_Hexen;
}
else if (sc.Compare ("Raven"))
{
info->GameFilter |= GAME_Raven;
}
else if (sc.Compare ("Strife"))
{
info->GameFilter |= GAME_Strife;
}
else if (sc.Compare ("Any"))
{
info->GameFilter = GAME_Any;
}
else
{
if (def != DEF_Decoration || info->GameFilter != 0x80)
{
sc.ScriptError ("Unknown game type %s in %s", sc.String, typeName.GetChars());
}
else
{
// If this is a regular decoration (without preceding keyword) and no game
// filters defined this is more likely a general syntax error so output a
// more meaningful message.
sc.ScriptError ("Syntax error: Unknown identifier '%s'", typeName.GetChars());
}
}
sc.MustGetString ();
}
if (info->GameFilter == 0x80)
{
info->GameFilter = GAME_Any;
}
else
{
info->GameFilter &= ~0x80;
}
#else
info->GameFilter = GAME_Any;
sc.MustGetStringName("{");
#endif
states.Clear ();
memset (&extra, 0, sizeof(extra));
@ -724,23 +576,9 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
}
else if (sc.String[0] != '*')
{
int bit = sc.MatchString (FlagNames1);
if (bit != -1)
{
defaults->flags |= 1 << bit;
}
else if ((bit = sc.MatchString (FlagNames2)) != -1)
{
defaults->flags2 |= 1 << bit;
}
else if ((bit = sc.MatchString (FlagNames3)) != -1)
{
defaults->flags3 |= 1 << bit;
}
else
{
sc.ScriptError (NULL);
}
Baggage bag;
bag.Info = info;
HandleActorFlag(sc, bag, sc.String, NULL, '+');
}
else
{

View File

@ -68,82 +68,6 @@
const PClass *QuestItemClasses[31];
//==========================================================================
//
// ActorConstDef
//
// Parses a constant definition.
//
//==========================================================================
void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls)
{
// Read the type and make sure it's int.
// (Maybe there will be other types later.)
sc.MustGetToken(TK_Int);
sc.MustGetToken(TK_Identifier);
FName symname = sc.String;
sc.MustGetToken('=');
int expr = ParseExpression (sc, false, cls);
sc.MustGetToken(';');
int val = EvalExpressionI (expr, NULL, cls);
PSymbolConst *sym = new PSymbolConst;
sym->SymbolName = symname;
sym->SymbolType = SYM_Const;
sym->Value = val;
if (symt->AddSymbol (sym) == NULL)
{
delete sym;
sc.ScriptError ("'%s' is already defined in class '%s'.",
symname.GetChars(), cls->TypeName.GetChars());
}
}
//==========================================================================
//
// ActorEnumDef
//
// Parses an enum definition.
//
//==========================================================================
void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls)
{
int currvalue = 0;
sc.MustGetToken('{');
while (!sc.CheckToken('}'))
{
sc.MustGetToken(TK_Identifier);
FName symname = sc.String;
if (sc.CheckToken('='))
{
int expr = ParseExpression(sc, false, cls);
currvalue = EvalExpressionI(expr, NULL, cls);
}
PSymbolConst *sym = new PSymbolConst;
sym->SymbolName = symname;
sym->SymbolType = SYM_Const;
sym->Value = currvalue;
if (symt->AddSymbol (sym) == NULL)
{
delete sym;
sc.ScriptError ("'%s' is already defined in class '%s'.",
symname.GetChars(), cls->TypeName.GetChars());
}
// This allows a comma after the last value but doesn't enforce it.
if (sc.CheckToken('}')) break;
sc.MustGetToken(',');
currvalue++;
}
sc.MustGetToken(';');
}
//==========================================================================
//
// ParseParameter
@ -560,6 +484,7 @@ static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *b
ResetBaggage (bag);
bag->Info = info;
bag->Lumpnum = sc.LumpNum;
info->DoomEdNum = -1;
if (parent->ActorInfo->DamageFactors != NULL)

View File

@ -5,6 +5,24 @@
class FScanner;
//==========================================================================
//
// A flag descriptor
//
//==========================================================================
struct FFlagDef
{
int flagbit;
const char *name;
int structoffset;
};
FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2);
void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index);
//==========================================================================
//
// This class is for storing a name inside a const PClass* field without
@ -30,27 +48,12 @@ public:
};
//==========================================================================
//
// Dropitem list
//
//==========================================================================
struct FDropItem
{
FName Name;
int probability;
int amount;
FDropItem * Next;
};
FDropItem *GetDropItems(const PClass * cls);
//==========================================================================
//
// Extra info maintained while defining an actor.
//
//==========================================================================
struct FDropItem;
struct Baggage
{
@ -58,6 +61,7 @@ struct Baggage
bool DropItemSet;
bool StateSet;
int CurrentState;
int Lumpnum;
FDropItem *DropItemList;
};
@ -70,7 +74,6 @@ inline void ResetBaggage (Baggage *bag)
bag->StateSet = false;
}
//==========================================================================
//
// Action function lookup
@ -115,6 +118,7 @@ FState *CheckState(FScanner &sc, PClass *type);
//==========================================================================
void ParseActorProperty(FScanner &sc, Baggage &bag);
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod);
void ParseActorFlag (FScanner &sc, Baggage &bag, int mod);
void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag);
@ -156,20 +160,91 @@ enum EDefinitionType
#if defined(_MSC_VER)
#pragma data_seg(".areg$u")
#pragma data_seg(".greg$u")
#pragma data_seg()
#define MSVC_ASEG __declspec(allocate(".areg$u"))
#define GCC_ASEG
#define MSVC_PSEG __declspec(allocate(".greg$u"))
#define GCC_PSEG
#else
#define MSVC_ASEG
#define GCC_ASEG __attribute__((section(AREG_SECTION)))
#define MSVC_PSEG
#define GCC_PSEG __attribute__((section(GREG_SECTION)))
#endif
union FPropParam
{
int i;
float f;
const char *s;
};
typedef void (*PropHandler)(AActor *defaults, Baggage &bag, FPropParam *params);
enum ECategory
{
CAT_PROPERTY, // Inheritable property
CAT_INFO // non-inheritable info (spawn ID, Doomednum, game filter, conversation ID)
};
struct FPropertyInfo
{
const char *name;
const char *params;
const PClass *cls;
PropHandler Handler;
int category;
};
FPropertyInfo *FindProperty(const char * string);
int MatchString (const char *in, const char **strings);
#define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \
static FPropertyInfo Prop_####name##_##paramlist##_##clas = \
{ #name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_####name##_##paramlist##_##clas; \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params)
#define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \
static FPropertyInfo Prop_####name##_##paramlist##_##clas = \
{ #prefix"."#name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_####name##_##paramlist##_##clas; \
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params)
#define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY)
#define DEFINE_INFO_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_INFO)
#define DEFINE_CLASS_PROPERTY(name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(clas, name, paramlist, clas, CAT_PROPERTY)
#define DEFINE_CLASS_PROPERTY_PREFIX(prefix, name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, CAT_PROPERTY)
#define PROP_PARM_COUNT (params[0].i)
#define PROP_STRING_PARM(var, no) \
const char *var = params[(no)+1].s;
#define PROP_INT_PARM(var, no) \
int var = params[(no)+1].i;
#define PROP_FLOAT_PARM(var, no) \
float var = params[(no)+1].f;
#define PROP_FIXED_PARM(var, no) \
fixed_t var = fixed_t(params[(no)+1].f * FRACUNIT);
#define PROP_COLOR_PARM(var, no) \
int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s);
struct StateCallData
{
FState * State;
AActor * Item;
FState *State;
AActor *Item;
bool Result;
};

View File

@ -2236,3 +2236,49 @@ DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter)
AWeapon *weapon = self->player->ReadyWeapon;
weapon->ReloadCounter = 0;
}
//===========================================================================
//
// A_ChangeFlag
//
//===========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag)
{
ACTION_PARAM_START(2);
ACTION_PARAM_STRING(flagname, 0);
ACTION_PARAM_BOOL(expression, 1);
const char *dot = strchr (flagname, '.');
FFlagDef *fd;
const PClass *cls = self->GetClass();
if (dot != NULL)
{
FString part1(flagname, dot-flagname);
fd = FindFlag (cls, part1, dot+1);
}
else
{
fd = FindFlag (cls, flagname, NULL);
}
if (fd != NULL)
{
if (fd->structoffset == -1)
{
HandleDeprecatedFlags(self, cls->ActorInfo, expression, fd->flagbit);
}
else
{
int * flagp = (int*) (((char*)self) + fd->structoffset);
if (expression) *flagp |= fd->flagbit;
else *flagp &= ~fd->flagbit;
}
}
else
{
Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars());
}
}

View File

@ -47,9 +47,6 @@
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void ParseActor(FScanner &sc);
void ParseClass(FScanner &sc);
void ParseGlobalConst(FScanner &sc);
void ParseGlobalEnum(FScanner &sc);
void FinishThingdef();
void ParseOldDecoration(FScanner &sc, EDefinitionType def);

View File

@ -0,0 +1,550 @@
/*
** thingdef-parse.cpp
**
** Actor definitions - all parser related code
**
**---------------------------------------------------------------------------
** Copyright 2002-2007 Christoph Oelckers
** Copyright 2004-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
** covered by the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or (at
** your option) any later version.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "doomtype.h"
#include "actor.h"
#include "a_pickups.h"
#include "sc_man.h"
#include "thingdef.h"
#include "a_morph.h"
#include "cmdlib.h"
#include "templates.h"
#include "v_palette.h"
#include "doomerrors.h"
#include "autosegs.h"
//==========================================================================
//
// ActorConstDef
//
// Parses a constant definition.
//
//==========================================================================
void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls)
{
// Read the type and make sure it's int.
// (Maybe there will be other types later.)
sc.MustGetToken(TK_Int);
sc.MustGetToken(TK_Identifier);
FName symname = sc.String;
sc.MustGetToken('=');
int expr = ParseExpression (sc, false, cls);
sc.MustGetToken(';');
int val = EvalExpressionI (expr, NULL, cls);
PSymbolConst *sym = new PSymbolConst;
sym->SymbolName = symname;
sym->SymbolType = SYM_Const;
sym->Value = val;
if (symt->AddSymbol (sym) == NULL)
{
delete sym;
sc.ScriptError ("'%s' is already defined in class '%s'.",
symname.GetChars(), cls->TypeName.GetChars());
}
}
//==========================================================================
//
// ActorEnumDef
//
// Parses an enum definition.
//
//==========================================================================
void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls)
{
int currvalue = 0;
sc.MustGetToken('{');
while (!sc.CheckToken('}'))
{
sc.MustGetToken(TK_Identifier);
FName symname = sc.String;
if (sc.CheckToken('='))
{
int expr = ParseExpression(sc, false, cls);
currvalue = EvalExpressionI(expr, NULL, cls);
}
PSymbolConst *sym = new PSymbolConst;
sym->SymbolName = symname;
sym->SymbolType = SYM_Const;
sym->Value = currvalue;
if (symt->AddSymbol (sym) == NULL)
{
delete sym;
sc.ScriptError ("'%s' is already defined in class '%s'.",
symname.GetChars(), cls->TypeName.GetChars());
}
// This allows a comma after the last value but doesn't enforce it.
if (sc.CheckToken('}')) break;
sc.MustGetToken(',');
currvalue++;
}
sc.MustGetToken(';');
}
//==========================================================================
//
// Parses a flag name
//
//==========================================================================
void ParseActorFlag (FScanner &sc, Baggage &bag, int mod)
{
sc.MustGetString ();
FString part1 = sc.String;
const char *part2 = NULL;
if (sc.CheckString ("."))
{
sc.MustGetString ();
part2 = sc.String;
}
HandleActorFlag(sc, bag, part1, part2, mod);
}
//==========================================================================
//
// Processes a flag. Also used by olddecorations.cpp
//
//==========================================================================
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod)
{
FFlagDef *fd;
if ( (fd = FindFlag (bag.Info->Class, part1, part2)) )
{
AActor *defaults = (AActor*)bag.Info->Class->Defaults;
if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property
{
HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit);
}
else
{
DWORD * flagvar = (DWORD*) ((char*)defaults + fd->structoffset);
if (mod == '+')
{
*flagvar |= fd->flagbit;
}
else
{
*flagvar &= ~fd->flagbit;
}
}
}
else
{
if (part2 == NULL)
{
sc.ScriptError("\"%s\" is an unknown flag\n", part1);
}
else
{
sc.ScriptError("\"%s.%s\" is an unknown flag\n", part1, part2);
}
}
}
//==========================================================================
//
// [MH] parses a morph style expression
//
//==========================================================================
static int ParseMorphStyle (FScanner &sc)
{
static const char * morphstyles[]={
"MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE",
"MRF_FAILNOTELEFRAG", "MRF_FAILNOLAUGH", "MRF_WHENINVULNERABLE", "MRF_LOSEACTUALWEAPON",
"MRF_NEWTIDBEHAVIOUR", "MRF_UNDOBYDEATH", "MRF_UNDOBYDEATHFORCED", "MRF_UNDOBYDEATHSAVES", NULL};
static const int morphstyle_values[]={
MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE,
MORPH_FAILNOTELEFRAG, MORPH_FAILNOLAUGH, MORPH_WHENINVULNERABLE, MORPH_LOSEACTUALWEAPON,
MORPH_NEWTIDBEHAVIOUR, MORPH_UNDOBYDEATH, MORPH_UNDOBYDEATHFORCED, MORPH_UNDOBYDEATHSAVES};
// May be given flags by number...
if (sc.CheckNumber())
{
sc.MustGetNumber();
return sc.Number;
}
// ... else should be flags by name.
// NOTE: Later this should be removed and a normal expression used.
// The current DECORATE parser can't handle this though.
bool gotparen = sc.CheckString("(");
int style = 0;
do
{
sc.MustGetString();
style |= morphstyle_values[sc.MustMatchString(morphstyles)];
}
while (sc.CheckString("|"));
if (gotparen)
{
sc.MustGetStringName(")");
}
return style;
}
//==========================================================================
//
// For getting a state address from the parent
// No attempts have been made to add new functionality here
// This is strictly for keeping compatibility with old WADs!
//
//==========================================================================
FState *CheckState(FScanner &sc, PClass *type)
{
int v=0;
if (sc.GetString() && !sc.Crossed)
{
if (sc.Compare("0")) return NULL;
else if (sc.Compare("PARENT"))
{
FState * state = NULL;
sc.MustGetString();
FActorInfo * info = type->ParentClass->ActorInfo;
if (info != NULL)
{
state = info->FindState(FName(sc.String));
}
if (sc.GetString ())
{
if (sc.Compare ("+"))
{
sc.MustGetNumber ();
v = sc.Number;
}
else
{
sc.UnGet ();
}
}
if (state == NULL && v==0) return NULL;
if (v!=0 && state==NULL)
{
sc.ScriptError("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars());
return NULL;
}
state+=v;
return state;
}
else sc.ScriptError("Invalid state assignment");
}
return NULL;
}
//==========================================================================
//
// Parses an actor property's parameters and calls the handler
//
//==========================================================================
bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defaults, Baggage &bag)
{
static TArray<FPropParam> params;
static TArray<FString> strings;
params.Clear();
strings.Clear();
params.Reserve(1);
params[0].i = 0;
if (prop->params[0] != '0')
{
const char * p = prop->params;
bool nocomma;
bool optcomma;
while (*p)
{
FPropParam conv;
FPropParam pref;
nocomma = false;
conv.s = NULL;
pref.i = -1;
switch ((*p) & 223)
{
case 'X': // Expression in parentheses or number.
if (sc.CheckString ("("))
{
conv.i = 0x40000000 | ParseExpression (sc, false, bag.Info->Class);
params.Push(conv);
sc.MustGetStringName(")");
break;
}
// fall through
case 'I':
sc.MustGetNumber();
conv.i = sc.Number;
break;
case 'F':
sc.MustGetFloat();
conv.f = sc.Float;
break;
case 'Z': // an optional string. Does not allow any numerical value.
if (sc.CheckFloat())
{
nocomma = true;
sc.UnGet();
break;
}
// fall through
case 'S':
case 'T':
sc.MustGetString();
conv.s = strings[strings.Reserve(1)] = sc.String;
break;
case 'C':
if (sc.CheckNumber ())
{
int R, G, B;
R = clamp (sc.Number, 0, 255);
sc.CheckString (",");
sc.MustGetNumber ();
G = clamp (sc.Number, 0, 255);
sc.CheckString (",");
sc.MustGetNumber ();
B = clamp (sc.Number, 0, 255);
conv.i = MAKERGB(R, G, B);
pref.i = 0;
}
else
{
sc.MustGetString ();
conv.s = strings[strings.Reserve(1)] = sc.String;
pref.i = 1;
}
break;
case 'M': // special case. An expression-aware parser will not need this.
conv.i = ParseMorphStyle(sc);
break;
case 'L': // Either a number or a list of strings
if (sc.CheckNumber())
{
pref.i = 0;
conv.i = sc.Number;
}
else
{
pref.i = 1;
params.Push(pref);
params[0].i++;
do
{
sc.MustGetString ();
conv.s = strings[strings.Reserve(1)] = sc.String;
params.Push(conv);
params[0].i++;
}
while (sc.CheckString(","));
goto endofparm;
}
break;
default:
assert(false);
break;
}
if (pref.i != -1)
{
params.Push(pref);
params[0].i++;
}
params.Push(conv);
params[0].i++;
endofparm:
p++;
// Hack for some properties that have to allow comma less
// parameter lists for compatibility.
if ((optcomma = (*p == '_')))
p++;
if (nocomma)
{
continue;
}
else if (*p == 0)
{
break;
}
else if (*p >= 'a')
{
if (!sc.CheckString(","))
{
if (optcomma)
{
if (!sc.CheckFloat()) break;
else sc.UnGet();
}
else break;
}
}
else
{
if (!optcomma) sc.MustGetStringName(",");
else sc.CheckString(",");
}
}
}
// call the handler
try
{
prop->Handler(defaults, bag, &params[0]);
}
catch (CRecoverableError &error)
{
sc.ScriptError("%s", error.GetMessage());
}
return true;
}
//==========================================================================
//
// Parses an actor property
//
//==========================================================================
void ParseActorProperty(FScanner &sc, Baggage &bag)
{
static const char *statenames[] = {
"Spawn", "See", "Melee", "Missile", "Pain", "Death", "XDeath", "Burn",
"Ice", "Raise", "Crash", "Crush", "Wound", "Disintegrate", "Heal", NULL };
strlwr (sc.String);
FString propname = sc.String;
if (sc.CheckString ("."))
{
sc.MustGetString ();
propname += '.';
strlwr (sc.String);
propname += sc.String;
}
else
{
sc.UnGet ();
}
FPropertyInfo *prop = FindProperty(propname);
if (prop != NULL)
{
if (bag.Info->Class->IsDescendantOf(prop->cls))
{
ParsePropertyParams(sc, prop, (AActor *)bag.Info->Class->Defaults, bag);
}
else
{
sc.ScriptError("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->cls->TypeName.GetChars());
}
}
else if (!propname.CompareNoCase("States"))
{
if (!bag.StateSet) ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag);
else sc.ScriptError("Multiple state declarations not allowed");
bag.StateSet=true;
}
else if (MatchString(propname, statenames) != -1)
{
AddState(propname, CheckState (sc, bag.Info->Class));
}
else
{
sc.ScriptError("\"%s\" is an unknown actor property\n", propname.GetChars());
}
}
//==========================================================================
//
// Finalizes an actor definition
//
//==========================================================================
void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag)
{
AActor *defaults = (AActor*)info->Class->Defaults;
FinishStates (sc, info, defaults, bag);
InstallStates (info, defaults);
if (bag.DropItemSet)
{
if (bag.DropItemList == NULL)
{
if (info->Class->Meta.GetMetaInt (ACMETA_DropItems) != 0)
{
info->Class->Meta.SetMetaInt (ACMETA_DropItems, 0);
}
}
else
{
info->Class->Meta.SetMetaInt (ACMETA_DropItems,
StoreDropItemChain(bag.DropItemList));
}
}
if (info->Class->IsDescendantOf (RUNTIME_CLASS(AInventory)))
{
defaults->flags |= MF_SPECIAL;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -998,57 +998,3 @@ int FinishStates (FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &ba
return count;
}
//==========================================================================
//
// For getting a state address from the parent
// No attempts have been made to add new functionality here
// This is strictly for keeping compatibility with old WADs!
//
//==========================================================================
FState *CheckState(FScanner &sc, PClass *type)
{
int v=0;
if (sc.GetString() && !sc.Crossed)
{
if (sc.Compare("0")) return NULL;
else if (sc.Compare("PARENT"))
{
FState * state = NULL;
sc.MustGetString();
FActorInfo * info = type->ParentClass->ActorInfo;
if (info != NULL)
{
state = info->FindState(FName(sc.String));
}
if (sc.GetString ())
{
if (sc.Compare ("+"))
{
sc.MustGetNumber ();
v = sc.Number;
}
else
{
sc.UnGet ();
}
}
if (state == NULL && v==0) return NULL;
if (v!=0 && state==NULL)
{
sc.ScriptError("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars());
return NULL;
}
state+=v;
return state;
}
else sc.ScriptError("Invalid state assignment");
}
return NULL;
}

View File

@ -763,7 +763,7 @@ void WI_drawLF ()
{
int y = WI_TITLEY;
FTexture * tex = wbs->lname0[0]? TexMan[wbs->lname0] : NULL;
FTexture * tex = wbs->LName0;
// draw <LevelName>
if (tex)
@ -825,7 +825,7 @@ void WI_drawEL ()
}
// draw <LevelName>
FTexture * tex = wbs->lname1[0]? TexMan[wbs->lname1] : NULL;
FTexture * tex = wbs->LName1;
if (tex)
{
screen->DrawTexture(tex, (SCREENWIDTH - tex->GetWidth() * CleanXfac) / 2, y * CleanYfac, DTA_CleanNoMove, true, TAG_DONE);

View File

@ -24,6 +24,8 @@
#include "doomdef.h"
class FTexture;
//
// INTERMISSION
// Structure passed e.g. to WI_Start(wb)
@ -50,8 +52,8 @@ struct wbstartstruct_t
FString current; // [RH] Name of map just finished
FString next; // next level, [RH] actual map name
FString lname0;
FString lname1;
FTexture *LName0;
FTexture *LName1;
int maxkills;
int maxitems;

View File

@ -28,3 +28,17 @@ const int LOF_NOSOUNDCHECK = 2;
const int LOF_DONTCHASEGOAL = 4;
const int LOF_NOSEESOUND = 8;
const int LOF_FULLVOLSEESOUND = 16;
// Morph constants
const int MRF_ADDSTAMINA = 1;
const int MRF_FULLHEALTH = 2;
const int MRF_UNDOBYTOMEOFPOWER = 4;
const int MRF_UNDOBYCHAOSDEVICE = 8;
const int MRF_FAILNOTELEFRAG = 16;
const int MRF_FAILNOLAUGH = 32;
const int MRF_WHENINVULNERABLE = 64;
const int MRF_LOSEACTUALWEAPON = 128;
const int MRF_NEWTIDBEHAVIOUR = 256;
const int MRF_UNDOBYDEATH = 512;
const int MRF_UNDOBYDEATHFORCED = 1024;
const int MRF_UNDOBYDEATHSAVES = 2048;

View File

@ -65,7 +65,7 @@ ACTOR LavaSmoke
+NOGRAVITY
+DONTSPLASH
RenderStyle Translucent
Alpha Default
DefaultAlpha
States
{
Spawn:

File diff suppressed because it is too large Load Diff