mirror of
https://github.com/ZDoom/gzdoom-last-svn.git
synced 2025-05-31 01:10:52 +00:00
Update to ZDoom r1246:
- Used the one unused byte in the state structure as a flag to tell what type the NextState parameter is. The code did some rather unsafe checks with it to determine its type. - moved all state related code into a new file: p_states.cpp. - merged all FindState functions. All the different variations are now inlined and call the same function to do the real work. - did some code cleanup and reorganization in thingdef.cpp. - Replaced the translation parser for TEXTURES with FRemapTable::AddToTranslation. - To get the game name the screenshot code might as well use the globally available GameNames array instead of creating its own list. - Moved backpack names for cheat into gameinfo. - Fixed: SNDINFO must be loaded before the textures. However, this required some changes to the MAPINFO parser which tried to access the texture manager to check if the level name patches exist. That check had to be moved to where the intermission screen is set up. - Fixed: 'bloodcolor' ignored the first parameter value when given a list of integers. Please note that this creates an incompatibility between old and new versions so if you want to create something that works with both 2.2.0 and current versions better use the string format version for the color parameter! - Rewrote the DECORATE property parser so that the parser is completely separated from the property handlers. This should allow reuse of all the handler code for a new format if Doomscript requires one. - Fixed: PClass::InitializeActorInfo copied too many bytes if a subclass's defaults were larger than the parent's. - Moved A_ChangeFlag to thingdef_codeptr.cpp. - Moved translation related code from thingdef_properties.cpp to r_translate.cpp and rewrote the translation parser to use FScanner instead of strtol. - replaced DECORATE's 'alpha default' by 'defaultalpha' for consistency. Since this was never used outside zdoom.pk3 it's not critical. - Removed support for game specific pickup messages because the only thing this was ever used for - Raven's invulnerability item - has already been split up into a Heretic and Hexen version. - Fixed: The Timidity config parser always tried to process the note number, even if it wasn't specified. - Fixed: When UpdateJoystickMenu() modifies the menu items for different controllers, the joystick axis selectors need to NULL the d.graycheck field, since this is shared by the axis sensitivity sliders' step values. - Fixed: The crosshair must be initialized after the texture manager because on the fly texture creation for graphics patches is no longer supported. - Fixed a few Linux compile errors. - Changed: Replaced weapons should not be given by generic cheats, only when explicitly giving them. - Changed 'give weapon' cheat so that in single player it only gives weapons belonging to the current game or are placed in a weapon slot to avoid giving the Chex Quest weapons in Doom and vice versa. - Fixed: The texture manager must be the first thing to be initialized because MAPINFO and DECORATE both can reference textures and letting them create their own textures is not safe. git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@181 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
parent
8302107238
commit
9d46cdadbe
67 changed files with 4610 additions and 3412 deletions
|
@ -1,4 +1,80 @@
|
|||
September 22, 2008 (Changes by Graf Zahl)
|
||||
- Used the one unused byte in the state structure as a flag to tell what type
|
||||
the NextState parameter is. The code did some rather unsafe checks with it
|
||||
to determine its type.
|
||||
- moved all state related code into a new file: p_states.cpp.
|
||||
- merged all FindState functions. All the different variations are now inlined
|
||||
and call the same function to do the real work.
|
||||
|
||||
September 21, 2008 (Changes by Graf Zahl)
|
||||
- did some code cleanup and reorganization in thingdef.cpp.
|
||||
- Replaced the translation parser for TEXTURES with FRemapTable::AddToTranslation.
|
||||
- To get the game name the screenshot code might as well use the globally
|
||||
available GameNames array instead of creating its own list.
|
||||
- Moved backpack names for cheat into gameinfo.
|
||||
- Fixed: SNDINFO must be loaded before the textures. However, this required
|
||||
some changes to the MAPINFO parser which tried to access the texture manager
|
||||
to check if the level name patches exist. That check had to be moved to
|
||||
where the intermission screen is set up.
|
||||
- Fixed: 'bloodcolor' ignored the first parameter value when given a list
|
||||
of integers.
|
||||
Please note that this creates an incompatibility between old and new
|
||||
versions so if you want to create something that works with both 2.2.0
|
||||
and current versions better use the string format version for the color
|
||||
parameter!
|
||||
- Rewrote the DECORATE property parser so that the parser is completely
|
||||
separated from the property handlers. This should allow reuse of all
|
||||
the handler code for a new format if Doomscript requires one.
|
||||
- Fixed: PClass::InitializeActorInfo copied too many bytes if a subclass's
|
||||
defaults were larger than the parent's.
|
||||
- Moved A_ChangeFlag to thingdef_codeptr.cpp.
|
||||
- Moved translation related code from thingdef_properties.cpp to r_translate.cpp
|
||||
and rewrote the translation parser to use FScanner instead of strtol.
|
||||
- replaced DECORATE's 'alpha default' by 'defaultalpha' for consistency.
|
||||
Since this was never used outside zdoom.pk3 it's not critical.
|
||||
- Removed support for game specific pickup messages because the only thing
|
||||
this was ever used for - Raven's invulnerability item - has already been
|
||||
split up into a Heretic and Hexen version.
|
||||
|
||||
September 20, 2008
|
||||
- Fixed: The Timidity config parser always tried to process the note number,
|
||||
even if it wasn't specified.
|
||||
|
||||
September 19, 2008
|
||||
- Fixed: When UpdateJoystickMenu() modifies the menu items for different
|
||||
controllers, the joystick axis selectors need to NULL the d.graycheck
|
||||
field, since this is shared by the axis sensitivity sliders' step values.
|
||||
|
||||
September 19, 2008 (Changes by Graf Zahl)
|
||||
- Fixed: The crosshair must be initialized after the texture manager because
|
||||
on the fly texture creation for graphics patches is no longer supported.
|
||||
- Fixed a few Linux compile errors.
|
||||
|
||||
September 16, 2008 (Changes by Graf Zahl)
|
||||
- Changed: Replaced weapons should not be given by generic cheats, only
|
||||
when explicitly giving them.
|
||||
- Changed 'give weapon' cheat so that in single player it only gives weapons
|
||||
belonging to the current game or are placed in a weapon slot to avoid
|
||||
giving the Chex Quest weapons in Doom and vice versa.
|
||||
- Fixed: The texture manager must be the first thing to be initialized
|
||||
because MAPINFO and DECORATE both can reference textures and letting them
|
||||
create their own textures is not safe.
|
||||
|
||||
September 15, 2008 (Changes by Graf Zahl)
|
||||
- Separated low level sound code from all high level dependencies.
|
||||
- Separated low level sound channel class from high level class which now
|
||||
is just a subclass of the low level class.
|
||||
- Moved some more high level sound logic out of FMODSoundRenderer:
|
||||
The rolloff and channel ended callbacks now call functions in s_sound.cpp
|
||||
instead of working on the data itself and GSnd->StopSound has been replaced
|
||||
with S_StopChannel.
|
||||
- Changed compilation for g_doom, g_heretic, g_hexen and g_strife folders so
|
||||
that all files are included by a central one instead of compiling each one
|
||||
separately. This speeds up the compilation process by 25% when doing a
|
||||
complete rebuild in Visual C.
|
||||
|
||||
September 14, 2008 (Changes by Graf Zahl)
|
||||
- Cleaned up some include dependencies.
|
||||
- fixed: For Chex Quest some CVars were initialized to Heretic's default.
|
||||
- fixed pickup message for LargeZorchPack.
|
||||
|
||||
|
|
1357
gzdoom.vcproj
1357
gzdoom.vcproj
File diff suppressed because it is too large
Load diff
|
@ -198,21 +198,21 @@ if( NOT NO_ASM )
|
|||
find_program( NASM_PATH NAMES ${NASM_NAMES} )
|
||||
find_program( YASM_PATH yasm )
|
||||
|
||||
if( YASM_PATH )
|
||||
set( ASSEMBLER ${YASM_PATH} )
|
||||
else( YASM_PATH )
|
||||
if( X64 )
|
||||
if( X64 )
|
||||
if( YASM_PATH )
|
||||
set( ASSEMBLER ${YASM_PATH} )
|
||||
else( YASM_PATH )
|
||||
message( STATUS "Could not find YASM. Disabling assembly code." )
|
||||
set( NO_ASM ON )
|
||||
else( X64 )
|
||||
if( NOT NASM_PATH )
|
||||
message( STATUS "Could not find YASM or NASM. Disabling assembly code." )
|
||||
set( NO_ASM ON )
|
||||
else( NOT NASM_PATH )
|
||||
set( ASSEMBLER ${NASM_PATH} )
|
||||
endif( NOT NASM_PATH )
|
||||
endif( X64 )
|
||||
endif( YASM_PATH )
|
||||
endif( YASM_PATH )
|
||||
else( X64 )
|
||||
if( NASM_PATH )
|
||||
set( ASSEMBLER ${NASM_PATH} )
|
||||
else( NASM_PATH )
|
||||
message( STATUS "Could not find NASM. Disabling assembly code." )
|
||||
set( NO_ASM ON )
|
||||
endif( NASM_PATH )
|
||||
endif( X64 )
|
||||
endif( UNIX AND X64 )
|
||||
|
||||
# I think the only reason there was a version requirement was because the
|
||||
|
@ -397,7 +397,7 @@ else( NO_ASM )
|
|||
endif( X64 )
|
||||
if( WIN32 )
|
||||
if( NOT X64 )
|
||||
ADD_ASM_FILE( win32/wrappers.asm )
|
||||
ADD_ASM_FILE( win32 wrappers )
|
||||
endif( NOT X64 )
|
||||
endif( WIN32 )
|
||||
endif( NO_ASM )
|
||||
|
@ -506,6 +506,7 @@ add_executable( zdoom WIN32
|
|||
p_sight.cpp
|
||||
p_slopes.cpp
|
||||
p_spec.cpp
|
||||
p_states.cpp
|
||||
p_switch.cpp
|
||||
p_teleport.cpp
|
||||
p_terrain.cpp
|
||||
|
@ -685,6 +686,7 @@ add_executable( zdoom WIN32
|
|||
thingdef/thingdef_codeptr.cpp
|
||||
thingdef/thingdef_exp.cpp
|
||||
thingdef/thingdef_main.cpp
|
||||
thingdef/thingdef_parse.cpp
|
||||
thingdef/thingdef_properties.cpp
|
||||
thingdef/thingdef_states.cpp
|
||||
timidity/common.cpp
|
||||
|
|
40
src/actor.h
40
src/actor.h
|
@ -430,6 +430,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
|
||||
{
|
||||
|
@ -451,6 +472,7 @@ public:
|
|||
return (AActor *)(RUNTIME_TYPE(this)->Defaults);
|
||||
}
|
||||
|
||||
FDropItem *GetDropItems();
|
||||
|
||||
// Return true if the monster should use a missile attack, false for melee
|
||||
bool SuggestMissileAttack (fixed_t dist);
|
||||
|
@ -766,14 +788,20 @@ public:
|
|||
bool isFast();
|
||||
void SetIdle();
|
||||
|
||||
FState *FindState (FName label) const;
|
||||
FState *FindState (FName label, FName sublabel, bool exact = false) const;
|
||||
FState *FindState (FName label) const
|
||||
{
|
||||
return GetClass()->ActorInfo->FindState(1, &label);
|
||||
}
|
||||
|
||||
FState *FindState (FName label, FName sublabel, bool exact = false) const
|
||||
{
|
||||
FName names[]={label, sublabel};
|
||||
return GetClass()->ActorInfo->FindState(2, &label, exact);
|
||||
}
|
||||
|
||||
|
||||
bool HasSpecialDeathStates () const;
|
||||
|
||||
static FState States[];
|
||||
|
||||
enum { S_NULL = 2, S_GENERICFREEZEDEATH = 3 };
|
||||
|
||||
TArray<TObjPtr<AActor> > dynamiclights;
|
||||
void * lightassociations;
|
||||
bool hasmodel;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -682,6 +682,7 @@ static int PatchThing (int thingy)
|
|||
bool hadHeight = false;
|
||||
bool hadTranslucency = false;
|
||||
bool hadStyle = false;
|
||||
FStateDefinitions statedef;
|
||||
bool patchedStates = false;
|
||||
int oldflags;
|
||||
const PClass *type;
|
||||
|
@ -813,36 +814,36 @@ static int PatchThing (int thingy)
|
|||
|
||||
if (type != NULL && !patchedStates)
|
||||
{
|
||||
MakeStateDefines(type->ActorInfo->StateList);
|
||||
statedef.MakeStateDefines(type);
|
||||
patchedStates = true;
|
||||
}
|
||||
|
||||
if (!strnicmp (Line1, "Initial", 7))
|
||||
AddState("Spawn", state ? state : GetDefault<AActor>()->SpawnState);
|
||||
statedef.AddState("Spawn", state ? state : GetDefault<AActor>()->SpawnState);
|
||||
else if (!strnicmp (Line1, "First moving", 12))
|
||||
AddState("See", state);
|
||||
statedef.AddState("See", state);
|
||||
else if (!strnicmp (Line1, "Injury", 6))
|
||||
AddState("Pain", state);
|
||||
statedef.AddState("Pain", state);
|
||||
else if (!strnicmp (Line1, "Close attack", 12))
|
||||
{
|
||||
if (thingy != 1) // Not for players!
|
||||
{
|
||||
AddState("Melee", state);
|
||||
statedef.AddState("Melee", state);
|
||||
}
|
||||
}
|
||||
else if (!strnicmp (Line1, "Far attack", 10))
|
||||
{
|
||||
if (thingy != 1) // Not for players!
|
||||
{
|
||||
AddState("Missile", state);
|
||||
statedef.AddState("Missile", state);
|
||||
}
|
||||
}
|
||||
else if (!strnicmp (Line1, "Death", 5))
|
||||
AddState("Death", state);
|
||||
statedef.AddState("Death", state);
|
||||
else if (!strnicmp (Line1, "Exploding", 9))
|
||||
AddState("XDeath", state);
|
||||
statedef.AddState("XDeath", state);
|
||||
else if (!strnicmp (Line1, "Respawn", 7))
|
||||
AddState("Raise", state);
|
||||
statedef.AddState("Raise", state);
|
||||
}
|
||||
else if (stricmp (Line1 + linelen - 6, " sound") == 0)
|
||||
{
|
||||
|
@ -1048,7 +1049,7 @@ static int PatchThing (int thingy)
|
|||
}
|
||||
if (patchedStates)
|
||||
{
|
||||
InstallStates(type->ActorInfo, info);
|
||||
statedef.InstallStates(type->ActorInfo, info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1359,6 +1360,7 @@ static int PatchWeapon (int weapNum)
|
|||
AWeapon *info;
|
||||
BYTE dummy[sizeof(AWeapon)];
|
||||
bool patchedStates = false;
|
||||
FStateDefinitions statedef;
|
||||
|
||||
if (weapNum >= 0 && weapNum < 9)
|
||||
{
|
||||
|
@ -1385,20 +1387,20 @@ static int PatchWeapon (int weapNum)
|
|||
|
||||
if (type != NULL && !patchedStates)
|
||||
{
|
||||
MakeStateDefines(type->ActorInfo->StateList);
|
||||
statedef.MakeStateDefines(type);
|
||||
patchedStates = true;
|
||||
}
|
||||
|
||||
if (strnicmp (Line1, "Deselect", 8) == 0)
|
||||
AddState("Select", state);
|
||||
statedef.AddState("Select", state);
|
||||
else if (strnicmp (Line1, "Select", 6) == 0)
|
||||
AddState("Deselect", state);
|
||||
statedef.AddState("Deselect", state);
|
||||
else if (strnicmp (Line1, "Bobbing", 7) == 0)
|
||||
AddState("Ready", state);
|
||||
statedef.AddState("Ready", state);
|
||||
else if (strnicmp (Line1, "Shooting", 8) == 0)
|
||||
AddState("Fire", state);
|
||||
statedef.AddState("Fire", state);
|
||||
else if (strnicmp (Line1, "Firing", 6) == 0)
|
||||
AddState("Flash", state);
|
||||
statedef.AddState("Flash", state);
|
||||
}
|
||||
else if (stricmp (Line1, "Ammo type") == 0)
|
||||
{
|
||||
|
@ -1455,7 +1457,7 @@ static int PatchWeapon (int weapNum)
|
|||
|
||||
if (patchedStates)
|
||||
{
|
||||
InstallStates(type->ActorInfo, info);
|
||||
statedef.InstallStates(type->ActorInfo, info);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1697,18 +1699,22 @@ static int PatchMisc (int dummy)
|
|||
{
|
||||
player->health = deh.StartHealth;
|
||||
|
||||
FDropItem * di = GetDropItems(PClass::FindClass(NAME_DoomPlayer));
|
||||
while (di != NULL)
|
||||
// Hm... I'm not sure that this is the right way to change this info...
|
||||
unsigned int index = PClass::FindClass(NAME_DoomPlayer)->Meta.GetMetaInt (ACMETA_DropItems) - 1;
|
||||
if (index >= 0 && index < DropItemList.Size())
|
||||
{
|
||||
if (di->Name == NAME_Clip)
|
||||
FDropItem * di = DropItemList[index];
|
||||
while (di != NULL)
|
||||
{
|
||||
di->amount = deh.StartBullets;
|
||||
if (di->Name == NAME_Clip)
|
||||
{
|
||||
di->amount = deh.StartBullets;
|
||||
}
|
||||
di = di->Next;
|
||||
}
|
||||
di = di->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 0xDD means "enable infighting"
|
||||
if (infighting == 0xDD)
|
||||
{
|
||||
|
@ -2195,14 +2201,6 @@ void DoDehPatch (const char *patchfile, bool autoloading, int lump)
|
|||
PatchFile[filelen] = 0;
|
||||
|
||||
dversion = pversion = -1;
|
||||
/*
|
||||
if (gameinfo.gametype != GAME_Doom)
|
||||
{
|
||||
Printf ("DeHackEd/BEX patches are only supported for DOOM mode\n");
|
||||
delete[] PatchFile;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
cont = 0;
|
||||
if (0 == strncmp (PatchFile, "Patch File for DeHackEd v", 25))
|
||||
{
|
||||
|
@ -2586,13 +2584,14 @@ void FinishDehPatch ()
|
|||
memcpy (defaults2, defaults1, sizeof(AActor));
|
||||
|
||||
// Make a copy the state labels
|
||||
MakeStateDefines(type->ActorInfo->StateList);
|
||||
if (!type->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
// If this is a hacked non-inventory item we must also copy AInventory's special states
|
||||
AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList);
|
||||
FStateDefinitions statedef;
|
||||
statedef.MakeStateDefines(type);
|
||||
statedef.AddStateDefines(RUNTIME_CLASS(AInventory)->ActorInfo->StateList);
|
||||
statedef.InstallStates(subclass->ActorInfo, defaults2);
|
||||
}
|
||||
InstallStates(subclass->ActorInfo, defaults2);
|
||||
|
||||
// Use the DECORATE replacement feature to redirect all spawns
|
||||
// of the original class to the new one.
|
||||
|
|
|
@ -2489,6 +2489,13 @@ void D_DoomMain (void)
|
|||
Printf ("S_InitData: Load sound definitions.\n");
|
||||
S_InitData ();
|
||||
|
||||
|
||||
Printf ("Texman.Init: Init texture manager.\n");
|
||||
TexMan.Init();
|
||||
|
||||
// Now that all textues have been loaded the crosshair can be initialized.
|
||||
crosshair.Callback ();
|
||||
|
||||
// [CW] Parse any TEAMINFO lumps
|
||||
Printf ("TEAMINFO_Init: Load team definitions.\n");
|
||||
TEAMINFO_Init ();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -170,6 +170,14 @@ struct PalEntry
|
|||
#endif
|
||||
};
|
||||
|
||||
// Screenshot buffer image data types
|
||||
enum ESSType
|
||||
{
|
||||
SS_PAL,
|
||||
SS_RGB,
|
||||
SS_BGRA
|
||||
};
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
|
||||
#endif
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -848,13 +848,15 @@ static void G_DoParseMapInfo (int lump)
|
|||
strcpy (levelinfo->skypic2, levelinfo->skypic1);
|
||||
}
|
||||
SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
|
||||
/* can't do this here.
|
||||
if (levelinfo->pname[0] != 0)
|
||||
{
|
||||
if (!TexMan.AddPatch(levelinfo->pname).Exists())
|
||||
if (!TexMan.CheckForTexture(levelinfo->pname, FTexture::TEX_MiscPatch).Exists())
|
||||
{
|
||||
levelinfo->pname[0] = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1722,7 +1724,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
|
|||
{
|
||||
int cstype = SBarInfoScript->GetGameType();
|
||||
|
||||
if(cstype == GAME_Doom || cstype == GAME_Chex) //Did the user specify a "base"
|
||||
if(cstype & GAME_DoomChex) //Did the user specify a "base"
|
||||
{
|
||||
StatusBar = CreateDoomStatusBar ();
|
||||
}
|
||||
|
@ -1854,7 +1856,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
|
|||
//
|
||||
// G_DoCompleted
|
||||
//
|
||||
static char nextlevel[9];
|
||||
static FString nextlevel;
|
||||
static int startpos; // [RH] Support for multiple starts per level
|
||||
extern int NoWipe; // [RH] Don't wipe when travelling in hubs
|
||||
static bool startkeepfacing; // [RH] Support for keeping your facing angle
|
||||
|
@ -1866,7 +1868,7 @@ static bool g_nomonsters;
|
|||
// match the first parameter of the single player start spots
|
||||
// that should appear in the next map.
|
||||
|
||||
void G_ChangeLevel(const char * levelname, int position, bool keepFacing, int nextSkill,
|
||||
void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nextSkill,
|
||||
bool nointermission, bool resetinv, bool nomonsters)
|
||||
{
|
||||
if (unloading)
|
||||
|
@ -1875,15 +1877,14 @@ void G_ChangeLevel(const char * levelname, int position, bool keepFacing, int ne
|
|||
return;
|
||||
}
|
||||
|
||||
strncpy (nextlevel, levelname, 8);
|
||||
nextlevel[8] = 0;
|
||||
nextlevel = levelname;
|
||||
|
||||
if (strncmp(nextlevel, "enDSeQ", 6))
|
||||
if (strncmp(levelname, "enDSeQ", 6))
|
||||
{
|
||||
level_info_t *nextinfo = CheckLevelRedirect (FindLevelInfo (nextlevel));
|
||||
if (nextinfo)
|
||||
{
|
||||
strncpy(nextlevel, nextinfo->mapname, 8);
|
||||
nextlevel = nextinfo->mapname;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1983,7 +1984,7 @@ void G_DoCompleted (void)
|
|||
|
||||
if (gamestate == GS_TITLELEVEL)
|
||||
{
|
||||
strncpy (level.mapname, nextlevel, 8);
|
||||
strncpy (level.mapname, nextlevel, 255);
|
||||
G_DoLoadLevel (startpos, false);
|
||||
startpos = 0;
|
||||
viewactive = true;
|
||||
|
@ -1998,7 +1999,7 @@ void G_DoCompleted (void)
|
|||
AM_Stop ();
|
||||
|
||||
wminfo.finished_ep = level.cluster - 1;
|
||||
wminfo.lname0 = level.info->pname;
|
||||
wminfo.LName0 = TexMan[TexMan.CheckForTexture(level.info->pname, FTexture::TEX_MiscPatch)];
|
||||
wminfo.current = level.mapname;
|
||||
|
||||
if (deathmatch &&
|
||||
|
@ -2006,26 +2007,27 @@ void G_DoCompleted (void)
|
|||
!(level.flags & LEVEL_CHANGEMAPCHEAT))
|
||||
{
|
||||
wminfo.next = level.mapname;
|
||||
wminfo.lname1 = level.info->pname;
|
||||
wminfo.LName1 = wminfo.LName0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp (nextlevel, "enDSeQ", 6) == 0)
|
||||
{
|
||||
wminfo.next = FString(nextlevel, 8);
|
||||
wminfo.lname1 = "";
|
||||
wminfo.LName1 = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
level_info_t *nextinfo = FindLevelInfo (nextlevel);
|
||||
wminfo.next = nextinfo->mapname;
|
||||
wminfo.lname1 = nextinfo->pname;
|
||||
wminfo.LName1 = TexMan[TexMan.CheckForTexture(nextinfo->pname, FTexture::TEX_MiscPatch)];
|
||||
}
|
||||
}
|
||||
|
||||
CheckWarpTransMap (wminfo.next, true);
|
||||
nextlevel = wminfo.next;
|
||||
|
||||
wminfo.next_ep = FindLevelInfo (nextlevel)->cluster - 1;
|
||||
wminfo.next_ep = FindLevelInfo (wminfo.next)->cluster - 1;
|
||||
wminfo.maxkills = level.total_monsters;
|
||||
wminfo.maxitems = level.total_items;
|
||||
wminfo.maxsecret = level.total_secrets;
|
||||
|
@ -2357,7 +2359,7 @@ void G_DoWorldDone (void)
|
|||
}
|
||||
else
|
||||
{
|
||||
strncpy (level.mapname, nextlevel, 8);
|
||||
strncpy (level.mapname, nextlevel, 255);
|
||||
}
|
||||
G_StartTravel ();
|
||||
G_DoLoadLevel (startpos, true);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -23,14 +23,14 @@ class ARandomSpawner : public AActor
|
|||
|
||||
void PostBeginPlay()
|
||||
{
|
||||
AActor *newmobj;
|
||||
AActor *newmobj = NULL;
|
||||
FDropItem *di; // di will be our drop item list iterator
|
||||
FDropItem *drop; // while drop stays as the reference point.
|
||||
int n=0;
|
||||
|
||||
Super::PostBeginPlay();
|
||||
|
||||
drop = di = GetDropItems(RUNTIME_TYPE(this));
|
||||
drop = di = GetDropItems();
|
||||
if (di != NULL)
|
||||
{
|
||||
while (di != NULL)
|
||||
|
|
|
@ -587,7 +587,7 @@ IMPLEMENT_CLASS(AWeaponGiver)
|
|||
|
||||
bool AWeaponGiver::TryPickup(AActor *&toucher)
|
||||
{
|
||||
FDropItem *di = GetDropItems(GetClass());
|
||||
FDropItem *di = GetDropItems();
|
||||
|
||||
if (di != NULL)
|
||||
{
|
||||
|
@ -737,8 +737,8 @@ bool FWeaponSlots::LocateWeapon (const PClass *type, int *const slot, int *const
|
|||
{
|
||||
if (Slots[i].Weapons[j] == type)
|
||||
{
|
||||
*slot = i;
|
||||
*index = j;
|
||||
if (slot != NULL) *slot = i;
|
||||
if (index != NULL) *index = j;
|
||||
return true;
|
||||
}
|
||||
else if (Slots[i].Weapons[j] == NULL)
|
||||
|
|
|
@ -94,7 +94,7 @@ CUSTOM_CVAR (Bool, st_scale, true, CVAR_ARCHIVE)
|
|||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CUSTOM_CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
|
||||
{
|
||||
int num = self;
|
||||
char name[16], size;
|
||||
|
@ -123,7 +123,7 @@ CUSTOM_CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
strcpy (name, "XHAIRS1");
|
||||
}
|
||||
}
|
||||
CrosshairImage = TexMan[TexMan.AddPatch (name)];
|
||||
CrosshairImage = TexMan[TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch)];
|
||||
}
|
||||
|
||||
CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
|
|
15
src/gi.cpp
15
src/gi.cpp
|
@ -100,6 +100,7 @@ gameinfo_t HexenGameInfo =
|
|||
{ "mapinfo/hexen.txt", NULL },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"BagOfHolding", // Hexen doesn't have a backpack so use Heretic's.
|
||||
};
|
||||
|
||||
gameinfo_t HexenDKGameInfo =
|
||||
|
@ -132,6 +133,7 @@ gameinfo_t HexenDKGameInfo =
|
|||
{ "mapinfo/hexen.txt", NULL },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"BagOfHolding",
|
||||
};
|
||||
|
||||
gameinfo_t HereticGameInfo =
|
||||
|
@ -164,6 +166,7 @@ gameinfo_t HereticGameInfo =
|
|||
{ "mapinfo/heretic.txt", NULL },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"BagOfHolding",
|
||||
};
|
||||
|
||||
gameinfo_t HereticSWGameInfo =
|
||||
|
@ -196,6 +199,7 @@ gameinfo_t HereticSWGameInfo =
|
|||
{ "mapinfo/heretic.txt", NULL },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"BagOfHolding",
|
||||
};
|
||||
|
||||
gameinfo_t SharewareGameInfo =
|
||||
|
@ -228,6 +232,7 @@ gameinfo_t SharewareGameInfo =
|
|||
{ "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"Backpack",
|
||||
};
|
||||
|
||||
gameinfo_t RegisteredGameInfo =
|
||||
|
@ -260,6 +265,7 @@ gameinfo_t RegisteredGameInfo =
|
|||
{ "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"Backpack",
|
||||
};
|
||||
|
||||
gameinfo_t ChexGameInfo =
|
||||
|
@ -292,6 +298,7 @@ gameinfo_t ChexGameInfo =
|
|||
{ "mapinfo/chex.txt", NULL },
|
||||
MAKERGB(63,125,57),
|
||||
MAKERGB(95,175,87),
|
||||
"ZorchPack",
|
||||
};
|
||||
|
||||
gameinfo_t Chex3GameInfo =
|
||||
|
@ -324,6 +331,7 @@ gameinfo_t Chex3GameInfo =
|
|||
{ "mapinfo/chex.txt", NULL },
|
||||
MAKERGB(63,125,57),
|
||||
MAKERGB(95,175,87),
|
||||
"ZorchPack",
|
||||
};
|
||||
|
||||
gameinfo_t RetailGameInfo =
|
||||
|
@ -356,6 +364,7 @@ gameinfo_t RetailGameInfo =
|
|||
{ "mapinfo/doomcommon.txt", "mapinfo/doom1.txt" },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"Backpack",
|
||||
};
|
||||
|
||||
gameinfo_t CommercialGameInfo =
|
||||
|
@ -388,6 +397,7 @@ gameinfo_t CommercialGameInfo =
|
|||
{ "mapinfo/doomcommon.txt", "mapinfo/doom2.txt" },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"Backpack",
|
||||
};
|
||||
|
||||
gameinfo_t PlutoniaGameInfo =
|
||||
|
@ -420,6 +430,7 @@ gameinfo_t PlutoniaGameInfo =
|
|||
{ "mapinfo/doomcommon.txt", "mapinfo/plutonia.txt" },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"Backpack",
|
||||
};
|
||||
|
||||
gameinfo_t TNTGameInfo =
|
||||
|
@ -452,6 +463,7 @@ gameinfo_t TNTGameInfo =
|
|||
{ "mapinfo/doomcommon.txt", "mapinfo/tnt.txt" },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"Backpack",
|
||||
};
|
||||
|
||||
gameinfo_t StrifeGameInfo =
|
||||
|
@ -484,6 +496,7 @@ gameinfo_t StrifeGameInfo =
|
|||
{ "mapinfo/strife.txt", NULL },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"AmmoSatchel",
|
||||
};
|
||||
|
||||
gameinfo_t StrifeTeaserGameInfo =
|
||||
|
@ -516,6 +529,7 @@ gameinfo_t StrifeTeaserGameInfo =
|
|||
{ "mapinfo/strife.txt", NULL },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"AmmoSatchel",
|
||||
};
|
||||
|
||||
gameinfo_t StrifeTeaser2GameInfo =
|
||||
|
@ -548,4 +562,5 @@ gameinfo_t StrifeTeaser2GameInfo =
|
|||
{ "mapinfo/strife.txt", NULL },
|
||||
MAKERGB(104,0,0),
|
||||
MAKERGB(255,0,0),
|
||||
"AmmoSatchel",
|
||||
};
|
||||
|
|
1
src/gi.h
1
src/gi.h
|
@ -121,6 +121,7 @@ typedef struct
|
|||
const char *mapinfo[2];
|
||||
DWORD defaultbloodcolor;
|
||||
DWORD defaultbloodparticlecolor;
|
||||
const char *backpacktype;
|
||||
} gameinfo_t;
|
||||
|
||||
extern gameinfo_t gameinfo;
|
||||
|
|
332
src/info.cpp
332
src/info.cpp
|
@ -51,122 +51,6 @@
|
|||
|
||||
extern void LoadDecorations ();
|
||||
|
||||
// Each state is owned by an actor. Actors can own any number of
|
||||
// states, but a single state cannot be owned by more than one
|
||||
// actor. States are archived by recording the actor they belong
|
||||
// to and the index into that actor's list of states.
|
||||
|
||||
// For NULL states, which aren't owned by any actor, the owner
|
||||
// is recorded as AActor with the following state. AActor should
|
||||
// never actually have this many states of its own, so this
|
||||
// is (relatively) safe.
|
||||
|
||||
#define NULL_STATE_INDEX 127
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FArchive &operator<< (FArchive &arc, FState *&state)
|
||||
{
|
||||
const PClass *info;
|
||||
|
||||
if (arc.IsStoring ())
|
||||
{
|
||||
if (state == NULL)
|
||||
{
|
||||
arc.UserWriteClass (RUNTIME_CLASS(AActor));
|
||||
arc.WriteCount (NULL_STATE_INDEX);
|
||||
return arc;
|
||||
}
|
||||
|
||||
info = FState::StaticFindStateOwner (state);
|
||||
|
||||
if (info != NULL)
|
||||
{
|
||||
arc.UserWriteClass (info);
|
||||
arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this was never working as intended.
|
||||
I_Error ("Cannot find owner for state %p:\n"
|
||||
"%s %c%c %3d [%p] -> %p", state,
|
||||
sprites[state->sprite].name,
|
||||
state->GetFrame() + 'A',
|
||||
state->GetFullbright() ? '*' : ' ',
|
||||
state->GetTics(),
|
||||
state->GetAction(),
|
||||
state->GetNextState());
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const PClass *info;
|
||||
DWORD ofs;
|
||||
|
||||
arc.UserReadClass (info);
|
||||
ofs = arc.ReadCount ();
|
||||
if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor))
|
||||
{
|
||||
state = NULL;
|
||||
}
|
||||
else if (info->ActorInfo != NULL)
|
||||
{
|
||||
state = info->ActorInfo->OwnedStates + ofs;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = NULL;
|
||||
}
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find the actor that a state belongs to.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const PClass *FState::StaticFindStateOwner (const FState *state)
|
||||
{
|
||||
for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
|
||||
{
|
||||
FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo;
|
||||
if (state >= info->OwnedStates &&
|
||||
state < info->OwnedStates + info->NumOwnedStates)
|
||||
{
|
||||
return info->Class;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find the actor that a state belongs to, but restrict the search to
|
||||
// the specified type and its ancestors.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info)
|
||||
{
|
||||
while (info != NULL)
|
||||
{
|
||||
if (state >= info->OwnedStates &&
|
||||
state < info->OwnedStates + info->NumOwnedStates)
|
||||
{
|
||||
return info->Class;
|
||||
}
|
||||
info = info->Class->ParentClass->ActorInfo;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -174,16 +58,23 @@ const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInf
|
|||
|
||||
int GetSpriteIndex(const char * spritename)
|
||||
{
|
||||
// Make sure that the string is upper case and 4 characters long
|
||||
char upper[5];
|
||||
for (int i = 0; spritename[i] != 0 && i < 4; i++)
|
||||
{
|
||||
upper[i] = toupper (spritename[i]);
|
||||
}
|
||||
upper[4] = 0;
|
||||
|
||||
for (unsigned i = 0; i < sprites.Size (); ++i)
|
||||
{
|
||||
if (strncmp (sprites[i].name, spritename, 4) == 0)
|
||||
if (strcmp (sprites[i].name, spritename) == 0)
|
||||
{
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
spritedef_t temp;
|
||||
strncpy (temp.name, spritename, 4);
|
||||
temp.name[4] = 0;
|
||||
strcpy (temp.name, upper);
|
||||
temp.numframes = 0;
|
||||
temp.spriteframes = 0;
|
||||
return (int)sprites.Push (temp);
|
||||
|
@ -337,209 +228,6 @@ void FActorInfo::SetPainChance(FName type, int chance)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FStateLabel *FStateLabels::FindLabel (FName label)
|
||||
{
|
||||
return const_cast<FStateLabel *>(BinarySearch<FStateLabel, FName> (Labels, NumLabels, &FStateLabel::Label, label));
|
||||
}
|
||||
|
||||
void FStateLabels::Destroy ()
|
||||
{
|
||||
for(int i=0; i<NumLabels;i++)
|
||||
{
|
||||
if (Labels[i].Children != NULL)
|
||||
{
|
||||
Labels[i].Children->Destroy();
|
||||
free (Labels[i].Children); // These are malloc'd, not new'd!
|
||||
Labels[i].Children=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// HasStates
|
||||
//
|
||||
// Checks whether the actor has special death states.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AActor::HasSpecialDeathStates () const
|
||||
{
|
||||
const FActorInfo *info = GetClass()->ActorInfo;
|
||||
|
||||
if (info->StateList != NULL)
|
||||
{
|
||||
FStateLabel *slabel = info->StateList->FindLabel (NAME_Death);
|
||||
if (slabel != NULL && slabel->Children != NULL)
|
||||
{
|
||||
for(int i=0;i<slabel->Children->NumLabels;i++)
|
||||
{
|
||||
if (slabel->Children->Labels[i].State != NULL) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindState (one name version)
|
||||
//
|
||||
// Finds a state with the exact specified name.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FState *AActor::FindState (FName label) const
|
||||
{
|
||||
const FActorInfo *info = GetClass()->ActorInfo;
|
||||
|
||||
if (info->StateList != NULL)
|
||||
{
|
||||
FStateLabel *slabel = info->StateList->FindLabel (label);
|
||||
if (slabel != NULL)
|
||||
{
|
||||
return slabel->State;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindState (two name version)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FState *AActor::FindState (FName label, FName sublabel, bool exact) const
|
||||
{
|
||||
const FActorInfo *info = GetClass()->ActorInfo;
|
||||
|
||||
if (info->StateList != NULL)
|
||||
{
|
||||
FStateLabel *slabel = info->StateList->FindLabel (label);
|
||||
if (slabel != NULL)
|
||||
{
|
||||
if (slabel->Children != NULL)
|
||||
{
|
||||
FStateLabel *slabel2 = slabel->Children->FindLabel(sublabel);
|
||||
if (slabel2 != NULL)
|
||||
{
|
||||
return slabel2->State;
|
||||
}
|
||||
}
|
||||
if (!exact) return slabel->State;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindState (multiple names version)
|
||||
//
|
||||
// Finds a state that matches as many of the supplied names as possible.
|
||||
// A state with more names than those provided does not match.
|
||||
// A state with fewer names can match if there are no states with the exact
|
||||
// same number of names.
|
||||
//
|
||||
// The search proceeds like this. For the current class, keeping matching
|
||||
// names until there are no more. If both the argument list and the state
|
||||
// are out of names, it's an exact match, so return it. If the state still
|
||||
// has names, ignore it. If the argument list still has names, remember it.
|
||||
//
|
||||
//===========================================================================
|
||||
FState *FActorInfo::FindState (FName name) const
|
||||
{
|
||||
return FindState(1, &name);
|
||||
}
|
||||
|
||||
FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const
|
||||
{
|
||||
FStateLabels *labels = StateList;
|
||||
FState *best = NULL;
|
||||
|
||||
if (labels != NULL)
|
||||
{
|
||||
int count = 0;
|
||||
FStateLabel *slabel = NULL;
|
||||
FName label;
|
||||
|
||||
// Find the best-matching label for this class.
|
||||
while (labels != NULL && count < numnames)
|
||||
{
|
||||
label = *names++;
|
||||
slabel = labels->FindLabel (label);
|
||||
|
||||
if (slabel != NULL)
|
||||
{
|
||||
count++;
|
||||
labels = slabel->Children;
|
||||
best = slabel->State;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count < numnames && exact) return NULL;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates a list of names from a string. Dots are used as separator
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void MakeStateNameList(const char * fname, TArray<FName> * out)
|
||||
{
|
||||
FName firstpart, secondpart;
|
||||
char * c;
|
||||
|
||||
// Handle the old names for the existing death states
|
||||
char * name = copystring(fname);
|
||||
firstpart = strtok(name, ".");
|
||||
switch (firstpart)
|
||||
{
|
||||
case NAME_Burn:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Fire;
|
||||
break;
|
||||
case NAME_Ice:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Ice;
|
||||
break;
|
||||
case NAME_Disintegrate:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Disintegrate;
|
||||
break;
|
||||
case NAME_XDeath:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Extreme;
|
||||
break;
|
||||
}
|
||||
|
||||
out->Clear();
|
||||
out->Push(firstpart);
|
||||
if (secondpart!=NAME_None) out->Push(secondpart);
|
||||
|
||||
while ((c = strtok(NULL, "."))!=NULL)
|
||||
{
|
||||
FName cc = c;
|
||||
out->Push(cc);
|
||||
}
|
||||
delete [] name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -89,6 +89,7 @@ struct FState
|
|||
SBYTE Misc1;
|
||||
BYTE Misc2;
|
||||
BYTE Frame;
|
||||
BYTE DefineFlags; // Unused byte so let's use it during state creation.
|
||||
FState *NextState;
|
||||
actionf_p ActionFunc;
|
||||
int ParameterIndex;
|
||||
|
@ -204,8 +205,12 @@ struct FActorInfo
|
|||
void SetDamageFactor(FName type, fixed_t factor);
|
||||
void SetPainChance(FName type, int chance);
|
||||
|
||||
FState *FindState (FName name) const;
|
||||
FState *FindState (int numnames, FName *names, bool exact=false) const;
|
||||
FState *FindStateByString(const char *name, bool exact=false);
|
||||
FState *FindState (FName name) const
|
||||
{
|
||||
return FindState(1, &name);
|
||||
}
|
||||
|
||||
FActorInfo *GetReplacement ();
|
||||
FActorInfo *GetReplacee ();
|
||||
|
@ -252,6 +257,6 @@ private:
|
|||
extern FDoomEdMap DoomEdMap;
|
||||
|
||||
int GetSpriteIndex(const char * spritename);
|
||||
void MakeStateNameList(const char * fname, TArray<FName> * out);
|
||||
TArray<FName> &MakeStateNameList(const char * fname);
|
||||
|
||||
#endif // __INFO_H__
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include "r_translate.h"
|
||||
#include "g_level.h"
|
||||
#include "d_net.h"
|
||||
#include "d_dehacked.h"
|
||||
#include "gi.h"
|
||||
|
||||
// [RH] Actually handle the cheat. The cheat code in st_stuff.c now just
|
||||
// writes some bytes to the network data stream, and the network code
|
||||
|
@ -629,26 +631,7 @@ void cht_Give (player_t *player, const char *name, int amount)
|
|||
if (giveall || stricmp (name, "backpack") == 0)
|
||||
{
|
||||
// Select the correct type of backpack based on the game
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
type = PClass::FindClass ("BagOfHolding");
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
type = PClass::FindClass ("AmmoSatchel");
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
type = PClass::FindClass ("Backpack");
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Chex)
|
||||
{
|
||||
type = PClass::FindClass ("Zorchpack");
|
||||
}
|
||||
else
|
||||
{ // Hexen doesn't have a backpack, foo!
|
||||
type = NULL;
|
||||
}
|
||||
type = PClass::FindClass(gameinfo.backpacktype);
|
||||
if (type != NULL)
|
||||
{
|
||||
GiveSpawner (player, type, 1);
|
||||
|
@ -743,13 +726,26 @@ void cht_Give (player_t *player, const char *name, int amount)
|
|||
for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i)
|
||||
{
|
||||
type = PClass::m_Types[i];
|
||||
// Don't give replaced weapons unless the replacement was done by Dehacked.
|
||||
if (type != RUNTIME_CLASS(AWeapon) &&
|
||||
type->IsDescendantOf (RUNTIME_CLASS(AWeapon)))
|
||||
type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) &&
|
||||
(type->ActorInfo->GetReplacement() == type->ActorInfo ||
|
||||
type->ActorInfo->GetReplacement()->Class->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup))))
|
||||
|
||||
{
|
||||
AWeapon *def = (AWeapon*)GetDefaultByType (type);
|
||||
if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON))
|
||||
// Give the weapon only if it belongs to the current game or
|
||||
// is in a weapon slot. Unfortunately this check only works in
|
||||
// singleplayer games because the weapon slots are stored locally.
|
||||
// In multiplayer games all weapons must be given.
|
||||
if (multiplayer || type->ActorInfo->GameFilter == GAME_Any ||
|
||||
(type->ActorInfo->GameFilter & gameinfo.gametype) ||
|
||||
LocalWeapons.LocateWeapon(type, NULL, NULL))
|
||||
{
|
||||
GiveSpawner (player, type, 1);
|
||||
AWeapon *def = (AWeapon*)GetDefaultByType (type);
|
||||
if (!(def->WeaponFlags & WIF_CHEATNOTWEAPON))
|
||||
{
|
||||
GiveSpawner (player, type, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -860,33 +856,17 @@ void cht_Take (player_t *player, const char *name, int amount)
|
|||
|
||||
if (takeall || stricmp (name, "backpack") == 0)
|
||||
{
|
||||
// Select the correct type of backpack based on the game
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
// Take away all types of backpacks the player might own.
|
||||
for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i)
|
||||
{
|
||||
type = PClass::FindClass ("BagOfHolding");
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
type = PClass::FindClass ("AmmoSatchel");
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Doom)
|
||||
{
|
||||
type = PClass::FindClass ("Backpack");
|
||||
}
|
||||
else if (gameinfo.gametype == GAME_Chex)
|
||||
{
|
||||
type = PClass::FindClass ("Zorchpack");
|
||||
}
|
||||
else
|
||||
{ // Hexen doesn't have a backpack, foo!
|
||||
type = NULL;
|
||||
}
|
||||
if (type != NULL)
|
||||
{
|
||||
AActor *backpack = player->mo->FindInventory (type);
|
||||
const PClass *type = PClass::m_Types[i];
|
||||
|
||||
if (backpack)
|
||||
backpack->Destroy ();
|
||||
if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem)))
|
||||
{
|
||||
AInventory *pack = player->mo->FindInventory (type);
|
||||
|
||||
if (pack) pack->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1392,7 +1392,7 @@ static BYTE BitTranslate[32];
|
|||
|
||||
void M_OptInit (void)
|
||||
{
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
if (gameinfo.gametype & GAME_DoomChex)
|
||||
{
|
||||
LabelColor = CR_UNTRANSLATED;
|
||||
ValueColor = CR_GRAY;
|
||||
|
@ -2999,6 +2999,7 @@ void UpdateJoystickMenu ()
|
|||
JoystickItems[line].type = discrete;
|
||||
JoystickItems[line].a.intcvar = cvars[i];
|
||||
JoystickItems[line].b.numvalues = 6.f;
|
||||
JoystickItems[line].d.graycheck = NULL;
|
||||
JoystickItems[line].e.values = JoyAxisMapNames;
|
||||
line++;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include "doomtype.h"
|
||||
|
||||
enum ESSType;
|
||||
#include "v_video.h"
|
||||
|
||||
// PNG Writing --------------------------------------------------------------
|
||||
|
||||
|
@ -116,4 +115,4 @@ class FTexture;
|
|||
|
||||
FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -5230,16 +5230,13 @@ int DLevelScript::RunScript ()
|
|||
case PCD_SETACTORSTATE:
|
||||
{
|
||||
const char *statename = FBehavior::StaticLookupString (STACK(2));
|
||||
TArray<FName> statelist;
|
||||
FState *state;
|
||||
|
||||
MakeStateNameList(statename, &statelist);
|
||||
|
||||
if (STACK(3) == 0)
|
||||
{
|
||||
if (activator != NULL)
|
||||
{
|
||||
state = activator->GetClass()->ActorInfo->FindState (statelist.Size(), &statelist[0], !!STACK(1));
|
||||
state = activator->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1));
|
||||
if (state != NULL)
|
||||
{
|
||||
activator->SetState (state);
|
||||
|
@ -5259,7 +5256,7 @@ int DLevelScript::RunScript ()
|
|||
|
||||
while ( (actor = iterator.Next ()) )
|
||||
{
|
||||
state = actor->GetClass()->ActorInfo->FindState (statelist.Size(), &statelist[0], !!STACK(1));
|
||||
state = actor->GetClass()->ActorInfo->FindStateByString (statename, !!STACK(1));
|
||||
if (state != NULL)
|
||||
{
|
||||
actor->SetState (state);
|
||||
|
|
|
@ -4968,10 +4968,6 @@ int AActor::DoSpecialDamage (AActor *target, int damage)
|
|||
|
||||
int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype)
|
||||
{
|
||||
// If the actor does not have a corresponding death state, then it does not take damage.
|
||||
// Note that DeathState matches every kind of damagetype, so if an actor has that, it can
|
||||
// be hurt with any type of damage. Exception: Massacre damage always succeeds, because
|
||||
// it needs to work.
|
||||
FState *death;
|
||||
|
||||
if (flags5 & MF5_NODAMAGE)
|
||||
|
@ -4985,7 +4981,7 @@ int AActor::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FN
|
|||
// it needs to work.
|
||||
|
||||
// Always kill if there is a regular death state or no death states at all.
|
||||
if (FindState (NAME_Death) != NULL || !HasSpecialDeathStates())
|
||||
if (FindState (NAME_Death) != NULL || !HasSpecialDeathStates() || damagetype == NAME_Massacre)
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
|
@ -5044,3 +5040,45 @@ void AActor::SetIdle()
|
|||
if (idle == NULL) idle = SpawnState;
|
||||
SetState(idle);
|
||||
}
|
||||
|
||||
FDropItem *AActor::GetDropItems()
|
||||
{
|
||||
unsigned int index = GetClass()->Meta.GetMetaInt (ACMETA_DropItems) - 1;
|
||||
|
||||
if (index >= 0 && index < DropItemList.Size())
|
||||
{
|
||||
return DropItemList[index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// DropItem handling
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
FDropItemPtrArray DropItemList;
|
||||
|
||||
void FreeDropItemChain(FDropItem *chain)
|
||||
{
|
||||
while (chain != NULL)
|
||||
{
|
||||
FDropItem *next = chain->Next;
|
||||
delete chain;
|
||||
chain = next;
|
||||
}
|
||||
}
|
||||
|
||||
FDropItemPtrArray::~FDropItemPtrArray()
|
||||
{
|
||||
for (unsigned int i = 0; i < Size(); ++i)
|
||||
{
|
||||
FreeDropItemChain ((*this)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int StoreDropItemChain(FDropItem *chain)
|
||||
{
|
||||
return DropItemList.Push (chain) + 1;
|
||||
}
|
||||
|
||||
|
|
814
src/p_states.cpp
Normal file
814
src/p_states.cpp
Normal file
|
@ -0,0 +1,814 @@
|
|||
/*
|
||||
** p_states.cpp
|
||||
** state management
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** Copyright 2006-2008 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
**
|
||||
*/
|
||||
#include "actor.h"
|
||||
#include "farchive.h"
|
||||
#include "templates.h"
|
||||
#include "cmdlib.h"
|
||||
#include "i_system.h"
|
||||
#include "thingdef/thingdef.h"
|
||||
|
||||
// Each state is owned by an actor. Actors can own any number of
|
||||
// states, but a single state cannot be owned by more than one
|
||||
// actor. States are archived by recording the actor they belong
|
||||
// to and the index into that actor's list of states.
|
||||
|
||||
// For NULL states, which aren't owned by any actor, the owner
|
||||
// is recorded as AActor with the following state. AActor should
|
||||
// never actually have this many states of its own, so this
|
||||
// is (relatively) safe.
|
||||
|
||||
#define NULL_STATE_INDEX 127
|
||||
|
||||
TArray<FName> JumpParameters;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FArchive &operator<< (FArchive &arc, FState *&state)
|
||||
{
|
||||
const PClass *info;
|
||||
|
||||
if (arc.IsStoring ())
|
||||
{
|
||||
if (state == NULL)
|
||||
{
|
||||
arc.UserWriteClass (RUNTIME_CLASS(AActor));
|
||||
arc.WriteCount (NULL_STATE_INDEX);
|
||||
return arc;
|
||||
}
|
||||
|
||||
info = FState::StaticFindStateOwner (state);
|
||||
|
||||
if (info != NULL)
|
||||
{
|
||||
arc.UserWriteClass (info);
|
||||
arc.WriteCount ((DWORD)(state - info->ActorInfo->OwnedStates));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this was never working as intended.
|
||||
I_Error ("Cannot find owner for state %p:\n"
|
||||
"%s %c%c %3d [%p] -> %p", state,
|
||||
sprites[state->sprite].name,
|
||||
state->GetFrame() + 'A',
|
||||
state->GetFullbright() ? '*' : ' ',
|
||||
state->GetTics(),
|
||||
state->GetAction(),
|
||||
state->GetNextState());
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const PClass *info;
|
||||
DWORD ofs;
|
||||
|
||||
arc.UserReadClass (info);
|
||||
ofs = arc.ReadCount ();
|
||||
if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor))
|
||||
{
|
||||
state = NULL;
|
||||
}
|
||||
else if (info->ActorInfo != NULL)
|
||||
{
|
||||
state = info->ActorInfo->OwnedStates + ofs;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = NULL;
|
||||
}
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find the actor that a state belongs to.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const PClass *FState::StaticFindStateOwner (const FState *state)
|
||||
{
|
||||
for (unsigned int i = 0; i < PClass::m_RuntimeActors.Size(); ++i)
|
||||
{
|
||||
FActorInfo *info = PClass::m_RuntimeActors[i]->ActorInfo;
|
||||
if (state >= info->OwnedStates &&
|
||||
state < info->OwnedStates + info->NumOwnedStates)
|
||||
{
|
||||
return info->Class;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find the actor that a state belongs to, but restrict the search to
|
||||
// the specified type and its ancestors.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const PClass *FState::StaticFindStateOwner (const FState *state, const FActorInfo *info)
|
||||
{
|
||||
while (info != NULL)
|
||||
{
|
||||
if (state >= info->OwnedStates &&
|
||||
state < info->OwnedStates + info->NumOwnedStates)
|
||||
{
|
||||
return info->Class;
|
||||
}
|
||||
info = info->Class->ParentClass->ActorInfo;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FStateLabel *FStateLabels::FindLabel (FName label)
|
||||
{
|
||||
return const_cast<FStateLabel *>(BinarySearch<FStateLabel, FName> (Labels, NumLabels, &FStateLabel::Label, label));
|
||||
}
|
||||
|
||||
void FStateLabels::Destroy ()
|
||||
{
|
||||
for(int i=0; i<NumLabels;i++)
|
||||
{
|
||||
if (Labels[i].Children != NULL)
|
||||
{
|
||||
Labels[i].Children->Destroy();
|
||||
free (Labels[i].Children); // These are malloc'd, not new'd!
|
||||
Labels[i].Children=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// HasStates
|
||||
//
|
||||
// Checks whether the actor has special death states.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool AActor::HasSpecialDeathStates () const
|
||||
{
|
||||
const FActorInfo *info = GetClass()->ActorInfo;
|
||||
|
||||
if (info->StateList != NULL)
|
||||
{
|
||||
FStateLabel *slabel = info->StateList->FindLabel (NAME_Death);
|
||||
if (slabel != NULL && slabel->Children != NULL)
|
||||
{
|
||||
for(int i=0;i<slabel->Children->NumLabels;i++)
|
||||
{
|
||||
if (slabel->Children->Labels[i].State != NULL) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Resolves a label parameter
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState *P_GetState(AActor *self, FState *CallingState, int offset)
|
||||
{
|
||||
if (offset == 0 || offset == INT_MIN)
|
||||
{
|
||||
return NULL; // 0 means 'no state'
|
||||
}
|
||||
else if (offset>0)
|
||||
{
|
||||
if (CallingState == NULL) return NULL;
|
||||
return CallingState + offset;
|
||||
}
|
||||
else if (self != NULL)
|
||||
{
|
||||
FName *params = &JumpParameters[-offset];
|
||||
|
||||
FName classname = params[0];
|
||||
const PClass *cls;
|
||||
cls = classname==NAME_None? RUNTIME_TYPE(self) : PClass::FindClass(classname);
|
||||
if (cls==NULL || cls->ActorInfo==NULL) return NULL; // shouldn't happen
|
||||
|
||||
int numnames = (int)params[1];
|
||||
FState *jumpto = cls->ActorInfo->FindState(numnames, ¶ms[2]);
|
||||
if (jumpto == NULL)
|
||||
{
|
||||
const char *dot="";
|
||||
Printf("Jump target '");
|
||||
if (classname != NAME_None) Printf("%s::", classname.GetChars());
|
||||
for (int i=0;i<numnames;i++)
|
||||
{
|
||||
Printf("%s%s", dot, params[2+i].GetChars());
|
||||
dot = ".";
|
||||
}
|
||||
Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars());
|
||||
}
|
||||
return jumpto;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates a list of names from a string. Dots are used as separator
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
TArray<FName> &MakeStateNameList(const char * fname)
|
||||
{
|
||||
static TArray<FName> namelist(3);
|
||||
FName firstpart, secondpart;
|
||||
char * c;
|
||||
|
||||
// Handle the old names for the existing death states
|
||||
char * name = copystring(fname);
|
||||
firstpart = strtok(name, ".");
|
||||
switch (firstpart)
|
||||
{
|
||||
case NAME_Burn:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Fire;
|
||||
break;
|
||||
case NAME_Ice:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Ice;
|
||||
break;
|
||||
case NAME_Disintegrate:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Disintegrate;
|
||||
break;
|
||||
case NAME_XDeath:
|
||||
firstpart = NAME_Death;
|
||||
secondpart = NAME_Extreme;
|
||||
break;
|
||||
}
|
||||
|
||||
namelist.Clear();
|
||||
namelist.Push(firstpart);
|
||||
if (secondpart!=NAME_None) namelist.Push(secondpart);
|
||||
|
||||
while ((c = strtok(NULL, "."))!=NULL)
|
||||
{
|
||||
FName cc = c;
|
||||
namelist.Push(cc);
|
||||
}
|
||||
delete [] name;
|
||||
return namelist;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindState (multiple names version)
|
||||
//
|
||||
// Finds a state that matches as many of the supplied names as possible.
|
||||
// A state with more names than those provided does not match.
|
||||
// A state with fewer names can match if there are no states with the exact
|
||||
// same number of names.
|
||||
//
|
||||
// The search proceeds like this. For the current class, keeping matching
|
||||
// names until there are no more. If both the argument list and the state
|
||||
// are out of names, it's an exact match, so return it. If the state still
|
||||
// has names, ignore it. If the argument list still has names, remember it.
|
||||
//
|
||||
//===========================================================================
|
||||
FState *FActorInfo::FindState (int numnames, FName *names, bool exact) const
|
||||
{
|
||||
FStateLabels *labels = StateList;
|
||||
FState *best = NULL;
|
||||
|
||||
if (labels != NULL)
|
||||
{
|
||||
int count = 0;
|
||||
FStateLabel *slabel = NULL;
|
||||
FName label;
|
||||
|
||||
// Find the best-matching label for this class.
|
||||
while (labels != NULL && count < numnames)
|
||||
{
|
||||
label = *names++;
|
||||
slabel = labels->FindLabel (label);
|
||||
|
||||
if (slabel != NULL)
|
||||
{
|
||||
count++;
|
||||
labels = slabel->Children;
|
||||
best = slabel->State;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count < numnames && exact) return NULL;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds the state associated with the given string
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState *FActorInfo::FindStateByString(const char *name, bool exact)
|
||||
{
|
||||
TArray<FName> &namelist = MakeStateNameList(name);
|
||||
return FindState(namelist.Size(), &namelist[0], exact);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Search one list of state definitions for the given name
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FStateDefine *FStateDefinitions::FindStateLabelInList(TArray<FStateDefine> & list, FName name, bool create)
|
||||
{
|
||||
for(unsigned i = 0; i<list.Size(); i++)
|
||||
{
|
||||
if (list[i].Label == name) return &list[i];
|
||||
}
|
||||
if (create)
|
||||
{
|
||||
FStateDefine def;
|
||||
def.Label=name;
|
||||
def.State=NULL;
|
||||
def.DefineFlags = SDF_NEXT;
|
||||
return &list[list.Push(def)];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds the address of a state label given by name.
|
||||
// Adds the state label if it doesn't exist
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FStateDefine * FStateDefinitions::FindStateAddress(const char *name)
|
||||
{
|
||||
FStateDefine * statedef=NULL;
|
||||
|
||||
TArray<FName> &namelist = MakeStateNameList(name);
|
||||
|
||||
TArray<FStateDefine> * statelist = &StateLabels;
|
||||
for(unsigned i=0;i<namelist.Size();i++)
|
||||
{
|
||||
statedef = FindStateLabelInList(*statelist, namelist[i], true);
|
||||
statelist = &statedef->Children;
|
||||
}
|
||||
return statedef;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Adds a new state tp the curremt list
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStateDefinitions::AddState (const char *statename, FState *state, BYTE defflags)
|
||||
{
|
||||
FStateDefine *std = FindStateAddress(statename);
|
||||
std->State = state;
|
||||
std->DefineFlags = defflags;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds the state associated with the given name
|
||||
// returns NULL if none found
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState * FStateDefinitions::FindState(const char * name)
|
||||
{
|
||||
FStateDefine * statedef=NULL;
|
||||
|
||||
TArray<FName> &namelist = MakeStateNameList(name);
|
||||
|
||||
TArray<FStateDefine> * statelist = &StateLabels;
|
||||
for(unsigned i=0;i<namelist.Size();i++)
|
||||
{
|
||||
statedef = FindStateLabelInList(*statelist, namelist[i], false);
|
||||
if (statedef == NULL) return NULL;
|
||||
statelist = &statedef->Children;
|
||||
}
|
||||
return statedef? statedef->State : NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates the final list of states from the state definitions
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int STACK_ARGS labelcmp(const void * a, const void * b)
|
||||
{
|
||||
FStateLabel * A = (FStateLabel *)a;
|
||||
FStateLabel * B = (FStateLabel *)b;
|
||||
return ((int)A->Label - (int)B->Label);
|
||||
}
|
||||
|
||||
FStateLabels * FStateDefinitions::CreateStateLabelList(TArray<FStateDefine> & statelist)
|
||||
{
|
||||
// First delete all empty labels from the list
|
||||
for (int i=statelist.Size()-1;i>=0;i--)
|
||||
{
|
||||
if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0))
|
||||
{
|
||||
statelist.Delete(i);
|
||||
}
|
||||
}
|
||||
|
||||
int count=statelist.Size();
|
||||
|
||||
if (count == 0) return NULL;
|
||||
|
||||
FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel));
|
||||
list->NumLabels = count;
|
||||
|
||||
for (int i=0;i<count;i++)
|
||||
{
|
||||
list->Labels[i].Label = statelist[i].Label;
|
||||
list->Labels[i].State = statelist[i].State;
|
||||
list->Labels[i].Children = CreateStateLabelList(statelist[i].Children);
|
||||
}
|
||||
qsort(list->Labels, count, sizeof(FStateLabel), labelcmp);
|
||||
return list;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// InstallStates
|
||||
//
|
||||
// Creates the actor's state list from the current definition
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FStateDefinitions::InstallStates(FActorInfo *info, AActor *defaults)
|
||||
{
|
||||
// First ensure we have a valid spawn state.
|
||||
FState *state = FindState("Spawn");
|
||||
|
||||
if (state == NULL)
|
||||
{
|
||||
// A NULL spawn state will crash the engine so set it to something valid.
|
||||
AddState("Spawn", GetDefault<AActor>()->SpawnState);
|
||||
}
|
||||
|
||||
if (info->StateList != NULL)
|
||||
{
|
||||
info->StateList->Destroy();
|
||||
M_Free(info->StateList);
|
||||
}
|
||||
info->StateList = CreateStateLabelList(StateLabels);
|
||||
|
||||
// Cache these states as member veriables.
|
||||
defaults->SpawnState = info->FindState(NAME_Spawn);
|
||||
defaults->SeeState = info->FindState(NAME_See);
|
||||
// Melee and Missile states are manipulated by the scripted marines so they
|
||||
// have to be stored locally
|
||||
defaults->MeleeState = info->FindState(NAME_Melee);
|
||||
defaults->MissileState = info->FindState(NAME_Missile);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// MakeStateDefines
|
||||
//
|
||||
// Creates a list of state definitions from an existing actor
|
||||
// Used by Dehacked to modify an actor's state list
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FStateDefinitions::MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest)
|
||||
{
|
||||
dest.Clear();
|
||||
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
||||
{
|
||||
FStateDefine def;
|
||||
|
||||
def.Label = list->Labels[i].Label;
|
||||
def.State = list->Labels[i].State;
|
||||
dest.Push(def);
|
||||
if (list->Labels[i].Children != NULL)
|
||||
{
|
||||
MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FStateDefinitions::MakeStateDefines(const PClass *cls)
|
||||
{
|
||||
if (cls->ActorInfo && cls->ActorInfo->StateList)
|
||||
{
|
||||
MakeStateList(cls->ActorInfo->StateList, StateLabels);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearStateLabels();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AddStateDefines
|
||||
//
|
||||
// Adds a list of states to the current definitions
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FStateDefinitions::AddStateDefines(const FStateLabels *list)
|
||||
{
|
||||
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
||||
{
|
||||
if (list->Labels[i].Children == NULL)
|
||||
{
|
||||
if (!FindStateLabelInList(StateLabels, list->Labels[i].Label, false))
|
||||
{
|
||||
FStateDefine def;
|
||||
|
||||
def.Label = list->Labels[i].Label;
|
||||
def.State = list->Labels[i].State;
|
||||
StateLabels.Push(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// RetargetState(Pointer)s
|
||||
//
|
||||
// These functions are used when a goto follows one or more labels.
|
||||
// Because multiple labels are permitted to occur consecutively with no
|
||||
// intervening states, it is not enough to remember the last label defined
|
||||
// and adjust it. So these functions search for all labels that point to
|
||||
// the current position in the state array and give them a copy of the
|
||||
// target string instead.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStateDefinitions::RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist)
|
||||
{
|
||||
for(unsigned i = 0;i<statelist.Size(); i++)
|
||||
{
|
||||
if (statelist[i].State == (FState*)count)
|
||||
{
|
||||
if (target == NULL)
|
||||
{
|
||||
statelist[i].State = NULL;
|
||||
statelist[i].DefineFlags = SDF_STOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
statelist[i].State = (FState *)copystring (target);
|
||||
statelist[i].DefineFlags = SDF_LABEL;
|
||||
}
|
||||
}
|
||||
if (statelist[i].Children.Size() > 0)
|
||||
{
|
||||
RetargetStatePointers(count, target, statelist[i].Children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FStateDefinitions::RetargetStates (intptr_t count, const char *target)
|
||||
{
|
||||
RetargetStatePointers(count, target, StateLabels);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ResolveGotoLabel
|
||||
//
|
||||
// Resolves any strings being stored in a state's NextState field
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name)
|
||||
{
|
||||
const PClass *type=mytype;
|
||||
FState *state;
|
||||
char *namestart = name;
|
||||
char *label, *offset, *pt;
|
||||
int v;
|
||||
|
||||
// Check for classname
|
||||
if ((pt = strstr (name, "::")) != NULL)
|
||||
{
|
||||
const char *classname = name;
|
||||
*pt = '\0';
|
||||
name = pt + 2;
|
||||
|
||||
// The classname may either be "Super" to identify this class's immediate
|
||||
// superclass, or it may be the name of any class that this one derives from.
|
||||
if (stricmp (classname, "Super") == 0)
|
||||
{
|
||||
type = type->ParentClass;
|
||||
actor = GetDefaultByType (type);
|
||||
}
|
||||
else
|
||||
{
|
||||
// first check whether a state of the desired name exists
|
||||
const PClass *stype = PClass::FindClass (classname);
|
||||
if (stype == NULL)
|
||||
{
|
||||
I_Error ("%s is an unknown class.", classname);
|
||||
}
|
||||
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
|
||||
{
|
||||
I_Error ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
|
||||
}
|
||||
if (!stype->IsAncestorOf (type))
|
||||
{
|
||||
I_Error ("%s is not derived from %s so cannot access its states.",
|
||||
type->TypeName.GetChars(), stype->TypeName.GetChars());
|
||||
}
|
||||
if (type != stype)
|
||||
{
|
||||
type = stype;
|
||||
actor = GetDefaultByType (type);
|
||||
}
|
||||
}
|
||||
}
|
||||
label = name;
|
||||
// Check for offset
|
||||
offset = NULL;
|
||||
if ((pt = strchr (name, '+')) != NULL)
|
||||
{
|
||||
*pt = '\0';
|
||||
offset = pt + 1;
|
||||
}
|
||||
v = offset ? strtol (offset, NULL, 0) : 0;
|
||||
|
||||
// Get the state's address.
|
||||
if (type==mytype) state = FindState (label);
|
||||
else state = type->ActorInfo->FindStateByString(label, true);
|
||||
|
||||
if (state != NULL)
|
||||
{
|
||||
state += v;
|
||||
}
|
||||
else if (v != 0)
|
||||
{
|
||||
I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars());
|
||||
}
|
||||
delete[] namestart; // free the allocated string buffer
|
||||
return state;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FixStatePointers
|
||||
//
|
||||
// Fixes an actor's default state pointers.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStateDefinitions::FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list)
|
||||
{
|
||||
for(unsigned i=0;i<list.Size(); i++)
|
||||
{
|
||||
size_t v=(size_t)list[i].State;
|
||||
if (v >= 1 && v < 0x10000)
|
||||
{
|
||||
list[i].State = actor->OwnedStates + v - 1;
|
||||
}
|
||||
if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ResolveGotoLabels
|
||||
//
|
||||
// Resolves an actor's state pointers that were specified as jumps.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FStateDefinitions::ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list)
|
||||
{
|
||||
for(unsigned i=0;i<list.Size(); i++)
|
||||
{
|
||||
if (list[i].State != NULL && list[i].DefineFlags == SDF_LABEL)
|
||||
{ // It's not a valid state, so it must be a label string. Resolve it.
|
||||
list[i].State = ResolveGotoLabel (defaults, actor->Class, (char *)list[i].State);
|
||||
list[i].DefineFlags = SDF_STATE;
|
||||
}
|
||||
if (list[i].Children.Size() > 0) ResolveGotoLabels(actor, defaults, list[i].Children);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FinishStates
|
||||
// copies a state block and fixes all state links using the current list of labels
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults, TArray<FState> &StateArray)
|
||||
{
|
||||
static int c=0;
|
||||
int count = StateArray.Size();
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
FState *realstates = new FState[count];
|
||||
int i;
|
||||
int currange;
|
||||
|
||||
memcpy(realstates, &StateArray[0], count*sizeof(FState));
|
||||
actor->OwnedStates = realstates;
|
||||
actor->NumOwnedStates = count;
|
||||
|
||||
// adjust the state pointers
|
||||
// In the case new states are added these must be adjusted, too!
|
||||
FixStatePointers (actor, StateLabels);
|
||||
|
||||
for(i = currange = 0; i < count; i++)
|
||||
{
|
||||
// resolve labels and jumps
|
||||
switch(realstates[i].DefineFlags)
|
||||
{
|
||||
case SDF_STOP: // stop
|
||||
realstates[i].NextState = NULL;
|
||||
break;
|
||||
|
||||
case SDF_WAIT: // wait
|
||||
realstates[i].NextState = &realstates[i];
|
||||
break;
|
||||
|
||||
case SDF_NEXT: // next
|
||||
realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]);
|
||||
break;
|
||||
|
||||
case SDF_INDEX: // loop
|
||||
realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1];
|
||||
break;
|
||||
|
||||
case SDF_LABEL:
|
||||
realstates[i].NextState = ResolveGotoLabel (defaults, actor->Class, (char *)realstates[i].NextState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fix state pointers that are gotos
|
||||
ResolveGotoLabels (actor, defaults, StateLabels);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -227,8 +227,8 @@ player_t::player_t()
|
|||
momy(0),
|
||||
centering(0),
|
||||
turnticks(0),
|
||||
oldbuttons(0),
|
||||
attackdown(0),
|
||||
oldbuttons(0),
|
||||
health(0),
|
||||
inventorytics(0),
|
||||
CurrentPlayerClass(0),
|
||||
|
@ -988,7 +988,7 @@ void APlayerPawn::GiveDefaultInventory ()
|
|||
AddInventory (barmor);
|
||||
|
||||
// Now add the items from the DECORATE definition
|
||||
FDropItem *di = GetDropItems(RUNTIME_TYPE(this));
|
||||
FDropItem *di = GetDropItems();
|
||||
|
||||
while (di)
|
||||
{
|
||||
|
|
|
@ -265,9 +265,7 @@ DWORD R_BlendForColormap (DWORD map)
|
|||
|
||||
void R_InitData ()
|
||||
{
|
||||
FTexture::InitGrayMap();
|
||||
StartScreen->Progress();
|
||||
TexMan.Init();
|
||||
|
||||
V_InitFonts();
|
||||
StartScreen->Progress();
|
||||
|
|
|
@ -54,8 +54,8 @@ extern bool LocalKeyboardTurner; // [RH] The local player used the keyboard t
|
|||
extern float WallTMapScale;
|
||||
extern float WallTMapScale2;
|
||||
|
||||
extern int viewwidth;
|
||||
extern int viewheight;
|
||||
extern "C" int viewwidth;
|
||||
extern "C" int viewheight;
|
||||
extern int viewwindowx;
|
||||
extern int viewwindowy;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -342,7 +342,10 @@ int S_PickReplacement (int refid)
|
|||
|
||||
unsigned int S_GetMSLength(FSoundID sound)
|
||||
{
|
||||
if (sound < 0 || sound >= S_sfx.Size()) return 0;
|
||||
if ((unsigned int)sound >= S_sfx.Size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sfxinfo_t *sfx = &S_sfx[sound];
|
||||
|
||||
|
|
|
@ -1478,6 +1478,7 @@ void S_RelinkSound (AActor *from, AActor *to)
|
|||
}
|
||||
else
|
||||
{
|
||||
chan->Actor = NULL;
|
||||
S_StopChannel(chan);
|
||||
}
|
||||
}
|
||||
|
@ -1778,7 +1779,7 @@ static void S_SetListener(SoundListener &listener, AActor *listenactor)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
float S_GetRolloff(FRolloffInfo *rolloff, float distance)
|
||||
float S_GetRolloff(FRolloffInfo *rolloff, float distance, bool logarithmic)
|
||||
{
|
||||
if (rolloff == NULL)
|
||||
{
|
||||
|
@ -1803,13 +1804,27 @@ float S_GetRolloff(FRolloffInfo *rolloff, float distance)
|
|||
{
|
||||
volume = S_SoundCurve[int(S_SoundCurveSize * (1 - volume))] / 127.f;
|
||||
}
|
||||
if (rolloff->RolloffType == ROLLOFF_Linear)
|
||||
if (logarithmic)
|
||||
{
|
||||
return volume;
|
||||
if (rolloff->RolloffType == ROLLOFF_Linear)
|
||||
{
|
||||
return volume;
|
||||
}
|
||||
else
|
||||
{
|
||||
return float((powf(10.f, volume) - 1.) / 9.);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (powf(10.f, volume) - 1.f) / 9.f;
|
||||
if (rolloff->RolloffType == ROLLOFF_Linear)
|
||||
{
|
||||
return float(log10(9. * volume + 1.));
|
||||
}
|
||||
else
|
||||
{
|
||||
return volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "v_video.h"
|
||||
|
||||
#include "d_main.h"
|
||||
#include "d_event.h"
|
||||
#include "d_gui.h"
|
||||
#include "c_console.h"
|
||||
#include "c_cvars.h"
|
||||
|
|
|
@ -54,6 +54,11 @@
|
|||
#include "errors.h"
|
||||
#include "version.h"
|
||||
#include "w_wad.h"
|
||||
#include "g_level.h"
|
||||
#include "r_state.h"
|
||||
#include "cmdlib.h"
|
||||
#include "r_main.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -180,7 +185,7 @@ static int DoomSpecificInfo (char *buffer, char *end)
|
|||
|
||||
if (!viewactive)
|
||||
{
|
||||
buffer += snprintf (buffer+p, size-p, "\n\nView not active.");
|
||||
p += snprintf (buffer+p, size-p, "\n\nView not active.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "SDL.h"
|
||||
#include "doomtype.h"
|
||||
#include "doomstat.h"
|
||||
#include "version.h"
|
||||
#include "doomdef.h"
|
||||
#include "cmdlib.h"
|
||||
|
@ -61,6 +62,9 @@
|
|||
#include "hardware.h"
|
||||
#include "gameconfigfile.h"
|
||||
|
||||
#include "m_fixed.h"
|
||||
#include "g_level.h"
|
||||
|
||||
EXTERN_CVAR (String, language)
|
||||
|
||||
extern "C"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "v_video.h"
|
||||
#include "v_pfx.h"
|
||||
#include "stats.h"
|
||||
|
||||
#include "v_palette.h"
|
||||
#include "sdlvideo.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "st_start.h"
|
||||
#include "doomdef.h"
|
||||
#include "i_system.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ extern HWND Window;
|
|||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#include <malloc.h>
|
||||
|
||||
#include "templates.h"
|
||||
#include "fmodsound.h"
|
||||
|
@ -2039,11 +2040,11 @@ float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNEL *channel, float
|
|||
|
||||
if (GRolloff != NULL)
|
||||
{
|
||||
return S_GetRolloff(GRolloff, distance * GDistScale);
|
||||
return S_GetRolloff(GRolloff, distance * GDistScale, true);
|
||||
}
|
||||
else if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL)
|
||||
{
|
||||
return S_GetRolloff(&schan->Rolloff, distance * schan->DistanceScale);
|
||||
return S_GetRolloff(&schan->Rolloff, distance * schan->DistanceScale, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -141,7 +141,7 @@ void I_InitSound ();
|
|||
void I_ShutdownSound ();
|
||||
|
||||
void S_ChannelEnded(FISoundChannel *schan);
|
||||
float S_GetRolloff(FRolloffInfo *rolloff, float distance);
|
||||
float S_GetRolloff(FRolloffInfo *rolloff, float distance, bool logarithmic);
|
||||
FISoundChannel *S_GetChannel(void *syschan);
|
||||
|
||||
extern ReverbContainer *DefaultEnvironments[26];
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include <malloc.h>
|
||||
#include "i_musicinterns.h"
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
|
|
|
@ -346,7 +346,7 @@ bool ST_Responder (event_t *ev)
|
|||
static int counts[] = { countof(DoomCheats), countof(HereticCheats), countof(HexenCheats),
|
||||
countof(StrifeCheats), countof(ChexCheats), countof(SpecialCheats) };
|
||||
|
||||
for (int i=0; i<countof(cheatlists); i++)
|
||||
for (size_t i=0; i<countof(cheatlists); i++)
|
||||
{
|
||||
if (CheatCheckList(ev, cheatlists[i], counts[i])) return true;
|
||||
}
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
// This file was automatically generated by the
|
||||
// updaterevision tool. Do not edit by hand.
|
||||
|
||||
#define ZD_SVN_REVISION_STRING "1229"
|
||||
#define ZD_SVN_REVISION_NUMBER 1229
|
||||
#define ZD_SVN_REVISION_STRING "1246"
|
||||
#define ZD_SVN_REVISION_NUMBER 1246
|
||||
|
|
|
@ -953,16 +953,11 @@ void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump)
|
|||
}
|
||||
|
||||
|
||||
static bool Check(char *& range, char c)
|
||||
{
|
||||
while (isspace(*range)) range++;
|
||||
if (*range==c)
|
||||
{
|
||||
range++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
|
||||
{
|
||||
|
@ -1056,46 +1051,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
|
|||
do
|
||||
{
|
||||
sc.MustGetString();
|
||||
|
||||
char *range = sc.String;
|
||||
int start,end;
|
||||
|
||||
start=strtol(range, &range, 10);
|
||||
if (!Check(range, ':')) return;
|
||||
end=strtol(range, &range, 10);
|
||||
if (!Check(range, '=')) return;
|
||||
if (!Check(range, '['))
|
||||
{
|
||||
int pal1,pal2;
|
||||
|
||||
pal1=strtol(range, &range, 10);
|
||||
if (!Check(range, ':')) return;
|
||||
pal2=strtol(range, &range, 10);
|
||||
|
||||
part.Translation->AddIndexRange(start, end, pal1, pal2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// translation using RGB values
|
||||
int r1,g1,b1,r2,g2,b2;
|
||||
|
||||
r1=strtol(range, &range, 10);
|
||||
if (!Check(range, ',')) return;
|
||||
g1=strtol(range, &range, 10);
|
||||
if (!Check(range, ',')) return;
|
||||
b1=strtol(range, &range, 10);
|
||||
if (!Check(range, ']')) return;
|
||||
if (!Check(range, ':')) return;
|
||||
if (!Check(range, '[')) return;
|
||||
r2=strtol(range, &range, 10);
|
||||
if (!Check(range, ',')) return;
|
||||
g2=strtol(range, &range, 10);
|
||||
if (!Check(range, ',')) return;
|
||||
b2=strtol(range, &range, 10);
|
||||
if (!Check(range, ']')) return;
|
||||
|
||||
part.Translation->AddColorRange(start, end, r1, g1, b1, r2, g2, b2);
|
||||
}
|
||||
part.Translation->AddToTranslation(sc.String);
|
||||
}
|
||||
while (sc.CheckString(","));
|
||||
}
|
||||
|
@ -1161,6 +1117,11 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Constructor for text based multipatch definitions
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
|
||||
: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false)
|
||||
|
|
|
@ -330,33 +330,6 @@ void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, b
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FTextureManager :: AddPatch
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FTextureID FTextureManager::AddPatch (const char *patchname, int namespc, bool tryany)
|
||||
{
|
||||
if (patchname == NULL)
|
||||
{
|
||||
return FTextureID(-1);
|
||||
}
|
||||
FTextureID texnum = CheckForTexture (patchname, FTexture::TEX_MiscPatch, tryany);
|
||||
|
||||
if (texnum.Exists())
|
||||
{
|
||||
return texnum;
|
||||
}
|
||||
int lumpnum = Wads.CheckNumForName (patchname, namespc==ns_global? ns_graphics:namespc);
|
||||
if (lumpnum < 0)
|
||||
{
|
||||
return FTextureID(-1);
|
||||
}
|
||||
|
||||
return CreateTexture (lumpnum, FTexture::TEX_MiscPatch);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FTextureManager :: AddGroup
|
||||
|
@ -440,11 +413,6 @@ void FTextureManager::AddHiresTextures (int wadnum)
|
|||
{
|
||||
int amount = ListTextures(name, tlist);
|
||||
if (amount == 0)
|
||||
{
|
||||
FTextureID oldtex = AddPatch(name);
|
||||
if (oldtex.Exists()) tlist.Push(oldtex);
|
||||
}
|
||||
if (tlist.Size() == 0)
|
||||
{
|
||||
// A texture with this name does not yet exist
|
||||
FTexture * newtex = FTexture::CreateTexture (firsttx, FTexture::TEX_Any);
|
||||
|
@ -519,11 +487,6 @@ void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname)
|
|||
|
||||
tlist.Clear();
|
||||
int amount = ListTextures(sc.String, tlist);
|
||||
if (amount == 0)
|
||||
{
|
||||
FTextureID oldtex = AddPatch(sc.String);
|
||||
if (oldtex.Exists()) tlist.Push(FTextureID(oldtex));
|
||||
}
|
||||
FName texname = sc.String;
|
||||
|
||||
sc.MustGetString();
|
||||
|
@ -624,6 +587,10 @@ void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname)
|
|||
{
|
||||
ParseXTexture(sc, FTexture::TEX_Flat);
|
||||
}
|
||||
else if (sc.Compare("graphic"))
|
||||
{
|
||||
ParseXTexture(sc, FTexture::TEX_MiscPatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -843,6 +810,8 @@ void FTextureManager::SortTexturesByType(int start, int end)
|
|||
|
||||
void FTextureManager::Init()
|
||||
{
|
||||
FTexture::InitGrayMap();
|
||||
|
||||
int wadcnt = Wads.GetNumWads();
|
||||
for(int i = 0; i< wadcnt; i++)
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
|
||||
FWarpTexture::FWarpTexture (FTexture *source)
|
||||
: SourcePic (source), Pixels (0), Spans (0), GenTime (0), Speed (1.f)
|
||||
: GenTime (0), SourcePic (source), Pixels (0), Spans (0), Speed (1.f)
|
||||
{
|
||||
CopySize(source);
|
||||
bNoDecals = source->bNoDecals;
|
||||
|
|
|
@ -103,8 +103,8 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name);
|
|||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||
TArray<FState> &states, FExtraInfo &extra, EDefinitionType def, FScanner &sc);
|
||||
static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
||||
FExtraInfo &extra, EDefinitionType def, FScanner &sc);
|
||||
static void ParseSpriteFrames (FActorInfo *info, TArray<FState> &states, FScanner &sc);
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
@ -123,97 +123,6 @@ static const char *RenderStyles[] =
|
|||
NULL
|
||||
};
|
||||
|
||||
static const char *FlagNames1[] =
|
||||
{
|
||||
"*",
|
||||
"Solid",
|
||||
"*",
|
||||
"NoSector",
|
||||
|
||||
"NoBlockmap",
|
||||
"*",
|
||||
"*",
|
||||
"*",
|
||||
|
||||
"SpawnCeiling",
|
||||
"NoGravity",
|
||||
"*",
|
||||
"*",
|
||||
|
||||
"*",
|
||||
"*",
|
||||
"*",
|
||||
"*",
|
||||
|
||||
"*",
|
||||
"*",
|
||||
"Shadow",
|
||||
"NoBlood",
|
||||
|
||||
"*",
|
||||
"*",
|
||||
"*",
|
||||
"CountItem",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *FlagNames2[] =
|
||||
{
|
||||
"LowGravity",
|
||||
"WindThrust",
|
||||
"*",
|
||||
"*",
|
||||
|
||||
"*",
|
||||
"FloorClip",
|
||||
"SpawnFloat",
|
||||
"NoTeleport",
|
||||
|
||||
"Ripper",
|
||||
"Pushable",
|
||||
"SlidesOnWalls",
|
||||
"*",
|
||||
|
||||
"CanPass",
|
||||
"CannotPush",
|
||||
"ThruGhost",
|
||||
"*",
|
||||
|
||||
"FireDamage",
|
||||
"NoDamageThrust",
|
||||
"Telestomp",
|
||||
"FloatBob",
|
||||
|
||||
"*",
|
||||
"ActivateImpact",
|
||||
"CanPushWalls",
|
||||
"ActivateMCross",
|
||||
|
||||
"ActivatePCross",
|
||||
"*",
|
||||
"*",
|
||||
"*",
|
||||
|
||||
"*",
|
||||
"*",
|
||||
"*",
|
||||
"Reflective",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *FlagNames3[] =
|
||||
{
|
||||
"FloorHugger",
|
||||
"CeilingHugger",
|
||||
"*",
|
||||
"*",
|
||||
|
||||
"*",
|
||||
"*",
|
||||
"DontSplash",
|
||||
NULL
|
||||
};
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
|
@ -226,11 +135,11 @@ static const char *FlagNames3[] =
|
|||
|
||||
void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
||||
{
|
||||
TArray<FState> states;
|
||||
Baggage bag;
|
||||
FExtraInfo extra;
|
||||
FActorInfo *info;
|
||||
PClass *type;
|
||||
PClass *parent;
|
||||
FActorInfo *info;
|
||||
FName typeName;
|
||||
|
||||
if (def == DEF_Pickup) parent = RUNTIME_CLASS(AFakeInventory);
|
||||
|
@ -239,76 +148,17 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
|||
sc.MustGetString();
|
||||
typeName = FName(sc.String);
|
||||
type = parent->CreateDerivedClass (typeName, parent->Size);
|
||||
info = type->ActorInfo;
|
||||
info->GameFilter = 0x80;
|
||||
MakeStateDefines(parent->ActorInfo->StateList);
|
||||
ResetBaggage(&bag, parent);
|
||||
info = bag.Info = type->ActorInfo;
|
||||
|
||||
// There isn't a single WAD out there which uses game filters with old style
|
||||
// decorations so this may as well be disabled. Without this option is is much
|
||||
// easier to detect incorrect declarations
|
||||
#if 0
|
||||
sc.MustGetString ();
|
||||
while (!sc.Compare ("{"))
|
||||
{
|
||||
if (sc.Compare ("Doom"))
|
||||
{
|
||||
info->GameFilter |= GAME_Doom;
|
||||
}
|
||||
else if (sc.Compare ("Heretic"))
|
||||
{
|
||||
info->GameFilter |= GAME_Heretic;
|
||||
}
|
||||
else if (sc.Compare ("Hexen"))
|
||||
{
|
||||
info->GameFilter |= GAME_Hexen;
|
||||
}
|
||||
else if (sc.Compare ("Raven"))
|
||||
{
|
||||
info->GameFilter |= GAME_Raven;
|
||||
}
|
||||
else if (sc.Compare ("Strife"))
|
||||
{
|
||||
info->GameFilter |= GAME_Strife;
|
||||
}
|
||||
else if (sc.Compare ("Any"))
|
||||
{
|
||||
info->GameFilter = GAME_Any;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (def != DEF_Decoration || info->GameFilter != 0x80)
|
||||
{
|
||||
sc.ScriptError ("Unknown game type %s in %s", sc.String, typeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this is a regular decoration (without preceding keyword) and no game
|
||||
// filters defined this is more likely a general syntax error so output a
|
||||
// more meaningful message.
|
||||
sc.ScriptError ("Syntax error: Unknown identifier '%s'", typeName.GetChars());
|
||||
}
|
||||
}
|
||||
sc.MustGetString ();
|
||||
}
|
||||
if (info->GameFilter == 0x80)
|
||||
{
|
||||
info->GameFilter = GAME_Any;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->GameFilter &= ~0x80;
|
||||
}
|
||||
#else
|
||||
info->GameFilter = GAME_Any;
|
||||
sc.MustGetStringName("{");
|
||||
#endif
|
||||
|
||||
states.Clear ();
|
||||
memset (&extra, 0, sizeof(extra));
|
||||
ParseInsideDecoration (info, (AActor *)(type->Defaults), states, extra, def, sc);
|
||||
ParseInsideDecoration (bag, (AActor *)(type->Defaults), extra, def, sc);
|
||||
|
||||
info->NumOwnedStates = states.Size();
|
||||
if (info->NumOwnedStates == 0)
|
||||
bag.Info->NumOwnedStates = bag.StateArray.Size();
|
||||
if (bag.Info->NumOwnedStates == 0)
|
||||
{
|
||||
sc.ScriptError ("%s does not define any animation frames", typeName.GetChars() );
|
||||
}
|
||||
|
@ -328,13 +178,13 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
|||
if (extra.IceDeathEnd != 0)
|
||||
{
|
||||
// Make a copy of the final frozen frame for A_FreezeDeathChunks
|
||||
FState icecopy = states[extra.IceDeathEnd-1];
|
||||
states.Push (icecopy);
|
||||
FState icecopy = bag.StateArray[extra.IceDeathEnd-1];
|
||||
bag.StateArray.Push (icecopy);
|
||||
info->NumOwnedStates += 1;
|
||||
}
|
||||
|
||||
info->OwnedStates = new FState[info->NumOwnedStates];
|
||||
memcpy (info->OwnedStates, &states[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
|
||||
memcpy (info->OwnedStates, &bag.StateArray[0], info->NumOwnedStates * sizeof(info->OwnedStates[0]));
|
||||
if (info->NumOwnedStates == 1)
|
||||
{
|
||||
info->OwnedStates->Tics = -1;
|
||||
|
@ -395,7 +245,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
|||
if (extra.DeathHeight == 0) extra.DeathHeight = ((AActor*)(type->Defaults))->height;
|
||||
info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, extra.DeathHeight);
|
||||
}
|
||||
AddState("Death", &info->OwnedStates[extra.DeathStart]);
|
||||
bag.statedef.AddState("Death", &info->OwnedStates[extra.DeathStart]);
|
||||
}
|
||||
|
||||
// Burn states are the same as death states, except they can optionally terminate
|
||||
|
@ -433,7 +283,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
|||
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->height;
|
||||
type->Meta.SetMetaFixed (AMETA_BurnHeight, extra.BurnHeight);
|
||||
|
||||
AddState("Burn", &info->OwnedStates[extra.FireDeathStart]);
|
||||
bag.statedef.AddState("Burn", &info->OwnedStates[extra.FireDeathStart]);
|
||||
}
|
||||
|
||||
// Ice states are similar to burn and death, except their final frame enters
|
||||
|
@ -454,11 +304,11 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
|||
info->OwnedStates[i].Tics = 1;
|
||||
info->OwnedStates[i].Misc1 = 0;
|
||||
info->OwnedStates[i].SetAction(FindGlobalActionFunction("A_FreezeDeathChunks"));
|
||||
AddState("Ice", &info->OwnedStates[extra.IceDeathStart]);
|
||||
bag.statedef.AddState("Ice", &info->OwnedStates[extra.IceDeathStart]);
|
||||
}
|
||||
else if (extra.bGenericIceDeath)
|
||||
{
|
||||
AddState("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath));
|
||||
bag.statedef.AddState("Ice", RUNTIME_CLASS(AActor)->ActorInfo->FindState(NAME_GenericFreezeDeath));
|
||||
}
|
||||
}
|
||||
if (def == DEF_BreakableDecoration)
|
||||
|
@ -469,8 +319,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
|||
{
|
||||
((AActor *)(type->Defaults))->flags |= MF_DROPOFF|MF_MISSILE;
|
||||
}
|
||||
AddState("Spawn", &info->OwnedStates[extra.SpawnStart]);
|
||||
InstallStates (info, ((AActor *)(type->Defaults)));
|
||||
bag.statedef.AddState("Spawn", &info->OwnedStates[extra.SpawnStart]);
|
||||
bag.statedef.InstallStates (info, ((AActor *)(type->Defaults)));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -481,8 +331,8 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
||||
TArray<FState> &states, FExtraInfo &extra, EDefinitionType def, FScanner &sc)
|
||||
static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
||||
FExtraInfo &extra, EDefinitionType def, FScanner &sc)
|
||||
{
|
||||
AFakeInventory *const inv = static_cast<AFakeInventory *>(defaults);
|
||||
char sprite[5] = "TNT1";
|
||||
|
@ -497,7 +347,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
|||
{
|
||||
sc.ScriptError ("DoomEdNum must be in the range [-1,32767]");
|
||||
}
|
||||
info->DoomEdNum = (SWORD)sc.Number;
|
||||
bag.Info->DoomEdNum = (SWORD)sc.Number;
|
||||
}
|
||||
else if (sc.Compare ("SpawnNum"))
|
||||
{
|
||||
|
@ -506,7 +356,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
|||
{
|
||||
sc.ScriptError ("SpawnNum must be in the range [0,255]");
|
||||
}
|
||||
info->SpawnID = (BYTE)sc.Number;
|
||||
bag.Info->SpawnID = (BYTE)sc.Number;
|
||||
}
|
||||
else if (sc.Compare ("Sprite") || (
|
||||
(def == DEF_BreakableDecoration || def == DEF_Projectile) &&
|
||||
|
@ -531,31 +381,31 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
|||
else if (sc.Compare ("Frames"))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
extra.SpawnStart = states.Size();
|
||||
ParseSpriteFrames (info, states, sc);
|
||||
extra.SpawnEnd = states.Size();
|
||||
extra.SpawnStart = bag.StateArray.Size();
|
||||
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||
extra.SpawnEnd = bag.StateArray.Size();
|
||||
}
|
||||
else if ((def == DEF_BreakableDecoration || def == DEF_Projectile) &&
|
||||
sc.Compare ("DeathFrames"))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
extra.DeathStart = states.Size();
|
||||
ParseSpriteFrames (info, states, sc);
|
||||
extra.DeathEnd = states.Size();
|
||||
extra.DeathStart = bag.StateArray.Size();
|
||||
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||
extra.DeathEnd = bag.StateArray.Size();
|
||||
}
|
||||
else if (def == DEF_BreakableDecoration && sc.Compare ("IceDeathFrames"))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
extra.IceDeathStart = states.Size();
|
||||
ParseSpriteFrames (info, states, sc);
|
||||
extra.IceDeathEnd = states.Size();
|
||||
extra.IceDeathStart = bag.StateArray.Size();
|
||||
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||
extra.IceDeathEnd = bag.StateArray.Size();
|
||||
}
|
||||
else if (def == DEF_BreakableDecoration && sc.Compare ("BurnDeathFrames"))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
extra.FireDeathStart = states.Size();
|
||||
ParseSpriteFrames (info, states, sc);
|
||||
extra.FireDeathEnd = states.Size();
|
||||
extra.FireDeathStart = bag.StateArray.Size();
|
||||
ParseSpriteFrames (bag.Info, bag.StateArray, sc);
|
||||
extra.FireDeathEnd = bag.StateArray.Size();
|
||||
}
|
||||
else if (def == DEF_BreakableDecoration && sc.Compare ("GenericIceDeath"))
|
||||
{
|
||||
|
@ -612,18 +462,18 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
|||
else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number);
|
||||
bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionRadius, sc.Number);
|
||||
extra.bExplosive = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number);
|
||||
bag.Info->Class->Meta.SetMetaInt(ACMETA_ExplosionDamage, sc.Number);
|
||||
extra.bExplosive = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter"))
|
||||
{
|
||||
info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true);
|
||||
bag.Info->Class->Meta.SetMetaInt(ACMETA_DontHurtShooter, true);
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("Damage"))
|
||||
{
|
||||
|
@ -708,7 +558,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
|||
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String);
|
||||
bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc.String);
|
||||
}
|
||||
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
|
||||
{
|
||||
|
@ -724,23 +574,7 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
|||
}
|
||||
else if (sc.String[0] != '*')
|
||||
{
|
||||
int bit = sc.MatchString (FlagNames1);
|
||||
if (bit != -1)
|
||||
{
|
||||
defaults->flags |= 1 << bit;
|
||||
}
|
||||
else if ((bit = sc.MatchString (FlagNames2)) != -1)
|
||||
{
|
||||
defaults->flags2 |= 1 << bit;
|
||||
}
|
||||
else if ((bit = sc.MatchString (FlagNames3)) != -1)
|
||||
{
|
||||
defaults->flags3 |= 1 << bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError (NULL);
|
||||
}
|
||||
HandleActorFlag(sc, bag, sc.String, NULL, '+');
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -752,16 +586,16 @@ static void ParseInsideDecoration (FActorInfo *info, AActor *defaults,
|
|||
unsigned int i;
|
||||
int spr = GetSpriteIndex(sprite);
|
||||
|
||||
for (i = 0; i < states.Size(); ++i)
|
||||
for (i = 0; i < bag.StateArray.Size(); ++i)
|
||||
{
|
||||
states[i].sprite = spr;
|
||||
bag.StateArray[i].sprite = spr;
|
||||
}
|
||||
if (extra.DeathSprite[0] && extra.DeathEnd != 0)
|
||||
{
|
||||
int spr = GetSpriteIndex(extra.DeathSprite);
|
||||
for (i = extra.DeathStart; i < extra.DeathEnd; ++i)
|
||||
{
|
||||
states[i].sprite = spr;
|
||||
bag.StateArray[i].sprite = spr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,82 +68,6 @@
|
|||
|
||||
const PClass *QuestItemClasses[31];
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ActorConstDef
|
||||
//
|
||||
// Parses a constant definition.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls)
|
||||
{
|
||||
// Read the type and make sure it's int.
|
||||
// (Maybe there will be other types later.)
|
||||
sc.MustGetToken(TK_Int);
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
FName symname = sc.String;
|
||||
sc.MustGetToken('=');
|
||||
int expr = ParseExpression (sc, false, cls);
|
||||
sc.MustGetToken(';');
|
||||
|
||||
int val = EvalExpressionI (expr, NULL, cls);
|
||||
PSymbolConst *sym = new PSymbolConst;
|
||||
sym->SymbolName = symname;
|
||||
sym->SymbolType = SYM_Const;
|
||||
sym->Value = val;
|
||||
if (symt->AddSymbol (sym) == NULL)
|
||||
{
|
||||
delete sym;
|
||||
sc.ScriptError ("'%s' is already defined in class '%s'.",
|
||||
symname.GetChars(), cls->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ActorEnumDef
|
||||
//
|
||||
// Parses an enum definition.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls)
|
||||
{
|
||||
int currvalue = 0;
|
||||
|
||||
sc.MustGetToken('{');
|
||||
while (!sc.CheckToken('}'))
|
||||
{
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
FName symname = sc.String;
|
||||
if (sc.CheckToken('='))
|
||||
{
|
||||
int expr = ParseExpression(sc, false, cls);
|
||||
currvalue = EvalExpressionI(expr, NULL, cls);
|
||||
}
|
||||
PSymbolConst *sym = new PSymbolConst;
|
||||
sym->SymbolName = symname;
|
||||
sym->SymbolType = SYM_Const;
|
||||
sym->Value = currvalue;
|
||||
if (symt->AddSymbol (sym) == NULL)
|
||||
{
|
||||
delete sym;
|
||||
sc.ScriptError ("'%s' is already defined in class '%s'.",
|
||||
symname.GetChars(), cls->TypeName.GetChars());
|
||||
}
|
||||
// This allows a comma after the last value but doesn't enforce it.
|
||||
if (sc.CheckToken('}')) break;
|
||||
sc.MustGetToken(',');
|
||||
currvalue++;
|
||||
}
|
||||
sc.MustGetToken(';');
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ParseParameter
|
||||
|
@ -245,8 +169,8 @@ int ParseParameter(FScanner &sc, PClass *cls, char type, bool constant)
|
|||
// be checked here.
|
||||
JumpParameters.Push(NAME_None);
|
||||
}
|
||||
TArray<FName> names;
|
||||
MakeStateNameList(statestring, &names);
|
||||
|
||||
TArray<FName> &names = MakeStateNameList(statestring);
|
||||
|
||||
if (stype != NULL)
|
||||
{
|
||||
|
@ -409,7 +333,8 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
|
|||
if (hasdefaults)
|
||||
{
|
||||
sym->defaultparameterindex = StateParameters.Size();
|
||||
for(int i = 0; i < DefaultParams.Size(); i++) StateParameters.Push(DefaultParams[i]);
|
||||
for(unsigned int i = 0; i < DefaultParams.Size(); i++)
|
||||
StateParameters.Push(DefaultParams[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -428,123 +353,63 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
|
|||
// Starts a new actor definition
|
||||
//
|
||||
//==========================================================================
|
||||
static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *bag)
|
||||
static FActorInfo *CreateNewActor(FName typeName, FName parentName, FName replaceName,
|
||||
int DoomEdNum, bool native)
|
||||
{
|
||||
FName typeName;
|
||||
const PClass *replacee = NULL;
|
||||
int DoomEdNum = -1;
|
||||
PClass *ti = NULL;
|
||||
FActorInfo *info = NULL;
|
||||
|
||||
// Get actor name
|
||||
sc.MustGetString();
|
||||
|
||||
char *colon = strchr(sc.String, ':');
|
||||
if (colon != NULL)
|
||||
{
|
||||
*colon++ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
if (PClass::FindClass (sc.String) != NULL)
|
||||
{
|
||||
sc.ScriptError ("Actor %s is already defined.", sc.String);
|
||||
}
|
||||
*/
|
||||
|
||||
typeName = sc.String;
|
||||
|
||||
PClass *parent = RUNTIME_CLASS(AActor);
|
||||
if (parentc)
|
||||
{
|
||||
*parentc = NULL;
|
||||
|
||||
// Do some tweaking so that a definition like 'Actor:Parent' which is read as a single token is recognized as well
|
||||
// without having resort to C-mode (which disallows periods in actor names.)
|
||||
if (colon == NULL)
|
||||
{
|
||||
sc.MustGetString ();
|
||||
if (sc.String[0]==':')
|
||||
{
|
||||
colon = sc.String + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (colon != NULL)
|
||||
{
|
||||
if (colon[0] == 0)
|
||||
{
|
||||
sc.MustGetString ();
|
||||
colon = sc.String;
|
||||
}
|
||||
}
|
||||
|
||||
if (colon != NULL)
|
||||
{
|
||||
parent = const_cast<PClass *> (PClass::FindClass (colon));
|
||||
|
||||
if (parent == NULL)
|
||||
{
|
||||
sc.ScriptError ("Parent type '%s' not found", colon);
|
||||
}
|
||||
else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor)))
|
||||
{
|
||||
sc.ScriptError ("Parent type '%s' is not an actor", colon);
|
||||
}
|
||||
else if (parent->ActorInfo == NULL)
|
||||
{
|
||||
sc.ScriptError ("uninitialized parent type '%s'", colon);
|
||||
}
|
||||
else
|
||||
{
|
||||
*parentc = parent->ActorInfo;
|
||||
}
|
||||
if (parentName != NAME_None)
|
||||
{
|
||||
parent = const_cast<PClass *> (PClass::FindClass (parentName));
|
||||
|
||||
if (parent == NULL)
|
||||
{
|
||||
I_Error ("Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars());
|
||||
}
|
||||
else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor)))
|
||||
{
|
||||
I_Error ("Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars());
|
||||
}
|
||||
else if (parent->ActorInfo == NULL)
|
||||
{
|
||||
I_Error ("uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars());
|
||||
}
|
||||
else sc.UnGet();
|
||||
}
|
||||
|
||||
// Check for "replaces"
|
||||
if (sc.CheckString ("replaces"))
|
||||
if (replaceName != NAME_None)
|
||||
{
|
||||
|
||||
// Get actor name
|
||||
sc.MustGetString ();
|
||||
replacee = PClass::FindClass (sc.String);
|
||||
replacee = PClass::FindClass (replaceName);
|
||||
|
||||
if (replacee == NULL)
|
||||
{
|
||||
sc.ScriptError ("Replaced type '%s' not found", sc.String);
|
||||
I_Error ("Replaced type '%s' not found in %s", replaceName.GetChars(), typeName.GetChars());
|
||||
}
|
||||
else if (replacee->ActorInfo == NULL)
|
||||
{
|
||||
sc.ScriptError ("Replaced type '%s' is not an actor", sc.String);
|
||||
I_Error ("Replaced type '%s' is not an actor in %s", replaceName.GetChars(), typeName.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
// Now, after the actor names have been parsed, it is time to switch to C-mode
|
||||
// for the rest of the actor definition.
|
||||
sc.SetCMode (true);
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
if (sc.Number>=-1 && sc.Number<32768) DoomEdNum = sc.Number;
|
||||
else sc.ScriptError ("DoomEdNum must be in the range [-1,32767]");
|
||||
}
|
||||
|
||||
if (sc.CheckString("native"))
|
||||
if (native)
|
||||
{
|
||||
ti = (PClass*)PClass::FindClass(typeName);
|
||||
if (ti == NULL)
|
||||
{
|
||||
sc.ScriptError("Unknown native class '%s'", typeName.GetChars());
|
||||
I_Error("Unknown native class '%s'", typeName.GetChars());
|
||||
}
|
||||
else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass())
|
||||
{
|
||||
sc.ScriptError("Native class '%s' does not inherit from '%s'",
|
||||
typeName.GetChars(),parent->TypeName.GetChars());
|
||||
I_Error("Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars());
|
||||
}
|
||||
else if (ti->ActorInfo != NULL)
|
||||
{
|
||||
sc.ScriptMessage("Redefinition of internal class '%s'", typeName.GetChars());
|
||||
I_Error("Redefinition of internal class '%s'", typeName.GetChars());
|
||||
}
|
||||
ti->InitializeActorInfo();
|
||||
info = ti->ActorInfo;
|
||||
|
@ -555,11 +420,6 @@ static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *b
|
|||
info = ti->ActorInfo;
|
||||
}
|
||||
|
||||
MakeStateDefines(parent->ActorInfo->StateList);
|
||||
|
||||
ResetBaggage (bag);
|
||||
bag->Info = info;
|
||||
|
||||
info->DoomEdNum = -1;
|
||||
if (parent->ActorInfo->DamageFactors != NULL)
|
||||
{
|
||||
|
@ -580,10 +440,98 @@ static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *b
|
|||
ti->ActorInfo->Replacee = replacee->ActorInfo;
|
||||
}
|
||||
|
||||
info->DoomEdNum = DoomEdNum;
|
||||
if (DoomEdNum > 0) info->DoomEdNum = DoomEdNum;
|
||||
return info;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Starts a new actor definition
|
||||
//
|
||||
//==========================================================================
|
||||
static FActorInfo *ParseActorHeader(FScanner &sc, Baggage *bag)
|
||||
{
|
||||
FName typeName;
|
||||
FName parentName;
|
||||
FName replaceName;
|
||||
bool native = false;
|
||||
int DoomEdNum = -1;
|
||||
|
||||
// Get actor name
|
||||
sc.MustGetString();
|
||||
|
||||
char *colon = strchr(sc.String, ':');
|
||||
if (colon != NULL)
|
||||
{
|
||||
*colon++ = 0;
|
||||
}
|
||||
|
||||
typeName = sc.String;
|
||||
|
||||
// Do some tweaking so that a definition like 'Actor:Parent' which is read as a single token is recognized as well
|
||||
// without having resort to C-mode (which disallows periods in actor names.)
|
||||
if (colon == NULL)
|
||||
{
|
||||
sc.MustGetString ();
|
||||
if (sc.String[0]==':')
|
||||
{
|
||||
colon = sc.String + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (colon != NULL)
|
||||
{
|
||||
if (colon[0] == 0)
|
||||
{
|
||||
sc.MustGetString ();
|
||||
colon = sc.String;
|
||||
}
|
||||
}
|
||||
|
||||
if (colon == NULL)
|
||||
{
|
||||
sc.UnGet();
|
||||
}
|
||||
|
||||
parentName = colon;
|
||||
|
||||
// Check for "replaces"
|
||||
if (sc.CheckString ("replaces"))
|
||||
{
|
||||
// Get actor name
|
||||
sc.MustGetString ();
|
||||
replaceName = sc.String;
|
||||
}
|
||||
|
||||
// Now, after the actor names have been parsed, it is time to switch to C-mode
|
||||
// for the rest of the actor definition.
|
||||
sc.SetCMode (true);
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
if (sc.Number>=-1 && sc.Number<32768) DoomEdNum = sc.Number;
|
||||
else sc.ScriptError ("DoomEdNum must be in the range [-1,32767]");
|
||||
}
|
||||
|
||||
if (sc.CheckString("native"))
|
||||
{
|
||||
native = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
FActorInfo *info = CreateNewActor(typeName, parentName, replaceName, DoomEdNum, native);
|
||||
ResetBaggage (bag, info->Class->ParentClass);
|
||||
bag->Info = info;
|
||||
bag->Lumpnum = sc.LumpNum;
|
||||
return info;
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
sc.ScriptError("%s", err.GetMessage());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Reads an actor definition
|
||||
|
@ -594,64 +542,41 @@ void ParseActor(FScanner &sc)
|
|||
FActorInfo * info=NULL;
|
||||
Baggage bag;
|
||||
|
||||
try
|
||||
info = ParseActorHeader(sc, &bag);
|
||||
sc.MustGetToken('{');
|
||||
while (sc.MustGetAnyToken(), sc.TokenType != '}')
|
||||
{
|
||||
FActorInfo * parent;
|
||||
|
||||
info = CreateNewActor(sc, &parent, &bag);
|
||||
sc.MustGetToken('{');
|
||||
while (sc.MustGetAnyToken(), sc.TokenType != '}')
|
||||
switch (sc.TokenType)
|
||||
{
|
||||
switch (sc.TokenType)
|
||||
{
|
||||
case TK_Action:
|
||||
ParseActionDef (sc, info->Class);
|
||||
break;
|
||||
case TK_Action:
|
||||
ParseActionDef (sc, info->Class);
|
||||
break;
|
||||
|
||||
case TK_Const:
|
||||
ParseConstant (sc, &info->Class->Symbols, info->Class);
|
||||
break;
|
||||
case TK_Const:
|
||||
ParseConstant (sc, &info->Class->Symbols, info->Class);
|
||||
break;
|
||||
|
||||
case TK_Enum:
|
||||
ParseEnum (sc, &info->Class->Symbols, info->Class);
|
||||
break;
|
||||
case TK_Enum:
|
||||
ParseEnum (sc, &info->Class->Symbols, info->Class);
|
||||
break;
|
||||
|
||||
case TK_Identifier:
|
||||
// other identifier related checks here
|
||||
case TK_Projectile: // special case: both keyword and property name
|
||||
ParseActorProperty(sc, bag);
|
||||
break;
|
||||
case TK_Identifier:
|
||||
// other identifier related checks here
|
||||
case TK_Projectile: // special case: both keyword and property name
|
||||
ParseActorProperty(sc, bag);
|
||||
break;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
ParseActorFlag(sc, bag, sc.TokenType);
|
||||
break;
|
||||
|
||||
default:
|
||||
sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars());
|
||||
break;
|
||||
}
|
||||
case '+':
|
||||
case '-':
|
||||
ParseActorFlag(sc, bag, sc.TokenType);
|
||||
break;
|
||||
|
||||
default:
|
||||
sc.ScriptError("Unexpected '%s' in definition of '%s'", sc.String, bag.Info->Class->TypeName.GetChars());
|
||||
break;
|
||||
}
|
||||
|
||||
FinishActor(sc, info, bag);
|
||||
}
|
||||
|
||||
catch(CRecoverableError & e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
// I think this is better than a crash log.
|
||||
#ifndef _DEBUG
|
||||
catch (...)
|
||||
{
|
||||
if (info)
|
||||
sc.ScriptError("Unexpected error during parsing of actor %s", info->Class->TypeName.GetChars());
|
||||
else
|
||||
sc.ScriptError("Unexpected error during parsing of actor definitions");
|
||||
}
|
||||
#endif
|
||||
|
||||
FinishActor(sc, info, bag);
|
||||
sc.SetCMode (false);
|
||||
}
|
||||
|
||||
|
@ -663,10 +588,33 @@ void ParseActor(FScanner &sc)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static int ResolvePointer(const PClass **pPtr, const PClass *owner, const PClass *destclass, const char *description)
|
||||
{
|
||||
fuglyname v;
|
||||
|
||||
v = *pPtr;
|
||||
if (v != NAME_None && v.IsValidName())
|
||||
{
|
||||
*pPtr = PClass::FindClass(v);
|
||||
if (!*pPtr)
|
||||
{
|
||||
Printf("Unknown %s '%s' in '%s'\n", description, v.GetChars(), owner->TypeName.GetChars());
|
||||
return 1;
|
||||
}
|
||||
else if (!(*pPtr)->IsDescendantOf(destclass))
|
||||
{
|
||||
*pPtr = NULL;
|
||||
Printf("Invalid %s '%s' in '%s'\n", description, v.GetChars(), owner->TypeName.GetChars());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FinishThingdef()
|
||||
{
|
||||
unsigned int i;
|
||||
bool isRuntimeActor=false;
|
||||
int errorcount=0;
|
||||
|
||||
for (i = 0;i < PClass::m_Types.Size(); i++)
|
||||
|
@ -676,13 +624,6 @@ void FinishThingdef()
|
|||
// Skip non-actors
|
||||
if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue;
|
||||
|
||||
// Everything coming after the first runtime actor is also a runtime actor
|
||||
// so this check is sufficient
|
||||
if (ti == PClass::m_RuntimeActors[0])
|
||||
{
|
||||
isRuntimeActor=true;
|
||||
}
|
||||
|
||||
AActor *def = GetDefaultByType(ti);
|
||||
|
||||
if (!def)
|
||||
|
@ -701,21 +642,7 @@ void FinishThingdef()
|
|||
if (ti->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
AInventory * defaults=(AInventory *)def;
|
||||
fuglyname v;
|
||||
|
||||
v = defaults->PickupFlash;
|
||||
if (v != NAME_None && v.IsValidName())
|
||||
{
|
||||
defaults->PickupFlash = PClass::FindClass(v);
|
||||
if (isRuntimeActor)
|
||||
{
|
||||
if (!defaults->PickupFlash)
|
||||
{
|
||||
Printf("Unknown pickup flash '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
errorcount += ResolvePointer(&defaults->PickupFlash, ti, RUNTIME_CLASS(AActor), "pickup flash");
|
||||
}
|
||||
|
||||
if (ti->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)) && ti != RUNTIME_CLASS(APowerupGiver))
|
||||
|
@ -757,122 +684,47 @@ void FinishThingdef()
|
|||
if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
||||
{
|
||||
AWeapon * defaults=(AWeapon *)def;
|
||||
fuglyname v;
|
||||
errorcount += ResolvePointer(&defaults->AmmoType1, ti, RUNTIME_CLASS(AAmmo), "ammo type");
|
||||
errorcount += ResolvePointer(&defaults->AmmoType2, ti, RUNTIME_CLASS(AAmmo), "ammo type");
|
||||
errorcount += ResolvePointer(&defaults->SisterWeaponType, ti, RUNTIME_CLASS(AWeapon), "sister weapon type");
|
||||
|
||||
v = defaults->AmmoType1;
|
||||
if (v != NAME_None && v.IsValidName())
|
||||
FState * ready = ti->ActorInfo->FindState(NAME_Ready);
|
||||
FState * select = ti->ActorInfo->FindState(NAME_Select);
|
||||
FState * deselect = ti->ActorInfo->FindState(NAME_Deselect);
|
||||
FState * fire = ti->ActorInfo->FindState(NAME_Fire);
|
||||
|
||||
// Consider any weapon without any valid state abstract and don't output a warning
|
||||
// This is for creating base classes for weapon groups that only set up some properties.
|
||||
if (ready || select || deselect || fire)
|
||||
{
|
||||
defaults->AmmoType1 = PClass::FindClass(v);
|
||||
if (isRuntimeActor)
|
||||
// Do some consistency checks. If these states are undefined the weapon cannot work!
|
||||
if (!ready)
|
||||
{
|
||||
if (!defaults->AmmoType1)
|
||||
{
|
||||
Printf("Unknown ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
else if (defaults->AmmoType1->ParentClass != RUNTIME_CLASS(AAmmo))
|
||||
{
|
||||
Printf("Invalid ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
Printf("Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
if (!select)
|
||||
{
|
||||
Printf("Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
if (!deselect)
|
||||
{
|
||||
Printf("Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
if (!fire)
|
||||
{
|
||||
Printf("Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
}
|
||||
|
||||
v = defaults->AmmoType2;
|
||||
if (v != NAME_None && v.IsValidName())
|
||||
{
|
||||
defaults->AmmoType2 = PClass::FindClass(v);
|
||||
if (isRuntimeActor)
|
||||
{
|
||||
if (!defaults->AmmoType2)
|
||||
{
|
||||
Printf("Unknown ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
else if (defaults->AmmoType2->ParentClass != RUNTIME_CLASS(AAmmo))
|
||||
{
|
||||
Printf("Invalid ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v = defaults->SisterWeaponType;
|
||||
if (v != NAME_None && v.IsValidName())
|
||||
{
|
||||
defaults->SisterWeaponType = PClass::FindClass(v);
|
||||
if (isRuntimeActor)
|
||||
{
|
||||
if (!defaults->SisterWeaponType)
|
||||
{
|
||||
Printf("Unknown sister weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
else if (!defaults->SisterWeaponType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
||||
{
|
||||
Printf("Invalid sister weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isRuntimeActor)
|
||||
{
|
||||
FState * ready = ti->ActorInfo->FindState(NAME_Ready);
|
||||
FState * select = ti->ActorInfo->FindState(NAME_Select);
|
||||
FState * deselect = ti->ActorInfo->FindState(NAME_Deselect);
|
||||
FState * fire = ti->ActorInfo->FindState(NAME_Fire);
|
||||
|
||||
// Consider any weapon without any valid state abstract and don't output a warning
|
||||
// This is for creating base classes for weapon groups that only set up some properties.
|
||||
if (ready || select || deselect || fire)
|
||||
{
|
||||
// Do some consistency checks. If these states are undefined the weapon cannot work!
|
||||
if (!ready)
|
||||
{
|
||||
Printf("Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
if (!select)
|
||||
{
|
||||
Printf("Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
if (!deselect)
|
||||
{
|
||||
Printf("Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
if (!fire)
|
||||
{
|
||||
Printf("Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// same for the weapon type of weapon pieces.
|
||||
else if (ti->IsDescendantOf(RUNTIME_CLASS(AWeaponPiece)))
|
||||
{
|
||||
AWeaponPiece * defaults=(AWeaponPiece *)def;
|
||||
fuglyname v;
|
||||
|
||||
v = defaults->WeaponClass;
|
||||
if (v != NAME_None && v.IsValidName())
|
||||
{
|
||||
defaults->WeaponClass = PClass::FindClass(v);
|
||||
if (!defaults->WeaponClass)
|
||||
{
|
||||
Printf("Unknown weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
else if (!defaults->WeaponClass->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
||||
{
|
||||
Printf("Invalid weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
||||
errorcount++;
|
||||
}
|
||||
}
|
||||
errorcount += ResolvePointer(&defaults->WeaponClass, ti, RUNTIME_CLASS(AWeapon), "weapon type");
|
||||
}
|
||||
}
|
||||
if (errorcount > 0)
|
||||
|
|
|
@ -5,6 +5,24 @@
|
|||
|
||||
class FScanner;
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// A flag descriptor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FFlagDef
|
||||
{
|
||||
int flagbit;
|
||||
const char *name;
|
||||
int structoffset;
|
||||
};
|
||||
|
||||
FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2);
|
||||
void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index);
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This class is for storing a name inside a const PClass* field without
|
||||
|
@ -32,25 +50,72 @@ public:
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// Dropitem list
|
||||
// State parser
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FDropItem
|
||||
extern TArray<int> StateParameters;
|
||||
extern TArray<FName> JumpParameters;
|
||||
|
||||
struct FStateLabels;
|
||||
|
||||
enum EStateDefineFlags
|
||||
{
|
||||
FName Name;
|
||||
int probability;
|
||||
int amount;
|
||||
FDropItem * Next;
|
||||
SDF_NEXT = 0,
|
||||
SDF_STATE = 1,
|
||||
SDF_STOP = 2,
|
||||
SDF_WAIT = 3,
|
||||
SDF_LABEL = 4,
|
||||
SDF_INDEX = 5,
|
||||
};
|
||||
|
||||
FDropItem *GetDropItems(const PClass * cls);
|
||||
struct FStateDefine
|
||||
{
|
||||
FName Label;
|
||||
TArray<FStateDefine> Children;
|
||||
FState *State;
|
||||
BYTE DefineFlags;
|
||||
};
|
||||
|
||||
class FStateDefinitions
|
||||
{
|
||||
TArray<FStateDefine> StateLabels;
|
||||
|
||||
static FStateDefine *FindStateLabelInList(TArray<FStateDefine> &list, FName name, bool create);
|
||||
static FStateLabels *CreateStateLabelList(TArray<FStateDefine> &statelist);
|
||||
static void MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest);
|
||||
static void RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist);
|
||||
FStateDefine *FindStateAddress(const char *name);
|
||||
FState *FindState(const char *name);
|
||||
|
||||
FState *ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name);
|
||||
static void FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list);
|
||||
void ResolveGotoLabels (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
void ClearStateLabels()
|
||||
{
|
||||
StateLabels.Clear();
|
||||
}
|
||||
|
||||
void AddState (const char * statename, FState * state, BYTE defflags = SDF_STATE);
|
||||
void InstallStates(FActorInfo *info, AActor *defaults);
|
||||
int FinishStates (FActorInfo *actor, AActor *defaults, TArray<FState> &StateArray);
|
||||
|
||||
void MakeStateDefines(const PClass *cls);
|
||||
void AddStateDefines(const FStateLabels *list);
|
||||
void RetargetStates (intptr_t count, const char *target);
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Extra info maintained while defining an actor.
|
||||
//
|
||||
//==========================================================================
|
||||
struct FDropItem;
|
||||
|
||||
struct Baggage
|
||||
{
|
||||
|
@ -58,19 +123,23 @@ struct Baggage
|
|||
bool DropItemSet;
|
||||
bool StateSet;
|
||||
int CurrentState;
|
||||
int Lumpnum;
|
||||
FStateDefinitions statedef;
|
||||
TArray<FState> StateArray;
|
||||
|
||||
FDropItem *DropItemList;
|
||||
};
|
||||
|
||||
inline void ResetBaggage (Baggage *bag)
|
||||
inline void ResetBaggage (Baggage *bag, const PClass *stateclass)
|
||||
{
|
||||
bag->DropItemList = NULL;
|
||||
bag->DropItemSet = false;
|
||||
bag->CurrentState = 0;
|
||||
bag->StateSet = false;
|
||||
bag->StateArray.Clear();
|
||||
bag->statedef.MakeStateDefines(stateclass);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Action function lookup
|
||||
|
@ -87,25 +156,8 @@ AFuncDesc * FindFunction(const char * string);
|
|||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// State parser
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
extern TArray<int> StateParameters;
|
||||
extern TArray<FName> JumpParameters;
|
||||
|
||||
void ClearStateLabels();
|
||||
void AddState (const char * statename, FState * state);
|
||||
FState * FindState(AActor * actor, const PClass * type, const char * name);
|
||||
void InstallStates(FActorInfo *info, AActor *defaults);
|
||||
void MakeStateDefines(const FStateLabels *list);
|
||||
void AddStateDefines(const FStateLabels *list);
|
||||
FState *P_GetState(AActor *self, FState *CallingState, int offset);
|
||||
int FinishStates (FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag);
|
||||
int ParseStates(FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag);
|
||||
FState *CheckState(FScanner &sc, PClass *type);
|
||||
|
||||
|
||||
//==========================================================================
|
||||
|
@ -115,6 +167,7 @@ FState *CheckState(FScanner &sc, PClass *type);
|
|||
//==========================================================================
|
||||
|
||||
void ParseActorProperty(FScanner &sc, Baggage &bag);
|
||||
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod);
|
||||
void ParseActorFlag (FScanner &sc, Baggage &bag, int mod);
|
||||
void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag);
|
||||
|
||||
|
@ -156,20 +209,91 @@ enum EDefinitionType
|
|||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma data_seg(".areg$u")
|
||||
#pragma data_seg(".greg$u")
|
||||
#pragma data_seg()
|
||||
|
||||
#define MSVC_ASEG __declspec(allocate(".areg$u"))
|
||||
#define GCC_ASEG
|
||||
#define MSVC_PSEG __declspec(allocate(".greg$u"))
|
||||
#define GCC_PSEG
|
||||
#else
|
||||
#define MSVC_ASEG
|
||||
#define GCC_ASEG __attribute__((section(AREG_SECTION)))
|
||||
#define MSVC_PSEG
|
||||
#define GCC_PSEG __attribute__((section(GREG_SECTION)))
|
||||
#endif
|
||||
|
||||
|
||||
union FPropParam
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
const char *s;
|
||||
};
|
||||
|
||||
typedef void (*PropHandler)(AActor *defaults, Baggage &bag, FPropParam *params);
|
||||
|
||||
enum ECategory
|
||||
{
|
||||
CAT_PROPERTY, // Inheritable property
|
||||
CAT_INFO // non-inheritable info (spawn ID, Doomednum, game filter, conversation ID)
|
||||
};
|
||||
|
||||
struct FPropertyInfo
|
||||
{
|
||||
const char *name;
|
||||
const char *params;
|
||||
const PClass *cls;
|
||||
PropHandler Handler;
|
||||
int category;
|
||||
};
|
||||
|
||||
FPropertyInfo *FindProperty(const char * string);
|
||||
int MatchString (const char *in, const char **strings);
|
||||
|
||||
|
||||
#define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \
|
||||
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
|
||||
{ #name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
|
||||
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params)
|
||||
|
||||
#define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params); \
|
||||
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
|
||||
{ #prefix"."#name, #paramlist, RUNTIME_CLASS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
|
||||
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, Baggage &bag, FPropParam *params)
|
||||
|
||||
|
||||
#define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY)
|
||||
#define DEFINE_INFO_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_INFO)
|
||||
|
||||
#define DEFINE_CLASS_PROPERTY(name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(clas, name, paramlist, clas, CAT_PROPERTY)
|
||||
#define DEFINE_CLASS_PROPERTY_PREFIX(prefix, name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, CAT_PROPERTY)
|
||||
|
||||
#define PROP_PARM_COUNT (params[0].i)
|
||||
|
||||
#define PROP_STRING_PARM(var, no) \
|
||||
const char *var = params[(no)+1].s;
|
||||
|
||||
#define PROP_INT_PARM(var, no) \
|
||||
int var = params[(no)+1].i;
|
||||
|
||||
#define PROP_FLOAT_PARM(var, no) \
|
||||
float var = params[(no)+1].f;
|
||||
|
||||
#define PROP_FIXED_PARM(var, no) \
|
||||
fixed_t var = fixed_t(params[(no)+1].f * FRACUNIT);
|
||||
|
||||
#define PROP_COLOR_PARM(var, no) \
|
||||
int var = params[(no)+1].i== 0? params[(no)+2].i : V_GetColor(NULL, params[(no)+2].s);
|
||||
|
||||
struct StateCallData
|
||||
{
|
||||
FState * State;
|
||||
AActor * Item;
|
||||
FState *State;
|
||||
AActor *Item;
|
||||
bool Result;
|
||||
};
|
||||
|
||||
|
|
|
@ -354,51 +354,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BulletAttack)
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Resolves a label parameter
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState *P_GetState(AActor *self, FState *CallingState, int offset)
|
||||
{
|
||||
if (offset == 0 || offset == INT_MIN)
|
||||
{
|
||||
return NULL; // 0 means 'no state'
|
||||
}
|
||||
else if (offset>0)
|
||||
{
|
||||
if (CallingState == NULL) return NULL;
|
||||
return CallingState + offset;
|
||||
}
|
||||
else if (self != NULL)
|
||||
{
|
||||
offset = -offset;
|
||||
|
||||
FName classname = JumpParameters[offset];
|
||||
const PClass *cls;
|
||||
cls = classname==NAME_None? RUNTIME_TYPE(self) : PClass::FindClass(classname);
|
||||
if (cls==NULL || cls->ActorInfo==NULL) return NULL; // shouldn't happen
|
||||
|
||||
int numnames = (int)JumpParameters[offset+1];
|
||||
FState *jumpto = cls->ActorInfo->FindState(numnames, &JumpParameters[offset+2]);
|
||||
if (jumpto == NULL)
|
||||
{
|
||||
const char *dot="";
|
||||
Printf("Jump target '");
|
||||
if (classname != NAME_None) Printf("%s::", classname.GetChars());
|
||||
for (int i=0;i<numnames;i++)
|
||||
{
|
||||
Printf("%s%s", dot, JumpParameters[offset+2+i].GetChars());
|
||||
dot = ".";
|
||||
}
|
||||
Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars());
|
||||
}
|
||||
return jumpto;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Do the state jump
|
||||
|
@ -2236,3 +2191,49 @@ DEFINE_ACTION_FUNCTION(AActor, A_ResetReloadCounter)
|
|||
AWeapon *weapon = self->player->ReadyWeapon;
|
||||
weapon->ReloadCounter = 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_ChangeFlag
|
||||
//
|
||||
//===========================================================================
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag)
|
||||
{
|
||||
ACTION_PARAM_START(2);
|
||||
ACTION_PARAM_STRING(flagname, 0);
|
||||
ACTION_PARAM_BOOL(expression, 1);
|
||||
|
||||
const char *dot = strchr (flagname, '.');
|
||||
FFlagDef *fd;
|
||||
const PClass *cls = self->GetClass();
|
||||
|
||||
if (dot != NULL)
|
||||
{
|
||||
FString part1(flagname, dot-flagname);
|
||||
fd = FindFlag (cls, part1, dot+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = FindFlag (cls, flagname, NULL);
|
||||
}
|
||||
|
||||
if (fd != NULL)
|
||||
{
|
||||
if (fd->structoffset == -1)
|
||||
{
|
||||
HandleDeprecatedFlags(self, cls->ActorInfo, expression, fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
int * flagp = (int*) (((char*)self) + fd->structoffset);
|
||||
|
||||
if (expression) *flagp |= fd->flagbit;
|
||||
else *flagp &= ~fd->flagbit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Unknown flag '%s' in '%s'\n", flagname, cls->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
559
src/thingdef/thingdef_parse.cpp
Normal file
559
src/thingdef/thingdef_parse.cpp
Normal file
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
** thingdef-parse.cpp
|
||||
**
|
||||
** Actor definitions - all parser related code
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2007 Christoph Oelckers
|
||||
** Copyright 2004-2007 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
||||
** covered by the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation; either version 2 of the License, or (at
|
||||
** your option) any later version.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "actor.h"
|
||||
#include "a_pickups.h"
|
||||
#include "sc_man.h"
|
||||
#include "thingdef.h"
|
||||
#include "a_morph.h"
|
||||
#include "cmdlib.h"
|
||||
#include "templates.h"
|
||||
#include "v_palette.h"
|
||||
#include "doomerrors.h"
|
||||
#include "autosegs.h"
|
||||
#include "i_system.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ActorConstDef
|
||||
//
|
||||
// Parses a constant definition.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ParseConstant (FScanner &sc, PSymbolTable * symt, PClass *cls)
|
||||
{
|
||||
// Read the type and make sure it's int.
|
||||
// (Maybe there will be other types later.)
|
||||
sc.MustGetToken(TK_Int);
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
FName symname = sc.String;
|
||||
sc.MustGetToken('=');
|
||||
int expr = ParseExpression (sc, false, cls);
|
||||
sc.MustGetToken(';');
|
||||
|
||||
int val = EvalExpressionI (expr, NULL, cls);
|
||||
PSymbolConst *sym = new PSymbolConst;
|
||||
sym->SymbolName = symname;
|
||||
sym->SymbolType = SYM_Const;
|
||||
sym->Value = val;
|
||||
if (symt->AddSymbol (sym) == NULL)
|
||||
{
|
||||
delete sym;
|
||||
sc.ScriptError ("'%s' is already defined in class '%s'.",
|
||||
symname.GetChars(), cls->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ActorEnumDef
|
||||
//
|
||||
// Parses an enum definition.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls)
|
||||
{
|
||||
int currvalue = 0;
|
||||
|
||||
sc.MustGetToken('{');
|
||||
while (!sc.CheckToken('}'))
|
||||
{
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
FName symname = sc.String;
|
||||
if (sc.CheckToken('='))
|
||||
{
|
||||
int expr = ParseExpression(sc, false, cls);
|
||||
currvalue = EvalExpressionI(expr, NULL, cls);
|
||||
}
|
||||
PSymbolConst *sym = new PSymbolConst;
|
||||
sym->SymbolName = symname;
|
||||
sym->SymbolType = SYM_Const;
|
||||
sym->Value = currvalue;
|
||||
if (symt->AddSymbol (sym) == NULL)
|
||||
{
|
||||
delete sym;
|
||||
sc.ScriptError ("'%s' is already defined in class '%s'.",
|
||||
symname.GetChars(), cls->TypeName.GetChars());
|
||||
}
|
||||
// This allows a comma after the last value but doesn't enforce it.
|
||||
if (sc.CheckToken('}')) break;
|
||||
sc.MustGetToken(',');
|
||||
currvalue++;
|
||||
}
|
||||
sc.MustGetToken(';');
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses a flag name
|
||||
//
|
||||
//==========================================================================
|
||||
void ParseActorFlag (FScanner &sc, Baggage &bag, int mod)
|
||||
{
|
||||
sc.MustGetString ();
|
||||
|
||||
FString part1 = sc.String;
|
||||
const char *part2 = NULL;
|
||||
if (sc.CheckString ("."))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
part2 = sc.String;
|
||||
}
|
||||
HandleActorFlag(sc, bag, part1, part2, mod);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Processes a flag. Also used by olddecorations.cpp
|
||||
//
|
||||
//==========================================================================
|
||||
void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *part2, int mod)
|
||||
{
|
||||
FFlagDef *fd;
|
||||
|
||||
if ( (fd = FindFlag (bag.Info->Class, part1, part2)) )
|
||||
{
|
||||
AActor *defaults = (AActor*)bag.Info->Class->Defaults;
|
||||
if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property
|
||||
{
|
||||
HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD * flagvar = (DWORD*) ((char*)defaults + fd->structoffset);
|
||||
if (mod == '+')
|
||||
{
|
||||
*flagvar |= fd->flagbit;
|
||||
}
|
||||
else
|
||||
{
|
||||
*flagvar &= ~fd->flagbit;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (part2 == NULL)
|
||||
{
|
||||
sc.ScriptError("\"%s\" is an unknown flag\n", part1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("\"%s.%s\" is an unknown flag\n", part1, part2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// [MH] parses a morph style expression
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int ParseMorphStyle (FScanner &sc)
|
||||
{
|
||||
static const char * morphstyles[]={
|
||||
"MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE",
|
||||
"MRF_FAILNOTELEFRAG", "MRF_FAILNOLAUGH", "MRF_WHENINVULNERABLE", "MRF_LOSEACTUALWEAPON",
|
||||
"MRF_NEWTIDBEHAVIOUR", "MRF_UNDOBYDEATH", "MRF_UNDOBYDEATHFORCED", "MRF_UNDOBYDEATHSAVES", NULL};
|
||||
|
||||
static const int morphstyle_values[]={
|
||||
MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE,
|
||||
MORPH_FAILNOTELEFRAG, MORPH_FAILNOLAUGH, MORPH_WHENINVULNERABLE, MORPH_LOSEACTUALWEAPON,
|
||||
MORPH_NEWTIDBEHAVIOUR, MORPH_UNDOBYDEATH, MORPH_UNDOBYDEATHFORCED, MORPH_UNDOBYDEATHSAVES};
|
||||
|
||||
// May be given flags by number...
|
||||
if (sc.CheckNumber())
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
return sc.Number;
|
||||
}
|
||||
|
||||
// ... else should be flags by name.
|
||||
// NOTE: Later this should be removed and a normal expression used.
|
||||
// The current DECORATE parser can't handle this though.
|
||||
bool gotparen = sc.CheckString("(");
|
||||
int style = 0;
|
||||
do
|
||||
{
|
||||
sc.MustGetString();
|
||||
style |= morphstyle_values[sc.MustMatchString(morphstyles)];
|
||||
}
|
||||
while (sc.CheckString("|"));
|
||||
if (gotparen)
|
||||
{
|
||||
sc.MustGetStringName(")");
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// For getting a state address from the parent
|
||||
// No attempts have been made to add new functionality here
|
||||
// This is strictly for keeping compatibility with old WADs!
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState *CheckState(FScanner &sc, PClass *type)
|
||||
{
|
||||
int v=0;
|
||||
|
||||
if (sc.GetString() && !sc.Crossed)
|
||||
{
|
||||
if (sc.Compare("0")) return NULL;
|
||||
else if (sc.Compare("PARENT"))
|
||||
{
|
||||
FState * state = NULL;
|
||||
sc.MustGetString();
|
||||
|
||||
FActorInfo * info = type->ParentClass->ActorInfo;
|
||||
|
||||
if (info != NULL)
|
||||
{
|
||||
state = info->FindState(FName(sc.String));
|
||||
}
|
||||
|
||||
if (sc.GetString ())
|
||||
{
|
||||
if (sc.Compare ("+"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
v = sc.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet ();
|
||||
}
|
||||
}
|
||||
|
||||
if (state == NULL && v==0) return NULL;
|
||||
|
||||
if (v!=0 && state==NULL)
|
||||
{
|
||||
sc.ScriptError("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars());
|
||||
return NULL;
|
||||
}
|
||||
state+=v;
|
||||
return state;
|
||||
}
|
||||
else sc.ScriptError("Invalid state assignment");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses an actor property's parameters and calls the handler
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defaults, Baggage &bag)
|
||||
{
|
||||
static TArray<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, ¶ms[0]);
|
||||
}
|
||||
catch (CRecoverableError &error)
|
||||
{
|
||||
sc.ScriptError("%s", error.GetMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses an actor property
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ParseActorProperty(FScanner &sc, Baggage &bag)
|
||||
{
|
||||
static const char *statenames[] = {
|
||||
"Spawn", "See", "Melee", "Missile", "Pain", "Death", "XDeath", "Burn",
|
||||
"Ice", "Raise", "Crash", "Crush", "Wound", "Disintegrate", "Heal", NULL };
|
||||
|
||||
strlwr (sc.String);
|
||||
|
||||
FString propname = sc.String;
|
||||
|
||||
if (sc.CheckString ("."))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
propname += '.';
|
||||
strlwr (sc.String);
|
||||
propname += sc.String;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet ();
|
||||
}
|
||||
|
||||
FPropertyInfo *prop = FindProperty(propname);
|
||||
|
||||
if (prop != NULL)
|
||||
{
|
||||
if (bag.Info->Class->IsDescendantOf(prop->cls))
|
||||
{
|
||||
ParsePropertyParams(sc, prop, (AActor *)bag.Info->Class->Defaults, bag);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->cls->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
else if (!propname.CompareNoCase("States"))
|
||||
{
|
||||
if (!bag.StateSet) ParseStates(sc, bag.Info, (AActor *)bag.Info->Class->Defaults, bag);
|
||||
else sc.ScriptError("Multiple state declarations not allowed");
|
||||
bag.StateSet=true;
|
||||
}
|
||||
else if (MatchString(propname, statenames) != -1)
|
||||
{
|
||||
bag.statedef.AddState(propname, CheckState (sc, bag.Info->Class));
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("\"%s\" is an unknown actor property\n", propname.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finalizes an actor definition
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag)
|
||||
{
|
||||
AActor *defaults = (AActor*)info->Class->Defaults;
|
||||
|
||||
try
|
||||
{
|
||||
bag.statedef.FinishStates (info, defaults, bag.StateArray);
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
sc.ScriptError(err.GetMessage());
|
||||
}
|
||||
bag.statedef.InstallStates (info, defaults);
|
||||
bag.StateArray.Clear ();
|
||||
if (bag.DropItemSet)
|
||||
{
|
||||
if (bag.DropItemList == NULL)
|
||||
{
|
||||
if (info->Class->Meta.GetMetaInt (ACMETA_DropItems) != 0)
|
||||
{
|
||||
info->Class->Meta.SetMetaInt (ACMETA_DropItems, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info->Class->Meta.SetMetaInt (ACMETA_DropItems,
|
||||
StoreDropItemChain(bag.DropItemList));
|
||||
}
|
||||
}
|
||||
if (info->Class->IsDescendantOf (RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
defaults->flags |= MF_SPECIAL;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -57,9 +57,7 @@
|
|||
#include "colormatcher.h"
|
||||
|
||||
TArray<int> StateParameters;
|
||||
TArray<FName> JumpParameters;
|
||||
static TArray<AFuncDesc> AFTable;
|
||||
static TArray<FState> StateArray;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -132,261 +130,12 @@ PSymbolActionFunction *FindGlobalActionFunction(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Find a state address
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FStateDefine
|
||||
{
|
||||
FName Label;
|
||||
TArray<FStateDefine> Children;
|
||||
FState *State;
|
||||
};
|
||||
|
||||
static TArray<FStateDefine> StateLabels;
|
||||
|
||||
void ClearStateLabels()
|
||||
{
|
||||
StateLabels.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Search one list of state definitions for the given name
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static FStateDefine * FindStateLabelInList(TArray<FStateDefine> & list, FName name, bool create)
|
||||
{
|
||||
for(unsigned i = 0; i<list.Size(); i++)
|
||||
{
|
||||
if (list[i].Label == name) return &list[i];
|
||||
}
|
||||
if (create)
|
||||
{
|
||||
FStateDefine def;
|
||||
def.Label=name;
|
||||
def.State=NULL;
|
||||
return &list[list.Push(def)];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds the address of a state given by name.
|
||||
// Adds the state if it doesn't exist
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static FStateDefine * FindStateAddress(const char * name)
|
||||
{
|
||||
static TArray<FName> namelist(3);
|
||||
FStateDefine * statedef=NULL;
|
||||
|
||||
MakeStateNameList(name, &namelist);
|
||||
|
||||
TArray<FStateDefine> * statelist = &StateLabels;
|
||||
for(unsigned i=0;i<namelist.Size();i++)
|
||||
{
|
||||
statedef = FindStateLabelInList(*statelist, namelist[i], true);
|
||||
statelist = &statedef->Children;
|
||||
}
|
||||
return statedef;
|
||||
}
|
||||
|
||||
void AddState (const char * statename, FState * state)
|
||||
{
|
||||
FStateDefine * std = FindStateAddress(statename);
|
||||
std->State = state;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds the state associated with the given name
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState * FindState(AActor * actor, const PClass * type, const char * name)
|
||||
{
|
||||
static TArray<FName> namelist(3);
|
||||
FStateDefine * statedef=NULL;
|
||||
|
||||
MakeStateNameList(name, &namelist);
|
||||
|
||||
TArray<FStateDefine> * statelist = &StateLabels;
|
||||
for(unsigned i=0;i<namelist.Size();i++)
|
||||
{
|
||||
statedef = FindStateLabelInList(*statelist, namelist[i], false);
|
||||
if (statedef == NULL) return NULL;
|
||||
statelist = &statedef->Children;
|
||||
}
|
||||
return statedef? statedef->State : NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Finds the state associated with the given name
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FState * FindStateInClass(AActor * actor, const PClass * type, const char * name)
|
||||
{
|
||||
static TArray<FName> namelist(3);
|
||||
|
||||
MakeStateNameList(name, &namelist);
|
||||
FActorInfo * info = type->ActorInfo;
|
||||
if (info) return info->FindState(namelist.Size(), &namelist[0], true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Checks if a state list is empty
|
||||
// A list is empty if it doesn't contain any states and no children
|
||||
// that contain any states
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool IsStateListEmpty(TArray<FStateDefine> & statelist)
|
||||
{
|
||||
for(unsigned i=0;i<statelist.Size();i++)
|
||||
{
|
||||
if (statelist[i].State!=NULL || !IsStateListEmpty(statelist[i].Children)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates the final list of states from the state definitions
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int STACK_ARGS labelcmp(const void * a, const void * b)
|
||||
{
|
||||
FStateLabel * A = (FStateLabel *)a;
|
||||
FStateLabel * B = (FStateLabel *)b;
|
||||
return ((int)A->Label - (int)B->Label);
|
||||
}
|
||||
|
||||
static FStateLabels * CreateStateLabelList(TArray<FStateDefine> & statelist)
|
||||
{
|
||||
// First delete all empty labels from the list
|
||||
for (int i=statelist.Size()-1;i>=0;i--)
|
||||
{
|
||||
if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0))
|
||||
{
|
||||
statelist.Delete(i);
|
||||
}
|
||||
}
|
||||
|
||||
int count=statelist.Size();
|
||||
|
||||
if (count == 0) return NULL;
|
||||
|
||||
FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel));
|
||||
list->NumLabels = count;
|
||||
|
||||
for (int i=0;i<count;i++)
|
||||
{
|
||||
list->Labels[i].Label = statelist[i].Label;
|
||||
list->Labels[i].State = statelist[i].State;
|
||||
list->Labels[i].Children = CreateStateLabelList(statelist[i].Children);
|
||||
}
|
||||
qsort(list->Labels, count, sizeof(FStateLabel), labelcmp);
|
||||
return list;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// InstallStates
|
||||
//
|
||||
// Creates the actor's state list from the current definition
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void InstallStates(FActorInfo *info, AActor *defaults)
|
||||
{
|
||||
// First ensure we have a valid spawn state.
|
||||
FState * state = FindState(defaults, info->Class, "Spawn");
|
||||
|
||||
if (state == NULL)
|
||||
{
|
||||
// A NULL spawn state will crash the engine so set it to something valid.
|
||||
AddState("Spawn", GetDefault<AActor>()->SpawnState);
|
||||
}
|
||||
|
||||
if (info->StateList != NULL)
|
||||
{
|
||||
info->StateList->Destroy();
|
||||
M_Free(info->StateList);
|
||||
}
|
||||
info->StateList = CreateStateLabelList(StateLabels);
|
||||
|
||||
// Cache these states as member veriables.
|
||||
defaults->SpawnState = info->FindState(NAME_Spawn);
|
||||
defaults->SeeState = info->FindState(NAME_See);
|
||||
// Melee and Missile states are manipulated by the scripted marines so they
|
||||
// have to be stored locally
|
||||
defaults->MeleeState = info->FindState(NAME_Melee);
|
||||
defaults->MissileState = info->FindState(NAME_Missile);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// MakeStateDefines
|
||||
//
|
||||
// Creates a list of state definitions from an existing actor
|
||||
// Used by Dehacked to modify an actor's state list
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static void MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest)
|
||||
{
|
||||
dest.Clear();
|
||||
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
||||
{
|
||||
FStateDefine def;
|
||||
|
||||
def.Label = list->Labels[i].Label;
|
||||
def.State = list->Labels[i].State;
|
||||
dest.Push(def);
|
||||
if (list->Labels[i].Children != NULL)
|
||||
{
|
||||
MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MakeStateDefines(const FStateLabels *list)
|
||||
{
|
||||
MakeStateList(list, StateLabels);
|
||||
}
|
||||
|
||||
void AddStateDefines(const FStateLabels *list)
|
||||
{
|
||||
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
||||
{
|
||||
if (list->Labels[i].Children == NULL)
|
||||
{
|
||||
if (!FindStateLabelInList(StateLabels, list->Labels[i].Label, false))
|
||||
{
|
||||
FStateDefine def;
|
||||
|
||||
def.Label = list->Labels[i].Label;
|
||||
def.State = list->Labels[i].State;
|
||||
StateLabels.Push(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//***
|
||||
// PrepareStateParameters
|
||||
// creates an empty parameter list for a parameterized function call
|
||||
//
|
||||
|
@ -403,7 +152,7 @@ int PrepareStateParameters(FState * state, int numparams)
|
|||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//***
|
||||
// DoActionSpecials
|
||||
// handles action specials as code pointers
|
||||
//
|
||||
|
@ -457,40 +206,7 @@ bool DoActionSpecials(FScanner &sc, FState & state, bool multistate, int * state
|
|||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// RetargetState(Pointer)s
|
||||
//
|
||||
// These functions are used when a goto follows one or more labels.
|
||||
// Because multiple labels are permitted to occur consecutively with no
|
||||
// intervening states, it is not enough to remember the last label defined
|
||||
// and adjust it. So these functions search for all labels that point to
|
||||
// the current position in the state array and give them a copy of the
|
||||
// target string instead.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist)
|
||||
{
|
||||
for(unsigned i = 0;i<statelist.Size(); i++)
|
||||
{
|
||||
if (statelist[i].State == (FState*)count)
|
||||
{
|
||||
statelist[i].State = target == NULL ? NULL : (FState *)copystring (target);
|
||||
}
|
||||
if (statelist[i].Children.Size() > 0)
|
||||
{
|
||||
RetargetStatePointers(count, target, statelist[i].Children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void RetargetStates (intptr_t count, const char *target)
|
||||
{
|
||||
RetargetStatePointers(count, target, StateLabels);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//***
|
||||
// Reads a state label that may contain '.'s.
|
||||
// processes a state block
|
||||
//
|
||||
|
@ -515,7 +231,7 @@ static FString ParseStateString(FScanner &sc)
|
|||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//***
|
||||
// ParseStates
|
||||
// parses a state block
|
||||
//
|
||||
|
@ -551,10 +267,11 @@ do_goto:
|
|||
if (laststate != NULL)
|
||||
{ // Following a state definition: Modify it.
|
||||
laststate->NextState = (FState*)copystring(statestring);
|
||||
laststate->DefineFlags = SDF_LABEL;
|
||||
}
|
||||
else if (lastlabel >= 0)
|
||||
{ // Following a label: Retarget it.
|
||||
RetargetStates (count+1, statestring);
|
||||
bag.statedef.RetargetStates (count+1, statestring);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -566,11 +283,11 @@ do_goto:
|
|||
do_stop:
|
||||
if (laststate!=NULL)
|
||||
{
|
||||
laststate->NextState=(FState*)-1;
|
||||
laststate->DefineFlags = SDF_STOP;
|
||||
}
|
||||
else if (lastlabel >=0)
|
||||
{
|
||||
RetargetStates (count+1, NULL);
|
||||
bag.statedef.RetargetStates (count+1, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -585,7 +302,7 @@ do_stop:
|
|||
sc.ScriptError("%s before first state", sc.String);
|
||||
continue;
|
||||
}
|
||||
laststate->NextState=(FState*)-2;
|
||||
laststate->DefineFlags = SDF_WAIT;
|
||||
}
|
||||
else if (!statestring.CompareNoCase("LOOP"))
|
||||
{
|
||||
|
@ -595,6 +312,7 @@ do_stop:
|
|||
continue;
|
||||
}
|
||||
laststate->NextState=(FState*)(lastlabel+1);
|
||||
laststate->DefineFlags = SDF_INDEX;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -607,7 +325,7 @@ do_stop:
|
|||
do
|
||||
{
|
||||
lastlabel = count;
|
||||
AddState(statestring, (FState *) (count+1));
|
||||
bag.statedef.AddState(statestring, (FState *) (count+1), SDF_INDEX);
|
||||
statestring = ParseStateString(sc);
|
||||
if (!statestring.CompareNoCase("GOTO"))
|
||||
{
|
||||
|
@ -788,7 +506,7 @@ do_stop:
|
|||
}
|
||||
sc.UnGet();
|
||||
endofstate:
|
||||
StateArray.Push(state);
|
||||
bag.StateArray.Push(state);
|
||||
while (*statestrp)
|
||||
{
|
||||
int frame=((*statestrp++)&223)-'A';
|
||||
|
@ -800,10 +518,10 @@ endofstate:
|
|||
}
|
||||
|
||||
state.Frame=(state.Frame&(SF_FULLBRIGHT))|frame;
|
||||
StateArray.Push(state);
|
||||
bag.StateArray.Push(state);
|
||||
count++;
|
||||
}
|
||||
laststate=&StateArray[count];
|
||||
laststate=&bag.StateArray[count];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -815,240 +533,3 @@ endofstate:
|
|||
return count;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ResolveGotoLabel
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static FState *ResolveGotoLabel (FScanner &sc, AActor *actor, const PClass *mytype, char *name)
|
||||
{
|
||||
const PClass *type=mytype;
|
||||
FState *state;
|
||||
char *namestart = name;
|
||||
char *label, *offset, *pt;
|
||||
int v;
|
||||
|
||||
// Check for classname
|
||||
if ((pt = strstr (name, "::")) != NULL)
|
||||
{
|
||||
const char *classname = name;
|
||||
*pt = '\0';
|
||||
name = pt + 2;
|
||||
|
||||
// The classname may either be "Super" to identify this class's immediate
|
||||
// superclass, or it may be the name of any class that this one derives from.
|
||||
if (stricmp (classname, "Super") == 0)
|
||||
{
|
||||
type = type->ParentClass;
|
||||
actor = GetDefaultByType (type);
|
||||
}
|
||||
else
|
||||
{
|
||||
// first check whether a state of the desired name exists
|
||||
const PClass *stype = PClass::FindClass (classname);
|
||||
if (stype == NULL)
|
||||
{
|
||||
sc.ScriptError ("%s is an unknown class.", classname);
|
||||
}
|
||||
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
|
||||
{
|
||||
sc.ScriptError ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
|
||||
}
|
||||
if (!stype->IsAncestorOf (type))
|
||||
{
|
||||
sc.ScriptError ("%s is not derived from %s so cannot access its states.",
|
||||
type->TypeName.GetChars(), stype->TypeName.GetChars());
|
||||
}
|
||||
if (type != stype)
|
||||
{
|
||||
type = stype;
|
||||
actor = GetDefaultByType (type);
|
||||
}
|
||||
}
|
||||
}
|
||||
label = name;
|
||||
// Check for offset
|
||||
offset = NULL;
|
||||
if ((pt = strchr (name, '+')) != NULL)
|
||||
{
|
||||
*pt = '\0';
|
||||
offset = pt + 1;
|
||||
}
|
||||
v = offset ? strtol (offset, NULL, 0) : 0;
|
||||
|
||||
// Get the state's address.
|
||||
if (type==mytype) state = FindState (actor, type, label);
|
||||
else state = FindStateInClass (actor, type, label);
|
||||
|
||||
if (state != NULL)
|
||||
{
|
||||
state += v;
|
||||
}
|
||||
else if (v != 0)
|
||||
{
|
||||
sc.ScriptError ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars());
|
||||
}
|
||||
delete[] namestart; // free the allocated string buffer
|
||||
return state;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FixStatePointers
|
||||
//
|
||||
// Fixes an actor's default state pointers.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list)
|
||||
{
|
||||
for(unsigned i=0;i<list.Size(); i++)
|
||||
{
|
||||
size_t v=(size_t)list[i].State;
|
||||
if (v >= 1 && v < 0x10000)
|
||||
{
|
||||
list[i].State = actor->OwnedStates + v - 1;
|
||||
}
|
||||
if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FixStatePointersAgain
|
||||
//
|
||||
// Resolves an actor's state pointers that were specified as jumps.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void FixStatePointersAgain (FScanner &sc, FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list)
|
||||
{
|
||||
for(unsigned i=0;i<list.Size(); i++)
|
||||
{
|
||||
if (list[i].State != NULL && FState::StaticFindStateOwner (list[i].State, actor) == NULL)
|
||||
{ // It's not a valid state, so it must be a label string. Resolve it.
|
||||
list[i].State = ResolveGotoLabel (sc, defaults, actor->Class, (char *)list[i].State);
|
||||
}
|
||||
if (list[i].Children.Size() > 0) FixStatePointersAgain(sc, actor, defaults, list[i].Children);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FinishStates
|
||||
// copies a state block and fixes all state links
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FinishStates (FScanner &sc, FActorInfo *actor, AActor *defaults, Baggage &bag)
|
||||
{
|
||||
static int c=0;
|
||||
int count = StateArray.Size();
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
FState *realstates = new FState[count];
|
||||
int i;
|
||||
int currange;
|
||||
|
||||
memcpy(realstates, &StateArray[0], count*sizeof(FState));
|
||||
actor->OwnedStates = realstates;
|
||||
actor->NumOwnedStates = count;
|
||||
|
||||
// adjust the state pointers
|
||||
// In the case new states are added these must be adjusted, too!
|
||||
FixStatePointers (actor, StateLabels);
|
||||
|
||||
for(i = currange = 0; i < count; i++)
|
||||
{
|
||||
// resolve labels and jumps
|
||||
switch((ptrdiff_t)realstates[i].NextState)
|
||||
{
|
||||
case 0: // next
|
||||
realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]);
|
||||
break;
|
||||
|
||||
case -1: // stop
|
||||
realstates[i].NextState = NULL;
|
||||
break;
|
||||
|
||||
case -2: // wait
|
||||
realstates[i].NextState = &realstates[i];
|
||||
break;
|
||||
|
||||
default: // loop
|
||||
if ((size_t)realstates[i].NextState < 0x10000)
|
||||
{
|
||||
realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1];
|
||||
}
|
||||
else // goto
|
||||
{
|
||||
realstates[i].NextState = ResolveGotoLabel (sc, defaults, bag.Info->Class, (char *)realstates[i].NextState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
StateArray.Clear ();
|
||||
|
||||
// Fix state pointers that are gotos
|
||||
FixStatePointersAgain (sc, actor, defaults, StateLabels);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// For getting a state address from the parent
|
||||
// No attempts have been made to add new functionality here
|
||||
// This is strictly for keeping compatibility with old WADs!
|
||||
//
|
||||
//==========================================================================
|
||||
FState *CheckState(FScanner &sc, PClass *type)
|
||||
{
|
||||
int v=0;
|
||||
|
||||
if (sc.GetString() && !sc.Crossed)
|
||||
{
|
||||
if (sc.Compare("0")) return NULL;
|
||||
else if (sc.Compare("PARENT"))
|
||||
{
|
||||
FState * state = NULL;
|
||||
sc.MustGetString();
|
||||
|
||||
FActorInfo * info = type->ParentClass->ActorInfo;
|
||||
|
||||
if (info != NULL)
|
||||
{
|
||||
state = info->FindState(FName(sc.String));
|
||||
}
|
||||
|
||||
if (sc.GetString ())
|
||||
{
|
||||
if (sc.Compare ("+"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
v = sc.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet ();
|
||||
}
|
||||
}
|
||||
|
||||
if (state == NULL && v==0) return NULL;
|
||||
|
||||
if (v!=0 && state==NULL)
|
||||
{
|
||||
sc.ScriptError("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars());
|
||||
return NULL;
|
||||
}
|
||||
state+=v;
|
||||
return state;
|
||||
}
|
||||
else sc.ScriptError("Invalid state assignment");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -383,7 +383,7 @@ static int read_config_file(const char *name, bool ismain)
|
|||
bank->tone[i].name = w[2];
|
||||
bank->tone[i].fontbank = atoi(w[3]);
|
||||
bank->tone[i].fontpreset = atoi(w[4]);
|
||||
if (bank->tone[i].fontbank == 128 || (w[5][0] >= '0' && w[5][0] <= '9'))
|
||||
if (words > 5 && (bank->tone[i].fontbank == 128 || (w[5][0] >= '0' && w[5][0] <= '9')))
|
||||
{
|
||||
bank->tone[i].fontnote = atoi(w[5]);
|
||||
j = 6;
|
||||
|
|
|
@ -62,12 +62,7 @@ void FImageCollection::Add (const char **patchNames, int numPatches, int namespc
|
|||
|
||||
for (int i = 0; i < numPatches; ++i)
|
||||
{
|
||||
FTextureID picnum = TexMan.AddPatch (patchNames[i], namespc, true);
|
||||
|
||||
if (!picnum.Exists() && namespc != ns_sprites)
|
||||
{
|
||||
picnum = TexMan.AddPatch (patchNames[i], ns_sprites);
|
||||
}
|
||||
FTextureID picnum = TexMan.CheckForTexture(patchNames[i], namespc);
|
||||
ImageMap[OldCount + i] = picnum;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1768,7 +1768,7 @@ void V_InitCustomFonts()
|
|||
return;
|
||||
|
||||
wrong:
|
||||
sc.ScriptError ("Invalid combination of properties in font '%s'", namebuffer);
|
||||
sc.ScriptError ("Invalid combination of properties in font '%s'", namebuffer.GetChars());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -114,13 +114,6 @@ enum
|
|||
HUD_HorizCenter
|
||||
};
|
||||
|
||||
// Screenshot buffer image data types
|
||||
enum ESSType
|
||||
{
|
||||
SS_PAL,
|
||||
SS_RGB,
|
||||
SS_BGRA
|
||||
};
|
||||
|
||||
class FFont;
|
||||
struct FRemapTable;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -13,7 +13,8 @@ const int SXF_ABSOLUTEMOMENTUM=8;
|
|||
const int SXF_SETMASTER=16;
|
||||
const int SXF_NOCHECKPOSITION = 32;
|
||||
const int SXF_TELEFRAG=64;
|
||||
const int SXF_TRANSFERAMBUSHFLAG=128;
|
||||
// 128 was uses by Skulltag
|
||||
const int SXF_TRANSFERAMBUSHFLAG=256;
|
||||
|
||||
// Flags for A_Chase
|
||||
const int CHF_FASTCHASE = 1;
|
||||
|
@ -28,3 +29,17 @@ const int LOF_NOSOUNDCHECK = 2;
|
|||
const int LOF_DONTCHASEGOAL = 4;
|
||||
const int LOF_NOSEESOUND = 8;
|
||||
const int LOF_FULLVOLSEESOUND = 16;
|
||||
|
||||
// Morph constants
|
||||
const int MRF_ADDSTAMINA = 1;
|
||||
const int MRF_FULLHEALTH = 2;
|
||||
const int MRF_UNDOBYTOMEOFPOWER = 4;
|
||||
const int MRF_UNDOBYCHAOSDEVICE = 8;
|
||||
const int MRF_FAILNOTELEFRAG = 16;
|
||||
const int MRF_FAILNOLAUGH = 32;
|
||||
const int MRF_WHENINVULNERABLE = 64;
|
||||
const int MRF_LOSEACTUALWEAPON = 128;
|
||||
const int MRF_NEWTIDBEHAVIOUR = 256;
|
||||
const int MRF_UNDOBYDEATH = 512;
|
||||
const int MRF_UNDOBYDEATHFORCED = 1024;
|
||||
const int MRF_UNDOBYDEATHSAVES = 2048;
|
||||
|
|
|
@ -65,7 +65,7 @@ ACTOR LavaSmoke
|
|||
+NOGRAVITY
|
||||
+DONTSPLASH
|
||||
RenderStyle Translucent
|
||||
Alpha Default
|
||||
DefaultAlpha
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue