diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 6c785c0c5a..edf6cb501e 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,29 @@ +January 12, 2007 (Changes by Graf Zahl) +- Converted the StrifePlayer to DECORATE. Even though it requires exporting + 3 new code pointers without general use it was necessary to handle + GiveDefaultInventory consistently for all players without the need to + subclass this function. +- Added a Player.RunHealth property to expose the StrifePlayer's behavior of + not being able to run when its health is below 10. +- Changed APlayerPawn::GiveDefaultInventory so that it always adds a HexenArmor + and a BasicArmor item to the inventory. If these items are not the first ones + added to the inventory anything else that might absorb damage is not guaranteed + to work consistently because their function depends on the order in the inventory. +- Changed handling of APowerup's DoEffect so that it is called from the owner's + Tick function, not the item's. This is so that the order of execution is + determined by the order in the inventory. When done in the item's Tick function + order depends on the global thinker table which can cause problems with the + order in which conflicting powerups apply their effect. Now it is guaranteed + that the item that was added to the inventory first applies its effect last. +- Fixed: Added checks for Speed==0 to A_Tracer and A_Tracer2 because this could + cause a divide by zero. +- Fixed: P_MoveThing must also set the moved actor's previous position to + prevent interpolation of the move. +- Fixed: APowerInvisibility and its subclasses need to constantly update + the owner's translucency information in case of interference between different + subclasses. Also changed Hexen's Cleric's invulnerability mode to disable + the translucency effect if an invisibility powerup is active. + January 9, 2007 (Changes by Graf Zahl) - Added Skulltag's REDMAP and GREENMAP. - Fixed: The PlayerSpeedTrail must copy the player's scaling information diff --git a/src/codepointers.h b/src/codepointers.h index 34d6a5c45d..b3edadd253 100644 --- a/src/codepointers.h +++ b/src/codepointers.h @@ -96,3 +96,8 @@ ACTOR(Respawn) ACTOR(BarrelDestroy) ACTOR(PlayerSkinCheck) ACTOR(QueueCorpse) + +// Special code pointers for Strife's player - not to be used elsewhere! +ACTOR(ItBurnsItBurns) +ACTOR(CrispyPlayer) +ACTOR(DropFire) diff --git a/src/d_player.h b/src/d_player.h index a6a28bcae5..ea017287ed 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -78,7 +78,6 @@ public: virtual void PlayIdle (); virtual void PlayRunning (); virtual void ThrowPoisonBag (); - virtual void GiveDefaultInventory (); virtual void TweakSpeeds (int &forwardmove, int &sidemove); virtual void MorphPlayerThink (); virtual void ActivateMorphWeapon (); @@ -87,6 +86,7 @@ public: virtual void GiveDeathmatchInventory (); virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer); + void GiveDefaultInventory (); void PlayAttacking (); void PlayAttacking2 (); const char *GetSoundClass (); @@ -104,6 +104,7 @@ public: int crouchsprite; int MaxHealth; + int RunHealth; AInventory *InvFirst; // first inventory item displayed on inventory bar AInventory *InvSel; // selected inventory item diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index cc71c27e40..ad4000e4f9 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -70,7 +70,7 @@ void A_Tracer (AActor *self) // adjust direction dest = self->tracer; - if (!dest || dest->health <= 0) + if (!dest || dest->health <= 0 || self->Speed == 0) return; // change angle diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 4f6be76ec5..f772b6f1cc 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -89,45 +89,14 @@ void APowerupGiver::Serialize (FArchive &arc) void APowerup::Tick () { + // Powerups cannot exist outside an inventory if (Owner == NULL) { Destroy (); } - else if (EffectTics > 0) + if (EffectTics > 0 && --EffectTics == 0) { - DoEffect (); - - if (EffectTics > BLINKTHRESHOLD || (EffectTics & 8)) - { - if (BlendColor == INVERSECOLOR) - { - Owner->player->fixedcolormap = INVERSECOLORMAP; - } - else if (BlendColor == GOLDCOLOR) - { - Owner->player->fixedcolormap = GOLDCOLORMAP; - } - else if (BlendColor == REDCOLOR) - { - Owner->player->fixedcolormap = REDCOLORMAP; - } - else if (BlendColor == GREENCOLOR) - { - Owner->player->fixedcolormap = GREENCOLORMAP; - } - } - else if ((BlendColor == INVERSECOLOR && Owner->player->fixedcolormap == INVERSECOLORMAP) || - (BlendColor == GOLDCOLOR && Owner->player->fixedcolormap == GOLDCOLORMAP) || - (BlendColor == REDCOLOR && Owner->player->fixedcolormap == REDCOLORMAP) || - (BlendColor == GREENCOLOR && Owner->player->fixedcolormap == GREENCOLORMAP)) - { - Owner->player->fixedcolormap = 0; - } - - if (--EffectTics == 0) - { - Destroy (); - } + Destroy (); } } @@ -182,6 +151,41 @@ void APowerup::InitEffect () void APowerup::DoEffect () { + if (Owner == NULL) + { + return; + } + + if (EffectTics > 0) + { + int oldcolormap = Owner->player->fixedcolormap; + if (EffectTics > BLINKTHRESHOLD || (EffectTics & 8)) + { + if (BlendColor == INVERSECOLOR) + { + Owner->player->fixedcolormap = INVERSECOLORMAP; + } + else if (BlendColor == GOLDCOLOR) + { + Owner->player->fixedcolormap = GOLDCOLORMAP; + } + else if (BlendColor == REDCOLOR) + { + Owner->player->fixedcolormap = REDCOLORMAP; + } + else if (BlendColor == GREENCOLOR) + { + Owner->player->fixedcolormap = GREENCOLORMAP; + } + } + else if ((BlendColor == INVERSECOLOR && Owner->player->fixedcolormap == INVERSECOLORMAP) || + (BlendColor == GOLDCOLOR && Owner->player->fixedcolormap == GOLDCOLORMAP) || + (BlendColor == REDCOLOR && Owner->player->fixedcolormap == REDCOLORMAP) || + (BlendColor == GREENCOLOR && Owner->player->fixedcolormap == GREENCOLORMAP)) + { + Owner->player->fixedcolormap = 0; + } + } } //=========================================================================== @@ -361,6 +365,8 @@ void APowerInvulnerable::InitEffect () void APowerInvulnerable::DoEffect () { + Super::DoEffect (); + if (Owner == NULL) { return; @@ -368,30 +374,39 @@ void APowerInvulnerable::DoEffect () if (mode == NAME_Ghost) { - Owner->RenderStyle = STYLE_Translucent; - if (!(level.time & 7) && Owner->alpha > 0 && Owner->alpha < OPAQUE) + if (!(Owner->flags & MF_SHADOW)) { - if (Owner->alpha == HX_SHADOW) + // Don't mess with the translucency settings if an + // invisibility powerup is active. + Owner->RenderStyle = STYLE_Translucent; + if (!(level.time & 7) && Owner->alpha > 0 && Owner->alpha < OPAQUE) { - Owner->alpha = HX_ALTSHADOW; + if (Owner->alpha == HX_SHADOW) + { + Owner->alpha = HX_ALTSHADOW; + } + else + { + Owner->alpha = 0; + Owner->flags2 |= MF2_NONSHOOTABLE; + } } - else + if (!(level.time & 31)) { - Owner->alpha = 0; - Owner->flags2 |= MF2_NONSHOOTABLE; + if (Owner->alpha == 0) + { + Owner->flags2 &= ~MF2_NONSHOOTABLE; + Owner->alpha = HX_ALTSHADOW; + } + else + { + Owner->alpha = HX_SHADOW; + } } } - if (!(level.time & 31)) + else { - if (Owner->alpha == 0) - { - Owner->flags2 &= ~MF2_NONSHOOTABLE; - Owner->alpha = HX_ALTSHADOW; - } - else - { - Owner->alpha = HX_SHADOW; - } + Owner->flags2 &= ~MF2_NONSHOOTABLE; } } } @@ -414,8 +429,13 @@ void APowerInvulnerable::EndEffect () if (mode == NAME_Ghost) { Owner->flags2 &= ~MF2_NONSHOOTABLE; - Owner->RenderStyle = STYLE_Normal; - Owner->alpha = OPAQUE; + if (!(Owner->flags & MF_SHADOW)) + { + // Don't mess with the translucency settings if an + // invisibility powerup is active. + Owner->RenderStyle = STYLE_Normal; + Owner->alpha = OPAQUE; + } } else if (mode == NAME_Reflective) { @@ -430,7 +450,7 @@ void APowerInvulnerable::EndEffect () //=========================================================================== // -// APowerInvuInvulnerable :: AlterWeaponSprite +// APowerInvulnerable :: AlterWeaponSprite // //=========================================================================== @@ -438,7 +458,7 @@ void APowerInvulnerable::AlterWeaponSprite (vissprite_t *vis) { if (Owner != NULL) { - if (mode == NAME_Ghost) + if (mode == NAME_Ghost && !(Owner->flags & MF_SHADOW)) { fixed_t wp_alpha = MIN(FRACUNIT/4 + Owner->alpha*3/4, FRACUNIT); if (wp_alpha != FIXED_MAX) vis->alpha = wp_alpha; @@ -486,10 +506,11 @@ void APowerStrength::InitEffect () // //=========================================================================== -void APowerStrength::DoEffect () +void APowerStrength::Tick () { // Strength counts up to diminish the fade. EffectTics += 2; + Super::Tick(); } //=========================================================================== @@ -531,6 +552,14 @@ void APowerInvisibility::InitEffect () Owner->RenderStyle = STYLE_OptFuzzy; } +void APowerInvisibility::DoEffect () +{ + Super::DoEffect(); + // Due to potential interference with other PowerInvisibility items + // the effect has to be refreshed each tic. + InitEffect(); +} + //=========================================================================== // // APowerInvisibility :: EndEffect @@ -556,15 +585,16 @@ void APowerInvisibility::EndEffect () void APowerInvisibility::AlterWeaponSprite (vissprite_t *vis) { + if (Inventory != NULL) + { + Inventory->AlterWeaponSprite (vis); + } + // Blink if the powerup is wearing off if (EffectTics < 4*32 && !(EffectTics & 8)) { vis->RenderStyle = STYLE_Normal; } - if (Inventory != NULL) - { - Inventory->AlterWeaponSprite (vis); - } } // Ghost Powerup (Heretic's version of invisibility) ------------------------- @@ -692,14 +722,13 @@ END_DEFAULTS void APowerLightAmp::DoEffect () { - if (Owner->player != NULL) + Super::DoEffect (); + + if (Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS) { if (EffectTics > BLINKTHRESHOLD || (EffectTics & 8)) - { // almost full bright - if (Owner->player->fixedcolormap != NUMCOLORMAPS) - { - Owner->player->fixedcolormap = 1; - } + { + Owner->player->fixedcolormap = 1; } else { @@ -716,7 +745,7 @@ void APowerLightAmp::DoEffect () void APowerLightAmp::EndEffect () { - if (Owner != NULL && Owner->player != NULL) + if (Owner != NULL && Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS) { Owner->player->fixedcolormap = 0; } @@ -748,31 +777,41 @@ void APowerTorch::Serialize (FArchive &arc) void APowerTorch::DoEffect () { - if (EffectTics <= BLINKTHRESHOLD || Owner->player->fixedcolormap == NUMCOLORMAPS) + if (Owner == NULL || Owner->player == NULL) + { + return; + } + + if (EffectTics <= BLINKTHRESHOLD || Owner->player->fixedcolormap >= NUMCOLORMAPS) { Super::DoEffect (); } - else if (!(level.time & 16) && Owner->player != NULL) + else { - if (NewTorch != 0) + APowerup::DoEffect (); + + if (!(level.time & 16) && Owner->player != NULL) { - if (Owner->player->fixedcolormap + NewTorchDelta > 7 - || Owner->player->fixedcolormap + NewTorchDelta < 1 - || NewTorch == Owner->player->fixedcolormap) + if (NewTorch != 0) { - NewTorch = 0; + if (Owner->player->fixedcolormap + NewTorchDelta > 7 + || Owner->player->fixedcolormap + NewTorchDelta < 1 + || NewTorch == Owner->player->fixedcolormap) + { + NewTorch = 0; + } + else + { + Owner->player->fixedcolormap += NewTorchDelta; + } } else { - Owner->player->fixedcolormap += NewTorchDelta; + NewTorch = (pr_torch() & 7) + 1; + NewTorchDelta = (NewTorch == Owner->player->fixedcolormap) ? + 0 : ((NewTorch > Owner->player->fixedcolormap) ? 1 : -1); } } - else - { - NewTorch = (pr_torch() & 7) + 1; - NewTorchDelta = (NewTorch == Owner->player->fixedcolormap) ? - 0 : ((NewTorch > Owner->player->fixedcolormap) ? 1 : -1); - } } } @@ -821,13 +860,16 @@ void APowerFlight::InitEffect () // //=========================================================================== -void APowerFlight::DoEffect () +void APowerFlight::Tick () { // The Wings of Wrath only expire in multiplayer and non-hub games if (!multiplayer && (level.clusterflags & CLUSTER_HUB)) { EffectTics++; } + + Super::Tick (); + // Owner->flags |= MF_NOGRAVITY; // Owner->flags2 |= MF2_FLY; } @@ -1026,6 +1068,8 @@ void APowerSpeed::InitEffect () void APowerSpeed::DoEffect () { + Super::DoEffect (); + if (Owner->player->cheats & CF_PREDICTING) return; @@ -1117,11 +1161,9 @@ void APowerTargeter::InitEffect () void APowerTargeter::DoEffect () { - if (Owner == NULL) - { - Destroy (); - } - else if (Owner->player != NULL) + Super::DoEffect (); + + if (Owner != NULL && Owner->player != NULL) { player_t *player = Owner->player; diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index b2c8ac76d9..fdb4885b22 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -79,7 +79,7 @@ public: PalEntry GetBlend (); protected: void InitEffect (); - void DoEffect (); + void Tick (); bool HandlePickup (AInventory *item); }; @@ -88,6 +88,7 @@ class APowerInvisibility : public APowerup DECLARE_STATELESS_ACTOR (APowerInvisibility, APowerup) protected: void InitEffect (); + void DoEffect (); void EndEffect (); void AlterWeaponSprite (vissprite_t *vis); }; @@ -148,7 +149,7 @@ public: protected: void InitEffect (); - void DoEffect (); + void Tick (); void EndEffect (); bool HitCenterFrame; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index af21e706a8..1bc01075d9 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -492,6 +492,19 @@ void AInventory::BeginPlay () flags |= MF_DROPPED; // [RH] Items are dropped by default } +//=========================================================================== +// +// AInventory :: DoEffect +// +// Handles any effect an item might apply to its owner +// Normally only used by subclasses of APowerup +// +//=========================================================================== + +void AInventory::DoEffect () +{ +} + //=========================================================================== // // AInventory :: Travelled diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index b989461a76..afe4ae578c 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -117,6 +117,7 @@ public: virtual void DoPickupSpecial (AActor *toucher); virtual bool SpecialDropAction (AActor *dropper); virtual bool DrawPowerup (int x, int y); + virtual void DoEffect (); virtual const char *PickupMessage (); virtual void PlayPickupSound (AActor *toucher); diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index 442cf39a5b..4d024771ff 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -316,7 +316,7 @@ void A_Tracer2 (AActor *self) dest = self->tracer; - if (dest == NULL || dest->health <= 0) + if (dest == NULL || dest->health <= 0 || self->Speed == 0) return; // change angle diff --git a/src/g_strife/a_strifeplayer.cpp b/src/g_strife/a_strifeplayer.cpp deleted file mode 100644 index 5c6d016c1a..0000000000 --- a/src/g_strife/a_strifeplayer.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "p_local.h" -#include "a_doomglobal.h" -#include "templates.h" - -void A_Pain (AActor *); -void A_PlayerScream (AActor *); -void A_XXScream (AActor *); -void A_TossGib (AActor *); - -void A_ItBurnsItBurns (AActor *); -void A_DropFire (AActor *); -void A_CrispyPlayer (AActor *); -void A_Yeargh (AActor *); -void A_Wander (AActor *); - -// The player --------------------------------------------------------------- - -class AStrifePlayer : public APlayerPawn -{ - DECLARE_ACTOR (AStrifePlayer, APlayerPawn) -public: - void GiveDefaultInventory (); - void TweakSpeeds (int &forward, int &side); -}; - -FState AStrifePlayer::States[] = -{ -#define S_PLAY 0 - S_NORMAL (PLAY, 'A', -1, NULL , NULL), - -#define S_PLAY_RUN (S_PLAY+1) - S_NORMAL (PLAY, 'A', 4, NULL , &States[S_PLAY_RUN+1]), - S_NORMAL (PLAY, 'B', 4, NULL , &States[S_PLAY_RUN+2]), - S_NORMAL (PLAY, 'C', 4, NULL , &States[S_PLAY_RUN+3]), - S_NORMAL (PLAY, 'D', 4, NULL , &States[S_PLAY_RUN+0]), - -#define S_PLAY_ATK (S_PLAY_RUN+4) - S_NORMAL (PLAY, 'E', 12, NULL , &States[S_PLAY]), - S_NORMAL (PLAY, 'F', 6, NULL , &States[S_PLAY_ATK+0]), - -#define S_PLAY_PAIN (S_PLAY_ATK+2) - S_NORMAL (PLAY, 'Q', 4, NULL , &States[S_PLAY_PAIN+1]), - S_NORMAL (PLAY, 'Q', 4, A_Pain , &States[S_PLAY]), - -#define S_PLAY_DIE (S_PLAY_PAIN+2) - S_NORMAL (PLAY, 'H', 3, NULL , &States[S_PLAY_DIE+1]), - S_NORMAL (PLAY, 'I', 3, A_PlayerScream , &States[S_PLAY_DIE+2]), - S_NORMAL (PLAY, 'J', 3, A_NoBlocking , &States[S_PLAY_DIE+3]), - S_NORMAL (PLAY, 'K', 4, NULL , &States[S_PLAY_DIE+4]), - S_NORMAL (PLAY, 'L', 4, NULL , &States[S_PLAY_DIE+5]), - S_NORMAL (PLAY, 'M', 4, NULL , &States[S_PLAY_DIE+6]), - S_NORMAL (PLAY, 'N', 4, NULL , &States[S_PLAY_DIE+7]), - S_NORMAL (PLAY, 'O', 4, NULL , &States[S_PLAY_DIE+8]), - S_NORMAL (PLAY, 'P', 700, NULL , &States[S_PLAY_DIE+9+7]), - -#define S_PLAY_XDIE (S_PLAY_DIE+9) - S_NORMAL (RGIB, 'A', 5, A_TossGib , &States[S_PLAY_XDIE+1]), - S_NORMAL (RGIB, 'B', 5, A_XXScream , &States[S_PLAY_XDIE+2]), - S_NORMAL (RGIB, 'C', 5, A_NoBlocking , &States[S_PLAY_XDIE+3]), - S_NORMAL (RGIB, 'D', 5, A_TossGib , &States[S_PLAY_XDIE+4]), - S_NORMAL (RGIB, 'E', 5, A_TossGib , &States[S_PLAY_XDIE+5]), - S_NORMAL (RGIB, 'F', 5, A_TossGib , &States[S_PLAY_XDIE+6]), - S_NORMAL (RGIB, 'G', 5, A_TossGib , &States[S_PLAY_XDIE+7]), - S_NORMAL (RGIB, 'H', -1, A_TossGib , NULL), - - // [RH] These weren't bright in Strife, but I think they should be. - // (After all, they are now a light source.) -#define S_PLAY_BURNDEATH (S_PLAY_XDIE+8) - S_BRIGHT (BURN, 'A', 3, A_ItBurnsItBurns, &States[S_PLAY_BURNDEATH+1]), - S_BRIGHT (BURN, 'B', 3, A_DropFire, &States[S_PLAY_BURNDEATH+2]), - S_BRIGHT (BURN, 'C', 3, A_Wander, &States[S_PLAY_BURNDEATH+3]), - S_BRIGHT (BURN, 'D', 3, A_NoBlocking, &States[S_PLAY_BURNDEATH+4]), - S_BRIGHT (BURN, 'E', 5, A_DropFire, &States[S_PLAY_BURNDEATH+5]), - S_BRIGHT (BURN, 'F', 5, A_Wander, &States[S_PLAY_BURNDEATH+6]), - S_BRIGHT (BURN, 'G', 5, A_Wander, &States[S_PLAY_BURNDEATH+7]), - S_BRIGHT (BURN, 'H', 5, A_Wander, &States[S_PLAY_BURNDEATH+8]), - S_BRIGHT (BURN, 'I', 5, A_DropFire, &States[S_PLAY_BURNDEATH+9]), - S_BRIGHT (BURN, 'J', 5, A_Wander, &States[S_PLAY_BURNDEATH+10]), - S_BRIGHT (BURN, 'K', 5, A_Wander, &States[S_PLAY_BURNDEATH+11]), - S_BRIGHT (BURN, 'L', 5, A_Wander, &States[S_PLAY_BURNDEATH+12]), - S_BRIGHT (BURN, 'M', 3, A_DropFire, &States[S_PLAY_BURNDEATH+13]), - S_BRIGHT (BURN, 'N', 3, A_CrispyPlayer, &States[S_PLAY_BURNDEATH+14]), - S_BRIGHT (BURN, 'O', 5, NULL, &States[S_PLAY_BURNDEATH+15]), - S_BRIGHT (BURN, 'P', 5, NULL, &States[S_PLAY_BURNDEATH+16]), - S_BRIGHT (BURN, 'Q', 5, NULL, &States[S_PLAY_BURNDEATH+17]), - S_BRIGHT (BURN, 'P', 5, NULL, &States[S_PLAY_BURNDEATH+18]), - S_BRIGHT (BURN, 'Q', 5, NULL, &States[S_PLAY_BURNDEATH+19]), - S_BRIGHT (BURN, 'R', 7, NULL, &States[S_PLAY_BURNDEATH+20]), - S_BRIGHT (BURN, 'S', 7, NULL, &States[S_PLAY_BURNDEATH+21]), - S_BRIGHT (BURN, 'T', 7, NULL, &States[S_PLAY_BURNDEATH+22]), - S_BRIGHT (BURN, 'U', 7, NULL, &States[S_PLAY_BURNDEATH+23]), - S_NORMAL (BURN, 'V',-1, NULL, NULL), - -#define S_PLAY_ZAPDEATH (S_PLAY_BURNDEATH+24) - S_NORMAL (DISR, 'A', 5, A_Yeargh, &States[S_PLAY_ZAPDEATH+1]), - S_NORMAL (DISR, 'B', 5, NULL, &States[S_PLAY_ZAPDEATH+2]), - S_NORMAL (DISR, 'C', 5, NULL, &States[S_PLAY_ZAPDEATH+3]), - S_NORMAL (DISR, 'D', 5, A_NoBlocking, &States[S_PLAY_ZAPDEATH+4]), - S_NORMAL (DISR, 'E', 5, NULL, &States[S_PLAY_ZAPDEATH+5]), - S_NORMAL (DISR, 'F', 5, NULL, &States[S_PLAY_ZAPDEATH+6]), - S_NORMAL (DISR, 'G', 4, NULL, &States[S_PLAY_ZAPDEATH+7]), - S_NORMAL (DISR, 'H', 4, NULL, &States[S_PLAY_ZAPDEATH+8]), - S_NORMAL (DISR, 'I', 4, NULL, &States[S_PLAY_ZAPDEATH+9]), - S_NORMAL (DISR, 'J', 4, NULL, &States[S_PLAY_ZAPDEATH+10]), - S_NORMAL (MEAT, 'D',-1, NULL, NULL) -}; - -IMPLEMENT_ACTOR (AStrifePlayer, Strife, -1, 0) - PROP_SpawnHealth (100) - PROP_RadiusFixed (18) - PROP_HeightFixed (56) - PROP_Mass (100) - PROP_PainChance (255) - PROP_SpeedFixed (1) - PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY) - PROP_Flags2 (MF2_SLIDE|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_FLOORCLIP) - PROP_Flags3 (MF3_NOBLOCKMONST) - PROP_MaxStepHeight (16) - - PROP_SpawnState (S_PLAY) - PROP_SeeState (S_PLAY_RUN) - PROP_PainState (S_PLAY_PAIN) - PROP_MissileState (S_PLAY_ATK) - PROP_MeleeState (S_PLAY_ATK+1) - PROP_DeathState (S_PLAY_DIE) - PROP_XDeathState (S_PLAY_XDIE) - PROP_BDeathState (S_PLAY_BURNDEATH) - PROP_EDeathState (S_PLAY_ZAPDEATH) - - // [GRB] - PROP_PlayerPawn_ColorRange (96, 111) - PROP_PlayerPawn_DisplayName ("Rebel") -END_DEFAULTS - -void AStrifePlayer::GiveDefaultInventory () -{ - Super::GiveDefaultInventory (); - - if (!Inventory) - { - AWeapon *weapon; - - player->health = GetDefault()->health; - weapon = static_cast(player->mo->GiveInventoryType (PClass::FindClass ("PunchDagger"))); - player->ReadyWeapon = player->PendingWeapon = weapon; - } -} - -void AStrifePlayer::TweakSpeeds (int &forward, int &side) -{ - if (health<=10) - { - forward = clamp(forward, -0x1900, 0x1900); - side = clamp(side, -0x1800, 0x1800); - } - Super::TweakSpeeds (forward, side); -} diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 11fb96c43b..7dc084a261 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -288,10 +288,16 @@ static void DoTakeInv (AActor *actor, const PClass *info, int amount) item->Amount -= amount; if (item->Amount <= 0) { - // If it's not ammo, destroy it. Ammo needs to stick around, even - // when it's zero for the benefit of the weapons that use it and - // to maintain the maximum ammo amounts a backpack might have given. - if (item->GetClass()->ParentClass != RUNTIME_CLASS(AAmmo)) + // If it's not ammo or an internal armor, destroy it. + // Ammo needs to stick around, even when it's zero for the benefit + // of the weapons that use it and to maintain the maximum ammo + // amounts a backpack might have given. + // Armor shouldn't be removed because they only work properly when + // they are the last items in the inventory. + if (item->GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && + item->GetClass() != RUNTIME_CLASS(ABasicArmor) && + item->GetClass() != RUNTIME_CLASS(AHexenArmor) + ) { item->Destroy (); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 29e408e39d..5849d816e7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2486,6 +2486,16 @@ void AActor::Tick () PrevY = y; PrevZ = z; + AInventory * item = Inventory; + + // Handle powerup effects here so that the order is controlled + // by the order in the inventory, not the order in the thinker table + while (item != NULL && item->Owner == this) + { + item->DoEffect(); + item = item->Inventory; + } + if (flags & MF_UNMORPHED) { return; diff --git a/src/p_things.cpp b/src/p_things.cpp index dacc24f4e4..d08b72f278 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -142,6 +142,9 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog) Spawn (x, y, z + TELEFOGHEIGHT, ALLOW_REPLACE); Spawn (oldx, oldy, oldz + TELEFOGHEIGHT, ALLOW_REPLACE); } + source->PrevX=x; + source->PrevY=y; + source->PrevZ=z; return true; } else diff --git a/src/p_user.cpp b/src/p_user.cpp index 7d6d7b7cc5..e6d2a1f5f0 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -400,6 +400,7 @@ void APlayerPawn::Serialize (FArchive &arc) arc << JumpZ << MaxHealth + << RunHealth << SpawnMask << ForwardMove1 << ForwardMove2 @@ -874,6 +875,32 @@ void APlayerPawn::GiveDefaultInventory () // [GRB] Give inventory specified in DECORATE player->health = GetDefault ()->health; + // HexenArmor must always be the first item in the inventory because + // it provides player class based protection that should not affect + // any other protection item. + fixed_t hx[5]; + for(int i=0;i<5;i++) + { + hx[i] = GetClass()->Meta.GetMetaFixed(APMETA_Hexenarmor0+i); + } + GiveInventoryType (RUNTIME_CLASS(AHexenArmor)); + AHexenArmor *harmor = FindInventory(); + harmor->Slots[4] = hx[0]; + harmor->SlotsIncrement[0] = hx[1]; + harmor->SlotsIncrement[1] = hx[2]; + harmor->SlotsIncrement[2] = hx[3]; + harmor->SlotsIncrement[3] = hx[4]; + + // BasicArmor must come right after that. It should not affect any + // other protection item as well but needs to process the damage + // before the HexenArmor does. + ABasicArmor *barmor = Spawn (0,0,0, NO_REPLACE); + barmor->BecomeItem (); + barmor->SavePercent = 0; + barmor->Amount = 0; + AddInventory (barmor); + + // Now add the items from the DECORATE definition FDropItem *di = GetDropItems(RUNTIME_TYPE(this)); while (di) @@ -913,26 +940,6 @@ void APlayerPawn::GiveDefaultInventory () } di = di->Next; } - - fixed_t hx[5]; - bool ishx=false; - - for(int i=0;i<5;i++) - { - hx[i] = GetClass()->Meta.GetMetaFixed(APMETA_Hexenarmor0+i); - ishx |= !!hx[i]; - } - if (ishx) - { - GiveInventoryType (RUNTIME_CLASS(AHexenArmor)); - AHexenArmor *armor = FindInventory(); - armor->Slots[4] = hx[0]; - armor->SlotsIncrement[0] = hx[1]; - armor->SlotsIncrement[1] = hx[2]; - armor->SlotsIncrement[2] = hx[3]; - armor->SlotsIncrement[3] = hx[4]; - } - } void APlayerPawn::MorphPlayerThink () @@ -1038,6 +1045,13 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor) void APlayerPawn::TweakSpeeds (int &forward, int &side) { + // Strife's player can't run when its healh is below 10 + if (health <= RunHealth) + { + forward = clamp(forward, -0x1900, 0x1900); + side = clamp(side, -0x1800, 0x1800); + } + // [GRB] if ((unsigned int)(forward + 0x31ff) < 0x63ff) { diff --git a/src/thingdef.cpp b/src/thingdef.cpp index 7e95504d3c..bb7228d269 100644 --- a/src/thingdef.cpp +++ b/src/thingdef.cpp @@ -3900,6 +3900,15 @@ static void PlayerMaxHealth (APlayerPawn *defaults, Baggage &bag) defaults->MaxHealth = sc_Number; } +//========================================================================== +// +//========================================================================== +static void PlayerRunHealth (APlayerPawn *defaults, Baggage &bag) +{ + SC_MustGetNumber (); + defaults->RunHealth = sc_Number; +} + //========================================================================== // //========================================================================== @@ -4134,6 +4143,7 @@ static const ActorProps props[] = { "player.jumpz", (apf)PlayerJumpZ, RUNTIME_CLASS(APlayerPawn) }, { "player.maxhealth", (apf)PlayerMaxHealth, RUNTIME_CLASS(APlayerPawn) }, { "player.morphweapon", (apf)PlayerMorphWeapon, RUNTIME_CLASS(APlayerPawn) }, + { "player.runhealth", (apf)PlayerRunHealth, RUNTIME_CLASS(APlayerPawn) }, { "player.scoreicon", (apf)PlayerScoreIcon, RUNTIME_CLASS(APlayerPawn) }, { "player.sidemove", (apf)PlayerSideMove, RUNTIME_CLASS(APlayerPawn) }, { "player.soundclass", (apf)PlayerSoundClass, RUNTIME_CLASS(APlayerPawn) }, diff --git a/wadsrc/decorate/decorate.txt b/wadsrc/decorate/decorate.txt index 25763758de..3524255534 100644 --- a/wadsrc/decorate/decorate.txt +++ b/wadsrc/decorate/decorate.txt @@ -68,6 +68,7 @@ #include "actors/hexen/centaur.txt" #include "actors/hexen/demons.txt" +#include "actors/strife/strifeplayer.txt" #include "actors/strife/beggars.txt" #include "actors/strife/merchants.txt" #include "actors/strife/peasants.txt" diff --git a/wadsrc/decorate/strife/strifeplayer.txt b/wadsrc/decorate/strife/strifeplayer.txt new file mode 100644 index 0000000000..6048e8adee --- /dev/null +++ b/wadsrc/decorate/strife/strifeplayer.txt @@ -0,0 +1,72 @@ +// The player --------------------------------------------------------------- + +ACTOR StrifePlayer : PlayerPawn +{ + Health 100 + Radius 18 + Height 56 + Mass 100 + PainChance 255 + Speed 1 + MaxStepHeight 16 + Player.ColorRange 96, 111 + Player.DisplayName "Rebel" + Player.StartItem "PunchDagger" + + action native A_ItBurnsItBurns(); + action native A_DropFire(); + action native A_CrispyPlayer(); + + States + { + Spawn: + PLAY A -1 + stop + See: + PLAY ABCD 4 + loop + Missile: + PLAY E 12 + goto Spawn + Melee: + PLAY F 6 + goto Missile + Death: + PLAY H 3 + PLAY I 3 A_PlayerScream + PLAY J 3 A_NoBlocking + PLAY KLMNO 4 + PLAY P -1 + Stop + XDeath: + RGIB A 5 A_TossGib + RGIB B 5 A_XScream + RGIB C 5 A_NoBlocking + RGIB DEFG 5 A_TossGib + RGIB H -1 A_TossGib + Burn: + BURN A 3 Bright A_ItBurnsItBurns + BURN B 3 Bright A_DropFire + BURN C 3 Bright A_Wander + BURN D 3 Bright A_NoBlocking + BURN E 5 Bright A_DropFire + BURN FGH 5 Bright A_Wander + BURN I 5 Bright A_DropFire + BURN JKL 5 Bright A_Wander + BURN M 5 Bright A_DropFire + BURN N 5 Bright A_CrispyPlayer + BURN OPQPQ 5 Bright + BURN RSTU 7 Bright + BURN V -1 + Stop + Disintegrate: + DISR A 5 A_PlaySoundEx("misc/disruptordeath", "Voice") + DISR BC 5 + DISR D 5 A_NoBlocking + DISR EF 5 + DISR GHIJ 4 + MEAT D -1 + Stop + } +} + diff --git a/wadsrc/zdoom.lst b/wadsrc/zdoom.lst index 80216bae3c..078ea23ee4 100644 --- a/wadsrc/zdoom.lst +++ b/wadsrc/zdoom.lst @@ -312,6 +312,7 @@ actors/hexen/ettin.txt decorate/hexen/ettin.txt actors/hexen/centaur.txt decorate/hexen/centaur.txt actors/hexen/demons.txt decorate/hexen/demons.txt +actors/strife/strifeplayer.txt decorate/strife/strifeplayer.txt actors/strife/beggars.txt decorate/strife/beggars.txt actors/strife/merchants.txt decorate/strife/merchants.txt actors/strife/peasants.txt decorate/strife/peasants.txt diff --git a/zdoom.vcproj b/zdoom.vcproj index c30c6483db..33df6a8d36 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - @@ -2725,6 +2717,14 @@ GeneratePreprocessedFile="0" /> + + + @@ -2747,7 +2747,7 @@ /> - - - @@ -4814,6 +4804,16 @@ Outputs="$(IntDir)/$(InputName).obj" /> + + + @@ -4838,16 +4838,6 @@ Outputs="$(IntDir)/$(InputName).obj" /> - - - @@ -4858,6 +4848,16 @@ Outputs="$(IntDir)/$(InputName).obj" /> + + + @@ -4882,16 +4882,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -4902,6 +4892,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + @@ -4926,16 +4926,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -4946,6 +4936,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + @@ -4970,16 +4970,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -4990,6 +4980,16 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + @@ -5069,7 +5069,7 @@ /> - - - @@ -5416,6 +5408,14 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + + + + @@ -5642,14 +5650,6 @@ GeneratePreprocessedFile="0" /> - - - @@ -5671,7 +5671,7 @@ /> - - @@ -8642,7 +8638,7 @@ /> - - - @@ -9164,6 +9152,14 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> + + + @@ -9338,7 +9334,7 @@ />