- Fixed: ACS improperly calculated the address of local variables when

returning from one function to another function when the function that
  was called was used as part of an expression.
- Fixed: Using Thing_Hate with arg0 (hater) set to 0 from an open script
  could crash.
- Fixed: Some items along ledges in Hexen's MAP32 (Orchard of Lamentations)
  appeared at the bottom of the ledge (and consequently inside it) instead
  of on top of it because the items were placed directly on the lines.
  AActor::LinkToWorldForMapThing() needs to use the original R_PointOnLineSide()
  code to handle situations like this. Previously, it just used the original
  code for straight horizontal/vertical lines and used the new code for
  diagonal lines.
- Fixed: FWadCollection::MergeLumps() used in incorrect realloc.
- Fixed: FPlayList::NextLine() did not properly handle blank lines in the
  playlist.
- Changed: Decals now use lightweight thinkers instead of actors. (76 bytes
  versus 396, so you save 320k if you have 1024 decals present.)
- Fixed: Wads added with pullin were loaded immediately after the IWAD.
  Exec files are now processed immediately before -file but after autoloading
  wads in D_DoomMain().
- Fixed: sdl/i_system.h unconditionally defined SHARE_DIR, preventing
  redefinition from the command line.
- Fixed: The standard way to include SDL.h is <SDL.h>, not <SDL/SDL.h>.
- Fixed: Returned FActiveInterpolation::HashKey()'s return type to size_t,
  avoiding a pointer truncation warning.


SVN r30 (trunk)
This commit is contained in:
Randy Heit 2006-04-12 01:50:09 +00:00
commit e815474cbe
29 changed files with 610 additions and 507 deletions

View file

@ -3,7 +3,7 @@
** Implements the actor that represents decals in the level
**
**---------------------------------------------------------------------------
** Copyright 1998-2005 Randy Heit
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -42,35 +42,91 @@
#include "statnums.h"
#include "c_dispatch.h"
// Decals overload snext and sprev to keep a list of decals attached to a wall.
static fixed_t DecalWidth, DecalLeft, DecalRight;
static fixed_t SpreadZ;
static const DBaseDecal *SpreadSource;
static const FDecalTemplate *SpreadTemplate;
static TArray<side_t *> SpreadStack;
static int ImpactCount;
static DImpactDecal *FirstImpact; // (but not the Second or Third Impact :-)
static DImpactDecal *LastImpact;
CVAR (Bool, cl_spreaddecals, true, CVAR_ARCHIVE)
// They also overload floorclip to be the fractional distance from the
// left edge of the side. This distance is stored as a 2.30 fixed pt number.
IMPLEMENT_STATELESS_ACTOR (ADecal, Any, 9200, 0)
PROP_Flags (MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY)
END_DEFAULTS
IMPLEMENT_CLASS (DBaseDecal)
IMPLEMENT_CLASS (DImpactDecal)
void ADecal::Destroy ()
DBaseDecal::DBaseDecal ()
: DThinker(STAT_DECAL),
WallNext(0), WallPrev(0), x(0), y(0), z(0), AlphaColor(0), Translation(0), PicNum(0xFFFF),
RenderFlags(0), XScale(8), YScale(8), RenderStyle(0), LeftDistance(0), Alpha(0)
{
}
DBaseDecal::DBaseDecal (fixed_t x, fixed_t y, fixed_t z)
: DThinker(STAT_DECAL),
WallNext(0), WallPrev(0), x(x), y(y), z(z), AlphaColor(0), Translation(0), PicNum(0xFFFF),
RenderFlags(0), XScale(8), YScale(8), RenderStyle(0), LeftDistance(0), Alpha(0)
{
}
DBaseDecal::DBaseDecal (const AActor *basis)
: DThinker(STAT_DECAL),
WallNext(0), WallPrev(0), x(basis->x), y(basis->y), z(basis->z), AlphaColor(basis->alphacolor),
Translation(basis->Translation), PicNum(basis->picnum), RenderFlags(basis->renderflags),
XScale(basis->xscale), YScale(basis->yscale), RenderStyle(basis->RenderStyle), LeftDistance(0),
Alpha(basis->alpha)
{
}
DBaseDecal::DBaseDecal (const DBaseDecal *basis)
: DThinker(STAT_DECAL),
WallNext(0), WallPrev(0), x(basis->x), y(basis->y), z(basis->z), AlphaColor(basis->AlphaColor),
Translation(basis->Translation), PicNum(basis->PicNum), RenderFlags(basis->RenderFlags),
XScale(basis->XScale), YScale(basis->YScale), RenderStyle(basis->RenderStyle), LeftDistance(0),
Alpha(basis->Alpha)
{
}
void DBaseDecal::Destroy ()
{
Remove ();
Super::Destroy ();
}
void ADecal::Remove ()
void DBaseDecal::Remove ()
{
AActor **prev = sprev;
AActor *next = snext;
DBaseDecal **prev = WallPrev;
DBaseDecal *next = WallNext;
if (prev && (*prev = next))
next->sprev = prev;
sprev = NULL;
snext = NULL;
next->WallPrev = prev;
WallPrev = NULL;
WallNext = NULL;
}
void ADecal::SerializeChain (FArchive &arc, ADecal **first)
void DBaseDecal::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << x << y << z
<< AlphaColor
<< Translation
<< PicNum
<< RenderFlags
<< XScale << YScale
<< RenderStyle
<< LeftDistance
<< Alpha;
}
void DBaseDecal::SerializeChain (FArchive &arc, DBaseDecal **first)
{
DWORD numInChain;
AActor *fresh;
AActor **firstptr = (AActor **)first;
DBaseDecal *fresh;
DBaseDecal **firstptr = first;
if (arc.IsLoading ())
{
@ -80,8 +136,8 @@ void ADecal::SerializeChain (FArchive &arc, ADecal **first)
{
arc << fresh;
*firstptr = fresh;
fresh->sprev = firstptr;
firstptr = &fresh->snext;
fresh->WallPrev = firstptr;
firstptr = &fresh->WallNext;
}
}
else
@ -90,7 +146,7 @@ void ADecal::SerializeChain (FArchive &arc, ADecal **first)
fresh = *firstptr;
while (fresh != NULL)
{
fresh = fresh->snext;
fresh = fresh->WallNext;
++numInChain;
}
arc.WriteCount (numInChain);
@ -98,24 +154,24 @@ void ADecal::SerializeChain (FArchive &arc, ADecal **first)
while (numInChain--)
{
arc << fresh;
fresh = fresh->snext;
fresh = fresh->WallNext;
}
}
}
void ADecal::MoveChain (ADecal *first, fixed_t x, fixed_t y)
void DBaseDecal::MoveChain (DBaseDecal *first, fixed_t x, fixed_t y)
{
while (first != NULL)
{
first->x += x;
first->y += y;
first = (ADecal *)first->snext;
first = (DBaseDecal *)first->WallNext;
}
}
void ADecal::FixForSide (side_t *wall)
void DBaseDecal::FixForSide (side_t *wall)
{
AActor *decal = wall->BoundActors;
DBaseDecal *decal = wall->AttachedDecals;
line_t *line = &lines[wall->linenum];
int wallnum = int(wall - sides);
vertex_t *v1, *v2;
@ -136,83 +192,45 @@ void ADecal::FixForSide (side_t *wall)
while (decal != NULL)
{
decal->x = v1->x + MulScale2 (decal->floorclip, dx);
decal->y = v1->y + MulScale2 (decal->floorclip, dy);
decal = decal->snext;
decal->x = v1->x + MulScale2 (decal->LeftDistance, dx);
decal->y = v1->y + MulScale2 (decal->LeftDistance, dy);
decal = decal->WallNext;
}
}
void ADecal::BeginPlay ()
void DBaseDecal::SetShade (DWORD rgb)
{
Super::BeginPlay ();
// Decals do not think.
ChangeStatNum (STAT_DECAL);
// Find a wall to attach to, and set renderflags to keep
// the decal at its current height. If the decal cannot find a wall
// within 64 units, it destroys itself.
//
// Subclasses can set special1 if they don't want this sticky logic.
if (special1 == 0)
{
DoTrace ();
}
if (args[0] != 0)
{
const FDecal *decal = DecalLibrary.GetDecalByNum (args[0]);
if (decal != NULL)
{
decal->ApplyToActor (this);
}
}
PalEntry *entry = (PalEntry *)&rgb;
AlphaColor = rgb | (ColorMatcher.Pick (entry->r, entry->g, entry->b) << 24);
}
void ADecal::DoTrace ()
void DBaseDecal::SetShade (int r, int g, int b)
{
FTraceResults trace;
Trace (x, y, z, Sector,
finecosine[(angle+ANGLE_180)>>ANGLETOFINESHIFT],
finesine[(angle+ANGLE_180)>>ANGLETOFINESHIFT], 0,
64*FRACUNIT, 0, 0, NULL, trace, TRACE_NoSky);
if (trace.HitType == TRACE_HitWall)
{
x = trace.X;
y = trace.Y;
StickToWall (sides + trace.Line->sidenum[trace.Side]);
}
else
{
Destroy ();
}
AlphaColor = MAKEARGB(ColorMatcher.Pick (r, g, b), r, g, b);
}
// Returns the texture the decal stuck to.
int ADecal::StickToWall (side_t *wall)
int DBaseDecal::StickToWall (side_t *wall)
{
// Stick the decal at the end of the chain so it appears on top
AActor *next, **prev;
DBaseDecal *next, **prev;
prev = (AActor **)&wall->BoundActors;
prev = &wall->AttachedDecals;
while (*prev != NULL)
{
next = *prev;
prev = &next->snext;
prev = &next->WallNext;
}
*prev = this;
snext = NULL;
sprev = prev;
WallNext = NULL;
WallPrev = prev;
/*
snext = wall->BoundActors;
sprev = &wall->BoundActors;
if (snext)
snext->sprev = &snext;
wall->BoundActors = this;
WallNext = wall->AttachedDecals;
WallPrev = &wall->AttachedDecals;
if (WallNext)
WallNext->WallPrev = &WallNext;
wall->AttachedDecals = this;
*/
sector_t *front, *back;
line_t *line;
@ -231,7 +249,7 @@ int ADecal::StickToWall (side_t *wall)
}
if (back == NULL)
{
renderflags |= RF_RELMID;
RenderFlags |= RF_RELMID;
if (line->flags & ML_DONTPEGBOTTOM)
z -= front->floortexz;
else
@ -240,7 +258,7 @@ int ADecal::StickToWall (side_t *wall)
}
else if (back->floorplane.ZatPoint (x, y) >= z)
{
renderflags |= RF_RELLOWER|RF_CLIPLOWER;
RenderFlags |= RF_RELLOWER|RF_CLIPLOWER;
if (line->flags & ML_DONTPEGBOTTOM)
z -= front->ceilingtexz;
else
@ -249,7 +267,7 @@ int ADecal::StickToWall (side_t *wall)
}
else
{
renderflags |= RF_RELUPPER|RF_CLIPUPPER;
RenderFlags |= RF_RELUPPER|RF_CLIPUPPER;
if (line->flags & ML_DONTPEGTOP)
z -= front->ceilingtexz;
else
@ -259,21 +277,10 @@ int ADecal::StickToWall (side_t *wall)
CalcFracPos (wall);
// Face the decal away from the wall
angle = R_PointToAngle2 (0, 0, line->dx, line->dy);
if (line->frontsector == front)
{
angle -= ANGLE_90;
}
else
{
angle += ANGLE_90;
}
return tex;
}
fixed_t ADecal::GetRealZ (const side_t *wall) const
fixed_t DBaseDecal::GetRealZ (const side_t *wall) const
{
const line_t *line = &lines[wall->linenum];
const sector_t *front, *back;
@ -293,7 +300,7 @@ fixed_t ADecal::GetRealZ (const side_t *wall) const
back = front;
}
switch (renderflags & RF_RELMASK)
switch (RenderFlags & RF_RELMASK)
{
default:
return z;
@ -327,16 +334,7 @@ fixed_t ADecal::GetRealZ (const side_t *wall) const
}
}
void ADecal::Relocate (fixed_t ix, fixed_t iy, fixed_t iz)
{
Remove ();
x = ix;
y = iy;
z = iz;
DoTrace ();
}
void ADecal::CalcFracPos (side_t *wall)
void DBaseDecal::CalcFracPos (side_t *wall)
{
line_t *line = &lines[wall->linenum];
int wallnum = int(wall - sides);
@ -358,123 +356,18 @@ void ADecal::CalcFracPos (side_t *wall)
if (abs(dx) > abs(dy))
{
floorclip = SafeDivScale2 (x - v1->x, dx);
LeftDistance = SafeDivScale2 (x - v1->x, dx);
}
else if (dy != 0)
{
floorclip = SafeDivScale2 (y - v1->y, dy);
LeftDistance = SafeDivScale2 (y - v1->y, dy);
}
else
{
floorclip = 0;
LeftDistance = 0;
}
}
static int ImpactCount;
static AActor *FirstImpact; // (but not the Second or Third Impact :-)
static AActor *LastImpact;
CVAR (Bool, cl_spreaddecals, true, CVAR_ARCHIVE)
CUSTOM_CVAR (Int, cl_maxdecals, 1024, CVAR_ARCHIVE)
{
if (self < 0)
{
self = 0;
}
else
{
while (ImpactCount > self)
{
FirstImpact->Destroy ();
}
}
}
// Uses: target points to previous impact decal
// tracer points to next impact decal
//
// Note that this means we can't simply serialize an impact decal as-is
// because doing so when many are present in a level could result in
// a lot of recursion and we would run out of stack. Not nice. So instead,
// the save game code calls AImpactDecal::SerializeAll to serialize a
// list of impact decals.
IMPLEMENT_STATELESS_ACTOR (AImpactDecal, Any, -1, 0)
END_DEFAULTS
void AImpactDecal::SerializeTime (FArchive &arc)
{
if (arc.IsLoading ())
{
ImpactCount = 0;
FirstImpact = LastImpact = NULL;
}
}
void AImpactDecal::Serialize (FArchive &arc)
{
if (arc.IsStoring ())
{
// NULL the next pointer so that the serializer will not follow it
// and possibly run out of stack space. NULLing target isn't
// required; it just makes the archive smaller.
AActor *saved1 = tracer, *saved2 = target;
tracer = NULL;
target = NULL;
Super::Serialize (arc);
tracer = saved1;
target = saved2;
}
else
{
Super::Serialize (arc);
ImpactCount++;
target = LastImpact;
if (target != NULL)
{
target->tracer = this;
}
else
{
FirstImpact = this;
}
LastImpact = this;
}
}
void AImpactDecal::BeginPlay ()
{
special1 = 1; // Don't want ADecal to find a wall to stick to
Super::BeginPlay ();
target = LastImpact;
if (target != NULL)
{
target->tracer = this;
}
else
{
FirstImpact = this;
}
LastImpact = this;
}
AImpactDecal *AImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color)
{
if (cl_maxdecals > 0)
{
const FDecal *decal = DecalLibrary.GetDecalByName (name);
if (decal != NULL && (decal = decal->GetDecal()) != NULL)
{
return StaticCreate (decal, x, y, z, wall, color);
}
}
return NULL;
}
static void GetWallStuff (side_t *wall, vertex_t *&v1, fixed_t &ldx, fixed_t &ldy)
{
line_t *line = &lines[wall->linenum];
@ -516,13 +409,7 @@ static side_t *NextWall (const side_t *wall)
return NULL;
}
static fixed_t DecalWidth, DecalLeft, DecalRight;
static fixed_t SpreadZ;
static const AImpactDecal *SpreadSource;
static const FDecal *SpreadDecal;
static TArray<side_t *> SpreadStack;
void AImpactDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall)
void DBaseDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall)
{
fixed_t ldx, ldy;
@ -542,7 +429,7 @@ void AImpactDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall)
x += Scale (r, ldx, wallsize);
y += Scale (r, ldy, wallsize);
r = wallsize + startr;
SpreadSource->CloneSelf (SpreadDecal, x, y, SpreadZ, feelwall);
SpreadSource->CloneSelf (SpreadTemplate, x, y, SpreadZ, feelwall);
SpreadStack.Push (feelwall);
side_t *nextwall = NextWall (feelwall);
@ -566,7 +453,7 @@ void AImpactDecal::SpreadLeft (fixed_t r, vertex_t *v1, side_t *feelwall)
}
}
void AImpactDecal::SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize)
void DBaseDecal::SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize)
{
vertex_t *v1;
fixed_t x, y, ldx, ldy;
@ -601,120 +488,220 @@ void AImpactDecal::SpreadRight (fixed_t r, side_t *feelwall, fixed_t wallsize)
x -= Scale (r, ldx, wallsize);
y -= Scale (r, ldy, wallsize);
r = DecalRight - r;
SpreadSource->CloneSelf (SpreadDecal, x, y, SpreadZ, feelwall);
SpreadSource->CloneSelf (SpreadTemplate, x, y, SpreadZ, feelwall);
SpreadStack.Push (feelwall);
}
}
AImpactDecal *AImpactDecal::StaticCreate (const FDecal *decal, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color)
void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall)
{
AImpactDecal *actor = NULL;
if (decal != NULL && cl_maxdecals > 0 &&
!(wall->Flags & WALLF_NOAUTODECALS))
FTexture *tex;
vertex_t *v1;
fixed_t rorg, ldx, ldy;
int xscale, yscale;
GetWallStuff (wall, v1, ldx, ldy);
rorg = Length (x - v1->x, y - v1->y);
tex = TexMan[PicNum];
int dwidth = tex->GetWidth ();
xscale = (XScale + 1) << (FRACBITS - 6);
yscale = (YScale + 1) << (FRACBITS - 6);
DecalWidth = dwidth * xscale;
DecalLeft = tex->LeftOffset * xscale;
DecalRight = DecalWidth - DecalLeft;
SpreadSource = this;
SpreadTemplate = tpl;
SpreadZ = z;
// Try spreading left first
SpreadLeft (rorg - DecalLeft, v1, wall);
SpreadStack.Clear ();
// Then try spreading right
SpreadRight (rorg + DecalRight, wall,
Length (lines[wall->linenum].dx, lines[wall->linenum].dy));
SpreadStack.Clear ();
}
DBaseDecal *DBaseDecal::CloneSelf (const FDecalTemplate *tpl, fixed_t ix, fixed_t iy, fixed_t iz, side_t *wall) const
{
DBaseDecal *decal = new DBaseDecal(ix, iy, iz);
if (decal != NULL)
{
if (decal->LowerDecal)
decal->StickToWall (wall);
tpl->ApplyToDecal (decal);
decal->AlphaColor = AlphaColor;
decal->RenderFlags = (decal->RenderFlags & RF_DECALMASK) |
(this->RenderFlags & ~RF_DECALMASK);
}
return decal;
}
CUSTOM_CVAR (Int, cl_maxdecals, 1024, CVAR_ARCHIVE)
{
if (self < 0)
{
self = 0;
}
else
{
while (ImpactCount > self)
{
StaticCreate (decal->LowerDecal->GetDecal(), x, y, z, wall);
FirstImpact->Destroy ();
}
}
}
// Uses: target points to previous impact decal
// tracer points to next impact decal
//
// Note that this means we can't simply serialize an impact decal as-is
// because doing so when many are present in a level could result in
// a lot of recursion and we would run out of stack. Not nice. So instead,
// the save game code calls DImpactDecal::SerializeAll to serialize a
// list of impact decals.
void DImpactDecal::SerializeTime (FArchive &arc)
{
if (arc.IsLoading ())
{
ImpactCount = 0;
FirstImpact = LastImpact = NULL;
}
}
void DImpactDecal::Serialize (FArchive &arc)
{
Super::Serialize (arc);
}
DImpactDecal::DImpactDecal ()
: ImpactNext(0), ImpactPrev(0)
{
Link();
}
DImpactDecal::DImpactDecal (fixed_t x, fixed_t y, fixed_t z)
: DBaseDecal (x, y, z),
ImpactNext(0), ImpactPrev(0)
{
Link();
}
void DImpactDecal::Link ()
{
ImpactCount++;
ImpactPrev = LastImpact;
if (ImpactPrev != NULL)
{
ImpactPrev->ImpactNext = this;
}
else
{
FirstImpact = this;
}
LastImpact = this;
}
DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color)
{
if (cl_maxdecals > 0)
{
const FDecalTemplate *tpl = DecalLibrary.GetDecalByName (name);
if (tpl != NULL && (tpl = tpl->GetDecal()) != NULL)
{
return StaticCreate (tpl, x, y, z, wall, color);
}
}
return NULL;
}
DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, PalEntry color)
{
DImpactDecal *decal = NULL;
if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS))
{
if (tpl->LowerDecal)
{
StaticCreate (tpl->LowerDecal->GetDecal(), x, y, z, wall);
}
if (ImpactCount >= cl_maxdecals)
{
FirstImpact->Destroy ();
}
ImpactCount++;
actor = Spawn<AImpactDecal> (x, y, z);
if (actor == NULL)
return NULL;
decal = new DImpactDecal (x, y, z);
int stickypic = actor->StickToWall (wall);
int stickypic = decal->StickToWall (wall);
FTexture *tex = TexMan[stickypic];
if (tex != NULL && tex->bNoDecals)
{
actor->Destroy ();
return NULL;
}
decal->ApplyToActor (actor);
if (color != 0) actor->SetShade (color.r, color.g, color.b);
if (decal == NULL)
{
return NULL;
}
if (!cl_spreaddecals || actor->picnum == 0xffff)
return actor;
tpl->ApplyToDecal (decal);
if (color != 0)
{
decal->SetShade (color.r, color.g, color.b);
}
if (!cl_spreaddecals || decal->PicNum == 0xffff)
{
return decal;
}
// Spread decal to nearby walls if it does not all fit on this one
vertex_t *v1;
fixed_t rorg, ldx, ldy;
int xscale, yscale;
GetWallStuff (wall, v1, ldx, ldy);
rorg = Length (x - v1->x, y - v1->y);
tex = TexMan[actor->picnum];
int dwidth = tex->GetWidth ();
xscale = (actor->xscale + 1) << (FRACBITS - 6);
yscale = (actor->yscale + 1) << (FRACBITS - 6);
DecalWidth = dwidth * xscale;
DecalLeft = tex->LeftOffset * xscale;
DecalRight = DecalWidth - DecalLeft;
SpreadSource = actor;
SpreadDecal = decal;
SpreadZ = z;
// Try spreading left first
SpreadLeft (rorg - DecalLeft, v1, wall);
SpreadStack.Clear ();
// Then try spreading right
SpreadRight (rorg + DecalRight, wall,
Length (lines[wall->linenum].dx, lines[wall->linenum].dy));
SpreadStack.Clear ();
decal->Spread (tpl, wall);
}
return actor;
return decal;
}
AImpactDecal *AImpactDecal::CloneSelf (const FDecal *decal, fixed_t ix, fixed_t iy, fixed_t iz, side_t *wall) const
DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, fixed_t ix, fixed_t iy, fixed_t iz, side_t *wall) const
{
AImpactDecal *actor = NULL;
// [SO] We used to have an 'else' here -- but that means we create an actor without increasing the
// count!!!
// [RH] Moved this before the destroy, just so it can't go negative temporarily.
ImpactCount++;
if (ImpactCount >= cl_maxdecals)
{
FirstImpact->Destroy ();
}
actor = Spawn<AImpactDecal> (ix, iy, iz);
if (actor != NULL)
DImpactDecal *decal = new DImpactDecal(ix, iy, iz);
if (decal != NULL)
{
actor->StickToWall (wall);
decal->ApplyToActor (actor);
actor->alphacolor = alphacolor;
actor->renderflags = (actor->renderflags & RF_DECALMASK) |
(this->renderflags & ~RF_DECALMASK);
decal->StickToWall (wall);
tpl->ApplyToDecal (decal);
decal->AlphaColor = AlphaColor;
decal->RenderFlags = (decal->RenderFlags & RF_DECALMASK) |
(this->RenderFlags & ~RF_DECALMASK);
}
return actor;
return decal;
}
void AImpactDecal::Destroy ()
void DImpactDecal::Destroy ()
{
if (target != NULL)
if (ImpactPrev != NULL)
{
target->tracer = tracer;
ImpactPrev->ImpactNext = ImpactNext;
}
if (tracer != NULL)
if (ImpactNext != NULL)
{
tracer->target = target;
ImpactNext->ImpactPrev = ImpactPrev;
}
if (LastImpact == this)
{
LastImpact = target;
LastImpact = ImpactPrev;
}
if (FirstImpact == this)
{
FirstImpact = tracer;
FirstImpact = ImpactNext;
}
ImpactCount--;
@ -728,7 +715,7 @@ CCMD (countdecals)
CCMD (countdecalsreal)
{
TThinkerIterator<AImpactDecal> iterator (STAT_DECAL);
TThinkerIterator<DImpactDecal> iterator (STAT_DECAL);
int count = 0;
while (iterator.Next())
@ -761,9 +748,67 @@ CCMD (spray)
{
if (trace.HitType == TRACE_HitWall)
{
AImpactDecal::StaticCreate (argv[1],
DImpactDecal::StaticCreate (argv[1],
trace.X, trace.Y, trace.Z,
sides + trace.Line->sidenum[trace.Side]);
}
}
}
class ADecal : public AActor
{
DECLARE_STATELESS_ACTOR (ADecal, AActor);
public:
void BeginPlay ();
bool DoTrace (DBaseDecal *decal, angle_t angle, sector_t *sec);
};
IMPLEMENT_STATELESS_ACTOR (ADecal, Any, 9200, 0)
END_DEFAULTS
void ADecal::BeginPlay ()
{
Super::BeginPlay ();
// Find a wall to attach to, and set RenderFlags to keep
// the decal at its current height. If the decal cannot find a wall
// within 64 units, it destroys itself.
//
// Subclasses can set special1 if they don't want this sticky logic.
DBaseDecal *decal = new DBaseDecal (this);
if (!DoTrace (decal, angle, Sector))
{
decal->Destroy();
return;
}
if (args[0] != 0)
{
const FDecalTemplate *tpl = DecalLibrary.GetDecalByNum (args[0]);
if (tpl != NULL)
{
tpl->ApplyToDecal (decal);
}
}
}
bool ADecal::DoTrace (DBaseDecal *decal, angle_t angle, sector_t *sec)
{
FTraceResults trace;
Trace (x, y, z, sec,
finecosine[(angle+ANGLE_180)>>ANGLETOFINESHIFT],
finesine[(angle+ANGLE_180)>>ANGLETOFINESHIFT], 0,
64*FRACUNIT, 0, 0, NULL, trace, TRACE_NoSky);
if (trace.HitType == TRACE_HitWall)
{
decal->x = trace.X;
decal->y = trace.Y;
decal->StickToWall (sides + trace.Line->sidenum[trace.Side]);
return true;
}
return false;
}