- added Skulltag's custom F1 help screen MAPINFO option.

- Fixed: Resurrecting a player must restore all flags words, not just the first one.
- Fixed: APowerWeaponLevel2::EndEffect must check PendingWeapon for WP_NOCHANGE.
- added Skulltag's high jump rune as a powerup
- Added Skulltag's Drain and Regeneration runes as powerups and used specific player
  sounds for their sound effects instead of using misc/i_pkup.
  (If I ever decide to implement runes it will be in a way that can use the regular
  powerups instead of having to define specific classes for them.)
- Added Skulltag's PowerQuadDamage and PowerQuarterDamage as more customizable
  PowerDamage and PowerProtection. These new powerups allow free customization of
  the damage modification per damage type by inheriting from these classes and
  setting specific values. Such derived damage/protection powerups will be considered
  as separate powers so that for example a QuadDamage and a DoubleDamage item can be
  stacked which would result in 8x damage.
- merged player_t::cheats and player_t::Powers into one variable.


SVN r529 (trunk)
This commit is contained in:
Christoph Oelckers 2007-05-10 22:22:38 +00:00
parent 15e473f729
commit d60a5ee1b9
17 changed files with 444 additions and 59 deletions

View file

@ -1,4 +1,27 @@
May 9, 2007 (Changes by Graf Zahl)
- added Skulltag's custom F1 help screen MAPINFO option.
May 4, 2007 (Changes by Graf Zahl)
- Fixed: Resurrecting a player must restore all flags words, not just the first one.
- Fixed: APowerWeaponLevel2::EndEffect must check PendingWeapon for WP_NOCHANGE.
May 3, 2007 (Changes by Graf Zahl)
- added Skulltag's high jump rune as a powerup
May 2, 2007 (Changes by Graf Zahl)
- Added Skulltag's Drain and Regeneration runes as powerups and used specific player
sounds for their sound effects instead of using misc/i_pkup.
(If I ever decide to implement runes it will be in a way that can use the regular
powerups instead of having to define specific classes for them.)
- Added Skulltag's PowerQuadDamage and PowerQuarterDamage as more customizable
PowerDamage and PowerProtection. These new powerups allow free customization of
the damage modification per damage type by inheriting from these classes and
setting specific values. Such derived damage/protection powerups will be considered
as separate powers so that for example a QuadDamage and a DoubleDamage item can be
stacked which would result in 8x damage.
May 1, 2007 (Changes by Graf Zahl) May 1, 2007 (Changes by Graf Zahl)
- merged player_t::cheats and player_t::Powers into one variable.
- Fixed: player_t::Powers was not saved in a savegame. - Fixed: player_t::Powers was not saved in a savegame.
- Removed all unused PW_* player power flags. - Removed all unused PW_* player power flags.
- Added Skulltag's TimeFreezer powerup. - Added Skulltag's TimeFreezer powerup.

View file

@ -160,19 +160,20 @@ typedef enum
CF_TOTALLYFROZEN = 4096, // [RH] All players can do is press +use CF_TOTALLYFROZEN = 4096, // [RH] All players can do is press +use
CF_PREDICTING = 8192, // [RH] Player movement is being predicted CF_PREDICTING = 8192, // [RH] Player movement is being predicted
CF_WEAPONREADY = 16384, // [RH] Weapon is in the ready state, so bob it when walking CF_WEAPONREADY = 16384, // [RH] Weapon is in the ready state, so bob it when walking
CF_TIMEFREEZE = 32768, // Player has an active time freezer
CF_DRAIN = 65536, // Player owns a drain powerup
CF_SPEED = 0x20000, // Player owns a speed artifact
CF_REGENERATION = 0x40000, // Player owns a regeneration artifact
CF_HIGHJUMP = 0x80000, // more Skulltag flags. Implemetation not guaranteed though. ;)
CF_REFLECTION = 0x100000,
CF_PROSPERITY = 0x200000,
CF_DOUBLEFIRINGSPEED= 0x400000,
} cheat_t; } cheat_t;
#define WPIECE1 1 #define WPIECE1 1
#define WPIECE2 2 #define WPIECE2 2
#define WPIECE3 4 #define WPIECE3 4
enum
{
PW_SPEED = 1,
PW_TIMEFREEZE = 2,
//
};
#define WP_NOCHANGE ((AWeapon*)~0) #define WP_NOCHANGE ((AWeapon*)~0)
// //
@ -232,7 +233,6 @@ public:
AWeapon *PendingWeapon; // WP_NOCHANGE if not changing AWeapon *PendingWeapon; // WP_NOCHANGE if not changing
int cheats; // bit flags int cheats; // bit flags
BITFIELD Powers; // powers
short refire; // refired shots are less accurate short refire; // refired shots are less accurate
short inconsistant; short inconsistant;
int killcount, itemcount, secretcount; // for intermission int killcount, itemcount, secretcount; // for intermission

View file

@ -155,7 +155,8 @@ static level_info_t TheDefaultLevelInfo =
unnamed, // level_name unnamed, // level_name
"COLORMAP", // fadetable "COLORMAP", // fadetable
+8, // WallVertLight +8, // WallVertLight
-8 // WallHorizLight -8, // WallHorizLight
"", // [RC] F1
}; };
static cluster_info_t TheDefaultClusterInfo = { 0 }; static cluster_info_t TheDefaultClusterInfo = { 0 };
@ -281,7 +282,7 @@ static const char *MapInfoMapLevel[] =
"compat_dropoff", "compat_dropoff",
"compat_boomscroll", "compat_boomscroll",
"bordertexture", "bordertexture",
"f1", // [RC] F1 help
NULL NULL
}; };
@ -307,6 +308,7 @@ enum EMIType
MITYPE_REDIRECT, MITYPE_REDIRECT,
MITYPE_SPECIALACTION, MITYPE_SPECIALACTION,
MITYPE_COMPATFLAG, MITYPE_COMPATFLAG,
MITYPE_F1, // [RC] F1 help
}; };
struct MapInfoHandler struct MapInfoHandler
@ -414,6 +416,7 @@ MapHandlers[] =
{ MITYPE_COMPATFLAG, COMPATF_DROPOFF}, { MITYPE_COMPATFLAG, COMPATF_DROPOFF},
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL}, { MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_LUMPNAME, lioffset(bordertexture), 0 }, { MITYPE_LUMPNAME, lioffset(bordertexture), 0 },
{ MITYPE_F1, lioffset(f1), 0, },
}; };
static const char *MapInfoClusterLevel[] = static const char *MapInfoClusterLevel[] =
@ -656,6 +659,10 @@ static void G_DoParseMapInfo (int lump)
{ {
strcpy (levelinfo->skypic2, levelinfo->skypic1); strcpy (levelinfo->skypic2, levelinfo->skypic1);
} }
if (levelinfo->f1 != NULL)
{
levelinfo->f1 = copystring (levelinfo->f1);
}
SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps. SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
if (levelinfo->pname[0] != 0) if (levelinfo->pname[0] != 0)
{ {
@ -992,6 +999,18 @@ static void ParseMapInfoLower (MapInfoHandler *handlers,
ReplaceString ((char **)(info + handler->data1), sc_String); ReplaceString ((char **)(info + handler->data1), sc_String);
break; break;
case MITYPE_F1:
SC_MustGetString ();
{
char *colon = strchr (sc_String, ':');
if (colon)
{
*colon = 0;
}
ReplaceString ((char **)(info + handler->data1), sc_String);
}
break;
case MITYPE_MUSIC: case MITYPE_MUSIC:
SC_MustGetString (); SC_MustGetString ();
{ {
@ -2256,6 +2275,7 @@ void G_InitLevelLocals ()
level.levelnum = info->levelnum; level.levelnum = info->levelnum;
level.music = info->music; level.music = info->music;
level.musicorder = info->musicorder; level.musicorder = info->musicorder;
level.f1 = info->f1; // [RC] And import the f1 name
strncpy (level.level_name, info->level_name, 63); strncpy (level.level_name, info->level_name, 63);
G_MaybeLookupLevelName (NULL); G_MaybeLookupLevelName (NULL);

View file

@ -134,6 +134,7 @@ struct level_info_s
char *level_name; char *level_name;
char fadetable[9]; char fadetable[9];
SBYTE WallVertLight, WallHorizLight; SBYTE WallVertLight, WallHorizLight;
char *f1;
// TheDefaultLevelInfo initializes everything above this line. // TheDefaultLevelInfo initializes everything above this line.
int musicorder; int musicorder;
FCompressedMemFile *snapshot; FCompressedMemFile *snapshot;
@ -231,6 +232,8 @@ struct level_locals_s
SBYTE WallVertLight; // Light diffs for vert/horiz walls SBYTE WallVertLight; // Light diffs for vert/horiz walls
SBYTE WallHorizLight; SBYTE WallHorizLight;
char *f1;
}; };
typedef struct level_locals_s level_locals_t; typedef struct level_locals_s level_locals_t;

View file

@ -159,6 +159,7 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
Owner->UseInventory (best); Owner->UseInventory (best);
} }
} }
damage = newdamage;
} }
if (Inventory != NULL) if (Inventory != NULL)
{ {
@ -477,6 +478,7 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
saved = savedPercent >> (FRACBITS-1); saved = savedPercent >> (FRACBITS-1);
} }
newdamage -= saved; newdamage -= saved;
damage = newdamage;
} }
} }
if (Inventory != NULL) if (Inventory != NULL)

View file

@ -1117,7 +1117,7 @@ void APowerWeaponLevel2::EndEffect ()
{ {
player->ReadyWeapon->EndPowerup (); player->ReadyWeapon->EndPowerup ();
} }
if (player->PendingWeapon != NULL && if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE &&
player->PendingWeapon->WeaponFlags & WIF_POWERED_UP && player->PendingWeapon->WeaponFlags & WIF_POWERED_UP &&
player->PendingWeapon->SisterWeapon != NULL) player->PendingWeapon->SisterWeapon != NULL)
{ {
@ -1175,7 +1175,7 @@ END_DEFAULTS
void APowerSpeed::InitEffect () void APowerSpeed::InitEffect ()
{ {
Owner->player->Powers |= PW_SPEED; Owner->player->cheats |= CF_SPEED;
} }
//=========================================================================== //===========================================================================
@ -1229,7 +1229,7 @@ void APowerSpeed::EndEffect ()
{ {
if (Owner != NULL && Owner->player != NULL) if (Owner != NULL && Owner->player != NULL)
{ {
Owner->player->Powers &= ~PW_SPEED; Owner->player->cheats &= ~CF_SPEED;
} }
} }
@ -1382,7 +1382,7 @@ void APowerTimeFreezer::InitEffect( )
S_PauseSound( false ); S_PauseSound( false );
// Give the player and his teammates the power to move when time is frozen. // Give the player and his teammates the power to move when time is frozen.
Owner->player->Powers |= PW_TIMEFREEZE; Owner->player->cheats |= CF_TIMEFREEZE;
for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ )
{ {
if ( playeringame[ulIdx] && if ( playeringame[ulIdx] &&
@ -1390,7 +1390,7 @@ void APowerTimeFreezer::InitEffect( )
players[ulIdx].mo->IsTeammate( Owner ) players[ulIdx].mo->IsTeammate( Owner )
) )
{ {
players[ulIdx].Powers |= PW_TIMEFREEZE; players[ulIdx].cheats |= CF_TIMEFREEZE;
} }
} }
@ -1439,7 +1439,7 @@ void APowerTimeFreezer::EndEffect( )
} }
// Take away the time freeze power, and his teammates. // Take away the time freeze power, and his teammates.
Owner->player->Powers &= ~PW_TIMEFREEZE; Owner->player->cheats &= ~CF_TIMEFREEZE;
for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ )
{ {
if ( playeringame[ulIdx] && if ( playeringame[ulIdx] &&
@ -1447,8 +1447,221 @@ void APowerTimeFreezer::EndEffect( )
players[ulIdx].mo->IsTeammate( Owner ) players[ulIdx].mo->IsTeammate( Owner )
) )
{ {
players[ulIdx].Powers &= ~PW_TIMEFREEZE; players[ulIdx].cheats &= ~CF_TIMEFREEZE;
} }
} }
} }
// Damage powerup ------------------------------------------------------
IMPLEMENT_STATELESS_ACTOR( APowerDamage, Any, -1, 0 )
PROP_Powerup_EffectTics( 25*TICRATE )
END_DEFAULTS
//===========================================================================
//
// APowerDamage :: InitEffect
//
//===========================================================================
void APowerDamage::InitEffect( )
{
// Use sound channel 5 to avoid interference with other actions.
if (Owner != NULL) S_SoundID(Owner, 5, SeeSound, 1.0f, ATTN_SURROUND);
}
//===========================================================================
//
// APowerDamage :: EndEffect
//
//===========================================================================
void APowerDamage::EndEffect( )
{
// Use sound channel 5 to avoid interference with other actions.
if (Owner != NULL) S_SoundID(Owner, 5, DeathSound, 1.0f, ATTN_SURROUND);
}
//===========================================================================
//
// APowerDamage :: AbsorbDamage
//
//===========================================================================
void APowerDamage::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive)
{
static const fixed_t def = 4*FRACUNIT;
if (!passive && damage > 0)
{
DmgFactors * df = GetClass()->ActorInfo->DamageFactors;
if (df != NULL)
{
const fixed_t * pdf = df->CheckKey(damageType);
if (pdf== NULL && damageType != NAME_None) pdf = df->CheckKey(NAME_None);
if (pdf == NULL) pdf = &def;
damage = newdamage = FixedMul(damage, *pdf);
if (*pdf > 0 && damage == 0) damage = newdamage = 1; // don't allow zero damage as result of an underflow
if (Owner != NULL && *pdf > FRACUNIT) S_SoundID(Owner, 5, ActiveSound, 1.0f, ATTN_SURROUND);
}
}
if (Inventory != NULL) Inventory->ModifyDamage(damage, damageType, newdamage, passive);
}
// Quarter damage powerup ------------------------------------------------------
IMPLEMENT_STATELESS_ACTOR( APowerProtection, Any, -1, 0 )
PROP_Powerup_EffectTics( 25*TICRATE )
END_DEFAULTS
//===========================================================================
//
// APowerProtection :: InitEffect
//
//===========================================================================
void APowerProtection::InitEffect( )
{
// Use sound channel 5 to avoid interference with other actions.
if (Owner != NULL) S_SoundID(Owner, 5, SeeSound, 1.0f, ATTN_SURROUND);
}
//===========================================================================
//
// APowerProtection :: EndEffect
//
//===========================================================================
void APowerProtection::EndEffect( )
{
// Use sound channel 5 to avoid interference with other actions.
if (Owner != NULL) S_SoundID(Owner, 5, DeathSound, 1.0f, ATTN_SURROUND);
}
//===========================================================================
//
// APowerProtection :: AbsorbDamage
//
//===========================================================================
void APowerProtection::ModifyDamage(int damage, FName damageType, int &newdamage, bool passive)
{
static const fixed_t def = FRACUNIT/4;
if (passive && damage > 0)
{
DmgFactors * df = GetClass()->ActorInfo->DamageFactors;
if (df != NULL)
{
const fixed_t * pdf = df->CheckKey(damageType);
if (pdf== NULL && damageType != NAME_None) pdf = df->CheckKey(NAME_None);
if (pdf == NULL) pdf = &def;
damage = newdamage = FixedMul(damage, *pdf);
if (Owner != NULL && *pdf < FRACUNIT) S_SoundID(Owner, 5, ActiveSound, 1.0f, ATTN_SURROUND);
}
}
if (Inventory != NULL) Inventory->ModifyDamage(damage, damageType, newdamage, passive);
}
// Drain rune -------------------------------------------------------
IMPLEMENT_STATELESS_ACTOR( APowerDrain, Any, -1, 0 )
PROP_Powerup_EffectTics( 60*TICRATE )
END_DEFAULTS
//===========================================================================
//
// ARuneDrain :: InitEffect
//
//===========================================================================
void APowerDrain::InitEffect( )
{
// Give the player the power to drain life from opponents when he damages them.
Owner->player->cheats |= CF_DRAIN;
}
//===========================================================================
//
// ARuneDrain :: EndEffect
//
//===========================================================================
void APowerDrain::EndEffect( )
{
// Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL)
{
// Take away the drain power.
Owner->player->cheats &= ~CF_DRAIN;
}
}
// Regeneration rune -------------------------------------------------------
IMPLEMENT_STATELESS_ACTOR( APowerRegeneration, Any, -1, 0 )
PROP_Powerup_EffectTics( 120*TICRATE )
END_DEFAULTS
//===========================================================================
//
// ARuneRegeneration :: InitEffect
//
//===========================================================================
void APowerRegeneration::InitEffect( )
{
// Give the player the power to regnerate lost life.
Owner->player->cheats |= CF_REGENERATION;
}
//===========================================================================
//
// ARuneRegeneration :: EndEffect
//
//===========================================================================
void APowerRegeneration::EndEffect( )
{
// Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL)
{
// Take away the regeneration power.
Owner->player->cheats &= ~CF_REGENERATION;
}
}
// High jump rune -------------------------------------------------------
IMPLEMENT_STATELESS_ACTOR( APowerHighJump, Any, -1, 0 )
END_DEFAULTS
//===========================================================================
//
// ARuneHighJump :: InitEffect
//
//===========================================================================
void APowerHighJump::InitEffect( )
{
// Give the player the power to jump much higher.
Owner->player->cheats |= CF_HIGHJUMP;
}
//===========================================================================
//
// ARuneHighJump :: EndEffect
//
//===========================================================================
void APowerHighJump::EndEffect( )
{
// Nothing to do if there's no owner.
if (Owner != NULL && Owner->player != NULL)
{
// Take away the high jump power.
Owner->player->cheats &= ~CF_HIGHJUMP;
}
}

View file

@ -213,6 +213,49 @@ protected:
void EndEffect( ); void EndEffect( );
}; };
class APowerDamage : public APowerup
{
DECLARE_STATELESS_ACTOR( APowerDamage, APowerup )
protected:
void InitEffect ();
void EndEffect ();
virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive);
};
class APowerProtection : public APowerup
{
DECLARE_STATELESS_ACTOR( APowerProtection, APowerup )
protected:
void InitEffect ();
void EndEffect ();
virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive);
};
class APowerDrain : public APowerup
{
DECLARE_STATELESS_ACTOR( APowerDrain, APowerup )
protected:
void InitEffect( );
void EndEffect( );
};
class APowerRegeneration : public APowerup
{
DECLARE_STATELESS_ACTOR( APowerRegeneration, APowerup )
protected:
void InitEffect( );
void EndEffect( );
};
class APowerHighJump : public APowerup
{
DECLARE_STATELESS_ACTOR( APowerHighJump, APowerup )
protected:
void InitEffect( );
void EndEffect( );
};
class player_s; class player_s;

View file

@ -760,6 +760,29 @@ void AInventory::AbsorbDamage (int damage, FName damageType, int &newdamage)
} }
} }
//===========================================================================
//
// AInventory :: ModifyDamage
//
// Allows inventory items to manipulate the amount of damage
// inflicted. Damage is the amount of damage that would be done without manipulation,
// and newdamage is the amount that should be done after the item has changed
// it.
// 'active' means it is called by the inflictor, 'passive' by the target.
// It may seem that this is redundant and AbsorbDamage is the same. However,
// AbsorbDamage is called only for players and also depends on other settings
// which are undesirable for a protection artifact.
//
//===========================================================================
void AInventory::ModifyDamage (int damage, FName damageType, int &newdamage, bool passive)
{
if (Inventory != NULL)
{
Inventory->ModifyDamage (damage, damageType, newdamage, passive);
}
}
//=========================================================================== //===========================================================================
// //
// AInventory :: AlterWeaponSprite // AInventory :: AlterWeaponSprite

View file

@ -152,6 +152,7 @@ public:
virtual void OwnerDied (); virtual void OwnerDied ();
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage); virtual void AbsorbDamage (int damage, FName damageType, int &newdamage);
virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive);
virtual int AlterWeaponSprite (vissprite_t *vis); virtual int AlterWeaponSprite (vissprite_t *vis);
virtual PalEntry GetBlend (); virtual PalEntry GetBlend ();

View file

@ -271,6 +271,10 @@ void cht_DoCheat (player_t *player, int cheat)
player->health = player->mo->health = player->mo->GetDefault()->health; player->health = player->mo->health = player->mo->GetDefault()->health;
player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight; player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight;
player->mo->flags = player->mo->GetDefault()->flags; player->mo->flags = player->mo->GetDefault()->flags;
player->mo->flags2 = player->mo->GetDefault()->flags2;
player->mo->flags3 = player->mo->GetDefault()->flags3;
player->mo->flags4 = player->mo->GetDefault()->flags4;
player->mo->flags5 = player->mo->GetDefault()->flags5;
player->mo->height = player->mo->GetDefault()->height; player->mo->height = player->mo->GetDefault()->height;
player->mo->SetState (player->mo->SpawnState); player->mo->SetState (player->mo->SpawnState);
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));

View file

@ -1427,6 +1427,13 @@ void M_DrawReadThis ()
else else
{ {
tex = TexMan[gameinfo.info.infoPage[InfoType-1]]; tex = TexMan[gameinfo.info.infoPage[InfoType-1]];
// Did the mapper choose a custom help page via MAPINFO?
if((level.f1 != NULL) && (strcmp(level.f1, "") != 0)) {
if(TexMan.CheckForTexture(level.f1,0,0) == -1)
TexMan.AddPatch(level.f1); // Needs to be marked as a patch.
tex = TexMan[level.f1];
}
if (InfoType > 1) if (InfoType > 1)
{ {
prevpic = TexMan[gameinfo.info.infoPage[InfoType-2]]; prevpic = TexMan[gameinfo.info.infoPage[InfoType-2]];

View file

@ -56,6 +56,7 @@
#include "gi.h" #include "gi.h"
#include "templates.h" #include "templates.h"
#include "sbar.h" #include "sbar.h"
#include "s_sound.h"
static FRandom pr_obituary ("Obituary"); static FRandom pr_obituary ("Obituary");
static FRandom pr_botrespawn ("BotRespawn"); static FRandom pr_botrespawn ("BotRespawn");
@ -886,6 +887,28 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
} }
} }
damage = inflictor->DoSpecialDamage (target, damage);
if (damage == -1)
{
return;
}
// Handle active damage modifiers (e.g. PowerDamage)
if (inflictor->Inventory != NULL)
{
int olddam = damage;
inflictor->Inventory->ModifyDamage(olddam, mod, damage, false);
if (olddam != damage && damage <= 0) return;
}
}
// Handle passive damage modifiers (e.g. PowerProtection)
if (target->Inventory != NULL)
{
int olddam = damage;
target->Inventory->ModifyDamage(olddam, mod, damage, true);
if (olddam != damage && damage <= 0) return;
}
// to be removed and replaced by an actual damage factor // to be removed and replaced by an actual damage factor
// once the actors using it are converted to DECORATE. // once the actors using it are converted to DECORATE.
if (mod == NAME_Fire && target->flags4 & MF4_FIRERESIST) if (mod == NAME_Fire && target->flags4 & MF4_FIRERESIST)
@ -905,13 +928,9 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
} }
} }
} }
damage = inflictor->DoSpecialDamage (target, damage);
if (damage == -1)
{
return;
}
}
damage = target->TakeSpecialDamage (inflictor, source, damage, mod); damage = target->TakeSpecialDamage (inflictor, source, damage, mod);
if (damage == -1) if (damage == -1)
{ {
return; return;
@ -1061,6 +1080,21 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
// //
// the damage has been dealt; now deal with the consequences // the damage has been dealt; now deal with the consequences
// //
// If the damaging player has the power of drain, give the player 50% of the damage
// done in health.
if ( source && source->player && source->player->cheats & CF_DRAIN)
{
if (!target->player || target->player != source->player)
{
if ( P_GiveBody( source, damage / 2 ))
{
S_Sound( source, CHAN_ITEM, "*drainhealth", 1, ATTN_NORM );
}
}
}
if (target->health <= 0) if (target->health <= 0)
{ // Death { // Death
target->special1 = damage; target->special1 = damage;

View file

@ -2535,7 +2535,7 @@ void AActor::Tick ()
} }
// Apply freeze mode. // Apply freeze mode.
if (( level.flags & LEVEL_FROZEN ) && ( player == NULL || !( player->Powers & PW_TIMEFREEZE ))) if (( level.flags & LEVEL_FROZEN ) && ( player == NULL || !( player->cheats & CF_TIMEFREEZE )))
{ {
return; return;
} }

View file

@ -306,7 +306,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
if (thing->player && (useFog || !keepOrientation)) if (thing->player && (useFog || !keepOrientation))
{ {
// Freeze player for about .5 sec // Freeze player for about .5 sec
if (!(thing->player->Powers & PW_SPEED)) if (!(thing->player->cheats & CF_SPEED))
thing->reactiontime = 18; thing->reactiontime = 18;
} }
if (thing->flags & MF_MISSILE) if (thing->flags & MF_MISSILE)

View file

@ -80,7 +80,7 @@ void P_Ticker (void)
// off the music. // off the music.
for (i = 0; i < MAXPLAYERS; i++ ) for (i = 0; i < MAXPLAYERS; i++ )
{ {
if (playeringame[i] && players[i].Powers & PW_TIMEFREEZE) if (playeringame[i] && players[i].cheats & CF_TIMEFREEZE)
break; break;
} }

View file

@ -229,7 +229,6 @@ player_s::player_s()
ReadyWeapon(0), ReadyWeapon(0),
PendingWeapon(0), PendingWeapon(0),
cheats(0), cheats(0),
Powers(0),
refire(0), refire(0),
inconsistant(0), inconsistant(0),
killcount(0), killcount(0),
@ -1121,7 +1120,7 @@ void APlayerPawn::TweakSpeeds (int &forward, int &side)
side = FixedMul (side, SideMove2); side = FixedMul (side, SideMove2);
} }
if ((player->Powers & PW_SPEED) && !player->morphTics) if ((player->cheats & CF_SPEED) && !player->morphTics)
{ // Adjust for a player with a speed artifact { // Adjust for a player with a speed artifact
forward = (3*forward)>>1; forward = (3*forward)>>1;
side = (3*side)>>1; side = (3*side)>>1;
@ -2062,7 +2061,12 @@ void P_PlayerThink (player_t *player)
} }
else if (!(dmflags & DF_NO_JUMP) && onground && !player->jumpTics) else if (!(dmflags & DF_NO_JUMP) && onground && !player->jumpTics)
{ {
player->mo->momz += player->mo->JumpZ * 35 / TICRATE; fixed_t jumpmomz = player->mo->JumpZ * 35 / TICRATE;
// [BC] If the player has the high jump power, double his jump velocity.
if ( player->cheats & CF_HIGHJUMP ) jumpmomz *= 2;
player->mo->momz += jumpmomz;
S_Sound (player->mo, CHAN_BODY, "*jump", 1, ATTN_NORM); S_Sound (player->mo, CHAN_BODY, "*jump", 1, ATTN_NORM);
player->mo->flags2 &= ~MF2_ONMOBJ; player->mo->flags2 &= ~MF2_ONMOBJ;
player->jumpTics = 18*TICRATE/35; player->jumpTics = 18*TICRATE/35;
@ -2172,6 +2176,15 @@ void P_PlayerThink (player_t *player)
P_PoisonDamage (player, player->poisoner, 1, true); P_PoisonDamage (player, player->poisoner, 1, true);
} }
// [BC] Apply regeneration.
if (( level.time & 31 ) == 0 && ( player->cheats & CF_REGENERATION ) && ( player->health ))
{
if ( P_GiveBody( player->mo, 5 ))
{
S_Sound(player->mo, CHAN_ITEM, "*regenerate", 1, ATTN_NORM );
}
}
// Handle air supply // Handle air supply
if (level.airsupply > 0) if (level.airsupply > 0)
{ {
@ -2359,8 +2372,7 @@ void player_s::Serialize (FArchive &arc)
<< BlendB << BlendB
<< BlendA << BlendA
<< accuracy << stamina << accuracy << stamina
<< LogText << LogText;
<< Powers;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
arc << frags[i]; arc << frags[i];

View file

@ -1073,7 +1073,7 @@ void R_SetupFrame (AActor *actor)
iview->oviewangle = iview->nviewangle; iview->oviewangle = iview->nviewangle;
} }
if (player != NULL && if (player != NULL && gamestate != GS_TITLELEVEL &&
((player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) && ((player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) &&
(camera->RenderStyle != STYLE_None) && (camera->RenderStyle != STYLE_None) &&
!(camera->renderflags & RF_INVISIBLE) && !(camera->renderflags & RF_INVISIBLE) &&