From d60a5ee1b9d8a35417cbe687258c0a974d251e81 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 10 May 2007 22:22:38 +0000 Subject: [PATCH] - 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) --- docs/rh-log.txt | 23 ++++ src/d_player.h | 44 +++---- src/g_level.cpp | 24 +++- src/g_level.h | 3 + src/g_shared/a_armor.cpp | 2 + src/g_shared/a_artifacts.cpp | 227 +++++++++++++++++++++++++++++++++-- src/g_shared/a_artifacts.h | 43 +++++++ src/g_shared/a_pickups.cpp | 23 ++++ src/g_shared/a_pickups.h | 1 + src/m_cheat.cpp | 4 + src/m_menu.cpp | 7 ++ src/p_interaction.cpp | 72 ++++++++--- src/p_mobj.cpp | 2 +- src/p_teleport.cpp | 2 +- src/p_tick.cpp | 2 +- src/p_user.cpp | 22 +++- src/r_main.cpp | 2 +- 17 files changed, 444 insertions(+), 59 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index a5f979076..14b4faaeb 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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) +- merged player_t::cheats and player_t::Powers into one variable. - Fixed: player_t::Powers was not saved in a savegame. - Removed all unused PW_* player power flags. - Added Skulltag's TimeFreezer powerup. diff --git a/src/d_player.h b/src/d_player.h index 3f57f3dc6..df59b5569 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -146,33 +146,34 @@ typedef enum // typedef enum { - CF_NOCLIP = 1, // No clipping, walk through barriers. - CF_GODMODE = 2, // No damage, no health loss. - CF_NOMOMENTUM = 4, // Not really a cheat, just a debug aid. - CF_NOTARGET = 8, // [RH] Monsters don't target - CF_FLY = 16, // [RH] Flying player - CF_CHASECAM = 32, // [RH] Put camera behind player - CF_FROZEN = 64, // [RH] Don't let the player move - CF_REVERTPLEASE = 128, // [RH] Stick camera in player's head if (s)he moves - CF_STEPLEFT = 512, // [RH] Play left footstep sound next time - CF_FRIGHTENING = 1024, // [RH] Scare monsters away - CF_INSTANTWEAPSWITCH= 2048, // [RH] Switch weapons instantly - CF_TOTALLYFROZEN = 4096, // [RH] All players can do is press +use - 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_NOCLIP = 1, // No clipping, walk through barriers. + CF_GODMODE = 2, // No damage, no health loss. + CF_NOMOMENTUM = 4, // Not really a cheat, just a debug aid. + CF_NOTARGET = 8, // [RH] Monsters don't target + CF_FLY = 16, // [RH] Flying player + CF_CHASECAM = 32, // [RH] Put camera behind player + CF_FROZEN = 64, // [RH] Don't let the player move + CF_REVERTPLEASE = 128, // [RH] Stick camera in player's head if (s)he moves + CF_STEPLEFT = 512, // [RH] Play left footstep sound next time + CF_FRIGHTENING = 1024, // [RH] Scare monsters away + CF_INSTANTWEAPSWITCH= 2048, // [RH] Switch weapons instantly + CF_TOTALLYFROZEN = 4096, // [RH] All players can do is press +use + 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_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; #define WPIECE1 1 #define WPIECE2 2 #define WPIECE3 4 -enum -{ - PW_SPEED = 1, - PW_TIMEFREEZE = 2, -// -}; - #define WP_NOCHANGE ((AWeapon*)~0) // @@ -232,7 +233,6 @@ public: AWeapon *PendingWeapon; // WP_NOCHANGE if not changing int cheats; // bit flags - BITFIELD Powers; // powers short refire; // refired shots are less accurate short inconsistant; int killcount, itemcount, secretcount; // for intermission diff --git a/src/g_level.cpp b/src/g_level.cpp index 88914ab7c..0cea81b59 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -155,7 +155,8 @@ static level_info_t TheDefaultLevelInfo = unnamed, // level_name "COLORMAP", // fadetable +8, // WallVertLight - -8 // WallHorizLight + -8, // WallHorizLight + "", // [RC] F1 }; static cluster_info_t TheDefaultClusterInfo = { 0 }; @@ -281,7 +282,7 @@ static const char *MapInfoMapLevel[] = "compat_dropoff", "compat_boomscroll", "bordertexture", - + "f1", // [RC] F1 help NULL }; @@ -307,6 +308,7 @@ enum EMIType MITYPE_REDIRECT, MITYPE_SPECIALACTION, MITYPE_COMPATFLAG, + MITYPE_F1, // [RC] F1 help }; struct MapInfoHandler @@ -414,6 +416,7 @@ MapHandlers[] = { MITYPE_COMPATFLAG, COMPATF_DROPOFF}, { MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL}, { MITYPE_LUMPNAME, lioffset(bordertexture), 0 }, + { MITYPE_F1, lioffset(f1), 0, }, }; static const char *MapInfoClusterLevel[] = @@ -656,6 +659,10 @@ static void G_DoParseMapInfo (int lump) { 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. if (levelinfo->pname[0] != 0) { @@ -992,6 +999,18 @@ static void ParseMapInfoLower (MapInfoHandler *handlers, ReplaceString ((char **)(info + handler->data1), sc_String); 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: SC_MustGetString (); { @@ -2256,6 +2275,7 @@ void G_InitLevelLocals () level.levelnum = info->levelnum; level.music = info->music; level.musicorder = info->musicorder; + level.f1 = info->f1; // [RC] And import the f1 name strncpy (level.level_name, info->level_name, 63); G_MaybeLookupLevelName (NULL); diff --git a/src/g_level.h b/src/g_level.h index 992e36fdd..205303206 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -134,6 +134,7 @@ struct level_info_s char *level_name; char fadetable[9]; SBYTE WallVertLight, WallHorizLight; + char *f1; // TheDefaultLevelInfo initializes everything above this line. int musicorder; FCompressedMemFile *snapshot; @@ -231,6 +232,8 @@ struct level_locals_s SBYTE WallVertLight; // Light diffs for vert/horiz walls SBYTE WallHorizLight; + + char *f1; }; typedef struct level_locals_s level_locals_t; diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index fedfcba1b..fdd2efeb8 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -159,6 +159,7 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) Owner->UseInventory (best); } } + damage = newdamage; } if (Inventory != NULL) { @@ -477,6 +478,7 @@ void AHexenArmor::AbsorbDamage (int damage, FName damageType, int &newdamage) saved = savedPercent >> (FRACBITS-1); } newdamage -= saved; + damage = newdamage; } } if (Inventory != NULL) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index da5baccb4..edd72c8f5 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1117,7 +1117,7 @@ void APowerWeaponLevel2::EndEffect () { player->ReadyWeapon->EndPowerup (); } - if (player->PendingWeapon != NULL && + if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE && player->PendingWeapon->WeaponFlags & WIF_POWERED_UP && player->PendingWeapon->SisterWeapon != NULL) { @@ -1175,7 +1175,7 @@ END_DEFAULTS 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) { - Owner->player->Powers &= ~PW_SPEED; + Owner->player->cheats &= ~CF_SPEED; } } @@ -1382,7 +1382,7 @@ void APowerTimeFreezer::InitEffect( ) S_PauseSound( false ); // 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++ ) { if ( playeringame[ulIdx] && @@ -1390,7 +1390,7 @@ void APowerTimeFreezer::InitEffect( ) 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. - Owner->player->Powers &= ~PW_TIMEFREEZE; + Owner->player->cheats &= ~CF_TIMEFREEZE; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if ( playeringame[ulIdx] && @@ -1447,8 +1447,221 @@ void APowerTimeFreezer::EndEffect( ) 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; + } +} + diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 25c2f6cde..027a4ce2c 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -213,6 +213,49 @@ protected: 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; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index ec0d91bdc..dec3fa83c 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -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 diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 3d7582f63..69a561451 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -152,6 +152,7 @@ public: virtual void OwnerDied (); 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 PalEntry GetBlend (); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 2c771414b..ae46a7d4d 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -271,6 +271,10 @@ void cht_DoCheat (player_t *player, int cheat) player->health = player->mo->health = player->mo->GetDefault()->health; player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight; 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->SetState (player->mo->SpawnState); player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); diff --git a/src/m_menu.cpp b/src/m_menu.cpp index c9994b05f..258fffc7a 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -1427,6 +1427,13 @@ void M_DrawReadThis () else { 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) { prevpic = TexMan[gameinfo.info.infoPage[InfoType-2]]; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 801885848..b73836bf4 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -56,6 +56,7 @@ #include "gi.h" #include "templates.h" #include "sbar.h" +#include "s_sound.h" static FRandom pr_obituary ("Obituary"); static FRandom pr_botrespawn ("BotRespawn"); @@ -886,32 +887,50 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage } } - // to be removed and replaced by an actual damage factor - // once the actors using it are converted to DECORATE. - if (mod == NAME_Fire && target->flags4 & MF4_FIRERESIST) - { - damage /= 2; - } - else - { - DmgFactors * df = target->GetClass()->ActorInfo->DamageFactors; - if (df != NULL) - { - fixed_t * pdf = df->CheckKey(mod); - if (pdf != NULL) - { - damage = FixedMul(damage, *pdf); - if (damage <= 0) return; - } - } - } 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 + // once the actors using it are converted to DECORATE. + if (mod == NAME_Fire && target->flags4 & MF4_FIRERESIST) + { + damage /= 2; + } + else + { + DmgFactors * df = target->GetClass()->ActorInfo->DamageFactors; + if (df != NULL) + { + fixed_t * pdf = df->CheckKey(mod); + if (pdf != NULL) + { + damage = FixedMul(damage, *pdf); + if (damage <= 0) return; + } + } + } + damage = target->TakeSpecialDamage (inflictor, source, damage, mod); + if (damage == -1) { 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 // + + // 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) { // Death target->special1 = damage; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 961cc066b..1de60f892 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2535,7 +2535,7 @@ void AActor::Tick () } // 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; } diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 1995e58fa..95e8ba868 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -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)) { // Freeze player for about .5 sec - if (!(thing->player->Powers & PW_SPEED)) + if (!(thing->player->cheats & CF_SPEED)) thing->reactiontime = 18; } if (thing->flags & MF_MISSILE) diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 8e6ecb343..5e4b0a74a 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -80,7 +80,7 @@ void P_Ticker (void) // off the music. for (i = 0; i < MAXPLAYERS; i++ ) { - if (playeringame[i] && players[i].Powers & PW_TIMEFREEZE) + if (playeringame[i] && players[i].cheats & CF_TIMEFREEZE) break; } diff --git a/src/p_user.cpp b/src/p_user.cpp index ceb143c28..6b5955cc7 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -229,7 +229,6 @@ player_s::player_s() ReadyWeapon(0), PendingWeapon(0), cheats(0), - Powers(0), refire(0), inconsistant(0), killcount(0), @@ -1121,7 +1120,7 @@ void APlayerPawn::TweakSpeeds (int &forward, int &side) 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 forward = (3*forward)>>1; side = (3*side)>>1; @@ -2062,7 +2061,12 @@ void P_PlayerThink (player_t *player) } 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); player->mo->flags2 &= ~MF2_ONMOBJ; player->jumpTics = 18*TICRATE/35; @@ -2172,6 +2176,15 @@ void P_PlayerThink (player_t *player) 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 if (level.airsupply > 0) { @@ -2359,8 +2372,7 @@ void player_s::Serialize (FArchive &arc) << BlendB << BlendA << accuracy << stamina - << LogText - << Powers; + << LogText; for (i = 0; i < MAXPLAYERS; i++) arc << frags[i]; diff --git a/src/r_main.cpp b/src/r_main.cpp index 9aad0b3dc..ce1d0a5fe 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1073,7 +1073,7 @@ void R_SetupFrame (AActor *actor) iview->oviewangle = iview->nviewangle; } - if (player != NULL && + if (player != NULL && gamestate != GS_TITLELEVEL && ((player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) && (camera->RenderStyle != STYLE_None) && !(camera->renderflags & RF_INVISIBLE) &&