- 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.


SVN r448 (trunk)
This commit is contained in:
Christoph Oelckers 2007-01-12 15:24:10 +00:00
parent 1cd8370327
commit 3c976ac02c
19 changed files with 943 additions and 904 deletions

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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<fixed_t>(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;

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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<AWeapon *>(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);
}

View file

@ -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 ();
}

View file

@ -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;

View file

@ -142,6 +142,9 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog)
Spawn<ATeleportFog> (x, y, z + TELEFOGHEIGHT, ALLOW_REPLACE);
Spawn<ATeleportFog> (oldx, oldy, oldz + TELEFOGHEIGHT, ALLOW_REPLACE);
}
source->PrevX=x;
source->PrevY=y;
source->PrevZ=z;
return true;
}
else

View file

@ -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<AHexenArmor>();
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<ABasicArmor> (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<AHexenArmor>();
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)
{

View file

@ -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) },

View file

@ -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"

View file

@ -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
}
}

View file

@ -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

File diff suppressed because it is too large Load diff