- Reworked a few options that previously depended on LEVEL_HEXENFORMAT

(actors being forced to the ground by instantly moving sectors, strife
  railing handling and shooting lines with a non-zero but unassigned tag.)
  With UDMF such semantics have to be handled diffently. 
- finalized UDMF 1.0 implementation.
- Added Martin Howe's latest morph update.


SVN r987 (trunk)
This commit is contained in:
Christoph Oelckers 2008-05-22 19:35:38 +00:00
parent 7160e09b04
commit ab6b5e337e
28 changed files with 843 additions and 226 deletions

View file

@ -1,3 +1,11 @@
May 22, 2008 (Changes by Graf Zahl)
- Reworked a few options that previously depended on LEVEL_HEXENFORMAT
(actors being forced to the ground by instantly moving sectors, strife
railing handling and shooting lines with a non-zero but unassigned tag.)
With UDMF such semantics have to be handled diffently.
- finalized UDMF 1.0 implementation.
- Added Martin Howe's latest morph update.
May 21, 2008 May 21, 2008
- Fixed: When R_DrawTiltedPlane() calculates the p vector, it can overflow - Fixed: When R_DrawTiltedPlane() calculates the p vector, it can overflow
if the view is near the bounds of the fixed point coordinate system. This if the view is near the bounds of the fixed point coordinate system. This

View file

@ -1123,7 +1123,7 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, bool resetinventory
if (p->morphTics) if (p->morphTics)
{ // Undo morph { // Undo morph
P_UndoPlayerMorph (p, true); P_UndoPlayerMorph (p, p, true);
} }
// Clears the entire inventory and gives back the defaults for starting a game // Clears the entire inventory and gives back the defaults for starting a game

View file

@ -34,7 +34,7 @@ bool AArtiTomeOfPower::Use (bool pickup)
{ {
if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYTOMEOFPOWER)) if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYTOMEOFPOWER))
{ // Attempt to undo chicken { // Attempt to undo chicken
if (!P_UndoPlayerMorph (Owner->player)) if (!P_UndoPlayerMorph (Owner->player, Owner->player))
{ // Failed { // Failed
if (!(Owner->player->MorphStyle & MORPH_FAILNOTELEFRAG)) if (!(Owner->player->MorphStyle & MORPH_FAILNOTELEFRAG))
{ {

View file

@ -118,6 +118,8 @@
#define LEVEL_FORCETEAMPLAYOFF UCONST64(0x8000000000000) #define LEVEL_FORCETEAMPLAYOFF UCONST64(0x8000000000000)
#define LEVEL_CONV_SINGLE_UNFREEZE UCONST64(0x10000000000000) #define LEVEL_CONV_SINGLE_UNFREEZE UCONST64(0x10000000000000)
#define LEVEL_RAILINGHACK UCONST64(0x20000000000000) // but UDMF requires them to be separate to have more control
#define LEVEL_DUMMYSWITCHES UCONST64(0x40000000000000)
struct acsdefered_s; struct acsdefered_s;

View file

@ -62,7 +62,7 @@ bool AArtiTeleport::Use (bool pickup)
bool canlaugh = true; bool canlaugh = true;
if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYCHAOSDEVICE)) if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYCHAOSDEVICE))
{ // Teleporting away will undo any morph effects (pig) { // Teleporting away will undo any morph effects (pig)
if (!P_UndoPlayerMorph (Owner->player) && (Owner->player->MorphStyle & MORPH_FAILNOLAUGH)) if (!P_UndoPlayerMorph (Owner->player, Owner->player) && (Owner->player->MorphStyle & MORPH_FAILNOLAUGH))
{ {
canlaugh = false; canlaugh = false;
} }

View file

@ -1740,7 +1740,7 @@ void APowerMorph::Serialize (FArchive &arc)
{ {
Super::Serialize (arc); Super::Serialize (arc);
arc << PlayerClass << MorphStyle << MorphFlash << UnMorphFlash; arc << PlayerClass << MorphStyle << MorphFlash << UnMorphFlash;
arc << player; arc << Player;
} }
//=========================================================================== //===========================================================================
@ -1761,7 +1761,7 @@ void APowerMorph::InitEffect( )
{ {
Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet
ItemFlags |= IF_CREATECOPYMOVED; // Let the caller know the "real" owner has changed (to the morphed actor) ItemFlags |= IF_CREATECOPYMOVED; // Let the caller know the "real" owner has changed (to the morphed actor)
player = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) Player = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field)
} }
else // morph failed - give the caller an opportunity to fail the pickup completely else // morph failed - give the caller an opportunity to fail the pickup completely
{ {
@ -1778,23 +1778,45 @@ void APowerMorph::InitEffect( )
void APowerMorph::EndEffect( ) void APowerMorph::EndEffect( )
{ {
if (Owner != NULL && player != NULL) // Abort if owner already destroyed
if (Owner == NULL)
{ {
int savedMorphTics = player->morphTics; assert(Player == NULL);
P_UndoPlayerMorph (player); return;
if (player->morphTics /*failed*/)
{
// Transfer retry timeout
// to the powerup's timer.
EffectTics = player->morphTics;
// Reload negative morph tics;
// use actual value; it may
// be in use for animation.
player->morphTics = savedMorphTics;
}
else // unmorph succeeded
{
player = NULL;
}
} }
// Abort if owner already unmorphed
if (Player == NULL)
{
return;
}
// Abort if owner is dead; their Die() method will
// take care of any required unmorphing on death.
if (Player->health <= 0)
{
return;
}
// Unmorph if possible
int savedMorphTics = Player->morphTics;
P_UndoPlayerMorph (Player, Player);
// Abort if unmorph failed; in that case,
// set the usual retry timer and return.
if (Player->morphTics)
{
// Transfer retry timeout
// to the powerup's timer.
EffectTics = Player->morphTics;
// Reload negative morph tics;
// use actual value; it may
// be in use for animation.
Player->morphTics = savedMorphTics;
// Try again some time later
return;
}
// Unmorph suceeded
Player = NULL;
} }

View file

@ -267,7 +267,7 @@ protected:
void InitEffect (); void InitEffect ();
void EndEffect (); void EndEffect ();
// Variables // Variables
player_s *player; player_s *Player;
}; };
#endif //__A_ARTIFACTS_H__ #endif //__A_ARTIFACTS_H__

View file

@ -63,6 +63,13 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i
morphed = static_cast<APlayerPawn *>(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE)); morphed = static_cast<APlayerPawn *>(Spawn (spawntype, actor->x, actor->y, actor->z, NO_REPLACE));
DObject::StaticPointerSubstitution (actor, morphed); DObject::StaticPointerSubstitution (actor, morphed);
if ((actor->tid != 0) && (style & MORPH_NEWTIDBEHAVIOUR))
{
morphed->tid = actor->tid;
morphed->AddToHash ();
actor->RemoveFromHash ();
actor->tid = 0;
}
morphed->angle = actor->angle; morphed->angle = actor->angle;
morphed->target = actor->target; morphed->target = actor->target;
morphed->tracer = actor; morphed->tracer = actor;
@ -159,7 +166,7 @@ bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, i
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool P_UndoPlayerMorph (player_t *player, bool force) bool P_UndoPlayerMorph (player_s *activator, player_t *player, bool force)
{ {
AWeapon *beastweap; AWeapon *beastweap;
APlayerPawn *mo; APlayerPawn *mo;
@ -177,11 +184,19 @@ bool P_UndoPlayerMorph (player_t *player, bool force)
{ {
return false; return false;
} }
if ((pmo->flags2 & MF2_INVULNERABLE) && ((player != activator) || (!(player->MorphStyle & MORPH_WHENINVULNERABLE))))
{ // Immune when invulnerable unless this is something we initiated.
// If the WORLD is the initiator, the same player should be given
// as the activator; WORLD initiated actions should always succeed.
return false;
}
mo = barrier_cast<APlayerPawn *>(pmo->tracer); mo = barrier_cast<APlayerPawn *>(pmo->tracer);
mo->SetOrigin (pmo->x, pmo->y, pmo->z); mo->SetOrigin (pmo->x, pmo->y, pmo->z);
mo->flags |= MF_SOLID; mo->flags |= MF_SOLID;
pmo->flags &= ~MF_SOLID; pmo->flags &= ~MF_SOLID;
if (!force && P_TestMobjLocation (mo) == false) if (!force && !P_TestMobjLocation (mo))
{ // Didn't fit { // Didn't fit
mo->flags &= ~MF_SOLID; mo->flags &= ~MF_SOLID;
pmo->flags |= MF_SOLID; pmo->flags |= MF_SOLID;
@ -192,6 +207,11 @@ bool P_UndoPlayerMorph (player_t *player, bool force)
mo->ObtainInventory (pmo); mo->ObtainInventory (pmo);
DObject::StaticPointerSubstitution (pmo, mo); DObject::StaticPointerSubstitution (pmo, mo);
if ((pmo->tid != 0) && (player->MorphStyle & MORPH_NEWTIDBEHAVIOUR))
{
mo->tid = pmo->tid;
mo->AddToHash ();
}
mo->angle = pmo->angle; mo->angle = pmo->angle;
mo->player = player; mo->player = player;
mo->reactiontime = 18; mo->reactiontime = 18;
@ -211,6 +231,7 @@ bool P_UndoPlayerMorph (player_t *player, bool force)
const PClass *exit_flash = player->MorphExitFlash; const PClass *exit_flash = player->MorphExitFlash;
bool correctweapon = !!(player->MorphStyle & MORPH_LOSEACTUALWEAPON); bool correctweapon = !!(player->MorphStyle & MORPH_LOSEACTUALWEAPON);
bool undobydeathsaves = !!(player->MorphStyle & MORPH_UNDOBYDEATHSAVES);
player->morphTics = 0; player->morphTics = 0;
player->MorphedPlayerClass = 0; player->MorphedPlayerClass = 0;
@ -222,7 +243,16 @@ bool P_UndoPlayerMorph (player_t *player, bool force)
{ {
level2->Destroy (); level2->Destroy ();
} }
player->health = mo->health = mo->GetDefault()->health;
if ((player->health > 0) || undobydeathsaves)
{
player->health = mo->health = mo->GetDefault()->health;
}
else // killed when morphed so stay dead
{
mo->health = player->health;
}
player->mo = mo; player->mo = mo;
if (player->camera == pmo) if (player->camera == pmo)
{ {
@ -363,18 +393,17 @@ bool P_MorphMonster (AActor *actor, const PClass *spawntype, int duration, int s
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// //
// FUNC P_UpdateMorphedMonster // FUNC P_UndoMonsterMorph
// //
// Returns true if the monster unmorphs. // Returns true if the monster unmorphs.
// //
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool P_UpdateMorphedMonster (AMorphedMonster *beast) bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force)
{ {
AActor *actor; AActor *actor;
if (beast->UnmorphTime == 0 || if (beast->UnmorphTime == 0 ||
beast->UnmorphTime > level.time ||
beast->UnmorphedMe == NULL || beast->UnmorphedMe == NULL ||
beast->flags3 & MF3_STAYMORPHED) beast->flags3 & MF3_STAYMORPHED)
{ {
@ -384,7 +413,7 @@ bool P_UpdateMorphedMonster (AMorphedMonster *beast)
actor->SetOrigin (beast->x, beast->y, beast->z); actor->SetOrigin (beast->x, beast->y, beast->z);
actor->flags |= MF_SOLID; actor->flags |= MF_SOLID;
beast->flags &= ~MF_SOLID; beast->flags &= ~MF_SOLID;
if (P_TestMobjLocation (actor) == false) if (!force && !P_TestMobjLocation (actor))
{ // Didn't fit { // Didn't fit
actor->flags &= ~MF_SOLID; actor->flags &= ~MF_SOLID;
beast->flags |= MF_SOLID; beast->flags |= MF_SOLID;
@ -417,6 +446,82 @@ bool P_UpdateMorphedMonster (AMorphedMonster *beast)
return true; return true;
} }
//----------------------------------------------------------------------------
//
// FUNC P_UpdateMorphedMonster
//
// Returns true if the monster unmorphs.
//
//----------------------------------------------------------------------------
bool P_UpdateMorphedMonster (AMorphedMonster *beast)
{
if (beast->UnmorphTime > level.time)
{
return false;
}
return P_UndoMonsterMorph (beast);
}
//----------------------------------------------------------------------------
//
// FUNC P_MorphedDeath
//
// Unmorphs the actor if possible.
// Returns the unmorphed actor, the style with which they were morphed and the
// health (of the AActor, not the player_s) they last had before unmorphing.
//
//----------------------------------------------------------------------------
bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *morphedhealth)
{
// May be a morphed player
if ((actor->player) &&
(actor->player->morphTics) &&
(actor->player->MorphStyle & MORPH_UNDOBYDEATH) &&
(actor->player->mo) &&
(actor->player->mo->tracer))
{
AActor *realme = actor->player->mo->tracer;
int realstyle = actor->player->MorphStyle;
int realhealth = actor->health;
if (P_UndoPlayerMorph(actor->player, actor->player, !!(actor->player->MorphStyle & MORPH_UNDOBYDEATHFORCED)))
{
*morphed = realme;
*morphedstyle = realstyle;
*morphedhealth = realhealth;
return true;
}
return false;
}
// May be a morphed monster
if (actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster)))
{
AMorphedMonster *fakeme = static_cast<AMorphedMonster *>(actor);
if ((fakeme->UnmorphTime) &&
(fakeme->MorphStyle & MORPH_UNDOBYDEATH) &&
(fakeme->UnmorphedMe))
{
AActor *realme = fakeme->UnmorphedMe;
int realstyle = fakeme->MorphStyle;
int realhealth = fakeme->health;
if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED)))
{
*morphed = realme;
*morphedstyle = realstyle;
*morphedhealth = realhealth;
return true;
}
}
fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die()
return false;
}
// Not a morphed player or monster
return false;
}
// Base class for morphing projectiles -------------------------------------- // Base class for morphing projectiles --------------------------------------
IMPLEMENT_STATELESS_ACTOR(AMorphProjectile, Any, -1, 0) IMPLEMENT_STATELESS_ACTOR(AMorphProjectile, Any, -1, 0)
@ -479,7 +584,11 @@ void AMorphedMonster::Destroy ()
void AMorphedMonster::Die (AActor *source, AActor *inflictor) void AMorphedMonster::Die (AActor *source, AActor *inflictor)
{ {
// Dead things don't unmorph // Dead things don't unmorph
flags3 |= MF3_STAYMORPHED; // flags3 |= MF3_STAYMORPHED;
// [MH]
// But they can now, so that line above has been
// moved into P_MorphedDeath() and is now set by
// that function if and only if it is needed.
Super::Die (source, inflictor); Super::Die (source, inflictor);
if (UnmorphedMe != NULL && (UnmorphedMe->flags & MF_UNMORPHED)) if (UnmorphedMe != NULL && (UnmorphedMe->flags & MF_UNMORPHED))
{ {

View file

@ -2,7 +2,7 @@
#define __A_MORPH__ #define __A_MORPH__
#define MORPHTICS (40*TICRATE) #define MORPHTICS (40*TICRATE)
#define MAXMORPHHEALTH 30 #define MAXMORPHHEALTH 30
// Morph style states how morphing affects health and // Morph style states how morphing affects health and
// other effects in the game; only valid for players. // other effects in the game; only valid for players.
@ -11,25 +11,32 @@
enum enum
{ {
MORPH_OLDEFFECTS = 0x00000000, // Default to old Heretic/HeXen behaviour unless flags given MORPH_OLDEFFECTS = 0x00000000, // Default to old Heretic/HeXen behaviour unless flags given
MORPH_ADDSTAMINA = 0x00000001, // Power instead of curse (add stamina instead of limiting to health) MORPH_ADDSTAMINA = 0x00000001, // Player has a "power" instead of a "curse" (add stamina instead of limiting to health)
MORPH_FULLHEALTH = 0x00000002, // New health semantics (!POWER => MaxHealth of animal, POWER => Normal health behaviour) MORPH_FULLHEALTH = 0x00000002, // Player uses new health semantics (!POWER => MaxHealth of animal, POWER => Normal health behaviour)
MORPH_UNDOBYTOMEOFPOWER = 0x00000004, // Player unmorphs upon activating a Tome of Power MORPH_UNDOBYTOMEOFPOWER = 0x00000004, // Player unmorphs upon activating a Tome of Power
MORPH_UNDOBYCHAOSDEVICE = 0x00000008, // Player unmorphs upon activating a Chaos Device MORPH_UNDOBYCHAOSDEVICE = 0x00000008, // Player unmorphs upon activating a Chaos Device
MORPH_FAILNOTELEFRAG = 0x00000010, // Player stays morphed if unmorph by Tome of Power fails MORPH_FAILNOTELEFRAG = 0x00000010, // Player stays morphed if unmorph by Tome of Power fails
MORPH_FAILNOLAUGH = 0x00000020, // Player doesn't laugh if unmorph by Chaos Device fails MORPH_FAILNOLAUGH = 0x00000020, // Player doesn't laugh if unmorph by Chaos Device fails
MORPH_WHENINVULNERABLE = 0x00000040, // Player can morph when invulnerable but ONLY if doing it to themselves MORPH_WHENINVULNERABLE = 0x00000040, // Player can morph (or scripted unmorph) when invulnerable but ONLY if doing it to themselves
MORPH_LOSEACTUALWEAPON = 0X00000080 // Player loses specified morph weapon only (not "whichever they have when unmorphing") MORPH_LOSEACTUALWEAPON = 0x00000080, // Player loses specified morph weapon only (not "whichever they have when unmorphing")
MORPH_NEWTIDBEHAVIOUR = 0x00000100, // Actor TID is by default transferred from the old actor to the new actor
MORPH_UNDOBYDEATH = 0x00000200, // Actor unmorphs when killed and (unless MORPH_UNDOBYDEATHSAVES) stays dead
MORPH_UNDOBYDEATHFORCED = 0x00000400, // Actor (if unmorphed when killed) forces unmorph (not very useful with UNDOBYDEATHSAVES)
MORPH_UNDOBYDEATHSAVES = 0x00000800, // Actor (if unmorphed when killed) regains their health and doesn't die
}; };
struct PClass; struct PClass;
class AActor; class AActor;
class player_s; class player_s;
class AMorphedMonster;
bool P_MorphPlayer (player_s *activator, player_s *player, const PClass *morphclass, int duration = 0, int style = 0, bool P_MorphPlayer (player_s *activator, player_s *player, const PClass *morphclass, int duration = 0, int style = 0,
const PClass *enter_flash = NULL, const PClass *exit_flash = NULL); const PClass *enter_flash = NULL, const PClass *exit_flash = NULL);
bool P_UndoPlayerMorph (player_s *player, bool force = false); bool P_UndoPlayerMorph (player_s *activator, player_s *player, bool force = false);
bool P_MorphMonster (AActor *actor, const PClass *morphclass, int duration = 0, int style = 0, bool P_MorphMonster (AActor *actor, const PClass *morphclass, int duration = 0, int style = 0,
const PClass *enter_flash = NULL, const PClass *exit_flash = NULL); const PClass *enter_flash = NULL, const PClass *exit_flash = NULL);
bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force = false);
bool P_UpdateMorphedMonster (AActor *actor); bool P_UpdateMorphedMonster (AActor *actor);
bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *morphedhealth);
#endif //__A_MORPH__ #endif //__A_MORPH__

View file

@ -291,7 +291,7 @@ void cht_DoCheat (player_t *player, int cheat)
if (player->morphTics > 0) if (player->morphTics > 0)
{ {
P_UndoPlayerMorph(player); P_UndoPlayerMorph(player, player);
} }
} }
@ -438,7 +438,7 @@ const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickund
if (player->morphTics) if (player->morphTics)
{ {
if (P_UndoPlayerMorph (player)) if (P_UndoPlayerMorph (player, player))
{ {
if (!quickundo && oldclass != morphclass && P_MorphPlayer (player, player, morphclass, 0, style)) if (!quickundo && oldclass != morphclass && P_MorphPlayer (player, player, morphclass, 0, style))
{ {

View file

@ -249,7 +249,6 @@ xx(Sector)
xx(Heightfloor) xx(Heightfloor)
xx(Heightceiling) xx(Heightceiling)
xx(Lightlevel) xx(Lightlevel)
xx(Tag)
xx(Texturefloor) xx(Texturefloor)
xx(Textureceiling) xx(Textureceiling)
@ -305,7 +304,7 @@ xx(Twosided)
xx(Dontpegtop) xx(Dontpegtop)
xx(Dontpegbottom) xx(Dontpegbottom)
xx(Secret) xx(Secret)
xx(Soundblock) xx(Blocksound)
xx(Dontdraw) xx(Dontdraw)
xx(Mapped) xx(Mapped)
xx(Monsteractivate) xx(Monsteractivate)
@ -321,6 +320,7 @@ xx(Checkswitchrange)
xx(Firstsideonly) xx(Firstsideonly)
xx(Transparent) xx(Transparent)
xx(Passuse) xx(Passuse)
xx(Repeatspecial)
xx(Playercross) xx(Playercross)
xx(Playeruse) xx(Playeruse)

View file

@ -5351,8 +5351,129 @@ int DLevelScript::RunScript ()
} }
} }
break; break;
}
} case PCD_MORPHACTOR:
{
int tag = STACK(7);
FName playerclass_name = FBehavior::StaticLookupString(STACK(6));
const PClass *playerclass = PClass::FindClass (playerclass_name);
FName monsterclass_name = FBehavior::StaticLookupString(STACK(5));
const PClass *monsterclass = PClass::FindClass (monsterclass_name);
int duration = STACK(4);
int style = STACK(3);
FName morphflash_name = FBehavior::StaticLookupString(STACK(2));
const PClass *morphflash = PClass::FindClass (morphflash_name);
FName unmorphflash_name = FBehavior::StaticLookupString(STACK(1));
const PClass *unmorphflash = PClass::FindClass (unmorphflash_name);
int changes = 0;
if (tag == 0)
{
if (activator->player)
{
if (P_MorphPlayer(activator->player, activator->player, playerclass, duration, style, morphflash, unmorphflash))
{
changes++;
}
}
else
{
if (P_MorphMonster(activator, monsterclass, duration, style, morphflash, unmorphflash))
{
changes++;
}
}
}
else
{
FActorIterator iterator (tag);
AActor *actor;
while ( (actor = iterator.Next ()) )
{
if (actor->player)
{
if (P_MorphPlayer(activator->player, actor->player, playerclass, duration, style, morphflash, unmorphflash))
{
changes++;
}
}
else
{
if (P_MorphMonster(actor, monsterclass, duration, style, morphflash, unmorphflash))
{
changes++;
}
}
}
}
STACK(7) = changes;
sp -= 6;
}
break;
case PCD_UNMORPHACTOR:
{
int tag = STACK(2);
bool force = !!STACK(1);
int changes = 0;
if (tag == 0)
{
if (activator->player)
{
if (P_UndoPlayerMorph(activator->player, activator->player, force))
{
changes++;
}
}
else
{
if (activator->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster)))
{
AMorphedMonster *morphed_actor = barrier_cast<AMorphedMonster *>(activator);
if (P_UndoMonsterMorph(morphed_actor, force))
{
changes++;
}
}
}
}
else
{
FActorIterator iterator (tag);
AActor *actor;
while ( (actor = iterator.Next ()) )
{
if (actor->player)
{
if (P_UndoPlayerMorph(activator->player, actor->player, force))
{
changes++;
}
}
else
{
if (actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster)))
{
AMorphedMonster *morphed_actor = static_cast<AMorphedMonster *>(actor);
if (P_UndoMonsterMorph(morphed_actor, force))
{
changes++;
}
}
}
}
}
STACK(2) = changes;
sp -= 1;
}
break;
}
}
if (state == SCRIPT_DivideBy0) if (state == SCRIPT_DivideBy0)
{ {

View file

@ -551,6 +551,8 @@ public:
PCD_THINGCOUNTSECTOR, PCD_THINGCOUNTSECTOR,
PCD_THINGCOUNTNAMESECTOR, PCD_THINGCOUNTNAMESECTOR,
PCD_CHECKPLAYERCAMERA, // [TN] PCD_CHECKPLAYERCAMERA, // [TN]
PCD_MORPHACTOR, // [MH]
PCD_UNMORPHACTOR, // [MH]
PCODE_COMMAND_COUNT PCODE_COMMAND_COUNT
}; };

View file

@ -236,6 +236,7 @@ static void LoadScriptFile (const char *name)
lump = Wads.ReopenLumpNum (lumpnum); lump = Wads.ReopenLumpNum (lumpnum);
LoadScriptFile(lump, Wads.LumpLength(lumpnum)); LoadScriptFile(lump, Wads.LumpLength(lumpnum));
delete lump;
} }
static void LoadScriptFile(FileReader *lump, int numnodes) static void LoadScriptFile(FileReader *lump, int numnodes)
@ -278,7 +279,6 @@ static void LoadScriptFile(FileReader *lump, int numnodes)
} }
StrifeDialogues.Push (node); StrifeDialogues.Push (node);
} }
delete lump;
} }
//============================================================================ //============================================================================

View file

@ -317,8 +317,40 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker)
// //
EXTERN_CVAR (Int, fraglimit) EXTERN_CVAR (Int, fraglimit)
static int GibHealth(AActor *actor)
{
return -abs(
actor->GetClass()->Meta.GetMetaInt (
AMETA_GibHealth,
gameinfo.gametype == GAME_Doom ?
-actor->GetDefault()->health :
-actor->GetDefault()->health/2));
}
void AActor::Die (AActor *source, AActor *inflictor) void AActor::Die (AActor *source, AActor *inflictor)
{ {
// Handle possible unmorph on death
bool wasgibbed = (health < GibHealth(this));
AActor *realthis = NULL;
int realstyle = 0;
int realhealth = 0;
if (P_MorphedDeath(this, &realthis, &realstyle, &realhealth))
{
if (!(realstyle & MORPH_UNDOBYDEATHSAVES))
{
if (wasgibbed)
{
int realgibhealth = GibHealth(realthis);
if (realthis->health >= realgibhealth)
{
realthis->health = realgibhealth -1; // if morphed was gibbed, so must original be (where allowed)
}
}
realthis->Die(source, inflictor);
}
return;
}
// [SO] 9/2/02 -- It's rather funny to see an exploded player body with the invuln sparkle active :) // [SO] 9/2/02 -- It's rather funny to see an exploded player body with the invuln sparkle active :)
effects &= ~FX_RESPAWNINVUL; effects &= ~FX_RESPAWNINVUL;
//flags &= ~MF_INVINCIBLE; //flags &= ~MF_INVINCIBLE;
@ -634,8 +666,7 @@ void AActor::Die (AActor *source, AActor *inflictor)
{ {
int flags4 = inflictor == NULL ? 0 : inflictor->flags4; int flags4 = inflictor == NULL ? 0 : inflictor->flags4;
int gibhealth = -abs(GetClass()->Meta.GetMetaInt (AMETA_GibHealth, int gibhealth = GibHealth(this);
gameinfo.gametype == GAME_Doom ? -GetDefault()->health : -GetDefault()->health/2));
// Don't pass on a damage type this actor cannot handle. // Don't pass on a damage type this actor cannot handle.
// (most importantly, prevent barrels from passing on ice damage.) // (most importantly, prevent barrels from passing on ice damage.)

View file

@ -564,9 +564,6 @@ enum
PO_SPAWNHURT_TYPE PO_SPAWNHURT_TYPE
}; };
#define PO_LINE_START 1 // polyobj line start special
#define PO_LINE_EXPLICIT 5
extern polyobj_t *polyobjs; // list of all poly-objects on the level extern polyobj_t *polyobjs; // list of all poly-objects on the level
extern int po_NumPolyobjs; extern int po_NumPolyobjs;
extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn

View file

@ -608,8 +608,7 @@ bool PIT_CheckLine (line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
// better than Strife's handling of rails, which lets you jump into rails // better than Strife's handling of rails, which lets you jump into rails
// from either side. How long until somebody reports this as a bug and I'm // from either side. How long until somebody reports this as a bug and I'm
// forced to say, "It's not a bug. It's a feature?" Ugh. // forced to say, "It's not a bug. It's a feature?" Ugh.
(gameinfo.gametype != GAME_Strife || (!(level.flags & LEVEL_RAILINGHACK) ||
level.flags & LEVEL_HEXENFORMAT ||
open.bottom == tm.thing->Sector->floorplane.ZatPoint (sx, sy))) open.bottom == tm.thing->Sector->floorplane.ZatPoint (sx, sy)))
{ {
open.bottom += 32*FRACUNIT; open.bottom += 32*FRACUNIT;
@ -3599,6 +3598,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b
struct FChangePosition struct FChangePosition
{ {
sector_t *sector;
int moveamt; int moveamt;
int crushchange; int crushchange;
bool nofit; bool nofit;
@ -3953,7 +3953,7 @@ void PIT_FloorDrop (AActor *thing, FChangePosition *cpos)
P_CheckFakeFloorTriggers (thing, oldz); P_CheckFakeFloorTriggers (thing, oldz);
} }
else if ((thing->flags & MF_NOGRAVITY) || else if ((thing->flags & MF_NOGRAVITY) ||
((!(level.flags & LEVEL_HEXENFORMAT) || cpos->moveamt < 9*FRACUNIT) (((cpos->sector->Flags & SECF_FLOORDROP) || cpos->moveamt < 9*FRACUNIT)
&& thing->z - thing->floorz <= cpos->moveamt)) && thing->z - thing->floorz <= cpos->moveamt))
{ {
thing->z = thing->floorz; thing->z = thing->floorz;
@ -4104,6 +4104,7 @@ bool P_ChangeSector (sector_t *sector, int crunch, int amt, int floorOrCeil, boo
cpos.crushchange = crunch; cpos.crushchange = crunch;
cpos.moveamt = abs (amt); cpos.moveamt = abs (amt);
cpos.movemidtex = false; cpos.movemidtex = false;
cpos.sector = sector;
// [RH] Use different functions for the four different types of sector // [RH] Use different functions for the four different types of sector
// movement. Also update the soundorg's z-coordinate for 3D sound. // movement. Also update the soundorg's z-coordinate for 3D sound.

View file

@ -370,6 +370,7 @@ MapData *P_OpenMapData(const char * mapname)
else if (!stricmp(lumpname, "BEHAVIOR")) else if (!stricmp(lumpname, "BEHAVIOR"))
{ {
index = ML_BEHAVIOR; index = ML_BEHAVIOR;
map->HasBehavior = true;
} }
else if (!stricmp(lumpname, "ENDMAP")) else if (!stricmp(lumpname, "ENDMAP"))
{ {
@ -411,14 +412,16 @@ MapData *P_OpenMapData(const char * mapname)
(*map->file) >> numentries >> dirofs; (*map->file) >> numentries >> dirofs;
map->file->Seek(dirofs, SEEK_SET); map->file->Seek(dirofs, SEEK_SET);
for(DWORD i = 0; i < numentries; i++) (*map->file) >> map->MapLumps[0].FilePos >> map->MapLumps[0].Size;
map->file->Read(map->MapLumps[0].Name, 8);
for(DWORD i = 1; i < numentries; i++)
{ {
DWORD offset, size; DWORD offset, size;
char lumpname[8]; char lumpname[8];
(*map->file) >> offset >> size; (*map->file) >> offset >> size;
map->file->Read(lumpname, 8); map->file->Read(lumpname, 8);
if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8)) if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8))
{ {
map->isText = true; map->isText = true;
@ -432,28 +435,29 @@ MapData *P_OpenMapData(const char * mapname)
{ {
I_Error("Invalid map definition for %s", mapname); I_Error("Invalid map definition for %s", mapname);
} }
else if (!stricmp(lumpname, "ZNODES")) else if (!strnicmp(lumpname, "ZNODES",8))
{ {
index = ML_GLZNODES; index = ML_GLZNODES;
} }
else if (!stricmp(lumpname, "BLOCKMAP")) else if (!strnicmp(lumpname, "BLOCKMAP",8))
{ {
// there is no real point in creating a blockmap but let's use it anyway // there is no real point in creating a blockmap but let's use it anyway
index = ML_BLOCKMAP; index = ML_BLOCKMAP;
} }
else if (!stricmp(lumpname, "REJECT")) else if (!strnicmp(lumpname, "REJECT",8))
{ {
index = ML_REJECT; index = ML_REJECT;
} }
else if (!stricmp(lumpname, "DIALOGUE")) else if (!strnicmp(lumpname, "DIALOGUE",8))
{ {
index = ML_CONVERSATION; index = ML_CONVERSATION;
} }
else if (!stricmp(lumpname, "BEHAVIOR")) else if (!strnicmp(lumpname, "BEHAVIOR",8))
{ {
index = ML_BEHAVIOR; index = ML_BEHAVIOR;
map->HasBehavior = true;
} }
else if (!stricmp(lumpname, "ENDMAP")) else if (!strnicmp(lumpname, "ENDMAP",8))
{ {
return map; return map;
} }
@ -1179,6 +1183,7 @@ void P_LoadSectors (MapData * map)
for (i = 0; i < numsectors; i++, ss++, ms++) for (i = 0; i < numsectors; i++, ss++, ms++)
{ {
ss->e = &sectors[0].e[i]; ss->e = &sectors[0].e[i];
if (!map->HasBehavior) ss->Flags |= SECF_FLOORDROP;
ss->floortexz = LittleShort(ms->floorheight)<<FRACBITS; ss->floortexz = LittleShort(ms->floorheight)<<FRACBITS;
ss->floorplane.d = -ss->floortexz; ss->floorplane.d = -ss->floortexz;
ss->floorplane.c = FRACUNIT; ss->floorplane.c = FRACUNIT;
@ -3266,6 +3271,16 @@ void P_SetupLevel (char *lumpname, int position)
} }
} }
if (!map->HasBehavior && !map->isText)
{
// set compatibility flags
if (gameinfo.gametype == GAME_Strife)
{
level.flags |= LEVEL_RAILINGHACK;
}
level.flags |= LEVEL_DUMMYSWITCHES;
}
FBehavior::StaticLoadDefaultModules (); FBehavior::StaticLoadDefaultModules ();
P_LoadStrifeConversations (map, lumpname); P_LoadStrifeConversations (map, lumpname);

View file

@ -229,11 +229,12 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
} }
// some old WADs use this method to create walls that change the texture when shot. // some old WADs use this method to create walls that change the texture when shot.
else if (activationType == SPAC_Impact && // only for shootable triggers else if (activationType == SPAC_Impact && // only for shootable triggers
!(level.flags & LEVEL_HEXENFORMAT) && // only in Doom-format maps (level.flags & LEVEL_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack!
!repeat && // only non-repeatable triggers !repeat && // only non-repeatable triggers
(special<Generic_Floor || special>Generic_Crusher) && // not for Boom's generalized linedefs (special<Generic_Floor || special>Generic_Crusher) && // not for Boom's generalized linedefs
special && // not for lines without a special special && // not for lines without a special
line->id && // only if there's a tag (which is stored in the id field) line->args[0] == line->id && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0]
line->args[0] && // only if there's a tag (which is stored in the first arg)
P_FindSectorFromTag (line->args[0], -1) == -1) // only if no sector is tagged to this linedef P_FindSectorFromTag (line->args[0], -1) == -1) // only if no sector is tagged to this linedef
{ {
P_ChangeSwitchTexture (&sides[line->sidenum[0]], repeat, special); P_ChangeSwitchTexture (&sides[line->sidenum[0]], repeat, special);

View file

@ -40,6 +40,67 @@
#include "p_lnspec.h" #include "p_lnspec.h"
#include "templates.h" #include "templates.h"
#include "i_system.h" #include "i_system.h"
#include "gi.h"
// These tables define whichline an
static char HexenLineSpecialOk[]={
1,1,1,1,1,1,1,1,1,0, // 0-9
1,1,1,1,0,0,0,0,0,0, // 10-19
1,1,1,1,1,1,1,1,1,1, // 20-29
1,1,1,0,0,1,1,0,0,0, // 30-39
1,1,1,1,1,1,1,0,0,0, // 40-49
0,0,0,0,0,0,0,0,0,0, // 50-59
1,1,1,1,1,1,1,1,1,1, // 60-69
1,1,1,1,1,1,0,0,0,0, // 70-79
1,1,1,1,0,0,0,0,0,0, // 80-89
1,1,1,1,1,1,1,0,0,0, // 90-99
1,1,1,1,0,0,0,0,0,1, // 100-109
1,1,1,1,1,1,1,0,0,0, // 110-119
1,0,0,0,0,0,0,0,0,1, // 120-129
1,1,1,1,1,1,1,1,1,0, // 130-139
1
// 140 is the highest valid special in Hexen.
};
static char HexenSectorSpecialOk[256]={
1,1,1,1,1,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,
};
enum
{
Dm=1,
Ht=2,
Hx=4,
St=8,
Zd=16,
Zdt=32,
// will be extended later. Unknown namespaces will always be treated like the base
// namespace for each game
};
void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, mapsidedef_t *msd, int special, int tag, short *alpha); void P_ProcessSideTextures(bool checktranmap, side_t *sd, sector_t *sec, mapsidedef_t *msd, int special, int tag, short *alpha);
void P_AdjustLine (line_t *ld); void P_AdjustLine (line_t *ld);
@ -49,12 +110,17 @@ extern bool ForceNodeBuild;
extern TArray<FMapThing> MapThingsConverted; extern TArray<FMapThing> MapThingsConverted;
extern TArray<int> linemap; extern TArray<int> linemap;
#define CHECK_N(f) if (!(namespace_bits&(f))) break;
struct UDMFParser struct UDMFParser
{ {
FScanner sc; FScanner sc;
FName namespc; FName namespc;
int namespace_bits;
bool isTranslated; bool isTranslated;
bool isExtended; bool isExtended;
bool floordrop;
TArray<line_t> ParsedLines; TArray<line_t> ParsedLines;
TArray<side_t> ParsedSides; TArray<side_t> ParsedSides;
@ -70,60 +136,126 @@ struct UDMFParser
fogMap = normMap = NULL; fogMap = normMap = NULL;
} }
void Flag(DWORD &value, int mask, const FString &svalue) FName ParseKey()
{ {
if (!svalue.CompareNoCase("true")) sc.MustGetString();
FName key = sc.String;
sc.MustGetToken('=');
sc.Number = 0;
sc.Float = 0;
sc.MustGetAnyToken();
if (sc.TokenType == '+' || sc.TokenType == '-')
{ {
value |= mask; bool neg = (sc.TokenType == '-');
sc.MustGetAnyToken();
if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst)
{
sc.ScriptMessage("Numeric constant expected");
}
if (neg)
{
sc.Number = -sc.Number;
sc.Float = -sc.Float;
}
} }
else return key;
}
int CheckInt(const char *key)
{
if (sc.TokenType != TK_IntConst)
{ {
value &= ~mask; sc.ScriptMessage("Integer value expected for key '%s'", key);
} }
return sc.Number;
}
double CheckFloat(const char *key)
{
if (sc.TokenType != TK_IntConst && sc.TokenType != TK_FloatConst)
{
sc.ScriptMessage("Floatint point value expected for key '%s'", key);
}
return sc.Float;
}
fixed_t CheckFixed(const char *key)
{
return FLOAT2FIXED(CheckFloat(key));
}
bool CheckBool(const char *key)
{
if (sc.TokenType == TK_True) return true;
if (sc.TokenType == TK_False) return false;
sc.ScriptMessage("Boolean value expected for key '%s'", key);
return false;
}
const char *CheckString(const char *key)
{
if (sc.TokenType != TK_StringConst)
{
sc.ScriptMessage("String value expected for key '%s'", key);
}
return sc.String;
}
void Flag(DWORD &value, int mask, const char *key)
{
if (CheckBool(key)) value |= mask;
else value &= ~mask;
} }
void ParseThing(FMapThing *th) void ParseThing(FMapThing *th)
{ {
memset(th, 0, sizeof(*th)); memset(th, 0, sizeof(*th));
sc.MustGetStringName("{"); sc.MustGetToken('{');
while (!sc.CheckString("}")) while (!sc.CheckToken('}'))
{ {
sc.MustGetString(); FName key = ParseKey();
FName key = sc.String;
sc.MustGetStringName("=");
sc.MustGetString();
FString value = sc.String;
sc.MustGetStringName(";");
switch(key) switch(key)
{ {
case NAME_TID: case NAME_Id:
th->thingid = (WORD)strtol(value, NULL, 0); th->thingid = CheckInt(key);
break; break;
case NAME_X: case NAME_X:
th->x = FLOAT2FIXED(strtod(value, NULL)); th->x = CheckFixed(key);
break; break;
case NAME_Y: case NAME_Y:
th->y = FLOAT2FIXED(strtod(value, NULL)); th->y = CheckFixed(key);
break; break;
case NAME_Height: case NAME_Height:
th->z = FLOAT2FIXED(strtod(value, NULL)); th->z = CheckFixed(key);
break; break;
case NAME_Angle: case NAME_Angle:
th->angle = (short)strtol(value, NULL, 0); th->angle = (short)CheckInt(key);
break; break;
case NAME_Type: case NAME_Type:
th->type = (short)strtol(value, NULL, 0); th->type = (short)CheckInt(key);
break; break;
case NAME_Special: case NAME_Special:
th->special = (short)strtol(value, NULL, 0); CHECK_N(Hx | Zd | Zdt)
th->special = CheckInt(key);
break; break;
case NAME_Arg0: case NAME_Arg0:
case NAME_Arg1: case NAME_Arg1:
case NAME_Arg2: case NAME_Arg2:
case NAME_Arg3: case NAME_Arg3:
case NAME_Arg4: case NAME_Arg4:
th->args[int(key)-int(NAME_Arg0)] = strtol(value, NULL, 0); CHECK_N(Hx | Zd | Zdt)
th->args[int(key)-int(NAME_Arg0)] = CheckInt(key);
break; break;
case NAME_Skill1: case NAME_Skill1:
case NAME_Skill2: case NAME_Skill2:
case NAME_Skill3: case NAME_Skill3:
@ -140,11 +272,10 @@ struct UDMFParser
case NAME_Skill14: case NAME_Skill14:
case NAME_Skill15: case NAME_Skill15:
case NAME_Skill16: case NAME_Skill16:
if (!value.CompareNoCase("true")) th->SkillFilter |= (1<<(int(key)-NAME_Skill1)); if (CheckBool(key)) th->SkillFilter |= (1<<(int(key)-NAME_Skill1));
else th->SkillFilter &= ~(1<<(int(key)-NAME_Skill1)); else th->SkillFilter &= ~(1<<(int(key)-NAME_Skill1));
break; break;
case NAME_Class0:
case NAME_Class1: case NAME_Class1:
case NAME_Class2: case NAME_Class2:
case NAME_Class3: case NAME_Class3:
@ -161,43 +292,72 @@ struct UDMFParser
case NAME_Class14: case NAME_Class14:
case NAME_Class15: case NAME_Class15:
case NAME_Class16: case NAME_Class16:
if (!value.CompareNoCase("true")) th->ClassFilter |= (1<<(int(key)-NAME_Class1)); CHECK_N(Hx | Zd | Zdt)
if (CheckBool(key)) th->ClassFilter |= (1<<(int(key)-NAME_Class1));
else th->SkillFilter &= ~(1<<(int(key)-NAME_Class1)); else th->SkillFilter &= ~(1<<(int(key)-NAME_Class1));
break; break;
case NAME_Ambush: case NAME_Ambush:
Flag(th->flags, MTF_AMBUSH, value); break; Flag(th->flags, MTF_AMBUSH, key);
break;
case NAME_Dormant: case NAME_Dormant:
Flag(th->flags, MTF_DORMANT, value); break; CHECK_N(Hx | Zd | Zdt)
Flag(th->flags, MTF_DORMANT, key);
break;
case NAME_Single: case NAME_Single:
Flag(th->flags, MTF_SINGLE, value); break; Flag(th->flags, MTF_SINGLE, key);
break;
case NAME_Coop: case NAME_Coop:
Flag(th->flags, MTF_COOPERATIVE, value); break; Flag(th->flags, MTF_COOPERATIVE, key);
break;
case NAME_Dm: case NAME_Dm:
Flag(th->flags, MTF_DEATHMATCH, value); break; Flag(th->flags, MTF_DEATHMATCH, key);
break;
case NAME_Translucent: case NAME_Translucent:
Flag(th->flags, MTF_SHADOW, value); break; CHECK_N(St | Zd | Zdt)
Flag(th->flags, MTF_SHADOW, key);
break;
case NAME_Invisible: case NAME_Invisible:
Flag(th->flags, MTF_ALTSHADOW, value); break; CHECK_N(St | Zd | Zdt)
case NAME_Friend: Flag(th->flags, MTF_ALTSHADOW, key);
break;
case NAME_Friend: // This maps to Strife's friendly flag
CHECK_N(Dm | Zd | Zdt)
Flag(th->flags, MTF_FRIENDLY, key);
break;
case NAME_Strifeally: case NAME_Strifeally:
Flag(th->flags, MTF_FRIENDLY, value); break; CHECK_N(St | Zd | Zdt)
Flag(th->flags, MTF_FRIENDLY, key);
break;
case NAME_Standing: case NAME_Standing:
Flag(th->flags, MTF_STANDSTILL, value); break; CHECK_N(St | Zd | Zdt)
Flag(th->flags, MTF_STANDSTILL, key);
break;
default: default:
break; break;
} }
sc.MustGetToken(';');
} }
if (isTranslated) // Thing specials are only valid in namespaces with Hexen-type specials
// and in ZDoomTranslated - which will use the translator on them.
if (namespc == NAME_ZDoomTranslated)
{ {
if (isExtended) maplinedef_t mld;
{ line_t ld;
// NOTE: Handling of this is undefined in the UDMF spec
// so it is only done for namespace ZDoomTranslated
maplinedef_t mld;
line_t ld;
if (th->special != 0) // if special is 0, keep the args (e.g. for bridge things)
{
// The trigger type is ignored here.
mld.flags = 0; mld.flags = 0;
mld.special = th->special; mld.special = th->special;
mld.tag = th->args[0]; mld.tag = th->args[0];
@ -205,17 +365,18 @@ struct UDMFParser
th->special = ld.special; th->special = ld.special;
memcpy(th->args, ld.args, sizeof (ld.args)); memcpy(th->args, ld.args, sizeof (ld.args));
} }
else // NULL the special }
{ else if (isTranslated)
th->special = 0; {
memset(th->args, 0, sizeof (th->args)); th->special = 0;
} memset(th->args, 0, sizeof (th->args));
} }
} }
void ParseLinedef(line_t *ld) void ParseLinedef(line_t *ld)
{ {
bool passuse = false; bool passuse = false;
bool strifetrans = false;
memset(ld, 0, sizeof(*ld)); memset(ld, 0, sizeof(*ld));
ld->Alpha = FRACUNIT; ld->Alpha = FRACUNIT;
@ -224,72 +385,109 @@ struct UDMFParser
if (level.flags & LEVEL_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX; if (level.flags & LEVEL_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
if (level.flags & LEVEL_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX; if (level.flags & LEVEL_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
if (level.flags & LEVEL_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE; if (level.flags & LEVEL_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;
sc.MustGetStringName("{");
while (!sc.CheckString("}")) sc.MustGetToken('{');
while (!sc.CheckToken('}'))
{ {
sc.MustGetString(); FName key = ParseKey();
FName key = sc.String;
sc.MustGetStringName("=");
sc.MustGetString();
FString value = sc.String;
sc.MustGetStringName(";");
// This switch contains all keys of the UDMF base spec // This switch contains all keys of the UDMF base spec
switch(key) switch(key)
{ {
case NAME_V1: case NAME_V1:
ld->v1 = (vertex_t*)(intptr_t)strtol(value, NULL, 0); // must be relocated later ld->v1 = (vertex_t*)(intptr_t)CheckInt(key); // must be relocated later
break; break;
case NAME_V2: case NAME_V2:
ld->v2 = (vertex_t*)(intptr_t)strtol(value, NULL, 0); // must be relocated later ld->v2 = (vertex_t*)(intptr_t)CheckInt(key); // must be relocated later
break; break;
case NAME_Special: case NAME_Special:
ld->special = strtol(value, NULL, 0); ld->special = CheckInt(key);
if (namespc == NAME_Hexen)
{
if (ld->special < 0 || ld->special > 140 || !HexenLineSpecialOk[ld->special])
ld->special = 0; // NULL all specials which don't exist in Hexen
}
break; break;
case NAME_Id: case NAME_Id:
ld->id = strtol(value, NULL, 0); ld->id = CheckInt(key);
break; break;
case NAME_Sidefront: case NAME_Sidefront:
ld->sidenum[0] = strtol(value, NULL, 0); ld->sidenum[0] = CheckInt(key);
break; break;
case NAME_Sideback: case NAME_Sideback:
ld->sidenum[1] = strtol(value, NULL, 0); ld->sidenum[1] = CheckInt(key);
break; break;
case NAME_Arg0: case NAME_Arg0:
case NAME_Arg1: case NAME_Arg1:
case NAME_Arg2: case NAME_Arg2:
case NAME_Arg3: case NAME_Arg3:
case NAME_Arg4: case NAME_Arg4:
ld->args[int(key)-int(NAME_Arg0)] = strtol(value, NULL, 0); ld->args[int(key)-int(NAME_Arg0)] = CheckInt(key);
break; break;
case NAME_Blocking: case NAME_Blocking:
Flag(ld->flags, ML_BLOCKING, value); break; Flag(ld->flags, ML_BLOCKING, key);
break;
case NAME_Blockmonsters: case NAME_Blockmonsters:
Flag(ld->flags, ML_BLOCKMONSTERS, value); break; Flag(ld->flags, ML_BLOCKMONSTERS, key);
break;
case NAME_Twosided: case NAME_Twosided:
Flag(ld->flags, ML_TWOSIDED, value); break; Flag(ld->flags, ML_TWOSIDED, key);
break;
case NAME_Dontpegtop: case NAME_Dontpegtop:
Flag(ld->flags, ML_DONTPEGTOP, value); break; Flag(ld->flags, ML_DONTPEGTOP, key);
break;
case NAME_Dontpegbottom: case NAME_Dontpegbottom:
Flag(ld->flags, ML_DONTPEGBOTTOM, value); break; Flag(ld->flags, ML_DONTPEGBOTTOM, key);
break;
case NAME_Secret: case NAME_Secret:
Flag(ld->flags, ML_SECRET, value); break; Flag(ld->flags, ML_SECRET, key);
case NAME_Soundblock: break;
Flag(ld->flags, ML_SOUNDBLOCK, value); break;
case NAME_Blocksound:
Flag(ld->flags, ML_SOUNDBLOCK, key);
break;
case NAME_Dontdraw: case NAME_Dontdraw:
Flag(ld->flags, ML_DONTDRAW, value); break; Flag(ld->flags, ML_DONTDRAW, key);
break;
case NAME_Mapped: case NAME_Mapped:
Flag(ld->flags, ML_MAPPED, value); break; Flag(ld->flags, ML_MAPPED, key);
case NAME_Monsteractivate: break;
Flag(ld->flags, ML_MONSTERSCANACTIVATE, value); break;
case NAME_Jumpover: case NAME_Jumpover:
Flag(ld->flags, ML_RAILING, value); break; CHECK_N(St | Zd | Zdt)
Flag(ld->flags, ML_RAILING, key);
break;
case NAME_Blockfloating: case NAME_Blockfloating:
Flag(ld->flags, ML_BLOCK_FLOATERS, value); break; CHECK_N(St | Zd | Zdt)
Flag(ld->flags, ML_BLOCK_FLOATERS, key);
break;
case NAME_Transparent: case NAME_Transparent:
ld->Alpha = !value.CompareNoCase("true")? FRACUNIT*3/4 : FRACUNIT; break; CHECK_N(St | Zd | Zdt)
strifetrans = CheckBool(key);
break;
case NAME_Passuse: case NAME_Passuse:
passuse = !value.CompareNoCase("true"); break; CHECK_N(Dm | Zd | Zdt)
passuse = CheckBool(key);
break;
default: default:
break; break;
} }
@ -298,48 +496,94 @@ struct UDMFParser
if (!isTranslated) switch (key) if (!isTranslated) switch (key)
{ {
case NAME_Playercross: case NAME_Playercross:
Flag(ld->activation, SPAC_Cross, value); break; Flag(ld->activation, SPAC_Cross, key);
break;
case NAME_Playeruse: case NAME_Playeruse:
Flag(ld->activation, SPAC_Use, value); break; Flag(ld->activation, SPAC_Use, key);
break;
case NAME_Monstercross: case NAME_Monstercross:
Flag(ld->activation, SPAC_MCross, value); break; Flag(ld->activation, SPAC_MCross, key);
break;
case NAME_Impact: case NAME_Impact:
Flag(ld->activation, SPAC_Impact, value); break; Flag(ld->activation, SPAC_Impact, key);
break;
case NAME_Playerpush: case NAME_Playerpush:
Flag(ld->activation, SPAC_Push, value); break; Flag(ld->activation, SPAC_Push, key);
break;
case NAME_Missilecross: case NAME_Missilecross:
Flag(ld->activation, SPAC_PCross, value); break; Flag(ld->activation, SPAC_PCross, key);
break;
case NAME_Monsteruse: case NAME_Monsteruse:
Flag(ld->activation, SPAC_MUse, value); break; Flag(ld->activation, SPAC_MUse, key);
break;
case NAME_Monsterpush: case NAME_Monsterpush:
Flag(ld->activation, SPAC_MPush, value); break; Flag(ld->activation, SPAC_MPush, key);
break;
case NAME_Repeatspecial:
Flag(ld->flags, ML_REPEAT_SPECIAL, key);
break;
default: default:
break; break;
} }
// This switch contains all keys which are ZDoom specific // This switch contains all keys which are ZDoom specific
if (isExtended) switch(key) if (namespace_bits & (Zd|Zdt)) switch(key)
{ {
case NAME_Anycross:
Flag(ld->activation, SPAC_AnyCross, key);
break;
case NAME_Monsteractivate:
Flag(ld->flags, ML_MONSTERSCANACTIVATE, key);
break;
case NAME_Blockplayers: case NAME_Blockplayers:
Flag(ld->flags, ML_BLOCK_PLAYERS, value); break; Flag(ld->flags, ML_BLOCK_PLAYERS, key);
break;
case NAME_Blockeverything: case NAME_Blockeverything:
Flag(ld->flags, ML_BLOCKEVERYTHING, value); break; Flag(ld->flags, ML_BLOCKEVERYTHING, key);
break;
case NAME_Zoneboundary: case NAME_Zoneboundary:
Flag(ld->flags, ML_ZONEBOUNDARY, value); break; Flag(ld->flags, ML_ZONEBOUNDARY, key);
break;
case NAME_Clipmidtex: case NAME_Clipmidtex:
Flag(ld->flags, ML_CLIP_MIDTEX, value); break; Flag(ld->flags, ML_CLIP_MIDTEX, key);
break;
case NAME_Wrapmidtex: case NAME_Wrapmidtex:
Flag(ld->flags, ML_WRAP_MIDTEX, value); break; Flag(ld->flags, ML_WRAP_MIDTEX, key);
break;
case NAME_Midtex3d: case NAME_Midtex3d:
Flag(ld->flags, ML_3DMIDTEX, value); break; Flag(ld->flags, ML_3DMIDTEX, key);
break;
case NAME_Checkswitchrange: case NAME_Checkswitchrange:
Flag(ld->flags, ML_CHECKSWITCHRANGE, value); break; Flag(ld->flags, ML_CHECKSWITCHRANGE, key);
break;
case NAME_Firstsideonly: case NAME_Firstsideonly:
Flag(ld->flags, ML_FIRSTSIDEONLY, value); break; Flag(ld->flags, ML_FIRSTSIDEONLY, key);
break;
default: default:
break; break;
} }
sc.MustGetToken(';');
} }
if (isTranslated) if (isTranslated)
{ {
int saved = ld->flags; int saved = ld->flags;
@ -355,6 +599,10 @@ struct UDMFParser
{ {
ld->activation = (ld->activation & ~SPAC_Use) | SPAC_UseThrough; ld->activation = (ld->activation & ~SPAC_Use) | SPAC_UseThrough;
} }
if (strifetrans && ld->Alpha == FRACUNIT)
{
ld->Alpha = FRACUNIT * 3/4;
}
} }
void ParseSidedef(side_t *sd, mapsidedef_t *sdt) void ParseSidedef(side_t *sd, mapsidedef_t *sdt)
@ -365,44 +613,41 @@ struct UDMFParser
strncpy(sdt->bottomtexture, "-", 8); strncpy(sdt->bottomtexture, "-", 8);
strncpy(sdt->toptexture, "-", 8); strncpy(sdt->toptexture, "-", 8);
strncpy(sdt->midtexture, "-", 8); strncpy(sdt->midtexture, "-", 8);
sc.MustGetStringName("{");
while (!sc.CheckString("}")) sc.MustGetToken('{');
while (!sc.CheckToken('}'))
{ {
sc.MustGetString(); FName key = ParseKey();
FName key = sc.String;
sc.MustGetStringName("=");
sc.MustGetString();
FString value = sc.String;
sc.MustGetStringName(";");
switch(key) switch(key)
{ {
case NAME_Offsetx: case NAME_Offsetx:
texofs[0] = strtol(value, NULL, 0) << FRACBITS; texofs[0] = CheckInt(key) << FRACBITS;
break; break;
case NAME_Offsety: case NAME_Offsety:
texofs[1] = strtol(value, NULL, 0) << FRACBITS; texofs[1] = CheckInt(key) << FRACBITS;
break; break;
case NAME_Texturetop: case NAME_Texturetop:
strncpy(sdt->toptexture, value, 8); strncpy(sdt->toptexture, CheckString(key), 8);
break; break;
case NAME_Texturebottom: case NAME_Texturebottom:
strncpy(sdt->bottomtexture, value, 8); strncpy(sdt->bottomtexture, CheckString(key), 8);
break; break;
case NAME_Texturemiddle: case NAME_Texturemiddle:
strncpy(sdt->midtexture, value, 8); strncpy(sdt->midtexture, CheckString(key), 8);
break; break;
case NAME_Sector: case NAME_Sector:
sd->sector = (sector_t*)(intptr_t)strtol(value, NULL, 0); sd->sector = (sector_t*)(intptr_t)CheckInt(key);
break; break;
default: default:
break; break;
} }
sc.MustGetToken(';');
} }
// initialization of these is delayed to allow separate offsets and add them with the global ones. // initialization of these is delayed to allow separate offsets and add them with the global ones.
sd->AddTextureXOffset(side_t::top, texofs[0]); sd->AddTextureXOffset(side_t::top, texofs[0]);
@ -416,7 +661,7 @@ struct UDMFParser
void ParseSector(sector_t *sec) void ParseSector(sector_t *sec)
{ {
memset(sec, 0, sizeof(*sec)); memset(sec, 0, sizeof(*sec));
sec->lightlevel = 255; sec->lightlevel = 160;
sec->floor_xscale = FRACUNIT; // [RH] floor and ceiling scaling sec->floor_xscale = FRACUNIT; // [RH] floor and ceiling scaling
sec->floor_yscale = FRACUNIT; sec->floor_yscale = FRACUNIT;
sec->ceiling_xscale = FRACUNIT; sec->ceiling_xscale = FRACUNIT;
@ -428,6 +673,7 @@ struct UDMFParser
sec->nextsec = -1; //jff 2/26/98 add fields to support locking out sec->nextsec = -1; //jff 2/26/98 add fields to support locking out
sec->prevsec = -1; // stair retriggering until build completes sec->prevsec = -1; // stair retriggering until build completes
sec->heightsec = NULL; // sector used to get floor and ceiling height sec->heightsec = NULL; // sector used to get floor and ceiling height
if (floordrop) sec->Flags = SECF_FLOORDROP;
// killough 3/7/98: end changes // killough 3/7/98: end changes
sec->gravity = 1.f; // [RH] Default sector gravity of 1.0 sec->gravity = 1.f; // [RH] Default sector gravity of 1.0
@ -437,49 +683,50 @@ struct UDMFParser
sec->friction = ORIG_FRICTION; sec->friction = ORIG_FRICTION;
sec->movefactor = ORIG_FRICTION_FACTOR; sec->movefactor = ORIG_FRICTION_FACTOR;
sc.MustGetStringName("{"); sc.MustGetToken('{');
while (!sc.CheckString("}")) while (!sc.CheckToken('}'))
{ {
sc.MustGetString(); FName key = ParseKey();
FName key = sc.String;
sc.MustGetStringName("=");
sc.MustGetString();
FString value = sc.String;
sc.MustGetStringName(";");
switch(key) switch(key)
{ {
case NAME_Heightfloor: case NAME_Heightfloor:
sec->floortexz = strtol(value, NULL, 0) << FRACBITS; sec->floortexz = CheckInt(key) << FRACBITS;
break; break;
case NAME_Heightceiling: case NAME_Heightceiling:
sec->ceilingtexz = strtol(value, NULL, 0) << FRACBITS; sec->ceilingtexz = CheckInt(key) << FRACBITS;
break; break;
case NAME_Texturefloor: case NAME_Texturefloor:
sec->floorpic = TexMan.GetTexture (value, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); sec->floorpic = TexMan.GetTexture (CheckString(key), FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
break; break;
case NAME_Textureceiling: case NAME_Textureceiling:
sec->ceilingpic = TexMan.GetTexture (value, FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable); sec->ceilingpic = TexMan.GetTexture (CheckString(key), FTexture::TEX_Flat, FTextureManager::TEXMAN_Overridable);
break; break;
case NAME_Lightlevel: case NAME_Lightlevel:
sec->lightlevel = (BYTE)clamp<int>(strtol(value, NULL, 0), 0, 255); sec->lightlevel = (BYTE)clamp<int>(CheckInt(key), 0, 255);
break; break;
case NAME_Special: case NAME_Special:
sec->special = (short)strtol(value, NULL, 0); sec->special = (short)CheckInt(key);
if (isTranslated) sec->special = P_TranslateSectorSpecial(sec->special); if (isTranslated) sec->special = P_TranslateSectorSpecial(sec->special);
else if (namespc == NAME_Hexen)
{
if (sec->special < 0 || sec->special > 255 || !HexenSectorSpecialOk[sec->special])
sec->special = 0; // NULL all unknown specials
}
break; break;
case NAME_Tag: case NAME_Id:
sec->tag = (short)strtol(value, NULL, 0); sec->tag = (short)CheckInt(key);
break; break;
default: default:
break; break;
} }
sc.MustGetToken(';');
} }
sec->floorplane.d = -sec->floortexz; sec->floorplane.d = -sec->floortexz;
@ -603,7 +850,6 @@ struct UDMFParser
char *buffer = new char[map->Size(ML_TEXTMAP)]; char *buffer = new char[map->Size(ML_TEXTMAP)];
isTranslated = true; isTranslated = true;
isExtended = false;
map->Read(ML_TEXTMAP, buffer); map->Read(ML_TEXTMAP, buffer);
sc.OpenMem(Wads.GetLumpFullName(map->lumpnum), buffer, map->Size(ML_TEXTMAP)); sc.OpenMem(Wads.GetLumpFullName(map->lumpnum), buffer, map->Size(ML_TEXTMAP));
@ -613,34 +859,58 @@ struct UDMFParser
sc.MustGetStringName("="); sc.MustGetStringName("=");
sc.MustGetString(); sc.MustGetString();
namespc = sc.String; namespc = sc.String;
if (namespc == NAME_ZDoom) switch(namespc)
{ {
case NAME_ZDoom:
namespace_bits = Zd;
isTranslated = false; isTranslated = false;
isExtended = true; break;
} case NAME_ZDoomTranslated:
else if (namespc == NAME_Hexen) namespace_bits = Zdt;
{ break;
case NAME_Hexen:
namespace_bits = Hx;
isTranslated = false; isTranslated = false;
} break;
else if (namespc == NAME_ZDoomTranslated) case NAME_Doom:
{ namespace_bits = Dm;
isExtended = true;
}
else if (namespc == NAME_Doom)
{
P_LoadTranslator("xlat/doom_base.txt"); P_LoadTranslator("xlat/doom_base.txt");
} level.flags |= LEVEL_DUMMYSWITCHES;
else if (namespc == NAME_Heretic) floordrop = true;
{ break;
case NAME_Heretic:
namespace_bits = Ht;
P_LoadTranslator("xlat/heretic_base.txt"); P_LoadTranslator("xlat/heretic_base.txt");
} level.flags |= LEVEL_DUMMYSWITCHES;
else if (namespc == NAME_Strife) floordrop = true;
{ break;
case NAME_Strife:
namespace_bits = St;
P_LoadTranslator("xlat/strife_base.txt"); P_LoadTranslator("xlat/strife_base.txt");
} level.flags |= LEVEL_DUMMYSWITCHES|LEVEL_RAILINGHACK;
else floordrop = true;
{ break;
Printf("Unknown namespace %s\n", sc.String); default:
Printf("Unknown namespace %s. Using defaults for %s\n", sc.String, GameNames[gameinfo.gametype]);
switch (gameinfo.gametype)
{
case GAME_Doom:
namespace_bits = Dm;
P_LoadTranslator("xlat/doom_base.txt");
break;
case GAME_Heretic:
namespace_bits = Ht;
P_LoadTranslator("xlat/heretic_base.txt");
break;
case GAME_Strife:
namespace_bits = St;
P_LoadTranslator("xlat/strife_base.txt");
break;
case GAME_Hexen:
namespace_bits = Hx;
isTranslated = false;
break;
}
} }
sc.MustGetStringName(";"); sc.MustGetStringName(";");
} }
@ -693,8 +963,8 @@ struct UDMFParser
// Create the real sectors // Create the real sectors
numsectors = ParsedSectors.Size(); numsectors = ParsedSectors.Size();
sectors = new sector_t[numsectors]; sectors = new sector_t[numsectors];
sectors[0].e = new extsector_t[numsectors];
memcpy(sectors, &ParsedSectors[0], numsectors * sizeof(*sectors)); memcpy(sectors, &ParsedSectors[0], numsectors * sizeof(*sectors));
sectors[0].e = new extsector_t[numsectors];
for(int i = 0; i < numsectors; i++) for(int i = 0; i < numsectors; i++)
{ {
sectors[i].e = &sectors[0].e[i]; sectors[i].e = &sectors[0].e[i];

View file

@ -2202,7 +2202,7 @@ void P_PlayerThink (player_t *player)
} }
if (!--player->morphTics) if (!--player->morphTics)
{ // Attempt to undo the chicken/pig { // Attempt to undo the chicken/pig
P_UndoPlayerMorph (player); P_UndoPlayerMorph (player, player);
} }
} }
// Cycle psprites // Cycle psprites

View file

@ -23,6 +23,7 @@
#include "s_sndseq.h" #include "s_sndseq.h"
#include "a_sharedglobal.h" #include "a_sharedglobal.h"
#include "r_main.h" #include "r_main.h"
#include "p_lnspec.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -1172,8 +1173,8 @@ static void InitSegLists ()
if (segs[i].linedef != NULL) if (segs[i].linedef != NULL)
{ {
SegListHead[segs[i].v1 - vertexes] = i; SegListHead[segs[i].v1 - vertexes] = i;
if ((segs[i].linedef->special == PO_LINE_START || if ((segs[i].linedef->special == Polyobj_StartLine ||
segs[i].linedef->special == PO_LINE_EXPLICIT)) segs[i].linedef->special == Polyobj_ExplicitLine))
{ {
KnownPolySegs.Push (i); KnownPolySegs.Push (i);
} }
@ -1265,7 +1266,7 @@ static void SpawnPolyobj (int index, int tag, int type)
continue; continue;
} }
if (segs[i].linedef->special == PO_LINE_START && if (segs[i].linedef->special == Polyobj_StartLine &&
segs[i].linedef->args[0] == tag) segs[i].linedef->args[0] == tag)
{ {
if (polyobjs[index].segs) if (polyobjs[index].segs)
@ -1306,7 +1307,7 @@ static void SpawnPolyobj (int index, int tag, int type)
i = KnownPolySegs[ii]; i = KnownPolySegs[ii];
if (i >= 0 && if (i >= 0 &&
segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->special == Polyobj_ExplicitLine &&
segs[i].linedef->args[0] == tag) segs[i].linedef->args[0] == tag)
{ {
if (!segs[i].linedef->args[1]) if (!segs[i].linedef->args[1])
@ -1327,7 +1328,7 @@ static void SpawnPolyobj (int index, int tag, int type)
{ {
i = KnownPolySegs[ii]; i = KnownPolySegs[ii];
if (i >= 0 && if (i >= 0 &&
segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->special == Polyobj_ExplicitLine &&
segs[i].linedef->args[0] == tag && segs[i].linedef->args[1] == j) segs[i].linedef->args[0] == tag && segs[i].linedef->args[1] == j)
{ {
segs[i].linedef->special = 0; segs[i].linedef->special = 0;
@ -1344,7 +1345,7 @@ static void SpawnPolyobj (int index, int tag, int type)
{ {
i = KnownPolySegs[ii]; i = KnownPolySegs[ii];
if (i >= 0 && if (i >= 0 &&
segs[i].linedef->special == PO_LINE_EXPLICIT && segs[i].linedef->special == Polyobj_ExplicitLine &&
segs[i].linedef->args[0] == tag) segs[i].linedef->args[0] == tag)
{ {
I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n", I_Error ("SpawnPolyobj: Missing explicit line %d for poly %d\n",

View file

@ -256,6 +256,7 @@ enum
{ {
SECF_SILENT = 1, // actors in sector make no noise SECF_SILENT = 1, // actors in sector make no noise
SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector
SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast.
}; };
struct FDynamicColormap; struct FDynamicColormap;

View file

@ -982,6 +982,32 @@ void STACK_ARGS FScanner::ScriptError (const char *message, ...)
AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); AlreadyGot? AlreadyGotLine : Line, composed.GetChars());
} }
//==========================================================================
//
// FScanner::ScriptError
//
//==========================================================================
void STACK_ARGS FScanner::ScriptMessage (const char *message, ...)
{
FString composed;
if (message == NULL)
{
composed = "Bad syntax.";
}
else
{
va_list arglist;
va_start (arglist, message);
composed.VFormat (message, arglist);
va_end (arglist);
}
Printf ("Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(),
AlreadyGot? AlreadyGotLine : Line, composed.GetChars());
}
//========================================================================== //==========================================================================
// //
// FScanner :: CheckOpen // FScanner :: CheckOpen

View file

@ -58,6 +58,7 @@ public:
int MustMatchString(const char **strings); int MustMatchString(const char **strings);
void ScriptError(const char *message, ...); void ScriptError(const char *message, ...);
void ScriptMessage(const char *message, ...);
// Members ------------------------------------------------------ // Members ------------------------------------------------------
char *String; char *String;

View file

@ -147,7 +147,7 @@ int FTextureManager::CheckForTexture (const char *name, int usetype, BITFIELD fl
if ((flags & TEXMAN_TryAny) && usetype != FTexture::TEX_Any) if ((flags & TEXMAN_TryAny) && usetype != FTexture::TEX_Any)
{ {
// Never return the index of NULL textures. // Never return the index of NULL textures.
if (firsttype == FTexture::TEX_Null) return 0; if (firstfound != -1 && firsttype == FTexture::TEX_Null) return 0;
return firstfound; return firstfound;
} }

View file

@ -756,11 +756,13 @@ static int ParseMorphStyle (FScanner &sc)
{ {
static const char * morphstyles[]={ static const char * morphstyles[]={
"MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE", "MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE",
"MRF_FAILNOTELEFRAG", "MRF_FAILNOLAUGH", "MRF_WHENINVULNERABLE", "MRF_LOSEACTUALWEAPON", NULL}; "MRF_FAILNOTELEFRAG", "MRF_FAILNOLAUGH", "MRF_WHENINVULNERABLE", "MRF_LOSEACTUALWEAPON",
"MRF_NEWTIDBEHAVIOUR", "MRF_UNDOBYDEATH", "MRF_UNDOBYDEATHFORCED", "MRF_UNDOBYDEATHSAVES", NULL};
static const int morphstyle_values[]={ static const int morphstyle_values[]={
MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE, MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE,
MORPH_FAILNOTELEFRAG, MORPH_FAILNOLAUGH, MORPH_WHENINVULNERABLE, MORPH_LOSEACTUALWEAPON}; MORPH_FAILNOTELEFRAG, MORPH_FAILNOLAUGH, MORPH_WHENINVULNERABLE, MORPH_LOSEACTUALWEAPON,
MORPH_NEWTIDBEHAVIOUR, MORPH_UNDOBYDEATH, MORPH_UNDOBYDEATHFORCED, MORPH_UNDOBYDEATHSAVES};
// May be given flags by number... // May be given flags by number...
if (sc.CheckNumber()) if (sc.CheckNumber())

View file

@ -115,13 +115,13 @@ struct XlatParseContext : public FParseContext
{ {
"arg2", "arg3", "arg4", "arg5", "bitmask", "clear", "arg2", "arg3", "arg4", "arg5", "bitmask", "clear",
"define", "enum", "flags", "include", "lineid", "define", "enum", "flags", "include", "lineid",
"nobitmask", "sector", "tag", "maxlinespecial" "maxlinespecial", "nobitmask", "sector", "tag"
}; };
static const short types[] = static const short types[] =
{ {
XLAT_ARG2, XLAT_ARG3, XLAT_ARG4, XLAT_ARG5, XLAT_BITMASK, XLAT_CLEAR, XLAT_ARG2, XLAT_ARG3, XLAT_ARG4, XLAT_ARG5, XLAT_BITMASK, XLAT_CLEAR,
XLAT_DEFINE, XLAT_ENUM, XLAT_FLAGS, XLAT_INCLUDE, XLAT_TAG, XLAT_DEFINE, XLAT_ENUM, XLAT_FLAGS, XLAT_INCLUDE, XLAT_TAG,
XLAT_NOBITMASK, XLAT_SECTOR, XLAT_TAG, XLAT_MAXLINESPECIAL XLAT_MAXLINESPECIAL, XLAT_NOBITMASK, XLAT_SECTOR, XLAT_TAG
}; };
int min = 0, max = countof(tokens) - 1; int min = 0, max = countof(tokens) - 1;