diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 190f953a0..ecc80cba1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/actor.h b/src/actor.h index 6b4ce4ae7..e1cc56290 100644 --- a/src/actor.h +++ b/src/actor.h @@ -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(); diff --git a/src/g_inventory/a_armor.cpp b/src/g_inventory/a_armor.cpp index ebe8f49f6..8bb32c921 100644 --- a/src/g_inventory/a_armor.cpp +++ b/src/g_inventory/a_armor.cpp @@ -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); - } } //=========================================================================== diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index f8e34c9a7..0cd4828b1 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -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(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(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(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) diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index d72ed42c3..f947e18d5 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -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 diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 72e51b0c9..13842d359 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -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 diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 9cd49bbaf..9f85e482b 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -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. diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index b645ac511..839582d34 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -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); diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index 953509495..d53e252e3 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -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); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 97787fd9c..a73e3d8b3 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -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) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b40b8baa3..9c18ea638 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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 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)) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 0909da70f..e5a1178d8 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -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; } } diff --git a/src/polyrenderer/scene/poly_playersprite.cpp b/src/polyrenderer/scene/poly_playersprite.cpp index 640d90252..a1a46deb6 100644 --- a/src/polyrenderer/scene/poly_playersprite.cpp +++ b/src/polyrenderer/scene/poly_playersprite.cpp @@ -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; + } } } diff --git a/src/r_defs.h b/src/r_defs.h index 81f6869f9..d0e565b41 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -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; }; diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 085f1869e..952a40d09 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -2127,6 +2127,7 @@ CCMD (soundlist) { Printf ("%3d. %s **not present**\n", i, sfx->name.GetChars()); } + Printf(" PitchMask = %d\n", sfx->PitchMask); } } diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 1eefba216..47a10f95d 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -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(Object->ValueType)->PointedType; if (ptype->IsKindOf(RUNTIME_CLASS(PStruct))) diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index f53b97006..c839a2dc0 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -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; iVariables.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(f->Type)->SetValue(addr, sc.Number); + } + else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat))) + { + sc.MustGetFloat(); + static_cast(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(f->Type)->ClassRestriction->FindClassTentative(sc.String); + } + else if (!cls->IsDescendantOf(static_cast(f->Type)->ClassRestriction)) + { + sc.ScriptMessage("class %s is not compatible with property type %s", sc.String, static_cast(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(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()); } } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 281f707d2..1687983f2 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -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(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(f->Type)->ClassRestriction->TypeName.GetChars()); + cls = static_cast(f->Type)->ClassRestriction->FindClassTentative(clsname); } + else if (!cls->IsDescendantOf(static_cast(f->Type)->ClassRestriction)) + { + Error(property, "class %s is not compatible with property type %s", clsname, static_cast(f->Type)->ClassRestriction->TypeName.GetChars()); + } + *(PClass**)addr = cls; } else { diff --git a/src/serializer.cpp b/src/serializer.cpp index 5154b0700..6d7a6ef7c 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -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(obj); if (think != nullptr) diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index 3e9b136aa..337603793 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -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 diff --git a/wadsrc/static/mapinfo/doom1.txt b/wadsrc/static/mapinfo/doom1.txt index 2baba9a5d..f767e1c38 100644 --- a/wadsrc/static/mapinfo/doom1.txt +++ b/wadsrc/static/mapinfo/doom1.txt @@ -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" } diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index d3f6bfef5..90ed458d0 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -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(); diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index db838b904..b744bfc97 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -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); + } + } + } //===========================================================================