- Added Martin Howe's morph system update.

- Added support for defining composite textures in HIRESTEX. It is not fully tested
  and right now can't do much more than the old TEXTUREx method.
- Added a few NULL pointer checks to the texture code.
- Made duplicate class names in DECORATE non-fatal. There is really no stability
  concern here and the worst that can happen is that the wrong actor is spawned.
  This was a constant hassle when testing with WADs that contain duplicate resources.


SVN r905 (trunk)
This commit is contained in:
Christoph Oelckers 2008-04-12 15:31:18 +00:00
parent b340f9c762
commit 6b2a7b8b03
19 changed files with 277 additions and 47 deletions

View file

@ -1,3 +1,12 @@
April 12, 2008 (Changes by Graf Zahl)
- Added Martin Howe's morph system update.
- Added support for defining composite textures in HIRESTEX. It is not fully tested
and right now can't do much more than the old TEXTUREx method.
- Added a few NULL pointer checks to the texture code.
- Made duplicate class names in DECORATE non-fatal. There is really no stability
concern here and the worst that can happen is that the wrong actor is spawned.
This was a constant hassle when testing with WADs that contain duplicate resources.
April 11, 2008
- Removed some GCC warnings.
- Fixed: MinGW doesn't have _get_pgmptr(), so it couldn't compile i_main.cpp.
@ -20,6 +29,15 @@ April 11, 2008
tables.cpp. (And interestingly, VC++ automatically renamed the object file,
so I wasn't aware of the problem with GCC.)
April 11, 2008 (Changes by Graf Zahl)
- Added a Gets function to the FileReader class which I planned to use
to enable Timidity to read its config and sound patches from Zips.
I put this on hold though after finding out that the sound quality
isn't even near that of Timidity++.
- GCC-Fixes (FString::GetChars() for Printf calls)
- Added a dummy Weapon.NOLMS flag so that Skulltag weapons using this flag
can be loaded
April 10, 2008
- Changed the MIDIStreamer to send the all notes off controller to each
channel when restarting the song, rather than emitting a single note off

View file

@ -181,7 +181,9 @@ void PClass::InsertIntoHash ()
}
else if (lexx == 0)
{ // This type has already been inserted
I_FatalError ("Tried to register class '%s' more than once.", TypeName.GetChars());
// ... but there is no need whatsoever to make it a fatal error!
Printf ("Tried to register class '%s' more than once.\n", TypeName.GetChars());
break;
}
else
{ // Type comes right here

View file

@ -36,7 +36,10 @@ bool AArtiTomeOfPower::Use (bool pickup)
{ // Attempt to undo chicken
if (!P_UndoPlayerMorph (Owner->player))
{ // Failed
P_DamageMobj (Owner, NULL, NULL, 1000000, NAME_Telefrag);
if (!(Owner->player->MorphStyle & MORPH_FAILNOTELEFRAG))
{
P_DamageMobj (Owner, NULL, NULL, 1000000, NAME_Telefrag);
}
}
else
{ // Succeeded

View file

@ -59,16 +59,18 @@ bool AArtiTeleport::Use (bool pickup)
destAngle = ANG45 * (playerstarts[Owner->player - players].angle/45);
}
P_Teleport (Owner, destX, destY, ONFLOORZ, destAngle, true, true, false);
if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYCHAOSDEVICE))
{ // Teleporting away will undo any morph effects (pig)
P_UndoPlayerMorph (Owner->player);
}
// The game check is not necessary because only Heretic defines *evillaugh by default
// However if it is there no other game can use it if it wants to.
//if (gameinfo.gametype == GAME_Heretic)
{ // Full volume laugh
S_Sound (Owner, CHAN_VOICE, "*evillaugh", 1, ATTN_NONE);
}
bool canlaugh = true;
if (Owner->player->morphTics && (Owner->player->MorphStyle & MORPH_UNDOBYCHAOSDEVICE))
{ // Teleporting away will undo any morph effects (pig)
if (!P_UndoPlayerMorph (Owner->player) && (Owner->player->MorphStyle & MORPH_FAILNOLAUGH))
{
canlaugh = false;
}
}
if (canlaugh)
{ // Full volume laugh
S_Sound (Owner, CHAN_VOICE, "*evillaugh", 1, ATTN_NONE);
}
return true;
}

View file

@ -1755,12 +1755,16 @@ void APowerMorph::InitEffect( )
const PClass *morph_flash = PClass::FindClass (MorphFlash);
const PClass *unmorph_flash = PClass::FindClass (UnMorphFlash);
const PClass *player_class = PClass::FindClass (PlayerClass);
if (P_MorphPlayer(realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash))
if (P_MorphPlayer(realplayer, realplayer, player_class, -1/*INDEFINITELY*/, MorphStyle, morph_flash, unmorph_flash))
{
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)
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
{
ItemFlags |= IF_INITEFFECTFAILED; // Let the caller know that the activation failed (can fail the pickup if appropriate)
}
}
}

View file

@ -21,7 +21,7 @@ static FRandom pr_morphmonst ("MorphMonster");
//
//---------------------------------------------------------------------------
bool P_MorphPlayer (player_t *p, const PClass *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash)
bool P_MorphPlayer (player_t *activator, player_t *p, const PClass *spawntype, int duration, int style, const PClass *enter_flash, const PClass *exit_flash)
{
AInventory *item;
APlayerPawn *morphed;
@ -36,8 +36,8 @@ bool P_MorphPlayer (player_t *p, const PClass *spawntype, int duration, int styl
{
return false;
}
if (p->mo->flags2 & MF2_INVULNERABLE)
{ // Immune when invulnerable
if ((p->mo->flags2 & MF2_INVULNERABLE) && ((p != activator) || (!(style & MORPH_WHENINVULNERABLE))))
{ // Immune when invulnerable unless this is a power we activated
return false;
}
if (p->morphTics)
@ -402,7 +402,7 @@ int AMorphProjectile::DoSpecialDamage (AActor *target, int damage)
if (target->player)
{
const PClass *player_class = PClass::FindClass (PlayerClass);
P_MorphPlayer (target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash);
P_MorphPlayer (NULL, target->player, player_class, Duration, MorphStyle, morph_flash, unmorph_flash);
}
else
{

View file

@ -7,30 +7,28 @@
// Morph style states how morphing affects health and
// other effects in the game; only valid for players.
// Default should be the old Heretic/HeXen behaviour,
// so the (int) value of MORPH_RAVEN *must* be zero.
// so (int) value of MORPH_OLDEFFECTS *must* be zero.
enum
{
MORPH_OLDEFFECTS = 0, // Default to old Heretic/HeXen behaviour unless flags given
MORPH_ADDSTAMINA = 1, // Power instead of curse (add stamina instead of limiting to health)
MORPH_FULLHEALTH = 2, // New health semantics (!POWER => MaxHealth of animal, POWER => Normal health behaviour)
MORPH_UNDOBYTOMEOFPOWER = 4,
MORPH_UNDOBYCHAOSDEVICE = 8,
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_FULLHEALTH = 0x00000002, // New health semantics (!POWER => MaxHealth of animal, POWER => Normal health behaviour)
MORPH_UNDOBYTOMEOFPOWER = 0x00000004, // Player unmorphs upon activating a Tome of Power
MORPH_UNDOBYCHAOSDEVICE = 0x00000008, // Player unmorphs upon activating a Chaos Device
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_WHENINVULNERABLE = 0x00000040 // Player can morph when invulnerable but ONLY if doing it to themselves
};
struct PClass;
class AActor;
class player_s;
//
// A_MORPH
//
bool P_MorphPlayer (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);
bool P_UndoPlayerMorph (player_s *player, bool force = false);
bool P_MorphMonster (AActor *actor, const PClass *morphclass, int duration = 0, int style = 0,
const PClass *enter_flash = NULL, const PClass *exit_flash = NULL);
bool P_UpdateMorphedMonster (AActor *actor);
#endif //__A_MORPH__

View file

@ -1227,6 +1227,14 @@ bool AInventory::TryPickup (AActor *toucher)
{
return false;
}
// Some powerups cannot activate absolutely, for
// example, PowerMorph; fail the pickup if so.
if (copy->ItemFlags & IF_INITEFFECTFAILED)
{
if (copy != this) copy->Destroy();
else ItemFlags &= ~IF_INITEFFECTFAILED;
return false;
}
// Handle owner-changing powerups
if (copy->ItemFlags & IF_CREATECOPYMOVED)
{

View file

@ -96,7 +96,8 @@ enum
IF_BIGPOWERUP = 1<<12, // Affected by RESPAWN_SUPER dmflag
IF_KEEPDEPLETED = 1<<13, // Items with this flag are retained even when they run out.
IF_IGNORESKILL = 1<<14, // Ignores any skill related multiplicators when giving this item.
IF_CREATECOPYMOVED = 1<<15 // CreateCopy changed the owner (copy's Owner field holds new owner).
IF_CREATECOPYMOVED = 1<<15, // CreateCopy changed the owner (copy's Owner field holds new owner).
IF_INITEFFECTFAILED = 1<<16 // CreateCopy tried to activate a powerup and activation failed (can happen with PowerMorph)
};
struct vissprite_t;

View file

@ -6,7 +6,7 @@
#include "actor.h"
class FDecalTemplate;
struct vertex_s;
struct vertex_t;
struct side_t;
extern void P_SpawnDirt (AActor *actor, fixed_t radius);
@ -50,7 +50,7 @@ protected:
void CalcFracPos (side_t *wall, fixed_t x, fixed_t y);
void Remove ();
static void SpreadLeft (fixed_t r, vertex_s *v1, side_t *feelwall);
static void SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall);
static void SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize);
};

View file

@ -440,14 +440,14 @@ const char *cht_Morph (player_t *player, const PClass *morphclass, bool quickund
{
if (P_UndoPlayerMorph (player))
{
if (!quickundo && oldclass != morphclass && P_MorphPlayer (player, morphclass, 0, style))
if (!quickundo && oldclass != morphclass && P_MorphPlayer (player, player, morphclass, 0, style))
{
return "You feel even stranger.";
}
return "You feel like yourself again.";
}
}
else if (P_MorphPlayer (player, morphclass, 0, style))
else if (P_MorphPlayer (player, player, morphclass, 0, style))
{
return "You feel strange...";
}

View file

@ -1061,6 +1061,8 @@ void APlayerPawn::ActivateMorphWeapon ()
}
}
P_SetPsprite (player, ps_flash, NULL);
player->PendingWeapon = WP_NOCHANGE;
}
//===========================================================================

View file

@ -83,6 +83,7 @@ class FMultiPatchTexture : public FTexture
{
public:
FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflump);
FMultiPatchTexture (FScanner &sc, int usetype);
~FMultiPatchTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
@ -102,7 +103,13 @@ protected:
struct TexPart
{
SWORD OriginX, OriginY;
BYTE Mirror:2;
BYTE Rotate:2;
BYTE textureOwned:1;
FTexture *Texture;
TexPart();
~TexPart();
};
int NumParts;
@ -113,6 +120,7 @@ protected:
private:
void CheckForHacks ();
void ParsePatch(FScanner &sc, TexPart & part);
};
// A texture defined between F_START and F_END markers

View file

@ -71,21 +71,21 @@ extern size_t MaxDrawSegs;
// Note: transformed values not buffered locally,
// like some DOOM-alikes ("wt", "WebView") did.
//
struct vertex_s
struct vertex_t
{
fixed_t x, y;
bool operator== (const vertex_s &other)
bool operator== (const vertex_t &other)
{
return x == other.x && y == other.y;
}
};
typedef struct vertex_s vertex_t;
// Forward of LineDefs, for Sectors.
struct line_t;
class player_s;
class FScanner;
//
// The SECTORS record, at runtime.
@ -744,7 +744,6 @@ public:
SWORD LeftOffset, TopOffset;
BYTE WidthBits, HeightBits;
//BYTE ScaleX, ScaleY;
fixed_t xScale;
fixed_t yScale;
@ -888,6 +887,7 @@ public:
FTexture *operator[] (const char *texname)
{
int texnum = GetTexture (texname, FTexture::TEX_MiscPatch);
if (texnum==-1) return NULL;
return Textures[texnum].Texture;
}
FTexture *FindTexture(const char *texname, int usetype = FTexture::TEX_MiscPatch, BITFIELD flags = TEXMAN_TryAny);
@ -901,6 +901,7 @@ public:
FTexture *operator() (const char *texname)
{
int texnum = GetTexture (texname, FTexture::TEX_MiscPatch);
if (texnum==-1) return NULL;
return Textures[Translation[texnum]].Texture;
}
@ -936,6 +937,7 @@ public:
void AddTiles (void *tileFile);
void AddHiresTextures (int wadnum);
void LoadHiresTex(int wadnum);
void ParseXTexture(FScanner &sc, int usetype);
int CreateTexture (int lumpnum, int usetype=FTexture::TEX_Any); // Also calls AddTexture
int AddTexture (FTexture *texture);

View file

@ -33,6 +33,7 @@
**
*/
#include <ctype.h>
#include "doomtype.h"
#include "files.h"
#include "r_data.h"
@ -40,6 +41,9 @@
#include "i_system.h"
#include "gi.h"
#include "st_start.h"
#include "sc_man.h"
#include "templates.h"
#include "vectors.h"
// On the Alpha, accessing the shorts directly if they aren't aligned on a
// 4-byte boundary causes unaligned access warnings. Why it does this at
@ -462,6 +466,32 @@ FTextureFormat FMultiPatchTexture::GetFormat()
}
//==========================================================================
//
// FMultiPatchTexture :: TexPart :: TexPart
//
//==========================================================================
FMultiPatchTexture::TexPart::TexPart()
{
OriginX = OriginY = 0;
Mirror = Rotate = 0;
textureOwned = false;
Texture = NULL;
}
//==========================================================================
//
// FMultiPatchTexture :: TexPart :: TexPart
//
//==========================================================================
FMultiPatchTexture::TexPart::~TexPart()
{
if (textureOwned && Texture != NULL) delete Texture;
Texture = NULL;
}
//==========================================================================
//
// FTextureManager :: AddTexturesLump
@ -631,3 +661,141 @@ void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump)
}
}
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
{
FString patchname;
sc.MustGetString();
int texno = TexMan.CheckForTexture(sc.String, TEX_WallPatch);
if (texno < 0)
{
int lumpnum = Wads.CheckNumForFullName(sc.String);
if (lumpnum >= 0)
{
part.Texture = FTexture::CreateTexture(lumpnum, TEX_WallPatch);
part.textureOwned = true;
}
}
else
{
part.Texture = TexMan[texno];
}
if (part.Texture == NULL)
{
Printf("Unknown patch '%s' in texture '%s'\n", sc.String, Name);
}
sc.MustGetStringName(",");
sc.MustGetNumber();
part.OriginX = sc.Number;
sc.MustGetStringName(",");
sc.MustGetNumber();
part.OriginY = sc.Number;
/* not yet implemented
if (sc.CheckString("{");
{
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("flipx"))
{
part.Mirror = 1;
}
else if (sc.Compare("flipy"))
{
part.Mirror = 2;
}
else if (sc.Compare("rotate"))
{
sc.MustGetNumber();
if (sc.Number != 0 && sc.Number !=90 && sc.Number != 180 && sc.Number != 270)
{
sc.ScriptError("Rotation must be 0, 90, 180 or 270 degrees");
}
part.Rotate = sc.Number / 90;
}
}
}
*/
}
FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
{
TArray<TexPart> parts;
sc.MustGetString();
uppercopy(Name, sc.String);
sc.MustGetStringName(",");
sc.MustGetNumber();
Width = sc.Number;
sc.MustGetStringName(",");
sc.MustGetNumber();
Height = sc.Number;
if (sc.CheckString("{"))
{
while (!sc.CheckString("}"))
{
sc.MustGetString();
if (sc.Compare("XScale"))
{
sc.MustGetFloat();
xScale = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("YScale"))
{
sc.MustGetFloat();
yScale = FLOAT2FIXED(sc.Float);
}
else if (sc.Compare("WorldPanning"))
{
bWorldPanning = true;
}
else if (sc.Compare("NoDecals"))
{
bNoDecals = true;
}
else if (sc.Compare("Patch"))
{
TexPart part;
ParsePatch(sc, part);
parts.Push(part);
}
}
NumParts = parts.Size();
UseType = FTexture::TEX_Override;
Parts = new TexPart[NumParts];
memcpy(Parts, &parts[0], NumParts * sizeof(*Parts));
CalcBitSize ();
// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.
if (NumParts == 1)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height &&
Parts->Mirror == 0 && Parts->Rotate == 0)
{
bRedirect = true;
}
}
//DefinitionLump = sc.G deflumpnum;
}
}
void FTextureManager::ParseXTexture(FScanner &sc, int usetype)
{
FTexture *tex = new FMultiPatchTexture(sc, usetype);
TexMan.AddTexture (tex);
}

View file

@ -611,6 +611,14 @@ void FTextureManager::LoadHiresTex(int wadnum)
}
//else Printf("Unable to define hires texture '%s'\n", tex->Name);
}
else if (sc.Compare("texture"))
{
ParseXTexture(sc, FTexture::TEX_Override);
}
else if (sc.Compare("sprite"))
{
ParseXTexture(sc, FTexture::TEX_Sprite);
}
}
}
}

View file

@ -297,10 +297,12 @@ static FActorInfo *CreateNewActor(FScanner &sc, FActorInfo **parentc, Baggage *b
*colon++ = 0;
}
/*
if (PClass::FindClass (sc.String) != NULL)
{
sc.ScriptError ("Actor %s is already defined.", sc.String);
}
*/
typeName = sc.String;

View file

@ -752,11 +752,13 @@ static bool CheckFloatParm(FScanner &sc)
// [MH]
static int ParseMorphStyle (FScanner &sc)
{
static const char * morphstyles[]={
"MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE", NULL};
static const int morphstyle_values[]={
MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE};
static const char * morphstyles[]={
"MRF_ADDSTAMINA", "MRF_FULLHEALTH", "MRF_UNDOBYTOMEOFPOWER", "MRF_UNDOBYCHAOSDEVICE",
"MRF_FAILNOTELEFRAG", "MRF_FAILNOLAUGH", "MRF_WHENINVULNERABLE", NULL};
static const int morphstyle_values[]={
MORPH_ADDSTAMINA, MORPH_FULLHEALTH, MORPH_UNDOBYTOMEOFPOWER, MORPH_UNDOBYCHAOSDEVICE,
MORPH_FAILNOTELEFRAG, MORPH_FAILNOLAUGH, MORPH_WHENINVULNERABLE};
// May be given flags by number...
if (sc.CheckNumber())
@ -2564,7 +2566,7 @@ static void PowerMorphMorphStyle (FScanner &sc, APowerMorph *defaults, Baggage &
static void PowerMorphMorphFlash (FScanner &sc, APowerMorph *defaults, Baggage &bag)
{
sc.MustGetString ();
defaults->UnMorphFlash = FName(sc.String);
defaults->MorphFlash = FName(sc.String);
}
//==========================================================================

View file

@ -322,14 +322,16 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count,
stcfn121 = true;
}
}
if (lump != -1 || i != 124-start || !stcfn121)
charlumps[i] = lump;
if (lump >= 0)
{
FTexture *pic = TexMan[buffer];
if (pic != NULL)
{
// set the lump here only if it represents a valid texture
if (i != 124-start || !stcfn121)
charlumps[i] = lump;
int height = pic->GetScaledHeight();
int yoffs = pic->GetScaledTopOffset();
@ -1200,7 +1202,7 @@ FFontChar1::FFontChar1 (int sourcelump, const BYTE *sourceremap)
Name[0] = 0; // Make this texture unnamed
// now copy all the properties from the base texture
CopySize(BaseTexture);
if (BaseTexture != NULL) CopySize(BaseTexture);
Pixels = NULL;
}