- 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 subsector_t;
struct FBlockNode; struct FBlockNode;
struct FPortalGroupArray; struct FPortalGroupArray;
struct visstyle_t;
// //
// NOTES: AActor // NOTES: AActor
// //
@ -617,6 +617,7 @@ public:
// Returns true if the missile should be allowed to explode anyway // Returns true if the missile should be allowed to explode anyway
bool AdjustReflectionAngle (AActor *thing, DAngle &angle); bool AdjustReflectionAngle (AActor *thing, DAngle &angle);
int AbsorbDamage(int damage, FName dmgtype); int AbsorbDamage(int damage, FName dmgtype);
void AlterWeaponSprite(visstyle_t *vis);
// Returns true if this actor is within melee range of its target // Returns true if this actor is within melee range of its target
bool CheckMeleeRange(); 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 -------------------------------------------- // Strength (aka Berserk) Powerup --------------------------------------------
IMPLEMENT_CLASS(APowerStrength, false, false) IMPLEMENT_CLASS(APowerStrength, false, false)
@ -624,211 +605,6 @@ PalEntry APowerStrength::GetBlend ()
return 0; 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 ------------------------------------------------------------- // Speed Powerup -------------------------------------------------------------
IMPLEMENT_CLASS(APowerSpeed, false, false) IMPLEMENT_CLASS(APowerSpeed, false, false)

View file

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

View file

@ -783,24 +783,6 @@ bool AInventory::GetNoTeleportFreeze ()
return false; 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 // 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. // 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 bool DrawPowerup(int x, int y);
virtual int AlterWeaponSprite(visstyle_t *vis);
// virtual on the script side only. // virtual on the script side only.

View file

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

View file

@ -3629,6 +3629,25 @@ int AActor::AbsorbDamage(int damage, FName dmgtype)
return damage; 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 () void AActor::PlayActiveSound ()
{ {
if (ActiveSound && !S_IsActorPlayingSomething (this, CHAN_VOICE, -1)) 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 // This encapsulates the fields of vissprite_t that can be altered by AlterWeaponSprite
struct visstyle_t struct visstyle_t
{ {
lighttable_t *colormap; bool Invert;
float Alpha; float Alpha;
FRenderStyle RenderStyle; ERenderStyle RenderStyle;
}; };

View file

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

View file

@ -95,6 +95,8 @@ struct vissprite_t
BYTE ColormapNum; // Which colormap is rendered (needed for shaded drawer) BYTE ColormapNum; // Which colormap is rendered (needed for shaded drawer)
short renderflags; short renderflags;
DWORD Translation; // [RH] for color translation DWORD Translation; // [RH] for color translation
lighttable_t *colormap;
FRenderStyle RenderStyle;
visstyle_t Style; visstyle_t Style;
int CurrentPortalUniq; // [ZZ] to identify the portal that this thing is in. used for clipping. 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 class Inventory : Actor native
{ {
const BLINKTHRESHOLD = (4*32); const BLINKTHRESHOLD = (4*32);
@ -56,6 +63,7 @@ class Inventory : Actor native
virtual double GetSpeedFactor() { return 1; } virtual double GetSpeedFactor() { return 1; }
virtual bool GetNoTeleportFreeze() { return false; } virtual bool GetNoTeleportFreeze() { return false; }
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {} 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 bool GoAway();
native void GoAwayAndDie(); native void GoAwayAndDie();

View file

@ -32,6 +32,12 @@ class Powerup : Inventory native
} }
//===========================================================================
//
// Invulnerable
//
//===========================================================================
class PowerInvulnerable : Powerup native class PowerInvulnerable : Powerup native
{ {
Default Default
@ -39,6 +45,17 @@ class PowerInvulnerable : Powerup native
Powerup.Duration -30; Powerup.Duration -30;
inventory.icon "SPSHLD0"; 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 class PowerStrength : Powerup native
@ -51,7 +68,13 @@ class PowerStrength : Powerup native
} }
} }
class PowerInvisibility : Powerup native //===========================================================================
//
// Invisibility
//
//===========================================================================
class PowerInvisibility : Powerup
{ {
Default Default
{ {
@ -60,6 +83,202 @@ class PowerInvisibility : Powerup native
Powerup.Strength 80; Powerup.Strength 80;
Powerup.Mode "Fuzzy"; 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 class PowerGhost : PowerInvisibility