- scriptified APowerInvisibility.

- changed AlterWeaponSprite so that it doesn't expose renderer internals to the script code.
This commit is contained in:
Christoph Oelckers 2017-01-16 20:33:41 +01:00
parent a5edd421bd
commit d3ab691afb
12 changed files with 339 additions and 349 deletions

View file

@ -46,7 +46,7 @@
struct subsector_t;
struct FBlockNode;
struct FPortalGroupArray;
struct visstyle_t;
//
// NOTES: AActor
//
@ -617,6 +617,7 @@ public:
// Returns true if the missile should be allowed to explode anyway
bool AdjustReflectionAngle (AActor *thing, DAngle &angle);
int AbsorbDamage(int damage, FName dmgtype);
void AlterWeaponSprite(visstyle_t *vis);
// Returns true if this actor is within melee range of its target
bool CheckMeleeRange();

View file

@ -540,25 +540,6 @@ void APowerInvulnerable::EndEffect ()
}
}
//===========================================================================
//
// APowerInvulnerable :: AlterWeaponSprite
//
//===========================================================================
int APowerInvulnerable::AlterWeaponSprite (visstyle_t *vis)
{
int changed = Inventory == NULL ? false : Inventory->AlterWeaponSprite(vis);
if (Owner != NULL)
{
if (Mode == NAME_Ghost && !(Owner->flags & MF_SHADOW))
{
vis->Alpha = MIN<float>(0.25f + (float)Owner->Alpha*0.75f, 1.f);
}
}
return changed;
}
// Strength (aka Berserk) Powerup --------------------------------------------
IMPLEMENT_CLASS(APowerStrength, false, false)
@ -624,211 +605,6 @@ PalEntry APowerStrength::GetBlend ()
return 0;
}
// Invisibility Powerup ------------------------------------------------------
IMPLEMENT_CLASS(APowerInvisibility, false, false)
// Invisibility flag combos
#define INVISIBILITY_FLAGS1 (MF_SHADOW)
#define INVISIBILITY_FLAGS3 (MF3_GHOST)
#define INVISIBILITY_FLAGS5 (MF5_CANTSEEK)
//===========================================================================
//
// APowerInvisibility :: InitEffect
//
//===========================================================================
void APowerInvisibility::InitEffect ()
{
Super::InitEffect();
// This used to call CommonInit(), which used to contain all the code that's repeated every
// tic, plus the following code that needs to happen once and only once.
// The CommonInit() code has been moved to DoEffect(), so this now ends with a call to DoEffect(),
// and DoEffect() no longer needs to call InitEffect(). CommonInit() has been removed for being redundant.
if (Owner != NULL)
{
flags &= ~(Owner->flags & INVISIBILITY_FLAGS1);
Owner->flags |= flags & INVISIBILITY_FLAGS1;
flags3 &= ~(Owner->flags3 & INVISIBILITY_FLAGS3);
Owner->flags3 |= flags3 & INVISIBILITY_FLAGS3;
flags5 &= ~(Owner->flags5 & INVISIBILITY_FLAGS5);
Owner->flags5 |= flags5 & INVISIBILITY_FLAGS5;
CallDoEffect();
}
}
//===========================================================================
//
// APowerInvisibility :: DoEffect
//
//===========================================================================
void APowerInvisibility::DoEffect ()
{
Super::DoEffect();
// Due to potential interference with other PowerInvisibility items
// the effect has to be refreshed each tic.
double ts = (Strength / 100) * (special1 + 1);
if (ts > 1.) ts = 1.;
Owner->Alpha = clamp((1. - ts), 0., 1.);
switch (Mode)
{
case (NAME_Fuzzy):
Owner->RenderStyle = STYLE_OptFuzzy;
break;
case (NAME_Opaque):
Owner->RenderStyle = STYLE_Normal;
break;
case (NAME_Additive):
Owner->RenderStyle = STYLE_Add;
break;
case (NAME_Stencil):
Owner->RenderStyle = STYLE_Stencil;
break;
case (NAME_AddStencil) :
Owner->RenderStyle = STYLE_AddStencil;
break;
case (NAME_TranslucentStencil) :
Owner->RenderStyle = STYLE_TranslucentStencil;
break;
case (NAME_None) :
case (NAME_Cumulative):
case (NAME_Translucent):
Owner->RenderStyle = STYLE_Translucent;
break;
default: // Something's wrong
Owner->RenderStyle = STYLE_Normal;
Owner->Alpha = 1.;
break;
}
}
//===========================================================================
//
// APowerInvisibility :: EndEffect
//
//===========================================================================
void APowerInvisibility::EndEffect ()
{
Super::EndEffect();
if (Owner != NULL)
{
Owner->flags &= ~(flags & INVISIBILITY_FLAGS1);
Owner->flags3 &= ~(flags3 & INVISIBILITY_FLAGS3);
Owner->flags5 &= ~(flags5 & INVISIBILITY_FLAGS5);
Owner->RenderStyle = STYLE_Normal;
Owner->Alpha = 1.;
// Check whether there are other invisibility items and refresh their effect.
// If this isn't done there will be one incorrectly drawn frame when this
// item expires.
AInventory *item = Owner->Inventory;
while (item != NULL)
{
if (item->IsKindOf(RUNTIME_CLASS(APowerInvisibility)) && item != this)
{
static_cast<APowerInvisibility*>(item)->DoEffect();
}
item = item->Inventory;
}
}
}
//===========================================================================
//
// APowerInvisibility :: AlterWeaponSprite
//
//===========================================================================
int APowerInvisibility::AlterWeaponSprite (visstyle_t *vis)
{
int changed = Inventory == NULL ? false : Inventory->AlterWeaponSprite(vis);
// Blink if the powerup is wearing off
if (changed == 0 && EffectTics < 4*32 && !(EffectTics & 8))
{
vis->RenderStyle = STYLE_Normal;
vis->Alpha = 1.f;
return 1;
}
else if (changed == 1)
{
// something else set the weapon sprite back to opaque but this item is still active.
float ts = float((Strength / 100) * (special1 + 1));
vis->Alpha = clamp<>((1.f - ts), 0.f, 1.f);
switch (Mode)
{
case (NAME_Fuzzy):
vis->RenderStyle = STYLE_OptFuzzy;
break;
case (NAME_Opaque):
vis->RenderStyle = STYLE_Normal;
break;
case (NAME_Additive):
vis->RenderStyle = STYLE_Add;
break;
case (NAME_Stencil):
vis->RenderStyle = STYLE_Stencil;
break;
case (NAME_TranslucentStencil) :
vis->RenderStyle = STYLE_TranslucentStencil;
break;
case (NAME_AddStencil) :
vis->RenderStyle = STYLE_AddStencil;
break;
case (NAME_None) :
case (NAME_Cumulative):
case (NAME_Translucent):
default:
vis->RenderStyle = STYLE_Translucent;
break;
}
}
// Handling of Strife-like cumulative invisibility powerups, the weapon itself shouldn't become invisible
if ((vis->Alpha < 0.25f && special1 > 0) || (vis->Alpha == 0))
{
vis->Alpha = clamp((1.f - float(Strength/100)), 0.f, 1.f);
vis->colormap = SpecialColormaps[INVERSECOLORMAP].Colormap;
}
return -1; // This item is valid so another one shouldn't reset the translucency
}
//===========================================================================
//
// APowerInvisibility :: HandlePickup
//
// If the player already has the first stage of a cumulative powerup, getting
// it again increases the player's alpha. (But shouldn't this be in Use()?)
//
//===========================================================================
bool APowerInvisibility::HandlePickup (AInventory *item)
{
if (Mode == NAME_Cumulative && ((Strength * special1) < 1.) && item->GetClass() == GetClass())
{
APowerup *power = static_cast<APowerup *>(item);
if (power->EffectTics == 0)
{
power->ItemFlags |= IF_PICKUPGOOD;
return true;
}
// Only increase the EffectTics, not decrease it.
// Color also gets transferred only when the new item has an effect.
if (power->EffectTics > EffectTics)
{
EffectTics = power->EffectTics;
BlendColor = power->BlendColor;
}
special1++; // increases power
power->ItemFlags |= IF_PICKUPGOOD;
return true;
}
return Super::HandlePickup (item);
}
// Speed Powerup -------------------------------------------------------------
IMPLEMENT_CLASS(APowerSpeed, false, false)

View file

@ -64,7 +64,6 @@ protected:
virtual void InitEffect () override;
virtual void DoEffect () override;
virtual void EndEffect () override;
virtual int AlterWeaponSprite (visstyle_t *vis) override;
};
class APowerStrength : public APowerup
@ -78,17 +77,6 @@ protected:
virtual bool HandlePickup (AInventory *item) override;
};
class APowerInvisibility : public APowerup
{
DECLARE_CLASS (APowerInvisibility, APowerup)
protected:
virtual bool HandlePickup (AInventory *item) override;
virtual void InitEffect () override;
virtual void DoEffect () override;
virtual void EndEffect () override;
virtual int AlterWeaponSprite (visstyle_t *vis) override;
};
class APowerSpeed : public APowerup
{
DECLARE_CLASS (APowerSpeed, APowerup)

View file

@ -783,24 +783,6 @@ bool AInventory::GetNoTeleportFreeze ()
return false;
}
//===========================================================================
//
// AInventory :: AlterWeaponSprite
//
// Allows inventory items to alter a player's weapon sprite just before it
// is drawn.
//
//===========================================================================
int AInventory::AlterWeaponSprite (visstyle_t *vis)
{
if (Inventory != NULL)
{
return Inventory->AlterWeaponSprite (vis);
}
return 0;
}
//===========================================================================
//
// AInventory :: Use

View file

@ -133,7 +133,6 @@ public:
// visual stuff is for later. Right now the VM has not yet access to the needed functionality.
virtual bool DrawPowerup(int x, int y);
virtual int AlterWeaponSprite(visstyle_t *vis);
// virtual on the script side only.

View file

@ -310,21 +310,21 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
visstyle_t vis;
vis.RenderStyle=playermo->RenderStyle;
vis.Alpha=playermo->Alpha;
vis.colormap = NULL;
if (playermo->Inventory)
vis.RenderStyle = STYLE_Count;
vis.Alpha = playermo->Alpha;
vis.Invert = false;
playermo->AlterWeaponSprite(&vis);
FRenderStyle RenderStyle;
if (vis.RenderStyle == STYLE_Count) RenderStyle = playermo->RenderStyle;
else RenderStyle = vis.RenderStyle;
if (vis.Invert)
{
playermo->Inventory->AlterWeaponSprite(&vis);
if (vis.colormap >= SpecialColormaps[0].Colormap &&
vis.colormap < SpecialColormaps[SpecialColormaps.Size()].Colormap &&
gl_fixedcolormap == CM_DEFAULT)
{
// this only happens for Strife's inverted weapon sprite
vis.RenderStyle.Flags |= STYLEF_InvertSource;
}
// this only happens for Strife's inverted weapon sprite
RenderStyle.Flags |= STYLEF_InvertSource;
}
if (vis.RenderStyle.AsDWORD == 0)
if (RenderStyle.AsDWORD == 0)
{
// This is RenderStyle None.
return;
@ -334,32 +334,32 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
int OverrideShader = -1;
float trans = 0.f;
if (vis.RenderStyle.BlendOp >= STYLEOP_Fuzz && vis.RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
if (RenderStyle.BlendOp >= STYLEOP_Fuzz && RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
{
vis.RenderStyle.CheckFuzz();
if (vis.RenderStyle.BlendOp == STYLEOP_Fuzz)
RenderStyle.CheckFuzz();
if (RenderStyle.BlendOp == STYLEOP_Fuzz)
{
if (gl_fuzztype != 0)
{
// Todo: implement shader selection here
vis.RenderStyle = LegacyRenderStyles[STYLE_Translucent];
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
OverrideShader = gl_fuzztype + 4;
trans = 0.99f; // trans may not be 1 here
}
else
{
vis.RenderStyle.BlendOp = STYLEOP_Shadow;
RenderStyle.BlendOp = STYLEOP_Shadow;
}
}
}
gl_SetRenderStyle(vis.RenderStyle, false, false);
gl_SetRenderStyle(RenderStyle, false, false);
if (vis.RenderStyle.Flags & STYLEF_TransSoulsAlpha)
if (RenderStyle.Flags & STYLEF_TransSoulsAlpha)
{
trans = transsouls;
}
else if (vis.RenderStyle.Flags & STYLEF_Alpha1)
else if (RenderStyle.Flags & STYLEF_Alpha1)
{
trans = 1.f;
}
@ -402,7 +402,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
ll = 255;
}
// set the lighting parameters
if (vis.RenderStyle.BlendOp == STYLEOP_Shadow)
if (RenderStyle.BlendOp == STYLEOP_Shadow)
{
gl_RenderState.SetColor(0.2f, 0.2f, 0.2f, 0.33f, cmc.desaturation);
}
@ -438,7 +438,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
}
DrawPSprite(player, psp, sx, sy, hudModelStep, OverrideShader, !!(vis.RenderStyle.Flags & STYLEF_RedIsAlpha));
DrawPSprite(player, psp, sx, sy, hudModelStep, OverrideShader, !!(RenderStyle.Flags & STYLEF_RedIsAlpha));
}
}
gl_RenderState.SetObjectColor(0xffffffff);

View file

@ -3629,6 +3629,25 @@ int AActor::AbsorbDamage(int damage, FName dmgtype)
return damage;
}
void AActor::AlterWeaponSprite(visstyle_t *vis)
{
int changed = 0;
TArray<AInventory *> items;
// This needs to go backwards through the items but the list has no backlinks.
for (AInventory *item = Inventory; item != nullptr; item = item->Inventory)
{
items.Push(item);
}
for(int i=items.Size()-1;i>=0;i--)
{
IFVIRTUALPTR(items[i], AInventory, AlterWeaponSprite)
{
VMValue params[3] = { items[i], vis, &changed };
GlobalVMStack.Call(func, params, 3, nullptr, 0, nullptr);
}
}
}
void AActor::PlayActiveSound ()
{
if (ActiveSound && !S_IsActorPlayingSomething (this, CHAN_VOICE, -1))

View file

@ -1489,9 +1489,9 @@ typedef BYTE lighttable_t; // This could be wider for >8 bit display.
// This encapsulates the fields of vissprite_t that can be altered by AlterWeaponSprite
struct visstyle_t
{
lighttable_t *colormap;
bool Invert;
float Alpha;
FRenderStyle RenderStyle;
ERenderStyle RenderStyle;
};

View file

@ -406,11 +406,11 @@ void R_DrawVisSprite (vissprite_t *vis)
}
fixed_t centeryfrac = FLOAT2FIXED(CenterY);
R_SetColorMapLight(vis->Style.colormap, 0.0f, 0);
R_SetColorMapLight(vis->colormap, 0.0f, 0);
mode = R_SetPatchStyle (vis->Style.RenderStyle, vis->Style.Alpha, vis->Translation, vis->FillColor);
mode = R_SetPatchStyle (vis->RenderStyle, vis->Style.Alpha, vis->Translation, vis->FillColor);
if (vis->Style.RenderStyle == LegacyRenderStyles[STYLE_Shaded])
if (vis->RenderStyle == LegacyRenderStyles[STYLE_Shaded])
{ // For shaded sprites, R_SetPatchStyle sets a dc_colormap to an alpha table, but
// it is the brightest one. We need to get back to the proper light level for
// this sprite.
@ -521,7 +521,7 @@ void R_DrawWallSprite(vissprite_t *spr)
bool rereadcolormap = true;
// Decals that are added to the scene must fade to black.
if (spr->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0)
if (spr->RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0)
{
usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate);
rereadcolormap = false;
@ -559,7 +559,7 @@ void R_DrawWallSprite(vissprite_t *spr)
dc_x = x1;
ESPSResult mode;
mode = R_SetPatchStyle (spr->Style.RenderStyle, spr->Style.Alpha, spr->Translation, spr->FillColor);
mode = R_SetPatchStyle (spr->RenderStyle, spr->Style.Alpha, spr->Translation, spr->FillColor);
// R_SetPatchStyle can modify basecolormap.
if (rereadcolormap)
@ -646,8 +646,8 @@ void R_DrawVisVoxel(vissprite_t *spr, int minslabz, int maxslabz, short *cliptop
int flags = 0;
// Do setup for blending.
R_SetColorMapLight(spr->Style.colormap, 0.0f, 0);
mode = R_SetPatchStyle(spr->Style.RenderStyle, spr->Style.Alpha, spr->Translation, spr->FillColor);
R_SetColorMapLight(spr->colormap, 0.0f, 0);
mode = R_SetPatchStyle(spr->RenderStyle, spr->Style.Alpha, spr->Translation, spr->FillColor);
if (mode == DontDraw)
{
@ -672,7 +672,7 @@ void R_DrawVisVoxel(vissprite_t *spr, int minslabz, int maxslabz, short *cliptop
// Render the voxel, either directly to the screen or offscreen.
R_DrawVoxel(spr->pa.vpos, spr->pa.vang, spr->gpos, spr->Angle,
spr->xscale, FLOAT2FIXED(spr->yscale), spr->voxel, spr->Style.colormap, cliptop, clipbot,
spr->xscale, FLOAT2FIXED(spr->yscale), spr->voxel, spr->colormap, cliptop, clipbot,
minslabz, maxslabz, flags);
// Blend the voxel, if that's what we need to do.
@ -1051,7 +1051,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
vis->renderflags = renderflags;
if(thing->flags5 & MF5_BRIGHT)
vis->renderflags |= RF_FULLBRIGHT; // kg3D
vis->Style.RenderStyle = thing->RenderStyle;
vis->RenderStyle = thing->RenderStyle;
vis->FillColor = thing->fillcolor;
vis->Translation = thing->Translation; // [RH] thing translation table
vis->FakeFlatStat = fakeside;
@ -1079,9 +1079,9 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
// The software renderer cannot invert the source without inverting the overlay
// too. That means if the source is inverted, we need to do the reverse of what
// the invert overlay flag says to do.
INTBOOL invertcolormap = (vis->Style.RenderStyle.Flags & STYLEF_InvertOverlay);
INTBOOL invertcolormap = (vis->RenderStyle.Flags & STYLEF_InvertOverlay);
if (vis->Style.RenderStyle.Flags & STYLEF_InvertSource)
if (vis->RenderStyle.Flags & STYLEF_InvertSource)
{
invertcolormap = !invertcolormap;
}
@ -1093,12 +1093,12 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
}
// Sprites that are added to the scene must fade to black.
if (vis->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
if (vis->RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate);
}
if (vis->Style.RenderStyle.Flags & STYLEF_FadeToBlack)
if (vis->RenderStyle.Flags & STYLEF_FadeToBlack)
{
if (invertcolormap)
{ // Fade to white
@ -1114,7 +1114,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
// get light level
if (fixedcolormap != NULL)
{ // fixed map
vis->Style.colormap = fixedcolormap;
vis->colormap = fixedcolormap;
}
else
{
@ -1124,17 +1124,17 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
}
if (fixedlightlev >= 0)
{
vis->Style.colormap = mybasecolormap->Maps + fixedlightlev;
vis->colormap = mybasecolormap->Maps + fixedlightlev;
}
else if (!foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)))
{ // full bright
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps;
vis->colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps;
}
else
{ // diminished light
vis->ColormapNum = GETPALOOKUP(
r_SpriteVisibility / MAX(tz, MINZ), spriteshade);
vis->Style.colormap = mybasecolormap->Maps + (vis->ColormapNum << COLORMAPSHIFT);
vis->colormap = mybasecolormap->Maps + (vis->ColormapNum << COLORMAPSHIFT);
}
}
}
@ -1196,7 +1196,7 @@ static void R_ProjectWallSprite(AActor *thing, const DVector3 &pos, FTextureID p
vis->deltay = float(pos.Y - ViewPos.Y);
vis->renderflags = renderflags;
if(thing->flags5 & MF5_BRIGHT) vis->renderflags |= RF_FULLBRIGHT; // kg3D
vis->Style.RenderStyle = thing->RenderStyle;
vis->RenderStyle = thing->RenderStyle;
vis->FillColor = thing->fillcolor;
vis->Translation = thing->Translation;
vis->FakeFlatStat = 0;
@ -1210,7 +1210,7 @@ static void R_ProjectWallSprite(AActor *thing, const DVector3 &pos, FTextureID p
vis->bWallSprite = true;
vis->ColormapNum = GETPALOOKUP(
r_SpriteVisibility / MAX(tz, MINZ), spriteshade);
vis->Style.colormap = basecolormap->Maps + (vis->ColormapNum << COLORMAPSHIFT);
vis->colormap = basecolormap->Maps + (vis->ColormapNum << COLORMAPSHIFT);
vis->wallc = wallc;
}
@ -1414,21 +1414,21 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double
if (pspr->GetID() < PSP_TARGETCENTER)
{
vis->Style.Alpha = float(owner->Alpha);
vis->Style.RenderStyle = owner->RenderStyle;
vis->RenderStyle = owner->RenderStyle;
// The software renderer cannot invert the source without inverting the overlay
// too. That means if the source is inverted, we need to do the reverse of what
// the invert overlay flag says to do.
INTBOOL invertcolormap = (vis->Style.RenderStyle.Flags & STYLEF_InvertOverlay);
INTBOOL invertcolormap = (vis->RenderStyle.Flags & STYLEF_InvertOverlay);
if (vis->Style.RenderStyle.Flags & STYLEF_InvertSource)
if (vis->RenderStyle.Flags & STYLEF_InvertSource)
{
invertcolormap = !invertcolormap;
}
FDynamicColormap *mybasecolormap = basecolormap;
if (vis->Style.RenderStyle.Flags & STYLEF_FadeToBlack)
if (vis->RenderStyle.Flags & STYLEF_FadeToBlack)
{
if (invertcolormap)
{ // Fade to white
@ -1443,7 +1443,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double
if (realfixedcolormap != nullptr)
{ // fixed color
vis->Style.colormap = realfixedcolormap->Colormap;
vis->colormap = realfixedcolormap->Colormap;
}
else
{
@ -1453,44 +1453,40 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double
}
if (fixedlightlev >= 0)
{
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (mybasecolormap->Maps + fixedlightlev);
vis->colormap = (r_fullbrightignoresectorcolor) ? (FullNormalLight.Maps + fixedlightlev) : (mybasecolormap->Maps + fixedlightlev);
}
else if (!foggy && pspr->GetState()->GetFullbright())
{ // full bright
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps; // [RH] use basecolormap
vis->colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps; // [RH] use basecolormap
}
else
{ // local light
vis->Style.colormap = mybasecolormap->Maps + (GETPALOOKUP(0, spriteshade) << COLORMAPSHIFT);
vis->colormap = mybasecolormap->Maps + (GETPALOOKUP(0, spriteshade) << COLORMAPSHIFT);
}
}
if (camera->Inventory != nullptr)
{
lighttable_t *oldcolormap = vis->Style.colormap;
camera->Inventory->AlterWeaponSprite(&vis->Style);
if (vis->Style.colormap != oldcolormap)
vis->Style.RenderStyle = STYLE_Count;
vis->Style.Invert = false;
camera->AlterWeaponSprite(&vis->Style);
if (vis->Style.Invert)
{
// The colormap has changed. Is it one we can easily identify?
// If not, then don't bother trying to identify it for
// hardware accelerated drawing.
if (vis->Style.colormap < SpecialColormaps[0].Colormap ||
vis->Style.colormap > SpecialColormaps.Last().Colormap)
{
noaccel = true;
}
vis->colormap = SpecialColormaps[0].Colormap;
// Has the basecolormap changed? If so, we can't hardware accelerate it,
// since we don't know what it is anymore.
else if (vis->Style.colormap < mybasecolormap->Maps ||
vis->Style.colormap >= mybasecolormap->Maps + NUMCOLORMAPS * 256)
if (vis->colormap < mybasecolormap->Maps ||
vis->colormap >= mybasecolormap->Maps + NUMCOLORMAPS * 256)
{
noaccel = true;
}
}
if (vis->Style.RenderStyle != STYLE_Count) vis->RenderStyle = vis->Style.RenderStyle;
}
// If we're drawing with a special colormap, but shaders for them are disabled, do
// not accelerate.
if (!r_shadercolormaps && (vis->Style.colormap >= SpecialColormaps[0].Colormap &&
vis->Style.colormap <= SpecialColormaps.Last().Colormap))
if (!r_shadercolormaps && (vis->colormap >= SpecialColormaps[0].Colormap &&
vis->colormap <= SpecialColormaps.Last().Colormap))
{
noaccel = true;
}
@ -1517,15 +1513,15 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double
else
{
colormap_to_use = basecolormap;
vis->Style.colormap = basecolormap->Maps;
vis->Style.RenderStyle = STYLE_Normal;
vis->colormap = basecolormap->Maps;
vis->RenderStyle = STYLE_Normal;
}
// Check for hardware-assisted 2D. If it's available, and this sprite is not
// fuzzy, don't draw it until after the switch to 2D mode.
if (!noaccel && RenderTarget == screen && (DFrameBuffer *)screen->Accel2D)
{
FRenderStyle style = vis->Style.RenderStyle;
FRenderStyle style = vis->RenderStyle;
style.CheckFuzz();
if (style.BlendOp != STYLEOP_Fuzz)
{
@ -1688,18 +1684,18 @@ void R_DrawRemainingPlayerSprites()
FColormapStyle colormapstyle;
bool usecolormapstyle = false;
if (vis->Style.colormap >= SpecialColormaps[0].Colormap &&
vis->Style.colormap < SpecialColormaps[SpecialColormaps.Size()].Colormap)
if (vis->colormap >= SpecialColormaps[0].Colormap &&
vis->colormap < SpecialColormaps[SpecialColormaps.Size()].Colormap)
{
// Yuck! There needs to be a better way to store colormaps in the vissprite... :(
ptrdiff_t specialmap = (vis->Style.colormap - SpecialColormaps[0].Colormap) / sizeof(FSpecialColormap);
ptrdiff_t specialmap = (vis->colormap - SpecialColormaps[0].Colormap) / sizeof(FSpecialColormap);
special = &SpecialColormaps[specialmap];
}
else if (colormap->Color == PalEntry(255,255,255) &&
colormap->Desaturate == 0)
{
overlay = colormap->Fade;
overlay.a = BYTE(((vis->Style.colormap - colormap->Maps) >> 8) * 255 / NUMCOLORMAPS);
overlay.a = BYTE(((vis->colormap - colormap->Maps) >> 8) * 255 / NUMCOLORMAPS);
}
else
{
@ -1707,7 +1703,7 @@ void R_DrawRemainingPlayerSprites()
colormapstyle.Color = colormap->Color;
colormapstyle.Fade = colormap->Fade;
colormapstyle.Desaturate = colormap->Desaturate;
colormapstyle.FadeLevel = ((vis->Style.colormap - colormap->Maps) >> 8) / float(NUMCOLORMAPS);
colormapstyle.FadeLevel = ((vis->colormap - colormap->Maps) >> 8) / float(NUMCOLORMAPS);
}
screen->DrawTexture(vis->pic,
viewwindowx + vispsprites[i].x1,
@ -1723,7 +1719,7 @@ void R_DrawRemainingPlayerSprites()
DTA_ClipRight, viewwindowx + viewwidth,
DTA_ClipBottom, viewwindowy + viewheight,
DTA_AlphaF, vis->Style.Alpha,
DTA_RenderStyle, vis->Style.RenderStyle,
DTA_RenderStyle, vis->RenderStyle,
DTA_FillColor, vis->FillColor,
DTA_SpecialColormap, special,
DTA_ColorOverlay, overlay.d,
@ -1950,7 +1946,7 @@ void R_DrawSprite (vissprite_t *spr)
int r1, r2;
short topclip, botclip;
short *clip1, *clip2;
lighttable_t *colormap = spr->Style.colormap;
lighttable_t *colormap = spr->colormap;
F3DFloor *rover;
FDynamicColormap *mybasecolormap;
@ -2014,20 +2010,20 @@ void R_DrawSprite (vissprite_t *spr)
// found new values, recalculate
if (sec)
{
INTBOOL invertcolormap = (spr->Style.RenderStyle.Flags & STYLEF_InvertOverlay);
INTBOOL invertcolormap = (spr->RenderStyle.Flags & STYLEF_InvertOverlay);
if (spr->Style.RenderStyle.Flags & STYLEF_InvertSource)
if (spr->RenderStyle.Flags & STYLEF_InvertSource)
{
invertcolormap = !invertcolormap;
}
// Sprites that are added to the scene must fade to black.
if (spr->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
if (spr->RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate);
}
if (spr->Style.RenderStyle.Flags & STYLEF_FadeToBlack)
if (spr->RenderStyle.Flags & STYLEF_FadeToBlack)
{
if (invertcolormap)
{ // Fade to white
@ -2047,16 +2043,16 @@ void R_DrawSprite (vissprite_t *spr)
}
if (fixedlightlev >= 0)
{
spr->Style.colormap = mybasecolormap->Maps + fixedlightlev;
spr->colormap = mybasecolormap->Maps + fixedlightlev;
}
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
{ // full bright
spr->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps;
spr->colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : mybasecolormap->Maps;
}
else
{ // diminished light
spriteshade = LIGHT2SHADE(sec->lightlevel + r_actualextralight);
spr->Style.colormap = mybasecolormap->Maps + (GETPALOOKUP(
spr->colormap = mybasecolormap->Maps + (GETPALOOKUP(
r_SpriteVisibility / MAX(MINZ, (double)spr->depth), spriteshade) << COLORMAPSHIFT);
}
}
@ -2205,7 +2201,7 @@ void R_DrawSprite (vissprite_t *spr)
if (topclip >= botclip)
{
spr->Style.colormap = colormap;
spr->colormap = colormap;
return;
}
@ -2335,7 +2331,7 @@ void R_DrawSprite (vissprite_t *spr)
}
if (i == x2)
{
spr->Style.colormap = colormap;
spr->colormap = colormap;
return;
}
}
@ -2353,7 +2349,7 @@ void R_DrawSprite (vissprite_t *spr)
int maxvoxely = spr->gzb > hzb ? INT_MAX : xs_RoundToInt((spr->gzt - hzb) / spr->yscale);
R_DrawVisVoxel(spr, minvoxely, maxvoxely, cliptop, clipbot);
}
spr->Style.colormap = colormap;
spr->colormap = colormap;
}
// kg3D:
@ -2601,21 +2597,21 @@ void R_ProjectParticle (particle_t *particle, const sector_t *sector, int shade,
if (fixedlightlev >= 0)
{
vis->Style.colormap = map + fixedlightlev;
vis->colormap = map + fixedlightlev;
}
else if (fixedcolormap)
{
vis->Style.colormap = fixedcolormap;
vis->colormap = fixedcolormap;
}
else if (particle->bright)
{
vis->Style.colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : map;
vis->colormap = (r_fullbrightignoresectorcolor) ? FullNormalLight.Maps : map;
}
else
{
// Particles are slightly more visible than regular sprites.
vis->ColormapNum = GETPALOOKUP(tiz * r_SpriteVisibility * 0.5, shade);
vis->Style.colormap = map + (vis->ColormapNum << COLORMAPSHIFT);
vis->colormap = map + (vis->ColormapNum << COLORMAPSHIFT);
}
}
@ -2650,7 +2646,7 @@ void R_DrawParticle_C (vissprite_t *vis)
int spacing;
BYTE *dest;
DWORD fg;
BYTE color = vis->Style.colormap[vis->startfrac];
BYTE color = vis->colormap[vis->startfrac];
int yl = vis->y1;
int ycount = vis->y2 - yl + 1;
int x1 = vis->x1;

View file

@ -95,6 +95,8 @@ struct vissprite_t
BYTE ColormapNum; // Which colormap is rendered (needed for shaded drawer)
short renderflags;
DWORD Translation; // [RH] for color translation
lighttable_t *colormap;
FRenderStyle RenderStyle;
visstyle_t Style;
int CurrentPortalUniq; // [ZZ] to identify the portal that this thing is in. used for clipping.

View file

@ -1,3 +1,10 @@
struct VisStyle
{
bool Invert;
float Alpha;
int RenderStyle;
}
class Inventory : Actor native
{
const BLINKTHRESHOLD = (4*32);
@ -56,6 +63,7 @@ class Inventory : Actor native
virtual double GetSpeedFactor() { return 1; }
virtual bool GetNoTeleportFreeze() { return false; }
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {}
virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {}
native bool GoAway();
native void GoAwayAndDie();

View file

@ -32,6 +32,12 @@ class Powerup : Inventory native
}
//===========================================================================
//
// Invulnerable
//
//===========================================================================
class PowerInvulnerable : Powerup native
{
Default
@ -39,6 +45,17 @@ class PowerInvulnerable : Powerup native
Powerup.Duration -30;
inventory.icon "SPSHLD0";
}
override void AlterWeaponSprite (VisStyle vis, in out int changed)
{
if (Owner != NULL)
{
if (Mode == 'Ghost' && !(Owner.bShadow))
{
vis.Alpha = min(0.25 + Owner.Alpha * 0.75, 1.);
}
}
}
}
class PowerStrength : Powerup native
@ -51,7 +68,13 @@ class PowerStrength : Powerup native
}
}
class PowerInvisibility : Powerup native
//===========================================================================
//
// Invisibility
//
//===========================================================================
class PowerInvisibility : Powerup
{
Default
{
@ -60,6 +83,202 @@ class PowerInvisibility : Powerup native
Powerup.Strength 80;
Powerup.Mode "Fuzzy";
}
//===========================================================================
//
// APowerInvisibility :: InitEffect
//
//===========================================================================
override void InitEffect ()
{
Super.InitEffect();
let Owner = self.Owner;
if (Owner != NULL)
{
let savedShadow = Owner.bShadow;
let savedGhost = Owner.bGhost;
let savedCantSeek = Owner.bCantSeek;
Owner.bShadow = bShadow;
Owner.bGhost = bGhost;
Owner.bCantSeek = bCantSeek;
bShadow = savedShadow;
bGhost = savedGhost;
bCantSeek = savedCantSeek;
DoEffect();
}
}
//===========================================================================
//
// APowerInvisibility :: DoEffect
//
//===========================================================================
override void DoEffect ()
{
Super.DoEffect();
// Due to potential interference with other PowerInvisibility items
// the effect has to be refreshed each tic.
double ts = (Strength / 100) * (special1 + 1);
if (ts > 1.) ts = 1.;
let newAlpha = clamp((1. - ts), 0., 1.);
int newStyle;
switch (Mode)
{
case 'Fuzzy':
newStyle = STYLE_OptFuzzy;
break;
case 'Opaque':
newStyle = STYLE_Normal;
break;
case 'Additive':
newStyle = STYLE_Add;
break;
case 'Stencil':
newStyle = STYLE_Stencil;
break;
case 'AddStencil' :
newStyle = STYLE_AddStencil;
break;
case 'TranslucentStencil':
newStyle = STYLE_TranslucentStencil;
break;
case 'None' :
case 'Cumulative':
case 'Translucent':
newStyle = STYLE_Translucent;
break;
default: // Something's wrong
newStyle = STYLE_Normal;
newAlpha = 1.;
break;
}
Owner.A_SetRenderStyle(newAlpha, newStyle);
}
//===========================================================================
//
// APowerInvisibility :: EndEffect
//
//===========================================================================
override void EndEffect ()
{
Super.EndEffect();
if (Owner != NULL)
{
Owner.bShadow = bShadow;
Owner.bGhost = bGhost;
Owner.bCantSeek = bCantSeek;
Owner.A_SetRenderStyle(1, STYLE_Normal);
// Check whether there are other invisibility items and refresh their effect.
// If this isn't done there will be one incorrectly drawn frame when this
// item expires.
for(let item = Owner.Inv; item != null; item = item.Inv)
{
if (item != self && item is 'PowerInvisibility')
{
item.DoEffect();
}
}
}
}
//===========================================================================
//
// APowerInvisibility :: AlterWeaponSprite
//
//===========================================================================
override void AlterWeaponSprite (VisStyle vis, in out int changed)
{
// Blink if the powerup is wearing off
if (changed == 0 && EffectTics < 4*32 && !(EffectTics & 8))
{
vis.RenderStyle = STYLE_Normal;
vis.Alpha = 1.f;
changed = 1;
return;
}
else if (changed == 1)
{
// something else set the weapon sprite back to opaque but this item is still active.
float ts = float((Strength / 100) * (special1 + 1));
vis.Alpha = clamp((1. - ts), 0., 1.);
switch (Mode)
{
case 'Fuzzy':
vis.RenderStyle = STYLE_OptFuzzy;
break;
case 'Opaque':
vis.RenderStyle = STYLE_Normal;
break;
case 'Additive':
vis.RenderStyle = STYLE_Add;
break;
case 'Stencil':
vis.RenderStyle = STYLE_Stencil;
break;
case 'TranslucentStencil':
vis.RenderStyle = STYLE_TranslucentStencil;
break;
case 'AddStencil':
vis.RenderStyle = STYLE_AddStencil;
break;
case 'None':
case 'Cumulative':
case 'Translucent':
default:
vis.RenderStyle = STYLE_Translucent;
break;
}
}
// Handling of Strife-like cumulative invisibility powerups, the weapon itself shouldn't become invisible
if ((vis.Alpha < 0.25f && special1 > 0) || (vis.Alpha == 0))
{
vis.Alpha = clamp((1. - Strength/100.), 0., 1.);
vis.invert = true;
}
changed = -1; // This item is valid so another one shouldn't reset the translucency
}
//===========================================================================
//
// APowerInvisibility :: HandlePickup
//
// If the player already has the first stage of a cumulative powerup, getting
// it again increases the player's alpha. (But shouldn't this be in Use()?)
//
//===========================================================================
override bool HandlePickup (Inventory item)
{
if (Mode == 'Cumulative' && ((Strength * special1) < 1.) && item.GetClass() == GetClass())
{
let power = Powerup(item);
if (power.EffectTics == 0)
{
power.bPickupGood = true;
return true;
}
// Only increase the EffectTics, not decrease it.
// Color also gets transferred only when the new item has an effect.
if (power.EffectTics > EffectTics)
{
EffectTics = power.EffectTics;
BlendColor = power.BlendColor;
}
special1++; // increases power
power.bPickupGood = true;
return true;
}
return Super.HandlePickup (item);
}
}
class PowerGhost : PowerInvisibility