Merge remote-tracking branch 'gzdoom/master' into qzdoom

# Conflicts:
#	src/r_things.cpp
#	src/r_things.h
This commit is contained in:
Magnus Norddahl 2017-01-16 23:05:34 +01:00
commit 2848ca53dc
23 changed files with 531 additions and 494 deletions

View File

@ -609,7 +609,7 @@ endif()
# Libraries ZDoom needs
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" "${CMAKE_DL_LIBS}" )
include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" )
if( SNDFILE_FOUND )
@ -625,8 +625,6 @@ if( NOT DYN_FLUIDSYNTH )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" )
endif()
else()
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${CMAKE_DL_LIBS} )
endif()
# Start defining source files for ZDoom

View File

@ -46,7 +46,7 @@
struct subsector_t;
struct FBlockNode;
struct FPortalGroupArray;
struct visstyle_t;
//
// NOTES: AActor
//
@ -616,6 +616,8 @@ public:
// Adjusts the angle for deflection/reflection of incoming missiles
// 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

@ -229,16 +229,14 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
// This code is taken and adapted from APowerProtection::ModifyDamage().
// The differences include not using a default value, and of course the way
// the damage factor info is obtained.
// ApplyDamageFactors(ArmorType, damageType, damage, damage);
DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
if (df != NULL)
{
damage = newdamage = df->Apply(damageType, damage);
}
}
if (Inventory != NULL)
{
Inventory->AbsorbDamage (damage, damageType, newdamage);
}
}
//===========================================================================
@ -629,10 +627,6 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
damage = newdamage;
}
}
if (Inventory != NULL)
{
Inventory->AbsorbDamage (damage, damageType, newdamage);
}
}
//===========================================================================

View File

@ -540,370 +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)
//===========================================================================
//
// APowerStrength :: HandlePickup
//
//===========================================================================
bool APowerStrength::HandlePickup (AInventory *item)
{
if (item->GetClass() == GetClass())
{ // Setting EffectTics to 0 will force Powerup's HandlePickup()
// method to reset the tic count so you get the red flash again.
EffectTics = 0;
}
return Super::HandlePickup (item);
}
//===========================================================================
//
// APowerStrength :: InitEffect
//
//===========================================================================
void APowerStrength::InitEffect ()
{
Super::InitEffect();
}
//===========================================================================
//
// APowerStrength :: DoEffect
//
//===========================================================================
void APowerStrength::Tick ()
{
// Strength counts up to diminish the fade.
assert(EffectTics < (INT_MAX - 1)); // I can't see a game lasting nearly two years, but...
EffectTics += 2;
Super::Tick();
}
//===========================================================================
//
// APowerStrength :: GetBlend
//
//===========================================================================
PalEntry APowerStrength::GetBlend ()
{
// slowly fade the berserk out
int cnt = 12 - (EffectTics >> 6);
if (cnt > 0)
{
cnt = (cnt + 7) >> 3;
return PalEntry (BlendColor.a*cnt*255/9,
BlendColor.r, BlendColor.g, BlendColor.b);
}
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);
}
// Ironfeet Powerup ----------------------------------------------------------
IMPLEMENT_CLASS(APowerIronFeet, false, false)
//===========================================================================
//
// APowerIronFeet :: AbsorbDamage
//
//===========================================================================
void APowerIronFeet::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (damageType == NAME_Drowning)
{
newdamage = 0;
}
else if (Inventory != NULL)
{
Inventory->AbsorbDamage (damage, damageType, newdamage);
}
}
//===========================================================================
//
// APowerIronFeet :: DoEffect
//
//===========================================================================
void APowerIronFeet::DoEffect ()
{
if (Owner->player != NULL)
{
Owner->player->mo->ResetAirSupply ();
}
}
// Strife Environment Suit Powerup -------------------------------------------
IMPLEMENT_CLASS(APowerMask, false, false)
//===========================================================================
//
// APowerMask :: AbsorbDamage
//
//===========================================================================
void APowerMask::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (damageType == NAME_Fire)
{
newdamage = 0;
}
else
{
Super::AbsorbDamage (damage, damageType, newdamage);
}
}
//===========================================================================
//
// APowerMask :: DoEffect
//
//===========================================================================
void APowerMask::DoEffect ()
{
Super::DoEffect ();
if (!(level.time & 0x3f))
{
S_Sound (Owner, CHAN_AUTO, "misc/mask", 1, ATTN_STATIC);
}
}
// Speed Powerup -------------------------------------------------------------
IMPLEMENT_CLASS(APowerSpeed, false, false)

View File

@ -64,45 +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
{
DECLARE_CLASS (APowerStrength, APowerup)
public:
PalEntry GetBlend ();
protected:
virtual void InitEffect () override;
virtual void Tick () 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 APowerIronFeet : public APowerup
{
DECLARE_CLASS (APowerIronFeet, APowerup)
public:
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
virtual void DoEffect () override;
};
class APowerMask : public APowerIronFeet
{
DECLARE_CLASS (APowerMask, APowerIronFeet)
public:
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
virtual void DoEffect () override;
};
class APowerSpeed : public APowerup

View File

@ -697,12 +697,17 @@ DEFINE_ACTION_FUNCTION(AInventory, BecomePickup)
void AInventory::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
if (Inventory != NULL)
{
Inventory->AbsorbDamage (damage, damageType, newdamage);
}
}
DEFINE_ACTION_FUNCTION(AInventory, AbsorbDamage)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_INT(damage);
PARAM_NAME(type);
PARAM_POINTER(newdmg, int);
self->AbsorbDamage(damage, type, *newdmg);
return 0;
}
//===========================================================================
//
// AInventory :: ModifyDamage
@ -778,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

@ -297,8 +297,8 @@ static void DrawHealth(player_t *CPlayer, int x, int y)
CR_BLUE;
const bool haveBerserk = hud_berserk_health
&& NULL != berserkpic
&& NULL != CPlayer->mo->FindInventory< APowerStrength >();
&& nullptr != berserkpic
&& nullptr != CPlayer->mo->FindInventory(PClass::FindActor(NAME_PowerStrength));
DrawImageToBox(haveBerserk ? berserkpic : healthpic, x, y, 31, 17);
DrawHudNumber(HudFont, fontcolor, health, x + 33, y + 17);

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

@ -1305,7 +1305,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
int newdam = damage;
if (damage > 0)
{
player->mo->Inventory->AbsorbDamage(damage, mod, newdam);
newdam = player->mo->AbsorbDamage(damage, mod);
}
if (!telefragDamage || (player->mo->flags7 & MF7_LAXTELEFRAGDMG)) //rawdamage is never modified.
{
@ -1385,7 +1385,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
if (!(flags & (DMG_NO_ARMOR|DMG_FORCED)) && target->Inventory != NULL && damage > 0)
{
int newdam = damage;
target->Inventory->AbsorbDamage (damage, mod, newdam);
newdam = target->AbsorbDamage(damage, mod);
damage = newdam;
if (damage <= 0)
{

View File

@ -3615,6 +3615,39 @@ bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle)
return false;
}
int AActor::AbsorbDamage(int damage, FName dmgtype)
{
for (AInventory *item = Inventory; item != nullptr; item = item->Inventory)
{
IFVIRTUALPTR(item, AInventory, AbsorbDamage)
{
VMValue params[4] = { item, damage, dmgtype.GetIndex(), &damage };
GlobalVMStack.Call(func, params, 4, nullptr, 0, nullptr);
}
else item->AbsorbDamage(damage, dmgtype, 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 ()
{
if (ActiveSound && !S_IsActorPlayingSomething (this, CHAN_VOICE, -1))

View File

@ -394,9 +394,10 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
// Allow subclasses. Better would be to implement it as armor and let that reduce
// the damage as part of the normal damage procedure. Unfortunately, I don't have
// different damage types yet, so that's not happening for now.
auto pitype = PClass::FindActor(NAME_PowerIronFeet);
for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
{
if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
if (ironfeet->IsKindOf(pitype))
break;
}
@ -578,9 +579,10 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType)
if (Terrains[floorType].AllowProtection)
{
auto pitype = PClass::FindActor(NAME_PowerIronFeet);
for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
{
if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
if (ironfeet->IsKindOf (pitype))
break;
}
}

View File

@ -289,19 +289,26 @@ void RenderPolyPlayerSprites::RenderSprite(DPSprite *sprite, AActor *owner, floa
{
visstyle_t visstyle;
visstyle.Alpha = Alpha;
visstyle.RenderStyle = RenderStyle;
visstyle.colormap = nullptr; // Same as the GL render is doing.
visstyle.RenderStyle = STYLE_Count;
visstyle.Invert = false;
camera->Inventory->AlterWeaponSprite(&visstyle);
RenderStyle = visstyle.RenderStyle;
Alpha = visstyle.Alpha;
// Only bother checking for the one type it changes it to until this has been ZScript'ed..
if (visstyle.colormap == SpecialColormaps[INVERSECOLORMAP].Colormap)
if (visstyle.RenderStyle != STYLE_Count)
{
RenderStyle = visstyle.RenderStyle;
}
if (visstyle.Invert)
{
BaseColormap = &SpecialColormaps[INVERSECOLORMAP];
ColormapNum = 0;
if (BaseColormap->Maps < mybasecolormap->Maps || BaseColormap->Maps >= mybasecolormap->Maps + NUMCOLORMAPS * 256)
{
noaccel = true;
}
}
}

View File

@ -1488,9 +1488,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

@ -2127,6 +2127,7 @@ CCMD (soundlist)
{
Printf ("%3d. %s **not present**\n", i, sfx->name.GetChars());
}
Printf(" PitchMask = %d\n", sfx->PitchMask);
}
}

View File

@ -5921,8 +5921,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
{
Object->ValueType = TypeColorStruct;
}
else if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
{
auto ptype = static_cast<PPointer *>(Object->ValueType)->PointedType;
if (ptype->IsKindOf(RUNTIME_CLASS(PStruct)))

View File

@ -819,6 +819,68 @@ static bool ParsePropertyParams(FScanner &sc, FPropertyInfo *prop, AActor *defau
return true;
}
//==========================================================================
//
// Parses an actor property's parameters and calls the handler
//
//==========================================================================
static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaults, Baggage &bag)
{
for (unsigned i=0; i<prop->Variables.Size();i++)
{
auto f = prop->Variables[i];
void *addr;
if (i > 0) sc.MustGetStringName(",");
if (f->Flags & VARF_Meta)
{
addr = ((char*)bag.Info) + f->Offset;
}
else
{
addr = ((char*)defaults) + f->Offset;
}
if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
{
sc.MustGetNumber();
static_cast<PInt*>(f->Type)->SetValue(addr, sc.Number);
}
else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
{
sc.MustGetFloat();
static_cast<PFloat*>(f->Type)->SetValue(addr, sc.Float);
}
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
{
sc.MustGetString();
*(FString*)addr = sc.String;
}
else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{
sc.MustGetString();
auto cls = PClass::FindClass(sc.String);
*(PClass**)addr = cls;
if (cls == nullptr)
{
cls = static_cast<PClassPointer*>(f->Type)->ClassRestriction->FindClassTentative(sc.String);
}
else if (!cls->IsDescendantOf(static_cast<PClassPointer*>(f->Type)->ClassRestriction))
{
sc.ScriptMessage("class %s is not compatible with property type %s", sc.String, static_cast<PClassPointer*>(f->Type)->ClassRestriction->TypeName.GetChars());
FScriptPosition::ErrorCounter++;
}
*(PClass**)addr = cls;
}
else
{
sc.ScriptMessage("unhandled property type %s", f->Type->DescriptiveName());
FScriptPosition::ErrorCounter++;
}
}
}
//==========================================================================
//
// Parses an actor property
@ -867,6 +929,17 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
}
else
{
propname.Insert(0, "@property@");
FName name(propname, true);
if (name != NAME_None)
{
auto propp = dyn_cast<PProperty>(bag.Info->Symbols.FindSymbol(name, true));
if (propp != nullptr)
{
DispatchScriptProperty(sc, propp, (AActor *)bag.Info->Defaults, bag);
return;
}
}
sc.ScriptError("'%s' is an unknown actor property\n", propname.GetChars());
}
}

View File

@ -1960,12 +1960,17 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
}
else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{
auto cls = PClass::FindClass(GetString(exp));
*(PClass**)addr = cls;
if (!cls->IsDescendantOf(static_cast<PClassPointer*>(f->Type)->ClassRestriction))
auto clsname = GetString(exp);
auto cls = PClass::FindClass(clsname);
if (cls == nullptr)
{
Error(property, "class %s is not compatible with property type %s", cls->TypeName.GetChars(), static_cast<PClassPointer*>(f->Type)->ClassRestriction->TypeName.GetChars());
cls = static_cast<PClassPointer*>(f->Type)->ClassRestriction->FindClassTentative(clsname);
}
else if (!cls->IsDescendantOf(static_cast<PClassPointer*>(f->Type)->ClassRestriction))
{
Error(property, "class %s is not compatible with property type %s", clsname, static_cast<PClassPointer*>(f->Type)->ClassRestriction->TypeName.GetChars());
}
*(PClass**)addr = cls;
}
else
{

View File

@ -495,7 +495,7 @@ void FSerializer::Close()
{
// we must explicitly delete all thinkers in the array which did not get linked into the thinker lists.
// Otherwise these objects may survive a level deletion and point to incorrect data.
for (auto &obj : r->mDObjects)
for (auto obj : r->mDObjects)
{
auto think = dyn_cast<DThinker>(obj);
if (think != nullptr)

View File

@ -493,19 +493,26 @@ namespace swrenderer
{
visstyle_t visstyle;
visstyle.Alpha = vis->Alpha;
visstyle.RenderStyle = vis->RenderStyle;
visstyle.colormap = nullptr; // Same as the GL render is doing.
visstyle.RenderStyle = STYLE_Count;
visstyle.Invert = false;
camera->Inventory->AlterWeaponSprite(&visstyle);
vis->RenderStyle = visstyle.RenderStyle;
vis->Alpha = visstyle.Alpha;
// Only bother checking for the one type it changes it to until this has been ZScript'ed..
if (visstyle.colormap == SpecialColormaps[INVERSECOLORMAP].Colormap)
if (visstyle.RenderStyle != STYLE_Count)
{
vis->RenderStyle = visstyle.RenderStyle;
}
if (visstyle.Invert)
{
vis->BaseColormap = &SpecialColormaps[INVERSECOLORMAP];
vis->ColormapNum = 0;
if (vis->BaseColormap->Maps < mybasecolormap->Maps || vis->BaseColormap->Maps >= mybasecolormap->Maps + NUMCOLORMAPS * 256)
{
noaccel = true;
}
}
}
// If we're drawing with a special colormap, but shaders for them are disabled, do

View File

@ -404,6 +404,7 @@ map E4M1 lookup "HUSTR_E4M1"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 165
music = "$MUSIC_E3M4"
}
@ -415,6 +416,7 @@ map E4M2 lookup "HUSTR_E4M2"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 255
music = "$MUSIC_E3M2"
}
@ -426,6 +428,7 @@ map E4M3 lookup "HUSTR_E4M3"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 135
music = "$MUSIC_E3M3"
}
@ -437,6 +440,7 @@ map E4M4 lookup "HUSTR_E4M4"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 150
music = "$MUSIC_E1M5"
}
@ -448,6 +452,7 @@ map E4M5 lookup "HUSTR_E4M5"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 180
music = "$MUSIC_E2M7"
}
@ -459,6 +464,7 @@ map E4M6 lookup "HUSTR_E4M6"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 390
cyberdemonspecial
specialaction_opendoor
music = "$MUSIC_E2M4"
@ -472,6 +478,7 @@ map E4M7 lookup "HUSTR_E4M7"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 135
music = "$MUSIC_E2M6"
}
@ -483,6 +490,7 @@ map E4M8 lookup "HUSTR_E4M8"
secretnext = "E4M9"
sky1 = "SKY4"
cluster = 4
par = 360
nointermission
nosoundclipping
spidermastermindspecial
@ -498,6 +506,7 @@ map E4M9 lookup "HUSTR_E4M9"
secretnext = "E4M3"
sky1 = "SKY4"
cluster = 4
par = 180
music = "$MUSIC_E1M9"
}

View File

@ -1,3 +1,10 @@
struct VisStyle
{
bool Invert;
float Alpha;
int RenderStyle;
}
class Inventory : Actor native
{
const BLINKTHRESHOLD = (4*32);
@ -39,6 +46,7 @@ class Inventory : Actor native
virtual native void AttachToOwner(Actor user);
virtual native void DetachFromOwner();
virtual native bool DrawPowerup(int x, int y);
virtual native void AbsorbDamage (int damage, Name damageType, out int newdamage);
//===========================================================================
//
@ -55,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,9 +45,26 @@ 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
//===========================================================================
//
// Strength
//
//===========================================================================
class PowerStrength : Powerup
{
Default
{
@ -49,9 +72,58 @@ class PowerStrength : Powerup native
Powerup.Color "ff 00 00", 0.5;
+INVENTORY.HUBPOWER
}
override bool HandlePickup (Inventory item)
{
if (item.GetClass() == GetClass())
{ // Setting EffectTics to 0 will force Powerup's HandlePickup()
// method to reset the tic count so you get the red flash again.
EffectTics = 0;
}
return Super.HandlePickup (item);
}
//===========================================================================
//
// APowerStrength :: DoEffect
//
//===========================================================================
override void Tick ()
{
// Strength counts up to diminish the fade.
EffectTics += 2;
Super.Tick();
}
//===========================================================================
//
// APowerStrength :: GetBlend
//
//===========================================================================
override color GetBlend ()
{
// slowly fade the berserk out
int cnt = 128 - (EffectTics>>3);
if (cnt > 0)
{
return Color(BlendColor.a*cnt/256,
BlendColor.r, BlendColor.g, BlendColor.b);
}
return 0;
}
}
class PowerInvisibility : Powerup native
//===========================================================================
//
// Invisibility
//
//===========================================================================
class PowerInvisibility : Powerup
{
Default
{
@ -60,6 +132,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
@ -84,16 +352,45 @@ class PowerShadow : PowerInvisibility
}
}
class PowerIronFeet : Powerup native
//===========================================================================
//
// IronFeet
//
//===========================================================================
class PowerIronFeet : Powerup
{
Default
{
Powerup.Duration -60;
Powerup.Color "00 ff 00", 0.125;
}
override void AbsorbDamage (int damage, Name damageType, out int newdamage)
{
if (damageType == 'Drowning')
{
newdamage = 0;
}
}
override void DoEffect ()
{
if (Owner.player != NULL)
{
Owner.player.mo.ResetAirSupply ();
}
}
}
class PowerMask : PowerIronFeet native
//===========================================================================
//
// Mask
//
//===========================================================================
class PowerMask : PowerIronFeet
{
Default
{
@ -102,6 +399,24 @@ class PowerMask : PowerIronFeet native
+INVENTORY.HUBPOWER
Inventory.Icon "I_MASK";
}
override void AbsorbDamage (int damage, Name damageType, out int newdamage)
{
if (damageType == 'Fire' || damageType == 'Drowning')
{
newdamage = 0;
}
}
override void DoEffect ()
{
Super.DoEffect ();
if (!(level.time & 0x3f))
{
Owner.A_PlaySound ("misc/mask", CHAN_AUTO);
}
}
}
//===========================================================================