This commit is contained in:
Christoph Oelckers 2014-10-25 15:11:29 +02:00
commit fc0025963b
47 changed files with 363 additions and 180 deletions

View file

@ -341,6 +341,9 @@ enum
MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings. MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings.
MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag
MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag MF7_WEAPONSPAWN = 0x00000010, // subject to DF_NO_COOP_WEAPON_SPAWN dmflag
MF7_HARMFRIENDS = 0x00000020, // is allowed to harm friendly monsters.
MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat.
MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode.
// --- mobj.renderflags --- // --- mobj.renderflags ---
@ -713,6 +716,9 @@ public:
// Transforms the actor into a finely-ground paste // Transforms the actor into a finely-ground paste
virtual bool Grind(bool items); virtual bool Grind(bool items);
// Get this actor's team
int GetTeam();
// Is the other actor on my team? // Is the other actor on my team?
bool IsTeammate (AActor *other); bool IsTeammate (AActor *other);

View file

@ -908,8 +908,8 @@ void AM_StaticInit()
if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow); if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow);
if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow); if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow);
AM_ParseArrow(CheatKey, "maparrows/key.txt"); AM_ParseArrow(CheatKey, gameinfo.mCheatKey);
AM_ParseArrow(EasyKey, "maparrows/ravenkey.txt"); AM_ParseArrow(EasyKey, gameinfo.mEasyKey);
if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined"); if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined");
char namebuf[9]; char namebuf[9];

View file

@ -124,6 +124,15 @@ CCMD (god)
Net_WriteByte (CHT_GOD); Net_WriteByte (CHT_GOD);
} }
CCMD(god2)
{
if (CheckCheatmode())
return;
Net_WriteByte(DEM_GENERICCHEAT);
Net_WriteByte(CHT_GOD2);
}
CCMD (iddqd) CCMD (iddqd)
{ {
if (CheckCheatmode ()) if (CheckCheatmode ())
@ -142,6 +151,15 @@ CCMD (buddha)
Net_WriteByte(CHT_BUDDHA); Net_WriteByte(CHT_BUDDHA);
} }
CCMD(buddha2)
{
if (CheckCheatmode())
return;
Net_WriteByte(DEM_GENERICCHEAT);
Net_WriteByte(CHT_BUDDHA2);
}
CCMD (notarget) CCMD (notarget)
{ {
if (CheckCheatmode ()) if (CheckCheatmode ())

View file

@ -500,9 +500,10 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
goodv = false; goodv = false;
break; break;
default: default:
if (value[i] < '0' && value[i] > '9' && if (value[i] < '0' ||
value[i] < 'A' && value[i] > 'F' && (value[i] > '9' && value[i] < 'A') ||
value[i] < 'a' && value[i] > 'f') (value[i] > 'F' && value[i] < 'a') ||
value[i] > 'f')
{ {
goodv = false; goodv = false;
} }

View file

@ -141,6 +141,7 @@ static FCompatOption Options[] =
{ "maskedmidtex", COMPATF_MASKEDMIDTEX, SLOT_COMPAT }, { "maskedmidtex", COMPATF_MASKEDMIDTEX, SLOT_COMPAT },
{ "badangles", COMPATF2_BADANGLES, SLOT_COMPAT2 }, { "badangles", COMPATF2_BADANGLES, SLOT_COMPAT2 },
{ "floormove", COMPATF2_FLOORMOVE, SLOT_COMPAT2 }, { "floormove", COMPATF2_FLOORMOVE, SLOT_COMPAT2 },
{ "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 },
{ NULL, 0, 0 } { NULL, 0, 0 }
}; };

View file

@ -466,7 +466,7 @@ CUSTOM_CVAR (Int, dmflags2, 0, CVAR_SERVERINFO)
} }
// Come out of chasecam mode if we're not allowed to use chasecam. // Come out of chasecam mode if we're not allowed to use chasecam.
if (!(dmflags2 & DF2_CHASECAM) && !G_SkillProperty (SKILLP_DisableCheats) && !sv_cheats) if (!(dmflags2 & DF2_CHASECAM) && CheckCheatmode(false))
{ {
// Take us out of chasecam mode only. // Take us out of chasecam mode only.
if (p->cheats & CF_CHASECAM) if (p->cheats & CF_CHASECAM)
@ -620,6 +620,7 @@ CVAR (Flag, compat_polyobj, compatflags, COMPATF_POLYOBJ);
CVAR (Flag, compat_maskedmidtex, compatflags, COMPATF_MASKEDMIDTEX); CVAR (Flag, compat_maskedmidtex, compatflags, COMPATF_MASKEDMIDTEX);
CVAR (Flag, compat_badangles, compatflags2, COMPATF2_BADANGLES); CVAR (Flag, compat_badangles, compatflags2, COMPATF2_BADANGLES);
CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE); CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE);
CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF);
//========================================================================== //==========================================================================
// //

View file

@ -205,6 +205,8 @@ typedef enum
CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact CF_DOUBLEFIRINGSPEED= 1 << 21, // Player owns a double firing speed artifact
CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths. CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths.
CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact CF_INFINITEAMMO = 1 << 23, // Player owns an infinite ammo artifact
CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either.
CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either.
CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die
CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip
} cheat_t; } cheat_t;

View file

@ -219,7 +219,9 @@ enum ECheatCommand
CHT_GIMMIEJ, CHT_GIMMIEJ,
CHT_GIMMIEZ, CHT_GIMMIEZ,
CHT_BUDDHA, CHT_BUDDHA,
CHT_NOCLIP2 CHT_NOCLIP2,
CHT_BUDDHA2,
CHT_GOD2
}; };
void StartChunk (int id, BYTE **stream); void StartChunk (int id, BYTE **stream);

View file

@ -339,6 +339,7 @@ enum
COMPATF2_BADANGLES = 1 << 0, // It is impossible to face directly NSEW. COMPATF2_BADANGLES = 1 << 0, // It is impossible to face directly NSEW.
COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom. COMPATF2_FLOORMOVE = 1 << 1, // Use the same floor motion behavior as Doom.
COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less
}; };
// Emulate old bugs for select maps. These are not exposed by a cvar // Emulate old bugs for select maps. These are not exposed by a cvar

View file

@ -1363,6 +1363,7 @@ void G_PlayerReborn (int player)
::new(p) player_t; ::new(p) player_t;
memcpy (p->frags, frags, sizeof(p->frags)); memcpy (p->frags, frags, sizeof(p->frags));
p->health = actor->health;
p->fragcount = fragcount; p->fragcount = fragcount;
p->killcount = killcount; p->killcount = killcount;
p->itemcount = itemcount; p->itemcount = itemcount;
@ -1381,6 +1382,8 @@ void G_PlayerReborn (int player)
if (gamestate != GS_TITLELEVEL) if (gamestate != GS_TITLELEVEL)
{ {
// [GRB] Give inventory specified in DECORATE
actor->GiveDefaultInventory (); actor->GiveDefaultInventory ();
p->ReadyWeapon = p->PendingWeapon; p->ReadyWeapon = p->PendingWeapon;
} }

View file

@ -1183,6 +1183,15 @@ void G_FinishTravel ()
pawn->AddToHash (); pawn->AddToHash ();
pawn->SetState(pawn->SpawnState); pawn->SetState(pawn->SpawnState);
pawn->player->SendPitchLimits(); pawn->player->SendPitchLimits();
// Sync the FLY flags.
if (pawn->flags2 & MF2_FLY)
{
pawn->player->cheats |= CF_FLY;
}
else
{
pawn->player->cheats &= ~CF_FLY;
}
for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory) for (inv = pawn->Inventory; inv != NULL; inv = inv->Inventory)
{ {

View file

@ -1306,6 +1306,7 @@ MapFlagHandlers[] =
{ "compat_maskedmidtex", MITYPE_COMPATFLAG, COMPATF_MASKEDMIDTEX, 0 }, { "compat_maskedmidtex", MITYPE_COMPATFLAG, COMPATF_MASKEDMIDTEX, 0 },
{ "compat_badangles", MITYPE_COMPATFLAG, 0, COMPATF2_BADANGLES }, { "compat_badangles", MITYPE_COMPATFLAG, 0, COMPATF2_BADANGLES },
{ "compat_floormove", MITYPE_COMPATFLAG, 0, COMPATF2_FLOORMOVE }, { "compat_floormove", MITYPE_COMPATFLAG, 0, COMPATF2_FLOORMOVE },
{ "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF },
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 },

View file

@ -1296,6 +1296,18 @@ void APowerTargeter::InitEffect ()
PositionAccuracy (); PositionAccuracy ();
} }
bool APowerTargeter::HandlePickup(AInventory *item)
{
if (Super::HandlePickup(item))
{
InitEffect(); // reset the HUD sprites
return true;
}
return false;
}
void APowerTargeter::DoEffect () void APowerTargeter::DoEffect ()
{ {
Super::DoEffect (); Super::DoEffect ();
@ -1384,6 +1396,42 @@ void APowerFrightener::EndEffect ()
Owner->player->cheats &= ~CF_FRIGHTENING; Owner->player->cheats &= ~CF_FRIGHTENING;
} }
// Buddha Powerup --------------------------------
IMPLEMENT_CLASS (APowerBuddha)
//===========================================================================
//
// APowerBuddha :: InitEffect
//
//===========================================================================
void APowerBuddha::InitEffect ()
{
Super::InitEffect();
if (Owner== NULL || Owner->player == NULL)
return;
Owner->player->cheats |= CF_BUDDHA;
}
//===========================================================================
//
// APowerBuddha :: EndEffect
//
//===========================================================================
void APowerBuddha::EndEffect ()
{
Super::EndEffect();
if (Owner== NULL || Owner->player == NULL)
return;
Owner->player->cheats &= ~CF_BUDDHA;
}
// Scanner powerup ---------------------------------------------------------- // Scanner powerup ----------------------------------------------------------
IMPLEMENT_CLASS (APowerScanner) IMPLEMENT_CLASS (APowerScanner)

View file

@ -173,6 +173,7 @@ protected:
void EndEffect (); void EndEffect ();
void PositionAccuracy (); void PositionAccuracy ();
void Travelled (); void Travelled ();
bool HandlePickup(AInventory *item);
}; };
class APowerFrightener : public APowerup class APowerFrightener : public APowerup
@ -183,6 +184,14 @@ protected:
void EndEffect (); void EndEffect ();
}; };
class APowerBuddha : public APowerup
{
DECLARE_CLASS (APowerBuddha, APowerup)
protected:
void InitEffect ();
void EndEffect ();
};
class APowerTimeFreezer : public APowerup class APowerTimeFreezer : public APowerup
{ {
DECLARE_CLASS( APowerTimeFreezer, APowerup ) DECLARE_CLASS( APowerTimeFreezer, APowerup )

View file

@ -12,6 +12,7 @@
#include "doomstat.h" #include "doomstat.h"
#include "g_level.h" #include "g_level.h"
#include "farchive.h" #include "farchive.h"
#include "p_enemy.h"
static FRandom pr_morphmonst ("MorphMonster"); static FRandom pr_morphmonst ("MorphMonster");
@ -527,11 +528,11 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
if (actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster))) if (actor->GetClass()->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster)))
{ {
AMorphedMonster *fakeme = static_cast<AMorphedMonster *>(actor); AMorphedMonster *fakeme = static_cast<AMorphedMonster *>(actor);
AActor *realme = fakeme->UnmorphedMe;
if ((fakeme->UnmorphTime) && if ((fakeme->UnmorphTime) &&
(fakeme->MorphStyle & MORPH_UNDOBYDEATH) && (fakeme->MorphStyle & MORPH_UNDOBYDEATH) &&
(fakeme->UnmorphedMe)) (realme))
{ {
AActor *realme = fakeme->UnmorphedMe;
int realstyle = fakeme->MorphStyle; int realstyle = fakeme->MorphStyle;
int realhealth = fakeme->health; int realhealth = fakeme->health;
if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED))) if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED)))
@ -542,6 +543,11 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
return true; return true;
} }
} }
if (realme->flags4 & MF4_BOSSDEATH)
{
realme->health = 0; // make sure that A_BossDeath considers it dead.
CALL_ACTION(A_BossDeath, realme);
}
fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die() fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die()
return false; return false;
} }

View file

@ -499,7 +499,7 @@ bool AInventory::ShouldRespawn ()
{ {
if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags2 & DF2_RESPAWN_SUPER)) return false; if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags2 & DF2_RESPAWN_SUPER)) return false;
if (ItemFlags & IF_NEVERRESPAWN) return false; if (ItemFlags & IF_NEVERRESPAWN) return false;
return !!(dmflags & DF_ITEMS_RESPAWN); return !!((dmflags & DF_ITEMS_RESPAWN) || (ItemFlags & IF_ALWAYSRESPAWN));
} }
//=========================================================================== //===========================================================================

View file

@ -135,6 +135,7 @@ enum
IF_NEVERRESPAWN = 1<<20, // Never, ever respawns IF_NEVERRESPAWN = 1<<20, // Never, ever respawns
IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen IF_NOSCREENFLASH = 1<<21, // No pickup flash on the player's screen
IF_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop) IF_TOSSED = 1<<22, // Was spawned by P_DropItem (i.e. as a monster drop)
IF_ALWAYSRESPAWN = 1<<23, // Always respawn, regardless of dmflag
}; };

View file

@ -444,7 +444,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
if (bNormal) if (bNormal)
{ {
bool good; bool good;
if ((player->cheats & CF_GODMODE) || (player->mo != NULL && player->mo->flags2 & MF2_INVULNERABLE)) if ((player->cheats & CF_GODMODE) || (player->cheats & CF_GODMODE2) || (player->mo != NULL && player->mo->flags2 & MF2_INVULNERABLE))
{ {
good = SetState((stateflags & ANIMATEDGODMODE) ? "godanimated" : "god"); good = SetState((stateflags & ANIMATEDGODMODE) ? "godanimated" : "god");
} }

View file

@ -106,7 +106,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath)
switch (self->GetClass()->TypeName) switch (self->GetClass()->TypeName)
{ {
case NAME_AlienSpectre1: case NAME_AlienSpectre1:
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 999, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorLowerToLowest, NULL, 999, FRACUNIT, 0, -1, 0, false);
log = 95; log = 95;
break; break;
@ -180,7 +180,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_AlienSpectreDeath)
{ // Another Sigil piece. Woohoo! { // Another Sigil piece. Woohoo!
log = 83; log = 83;
} }
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, -1, 0, false);
break; break;
default: default:

View file

@ -80,6 +80,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderDeath)
{ {
if (CheckBossDeath (self)) if (CheckBossDeath (self))
{ {
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorLowerToLowest, NULL, 667, FRACUNIT, 0, -1, 0, false);
} }
} }

View file

@ -548,7 +548,7 @@ void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags)
P_NoiseAlert (source, this); P_NoiseAlert (source, this);
} }
EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2*FRACUNIT, 0, 0, 0); EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2*FRACUNIT, 0, 0, 0);
EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, FRACUNIT, 0, -1, 0, false);
players[i].mo->GiveInventoryType (QuestItemClasses[5]); players[i].mo->GiveInventoryType (QuestItemClasses[5]);
S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM); S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM);
players[i].SetLogNumber (13); players[i].SetLogNumber (13);

View file

@ -290,6 +290,9 @@ void FMapInfoParser::ParseGameInfo()
else gameinfo.mCheatMapArrow = ""; else gameinfo.mCheatMapArrow = "";
} }
// Insert valid keys here. // Insert valid keys here.
GAMEINFOKEY_STRING(mCheatKey, "cheatKey")
GAMEINFOKEY_STRING(mEasyKey, "easyKey")
GAMEINFOKEY_STRING(TitlePage, "titlePage")
GAMEINFOKEY_STRING(TitlePage, "titlePage") GAMEINFOKEY_STRING(TitlePage, "titlePage")
GAMEINFOKEY_STRINGARRAY(creditPages, "addcreditPage", 8, false) GAMEINFOKEY_STRINGARRAY(creditPages, "addcreditPage", 8, false)
GAMEINFOKEY_STRINGARRAY(creditPages, "CreditPage", 8, true) GAMEINFOKEY_STRINGARRAY(creditPages, "CreditPage", 8, true)

View file

@ -169,6 +169,7 @@ struct gameinfo_t
int TextScreenY; int TextScreenY;
FName DefaultEndSequence; FName DefaultEndSequence;
FString mMapArrow, mCheatMapArrow; FString mMapArrow, mCheatMapArrow;
FString mEasyKey, mCheatKey;
FGIFont mStatscreenMapNameFont; FGIFont mStatscreenMapNameFont;
FGIFont mStatscreenFinishedFont; FGIFont mStatscreenFinishedFont;
FGIFont mStatscreenEnteringFont; FGIFont mStatscreenEnteringFont;

View file

@ -99,6 +99,23 @@ void cht_DoCheat (player_t *player, int cheat)
msg = GStrings("TXT_BUDDHAOFF"); msg = GStrings("TXT_BUDDHAOFF");
break; break;
case CHT_GOD2:
player->cheats ^= CF_GODMODE2;
if (player->cheats & CF_GODMODE2)
msg = GStrings("STSTR_DQD2ON");
else
msg = GStrings("STSTR_DQD2OFF");
ST_SetNeedRefresh();
break;
case CHT_BUDDHA2:
player->cheats ^= CF_BUDDHA2;
if (player->cheats & CF_BUDDHA2)
msg = GStrings("TXT_BUDDHA2ON");
else
msg = GStrings("TXT_BUDDHA2OFF");
break;
case CHT_NOCLIP: case CHT_NOCLIP:
player->cheats ^= CF_NOCLIP; player->cheats ^= CF_NOCLIP;
if (player->cheats & CF_NOCLIP) if (player->cheats & CF_NOCLIP)
@ -323,7 +340,6 @@ void cht_DoCheat (player_t *player, int cheat)
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
} }
player->mo->DamageType = NAME_None; player->mo->DamageType = NAME_None;
// player->mo->GiveDefaultInventory();
if (player->ReadyWeapon != NULL) if (player->ReadyWeapon != NULL)
{ {
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->GetUpState()); P_SetPsprite(player, ps_weapon, player->ReadyWeapon->GetUpState());

View file

@ -1592,7 +1592,7 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
} }
#endif #endif
// [SP] If you don't see any enemies in deathmatch, look for players (but only when friend to a specific player.) // [SP] If you don't see any enemies in deathmatch, look for players (but only when friend to a specific player.)
if (actor->FriendPlayer == 0 && (!teamplay || actor->DesignatedTeam == TEAM_NONE)) return result; if (actor->FriendPlayer == 0 && (!teamplay || actor->GetTeam() == TEAM_NONE)) return result;
if (result || !deathmatch) return true; if (result || !deathmatch) return true;
@ -3275,13 +3275,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_BossDeath)
{ {
if (type == NAME_Fatso) if (type == NAME_Fatso)
{ {
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, -1, 0, false);
return; return;
} }
if (type == NAME_Arachnotron) if (type == NAME_Arachnotron)
{ {
EV_DoFloor (DFloor::floorRaiseByTexture, NULL, 667, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorRaiseByTexture, NULL, 667, FRACUNIT, 0, -1, 0, false);
return; return;
} }
} }
@ -3290,11 +3290,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_BossDeath)
switch (level.flags & LEVEL_SPECACTIONSMASK) switch (level.flags & LEVEL_SPECACTIONSMASK)
{ {
case LEVEL_SPECLOWERFLOOR: case LEVEL_SPECLOWERFLOOR:
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, FRACUNIT, 0, -1, 0, false);
return; return;
case LEVEL_SPECLOWERFLOORTOHIGHEST: case LEVEL_SPECLOWERFLOORTOHIGHEST:
EV_DoFloor (DFloor::floorLowerToHighest, NULL, 666, FRACUNIT, 0, 0, 0, false); EV_DoFloor (DFloor::floorLowerToHighest, NULL, 666, FRACUNIT, 0, -1, 0, false);
return; return;
case LEVEL_SPECOPENDOOR: case LEVEL_SPECOPENDOOR:

View file

@ -320,7 +320,7 @@ manual_floor:
rtn = true; rtn = true;
floor = new DFloor (sec); floor = new DFloor (sec);
floor->m_Type = floortype; floor->m_Type = floortype;
floor->m_Crush = -1; floor->m_Crush = crush;
floor->m_Hexencrush = hexencrush; floor->m_Hexencrush = hexencrush;
floor->m_Speed = speed; floor->m_Speed = speed;
floor->m_ResetCount = 0; // [RH] floor->m_ResetCount = 0; // [RH]
@ -374,7 +374,6 @@ manual_floor:
break; break;
case DFloor::floorRaiseAndCrushDoom: case DFloor::floorRaiseAndCrushDoom:
floor->m_Crush = crush;
case DFloor::floorRaiseToLowestCeiling: case DFloor::floorRaiseToLowestCeiling:
floor->m_Direction = 1; floor->m_Direction = 1;
newheight = sec->FindLowestCeilingSurrounding (&spot); newheight = sec->FindLowestCeilingSurrounding (&spot);
@ -406,7 +405,6 @@ manual_floor:
break; break;
case DFloor::floorRaiseAndCrush: case DFloor::floorRaiseAndCrush:
floor->m_Crush = crush;
floor->m_Direction = 1; floor->m_Direction = 1;
newheight = sec->FindLowestCeilingPoint (&spot) - 8*FRACUNIT; newheight = sec->FindLowestCeilingPoint (&spot) - 8*FRACUNIT;
floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight); floor->m_FloorDestDist = sec->floorplane.PointToDist (spot, newheight);

View file

@ -938,7 +938,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
FState * woundstate = NULL; FState * woundstate = NULL;
PainChanceList * pc = NULL; PainChanceList * pc = NULL;
bool justhit = false; bool justhit = false;
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE))) if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
{ // Shouldn't happen { // Shouldn't happen
return -1; return -1;
@ -1209,8 +1209,10 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
if (!(flags & DMG_FORCED)) if (!(flags & DMG_FORCED))
{ {
// check the real player, not a voodoo doll here for invulnerability effects // check the real player, not a voodoo doll here for invulnerability effects
if (damage < TELEFRAG_DAMAGE && ((player->mo->flags2 & MF2_INVULNERABLE) || if ((damage < TELEFRAG_DAMAGE && ((player->mo->flags2 & MF2_INVULNERABLE) ||
(player->cheats & CF_GODMODE))) (player->cheats & CF_GODMODE))) ||
(player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE))
//Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2.
{ // player is invulnerable, so don't hurt him { // player is invulnerable, so don't hurt him
return -1; return -1;
} }
@ -1218,8 +1220,13 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL)
{ {
int newdam = damage; int newdam = damage;
player->mo->Inventory->AbsorbDamage (damage, mod, newdam); player->mo->Inventory->AbsorbDamage(damage, mod, newdam);
damage = newdam; if (damage < TELEFRAG_DAMAGE)
{
// if we are telefragging don't let the damage value go below that magic value. Some further checks would fail otherwise.
damage = newdam;
}
if (damage <= 0) if (damage <= 0)
{ {
// If MF6_FORCEPAIN is set, make the player enter the pain state. // If MF6_FORCEPAIN is set, make the player enter the pain state.
@ -1232,7 +1239,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
} }
} }
if (damage >= player->health if (damage >= player->health && damage < TELEFRAG_DAMAGE
&& (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch)
&& !player->morphTics) && !player->morphTics)
{ // Try to use some inventory health { // Try to use some inventory health
@ -1254,9 +1261,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// This does not save the player if damage >= TELEFRAG_DAMAGE, still need to // This does not save the player if damage >= TELEFRAG_DAMAGE, still need to
// telefrag him right? ;) (Unfortunately the damage is "absorbed" by armor, // telefrag him right? ;) (Unfortunately the damage is "absorbed" by armor,
// but telefragging should still do enough damage to kill the player) // but telefragging should still do enough damage to kill the player)
if ((player->cheats & CF_BUDDHA) && damage < TELEFRAG_DAMAGE // Ignore players that are already dead.
// Ignore players that are already dead. if (((player->cheats & CF_BUDDHA2) || ((player->cheats & CF_BUDDHA) && damage < TELEFRAG_DAMAGE)) && player->playerstate != PST_DEAD)
&& player->playerstate != PST_DEAD)
{ {
// If this is a voodoo doll we need to handle the real player as well. // If this is a voodoo doll we need to handle the real player as well.
player->mo->health = target->health = player->health = 1; player->mo->health = target->health = player->health = 1;
@ -1316,43 +1322,52 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
if (target->health <= 0) if (target->health <= 0)
{ // Death {
target->special1 = damage; if ((target->flags7 & MF7_BUDDHA) && (damage < TELEFRAG_DAMAGE) && (!(inflictor->flags3 & MF7_FOILBUDDHA) && !(flags & DMG_FOILBUDDHA)))
{ //Make sure FOILINVUL flags work here too for monsters. Or perhaps consider a FOILBUDDHA flag...
// use inflictor's death type if it got one. target->health = 1;
if (inflictor && inflictor->DeathType != NAME_None) mod = inflictor->DeathType; }
else
// check for special fire damage or ice damage deaths
if (mod == NAME_Fire)
{ {
if (player && !player->morphTics)
{ // Check for flame death // Death
if (!inflictor || target->special1 = damage;
((target->health > -50) && (damage > 25)) ||
!(inflictor->flags5 & MF5_SPECIALFIREDAMAGE)) // use inflictor's death type if it got one.
if (inflictor && inflictor->DeathType != NAME_None) mod = inflictor->DeathType;
// check for special fire damage or ice damage deaths
if (mod == NAME_Fire)
{
if (player && !player->morphTics)
{ // Check for flame death
if (!inflictor ||
((target->health > -50) && (damage > 25)) ||
!(inflictor->flags5 & MF5_SPECIALFIREDAMAGE))
{
target->DamageType = NAME_Fire;
}
}
else
{ {
target->DamageType = NAME_Fire; target->DamageType = NAME_Fire;
} }
} }
else else
{ {
target->DamageType = NAME_Fire; target->DamageType = mod;
} }
} if (source && source->tracer && (source->flags5 & MF5_SUMMONEDMONSTER))
else { // Minotaur's kills go to his master
{ // Make sure still alive and not a pointer to fighter head
target->DamageType = mod; if (source->tracer->player && (source->tracer->player->mo == source->tracer))
} {
if (source && source->tracer && (source->flags5 & MF5_SUMMONEDMONSTER)) source = source->tracer;
{ // Minotaur's kills go to his master }
// Make sure still alive and not a pointer to fighter head
if (source->tracer->player && (source->tracer->player->mo == source->tracer))
{
source = source->tracer;
} }
target->Die (source, inflictor, flags);
return damage;
} }
target->Die (source, inflictor, flags);
return damage;
} }
woundstate = target->FindState(NAME_Wound, mod); woundstate = target->FindState(NAME_Wound, mod);
@ -1672,7 +1687,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage,
target->health -= damage; target->health -= damage;
if (target->health <= 0) if (target->health <= 0)
{ // Death { // Death
if (player->cheats & CF_BUDDHA) if ((player->cheats & CF_BUDDHA && damage < TELEFRAG_DAMAGE) || (player->cheats & CF_BUDDHA2))
{ // [SP] Save the player... { // [SP] Save the player...
player->health = target->health = 1; player->health = target->health = 1;
} }

View file

@ -281,43 +281,43 @@ FUNC(LS_Generic_Door)
FUNC(LS_Floor_LowerByValue) FUNC(LS_Floor_LowerByValue)
// Floor_LowerByValue (tag, speed, height) // Floor_LowerByValue (tag, speed, height)
{ {
return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, 0, 0, false); return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, -1, 0, false);
} }
FUNC(LS_Floor_LowerToLowest) FUNC(LS_Floor_LowerToLowest)
// Floor_LowerToLowest (tag, speed) // Floor_LowerToLowest (tag, speed)
{ {
return EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0, false); return EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, -1, 0, false);
} }
FUNC(LS_Floor_LowerToHighest) FUNC(LS_Floor_LowerToHighest)
// Floor_LowerToHighest (tag, speed, adjust, hereticlower) // Floor_LowerToHighest (tag, speed, adjust, hereticlower)
{ {
return EV_DoFloor (DFloor::floorLowerToHighest, ln, arg0, SPEED(arg1), (arg2-128)*FRACUNIT, 0, 0, false, arg3==1); return EV_DoFloor (DFloor::floorLowerToHighest, ln, arg0, SPEED(arg1), (arg2-128)*FRACUNIT, -1, 0, false, arg3==1);
} }
FUNC(LS_Floor_LowerToNearest) FUNC(LS_Floor_LowerToNearest)
// Floor_LowerToNearest (tag, speed) // Floor_LowerToNearest (tag, speed)
{ {
return EV_DoFloor (DFloor::floorLowerToNearest, ln, arg0, SPEED(arg1), 0, 0, 0, false); return EV_DoFloor (DFloor::floorLowerToNearest, ln, arg0, SPEED(arg1), 0, -1, 0, false);
} }
FUNC(LS_Floor_RaiseByValue) FUNC(LS_Floor_RaiseByValue)
// Floor_RaiseByValue (tag, speed, height) // Floor_RaiseByValue (tag, speed, height)
{ {
return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2, -1, 0, false);
} }
FUNC(LS_Floor_RaiseToHighest) FUNC(LS_Floor_RaiseToHighest)
// Floor_RaiseToHighest (tag, speed) // Floor_RaiseToHighest (tag, speed)
{ {
return EV_DoFloor (DFloor::floorRaiseToHighest, ln, arg0, SPEED(arg1), 0, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseToHighest, ln, arg0, SPEED(arg1), 0, -1, 0, false);
} }
FUNC(LS_Floor_RaiseToNearest) FUNC(LS_Floor_RaiseToNearest)
// Floor_RaiseToNearest (tag, speed) // Floor_RaiseToNearest (tag, speed)
{ {
return EV_DoFloor (DFloor::floorRaiseToNearest, ln, arg0, SPEED(arg1), 0, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseToNearest, ln, arg0, SPEED(arg1), 0, -1, 0, false);
} }
FUNC(LS_Floor_RaiseAndCrush) FUNC(LS_Floor_RaiseAndCrush)
@ -335,13 +335,13 @@ FUNC(LS_Floor_RaiseAndCrushDoom)
FUNC(LS_Floor_RaiseByValueTimes8) FUNC(LS_Floor_RaiseByValueTimes8)
// FLoor_RaiseByValueTimes8 (tag, speed, height) // FLoor_RaiseByValueTimes8 (tag, speed, height)
{ {
return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, -1, 0, false);
} }
FUNC(LS_Floor_LowerByValueTimes8) FUNC(LS_Floor_LowerByValueTimes8)
// Floor_LowerByValueTimes8 (tag, speed, height) // Floor_LowerByValueTimes8 (tag, speed, height)
{ {
return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, 0, 0, false); return EV_DoFloor (DFloor::floorLowerByValue, ln, arg0, SPEED(arg1), FRACUNIT*arg2*8, -1, 0, false);
} }
FUNC(LS_Floor_CrushStop) FUNC(LS_Floor_CrushStop)
@ -353,51 +353,51 @@ FUNC(LS_Floor_CrushStop)
FUNC(LS_Floor_LowerInstant) FUNC(LS_Floor_LowerInstant)
// Floor_LowerInstant (tag, unused, height) // Floor_LowerInstant (tag, unused, height)
{ {
return EV_DoFloor (DFloor::floorLowerInstant, ln, arg0, 0, arg2*FRACUNIT*8, 0, 0, false); return EV_DoFloor (DFloor::floorLowerInstant, ln, arg0, 0, arg2*FRACUNIT*8, -1, 0, false);
} }
FUNC(LS_Floor_RaiseInstant) FUNC(LS_Floor_RaiseInstant)
// Floor_RaiseInstant (tag, unused, height) // Floor_RaiseInstant (tag, unused, height)
{ {
return EV_DoFloor (DFloor::floorRaiseInstant, ln, arg0, 0, arg2*FRACUNIT*8, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseInstant, ln, arg0, 0, arg2*FRACUNIT*8, -1, 0, false);
} }
FUNC(LS_Floor_MoveToValueTimes8) FUNC(LS_Floor_MoveToValueTimes8)
// Floor_MoveToValueTimes8 (tag, speed, height, negative) // Floor_MoveToValueTimes8 (tag, speed, height, negative)
{ {
return EV_DoFloor (DFloor::floorMoveToValue, ln, arg0, SPEED(arg1), return EV_DoFloor (DFloor::floorMoveToValue, ln, arg0, SPEED(arg1),
arg2*FRACUNIT*8*(arg3?-1:1), 0, 0, false); arg2*FRACUNIT*8*(arg3?-1:1), -1, 0, false);
} }
FUNC(LS_Floor_MoveToValue) FUNC(LS_Floor_MoveToValue)
// Floor_MoveToValue (tag, speed, height, negative) // Floor_MoveToValue (tag, speed, height, negative)
{ {
return EV_DoFloor (DFloor::floorMoveToValue, ln, arg0, SPEED(arg1), return EV_DoFloor (DFloor::floorMoveToValue, ln, arg0, SPEED(arg1),
arg2*FRACUNIT*(arg3?-1:1), 0, 0, false); arg2*FRACUNIT*(arg3?-1:1), -1, 0, false);
} }
FUNC(LS_Floor_RaiseToLowestCeiling) FUNC(LS_Floor_RaiseToLowestCeiling)
// Floor_RaiseToLowestCeiling (tag, speed) // Floor_RaiseToLowestCeiling (tag, speed)
{ {
return EV_DoFloor (DFloor::floorRaiseToLowestCeiling, ln, arg0, SPEED(arg1), 0, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseToLowestCeiling, ln, arg0, SPEED(arg1), 0, -1, 0, false);
} }
FUNC(LS_Floor_RaiseByTexture) FUNC(LS_Floor_RaiseByTexture)
// Floor_RaiseByTexture (tag, speed) // Floor_RaiseByTexture (tag, speed)
{ {
return EV_DoFloor (DFloor::floorRaiseByTexture, ln, arg0, SPEED(arg1), 0, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseByTexture, ln, arg0, SPEED(arg1), 0, -1, 0, false);
} }
FUNC(LS_Floor_RaiseByValueTxTy) FUNC(LS_Floor_RaiseByValueTxTy)
// Floor_RaiseByValueTxTy (tag, speed, height) // Floor_RaiseByValueTxTy (tag, speed, height)
{ {
return EV_DoFloor (DFloor::floorRaiseAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, 0, false); return EV_DoFloor (DFloor::floorRaiseAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, -1, 0, false);
} }
FUNC(LS_Floor_LowerToLowestTxTy) FUNC(LS_Floor_LowerToLowestTxTy)
// Floor_LowerToLowestTxTy (tag, speed) // Floor_LowerToLowestTxTy (tag, speed)
{ {
return EV_DoFloor (DFloor::floorLowerAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, 0, false); return EV_DoFloor (DFloor::floorLowerAndChange, ln, arg0, SPEED(arg1), arg2*FRACUNIT, -1, 0, false);
} }
FUNC(LS_Floor_Waggle) FUNC(LS_Floor_Waggle)
@ -1764,7 +1764,7 @@ FUNC(LS_FloorAndCeiling_LowerRaise)
// more or less unintuitive value for the fourth arg to trigger Boom's broken behavior // more or less unintuitive value for the fourth arg to trigger Boom's broken behavior
if (arg3 != 1998 || !res) // (1998 for the year in which Boom was released... :P) if (arg3 != 1998 || !res) // (1998 for the year in which Boom was released... :P)
{ {
res |= EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0, false); res |= EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, -1, 0, false);
} }
return res; return res;
} }

View file

@ -559,6 +559,7 @@ enum EDmgFlags
DMG_NO_FACTOR = 16, DMG_NO_FACTOR = 16,
DMG_PLAYERATTACK = 32, DMG_PLAYERATTACK = 32,
DMG_FOILINVUL = 64, DMG_FOILINVUL = 64,
DMG_FOILBUDDHA = 128,
}; };

View file

@ -198,7 +198,7 @@ void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags)
if (ff_top > tmf.floorz) if (ff_top > tmf.floorz)
{ {
if (ff_top <= tmf.z || (!(flags && FFCF_3DRESTRICT) && (tmf.thing != NULL && ff_bottom < tmf.z && ff_top < tmf.z + tmf.thing->MaxStepHeight))) if (ff_top <= tmf.z || (!(flags & FFCF_3DRESTRICT) && (tmf.thing != NULL && ff_bottom < tmf.z && ff_top < tmf.z + tmf.thing->MaxStepHeight)))
{ {
tmf.dropoffz = tmf.floorz = ff_top; tmf.dropoffz = tmf.floorz = ff_top;
tmf.floorpic = *rover->top.texture; tmf.floorpic = *rover->top.texture;
@ -1111,24 +1111,27 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
// cases where they are clearly supposed to do that // cases where they are clearly supposed to do that
if (thing->IsFriend(tm.thing->target)) if (thing->IsFriend(tm.thing->target))
{ {
// Friends never harm each other // Friends never harm each other, unless the shooter has the HARMFRIENDS set.
return false; if (!(thing->flags7 & MF7_HARMFRIENDS)) return false;
} }
if (thing->TIDtoHate != 0 && thing->TIDtoHate == tm.thing->target->TIDtoHate) else
{ {
// [RH] Don't hurt monsters that hate the same thing as you do if (thing->TIDtoHate != 0 && thing->TIDtoHate == tm.thing->target->TIDtoHate)
return false;
}
if (thing->GetSpecies() == tm.thing->target->GetSpecies() && !(thing->flags6 & MF6_DOHARMSPECIES))
{
// Don't hurt same species or any relative -
// but only if the target isn't one's hostile.
if (!thing->IsHostile(tm.thing->target))
{ {
// Allow hurting monsters the shooter hates. // [RH] Don't hurt monsters that hate the same thing as you do
if (thing->tid == 0 || tm.thing->target->TIDtoHate != thing->tid) return false;
}
if (thing->GetSpecies() == tm.thing->target->GetSpecies() && !(thing->flags6 & MF6_DOHARMSPECIES))
{
// Don't hurt same species or any relative -
// but only if the target isn't one's hostile.
if (!thing->IsHostile(tm.thing->target))
{ {
return false; // Allow hurting monsters the shooter hates.
if (thing->tid == 0 || tm.thing->target->TIDtoHate != thing->tid)
{
return false;
}
} }
} }
} }
@ -2157,7 +2160,7 @@ bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y)
{ // too big a step up { // too big a step up
return false; return false;
} }
else if ((thing->flags & MF_MISSILE) && !(thing->flags6 && MF6_STEPMISSILE) && tm.floorz > newz) else if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > newz)
{ // [RH] Don't let normal missiles climb steps { // [RH] Don't let normal missiles climb steps
return false; return false;
} }

View file

@ -1199,13 +1199,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
if (nextstate == NULL) nextstate = mo->FindState(NAME_Death, NAME_Extreme); if (nextstate == NULL) nextstate = mo->FindState(NAME_Death, NAME_Extreme);
} }
if (nextstate == NULL) nextstate = mo->FindState(NAME_Death); if (nextstate == NULL) nextstate = mo->FindState(NAME_Death);
mo->SetState (nextstate);
if (mo->ObjectFlags & OF_EuthanizeMe)
{
return;
}
if (line != NULL && line->special == Line_Horizon && !(mo->flags3 & MF3_SKYEXPLODE)) if (line != NULL && line->special == Line_Horizon && !(mo->flags3 & MF3_SKYEXPLODE))
{ {
// [RH] Don't explode missiles on horizon lines. // [RH] Don't explode missiles on horizon lines.
@ -1280,8 +1274,17 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
} }
} }
if (nextstate != NULL) // play the sound before changing the state, so that AActor::Destroy can call S_RelinkSounds on it and the death state can override it.
if (mo->DeathSound)
{ {
S_Sound (mo, CHAN_VOICE, mo->DeathSound, 1,
(mo->flags3 & MF3_FULLVOLDEATH) ? ATTN_NONE : ATTN_NORM);
}
mo->SetState (nextstate);
if (!(mo->ObjectFlags & OF_EuthanizeMe))
{
// The rest only applies if the missile actor still exists.
// [RH] Change render style of exploding rockets // [RH] Change render style of exploding rockets
if (mo->flags5 & MF5_DEHEXPLOSION) if (mo->flags5 & MF5_DEHEXPLOSION)
{ {
@ -1314,11 +1317,6 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
mo->flags &= ~MF_MISSILE; mo->flags &= ~MF_MISSILE;
if (mo->DeathSound)
{
S_Sound (mo, CHAN_VOICE, mo->DeathSound, 1,
(mo->flags3 & MF3_FULLVOLDEATH) ? ATTN_NONE : ATTN_NORM);
}
} }
} }
@ -5018,10 +5016,11 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc
cls = cls->ParentClass; cls = cls->ParentClass;
} }
} }
statedone:
if (!(bloodtype <= 1)) th->renderflags |= RF_INVISIBLE;
} }
statedone:
if (!(bloodtype <= 1)) th->renderflags |= RF_INVISIBLE;
if (bloodtype >= 1) if (bloodtype >= 1)
P_DrawSplash2 (40, x, y, z, dir, 2, bloodcolor); P_DrawSplash2 (40, x, y, z, dir, 2, bloodcolor);
} }
@ -5857,22 +5856,41 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z,
return NULL; return NULL;
} }
int AActor::GetTeam()
{
if (player)
{
return player->userinfo.GetTeam();
}
int myTeam = DesignatedTeam;
// Check for monsters that belong to a player on the team but aren't part of the team themselves.
if (myTeam == TEAM_NONE && FriendPlayer != 0)
{
myTeam = players[FriendPlayer - 1].userinfo.GetTeam();
}
return myTeam;
}
bool AActor::IsTeammate (AActor *other) bool AActor::IsTeammate (AActor *other)
{ {
if (!other) if (!other)
{
return false; return false;
}
else if (!deathmatch && player && other->player) else if (!deathmatch && player && other->player)
return true;
int myTeam = DesignatedTeam;
int otherTeam = other->DesignatedTeam;
if (player)
myTeam = player->userinfo.GetTeam();
if (other->player)
otherTeam = other->player->userinfo.GetTeam();
if (teamplay && myTeam != TEAM_NONE && myTeam == otherTeam)
{ {
return true; return true;
} }
else if (teamplay)
{
int myTeam = GetTeam();
int otherTeam = other->GetTeam();
return (myTeam != TEAM_NONE && myTeam == otherTeam);
}
return false; return false;
} }

View file

@ -39,6 +39,7 @@
#include "cmdlib.h" #include "cmdlib.h"
#include "i_system.h" #include "i_system.h"
#include "c_dispatch.h" #include "c_dispatch.h"
#include "v_text.h"
#include "thingdef/thingdef.h" #include "thingdef/thingdef.h"
// Each state is owned by an actor. Actors can own any number of // Each state is owned by an actor. Actors can own any number of
@ -699,6 +700,10 @@ FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, const PClass *mytype
{ {
I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars()); I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars());
} }
else
{
Printf (TEXTCOLOR_RED "Attempt to get invalid state %s from actor %s.\n", label, type->TypeName.GetChars());
}
delete[] namestart; // free the allocated string buffer delete[] namestart; // free the allocated string buffer
return state; return state;
} }

View file

@ -366,7 +366,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling); Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
} }
else if (entersector == NULL || else if (entersector == NULL ||
hitz <= bf || hitz >= bc || hitz < bf || hitz > bc ||
in->d.line->flags & WallMask) in->d.line->flags & WallMask)
{ // hit the wall { // hit the wall
Results->HitType = TRACE_HitWall; Results->HitType = TRACE_HitWall;

View file

@ -1203,9 +1203,6 @@ void APlayerPawn::GiveDefaultInventory ()
{ {
if (player == NULL) return; if (player == NULL) return;
// [GRB] Give inventory specified in DECORATE
player->health = GetDefault ()->health;
// HexenArmor must always be the first item in the inventory because // HexenArmor must always be the first item in the inventory because
// it provides player class based protection that should not affect // it provides player class based protection that should not affect
// any other protection item. // any other protection item.

View file

@ -1575,7 +1575,7 @@ void S_RelinkSound (AActor *from, AActor *to)
{ {
chan->Actor = to; chan->Actor = to;
} }
else if (!(chan->ChanFlags & CHAN_LOOP)) else if (!(chan->ChanFlags & CHAN_LOOP) && !(compatflags2 & COMPATF2_SOUNDCUTOFF))
{ {
chan->Actor = NULL; chan->Actor = NULL;
chan->SourceType = SOURCE_Unattached; chan->SourceType = SOURCE_Unattached;

View file

@ -38,6 +38,7 @@
#include "templates.h" #include "templates.h"
#include "doomdef.h" #include "doomdef.h"
#include "m_swap.h" #include "m_swap.h"
#include "doomerrors.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -277,7 +278,16 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
return new TimidityMIDIDevice; return new TimidityMIDIDevice;
case MDEV_OPL: case MDEV_OPL:
return new OPLMIDIDevice; try
{
return new OPLMIDIDevice;
}
catch (CRecoverableError &err)
{
// The creation of an OPL MIDI device can abort with an error if no GENMIDI lump can be found.
Printf("Unable to create OPL MIDI device: %s\nFalling back to FModEx playback", err.GetMessage());
return new FMODMIDIDevice;
}
case MDEV_TIMIDITY: case MDEV_TIMIDITY:
return new TimidityPPMIDIDevice; return new TimidityPPMIDIDevice;

View file

@ -2912,6 +2912,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn)
self->flags3 = (defs->flags3 & ~(MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS)) | (self->flags3 & (MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS)); self->flags3 = (defs->flags3 & ~(MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS)) | (self->flags3 & (MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS));
self->flags4 = (defs->flags4 & ~MF4_NOHATEPLAYERS) | (self->flags4 & MF4_NOHATEPLAYERS); self->flags4 = (defs->flags4 & ~MF4_NOHATEPLAYERS) | (self->flags4 & MF4_NOHATEPLAYERS);
self->flags5 = defs->flags5; self->flags5 = defs->flags5;
self->flags6 = defs->flags6;
self->flags7 = defs->flags7;
self->SetState (self->SpawnState); self->SetState (self->SpawnState);
self->renderflags &= ~RF_INVISIBLE; self->renderflags &= ~RF_INVISIBLE;
@ -4348,12 +4350,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp)
ACTION_PARAM_INT(flags, 5); ACTION_PARAM_INT(flags, 5);
ACTION_PARAM_STATE(success_state, 6); ACTION_PARAM_STATE(success_state, 6);
fixed_t
oldx,
oldy,
oldz;
AActor *reference = COPY_AAPTR(self, destination_selector); AActor *reference = COPY_AAPTR(self, destination_selector);
if (!reference) if (!reference)
@ -4362,6 +4358,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp)
return; return;
} }
fixed_t oldx = self->x;
fixed_t oldy = self->y;
fixed_t oldz = self->z;
if (!(flags & WARPF_ABSOLUTEANGLE)) if (!(flags & WARPF_ABSOLUTEANGLE))
{ {
angle += (flags & WARPF_USECALLERANGLE) ? self->angle : reference->angle; angle += (flags & WARPF_USECALLERANGLE) ? self->angle : reference->angle;
@ -4371,20 +4371,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp)
if (!(flags & WARPF_ABSOLUTEOFFSET)) if (!(flags & WARPF_ABSOLUTEOFFSET))
{ {
angle_t fineangle = angle >> ANGLETOFINESHIFT; angle_t fineangle = angle >> ANGLETOFINESHIFT;
oldx = xofs; fixed_t xofs1 = xofs;
// (borrowed from A_SpawnItemEx, assumed workable) // (borrowed from A_SpawnItemEx, assumed workable)
// in relative mode negative y values mean 'left' and positive ones mean 'right' // in relative mode negative y values mean 'left' and positive ones mean 'right'
// This is the inverse orientation of the absolute mode! // This is the inverse orientation of the absolute mode!
xofs = FixedMul(oldx, finecosine[fineangle]) + FixedMul(yofs, finesine[fineangle]); xofs = FixedMul(xofs1, finecosine[fineangle]) + FixedMul(yofs, finesine[fineangle]);
yofs = FixedMul(oldx, finesine[fineangle]) - FixedMul(yofs, finecosine[fineangle]); yofs = FixedMul(xofs1, finesine[fineangle]) - FixedMul(yofs, finecosine[fineangle]);
} }
oldx = self->x;
oldy = self->y;
oldz = self->z;
if (flags & WARPF_TOFLOOR) if (flags & WARPF_TOFLOOR)
{ {
// set correct xy // set correct xy
@ -4835,43 +4831,26 @@ enum DMSS
DMSS_AFFECTARMOR = 2, DMSS_AFFECTARMOR = 2,
DMSS_KILL = 4, DMSS_KILL = 4,
DMSS_NOFACTOR = 8, DMSS_NOFACTOR = 8,
DMSS_FOILBUDDHA = 16,
}; };
static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageType, int flags) static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageType, int flags)
{ {
if ((amount > 0) || (flags & DMSS_KILL)) int dmgFlags = 0;
{ if (flags & DMSS_FOILINVUL)
if (!(dmgtarget->flags2 & MF2_INVULNERABLE) || (flags & DMSS_FOILINVUL)) dmgFlags += DMG_FOILINVUL;
{ if (flags & DMSS_FOILBUDDHA)
if (flags & DMSS_KILL) dmgFlags += DMG_FOILBUDDHA;
{ if ((flags & DMSS_KILL) || (flags & DMSS_NOFACTOR)) //Kill implies NoFactor
P_DamageMobj(dmgtarget, self, self, dmgtarget->health, DamageType, DMG_NO_FACTOR | DMG_NO_ARMOR | DMG_FOILINVUL); dmgFlags += DMG_NO_FACTOR;
} if (!(flags & DMSS_AFFECTARMOR) || (flags & DMSS_KILL)) //Kill overrides AffectArmor
if (flags & DMSS_AFFECTARMOR) dmgFlags += DMG_NO_ARMOR;
{ if (flags & DMSS_KILL) //Kill adds the value of the damage done to it. Allows for more controlled extreme death types.
if (flags & DMSS_NOFACTOR) amount += dmgtarget->health;
{
P_DamageMobj(dmgtarget, self, self, amount, DamageType, DMG_FOILINVUL | DMG_NO_FACTOR); if (amount > 0)
} P_DamageMobj(dmgtarget, self, self, amount, DamageType, dmgFlags); //Should wind up passing them through just fine.
else
{
P_DamageMobj(dmgtarget, self, self, amount, DamageType, DMG_FOILINVUL);
}
}
else
{
if (flags & DMSS_NOFACTOR)
{
P_DamageMobj(dmgtarget, self, self, amount, DamageType, DMG_FOILINVUL | DMG_NO_ARMOR | DMG_NO_FACTOR);
}
//[MC] DMG_FOILINVUL is needed for making the damage occur on the actor.
else
{
P_DamageMobj(dmgtarget, self, self, amount, DamageType, DMG_FOILINVUL | DMG_NO_ARMOR);
}
}
}
}
else if (amount < 0) else if (amount < 0)
{ {
amount = -amount; amount = -amount;
@ -4995,30 +4974,32 @@ enum KILS
KILS_FOILINVUL = 1 << 0, KILS_FOILINVUL = 1 << 0,
KILS_KILLMISSILES = 1 << 1, KILS_KILLMISSILES = 1 << 1,
KILS_NOMONSTERS = 1 << 2, KILS_NOMONSTERS = 1 << 2,
KILS_FOILBUDDHA = 1 << 3,
}; };
static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags) static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags)
{ {
int dmgFlags = DMG_NO_ARMOR + DMG_NO_FACTOR;
if (KILS_FOILINVUL)
dmgFlags += DMG_FOILINVUL;
if (KILS_FOILBUDDHA)
dmgFlags += DMG_FOILBUDDHA;
if ((killtarget->flags & MF_MISSILE) && (flags & KILS_KILLMISSILES)) if ((killtarget->flags & MF_MISSILE) && (flags & KILS_KILLMISSILES))
{ {
//[MC] Now that missiles can set masters, lets put in a check to properly destroy projectiles. BUT FIRST! New feature~! //[MC] Now that missiles can set masters, lets put in a check to properly destroy projectiles. BUT FIRST! New feature~!
//Check to see if it's invulnerable. Disregarded if foilinvul is on, but never works on a missile with NODAMAGE //Check to see if it's invulnerable. Disregarded if foilinvul is on, but never works on a missile with NODAMAGE
//since that's the whole point of it. //since that's the whole point of it.
if ((!(killtarget->flags2 & MF2_INVULNERABLE) || (flags & KILS_FOILINVUL)) && !(killtarget->flags5 & MF5_NODAMAGE)) if ((!(killtarget->flags2 & MF2_INVULNERABLE) || (flags & KILS_FOILINVUL)) &&
(!(killtarget->flags2 & MF7_BUDDHA) || (flags & KILS_FOILBUDDHA)) && !(killtarget->flags5 & MF5_NODAMAGE))
{ {
P_ExplodeMissile(killtarget, NULL, NULL); P_ExplodeMissile(killtarget, NULL, NULL);
} }
} }
if (!(flags & KILS_NOMONSTERS)) if (!(flags & KILS_NOMONSTERS))
{ {
if (flags & KILS_FOILINVUL) P_DamageMobj(killtarget, self, self, killtarget->health, damagetype, dmgFlags);
{
P_DamageMobj(killtarget, self, self, killtarget->health, damagetype, DMG_NO_ARMOR | DMG_NO_FACTOR | DMG_FOILINVUL);
}
else
{
P_DamageMobj(killtarget, self, self, killtarget->health, damagetype, DMG_NO_ARMOR | DMG_NO_FACTOR);
}
} }
} }

View file

@ -241,6 +241,9 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF7, NOTELESTOMP, AActor, flags7), DEFINE_FLAG(MF7, NOTELESTOMP, AActor, flags7),
DEFINE_FLAG(MF7, ALWAYSTELEFRAG, AActor, flags7), DEFINE_FLAG(MF7, ALWAYSTELEFRAG, AActor, flags7),
DEFINE_FLAG(MF7, WEAPONSPAWN, AActor, flags7), DEFINE_FLAG(MF7, WEAPONSPAWN, AActor, flags7),
DEFINE_FLAG(MF7, HARMFRIENDS, AActor, flags7),
DEFINE_FLAG(MF7, BUDDHA, AActor, flags7),
DEFINE_FLAG(MF7, FOILBUDDHA, AActor, flags7),
// Effect flags // Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
@ -311,6 +314,7 @@ static FFlagDef InventoryFlags[] =
DEFINE_FLAG(IF, NEVERRESPAWN, AInventory, ItemFlags), DEFINE_FLAG(IF, NEVERRESPAWN, AInventory, ItemFlags),
DEFINE_FLAG(IF, NOSCREENFLASH, AInventory, ItemFlags), DEFINE_FLAG(IF, NOSCREENFLASH, AInventory, ItemFlags),
DEFINE_FLAG(IF, TOSSED, AInventory, ItemFlags), DEFINE_FLAG(IF, TOSSED, AInventory, ItemFlags),
DEFINE_FLAG(IF, ALWAYSRESPAWN, AInventory, ItemFlags),
DEFINE_DEPRECATED_FLAG(PICKUPFLASH), DEFINE_DEPRECATED_FLAG(PICKUPFLASH),
DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP),}; DEFINE_DEPRECATED_FLAG(INTERHUBSTRIP),};

View file

@ -375,12 +375,14 @@ enum
const int KILS_FOILINVUL = 1; const int KILS_FOILINVUL = 1;
const int KILS_KILLMISSILES = 2; const int KILS_KILLMISSILES = 2;
const int KILS_NOMONSTERS = 4; const int KILS_NOMONSTERS = 4;
const int KILS_FOILBUDDHA = 8;
// Flags for A_Damage (Master/Target/Tracer/Children/Siblings/Self) series // Flags for A_Damage (Master/Target/Tracer/Children/Siblings/Self) series
const int DMSS_FOILINVUL = 1; const int DMSS_FOILINVUL = 1;
const int DMSS_AFFECTARMOR = 2; const int DMSS_AFFECTARMOR = 2;
const int DMSS_KILL = 4; const int DMSS_KILL = 4;
const int DMSS_NOFACTOR = 8; const int DMSS_NOFACTOR = 8;
const int DMSS_FOILBUDDHA = 16;
// Flags for A_AlertMonsters // Flags for A_AlertMonsters
const int AMF_TARGETEMITTER = 1; const int AMF_TARGETEMITTER = 1;

View file

@ -110,7 +110,7 @@ ACTOR StaffPuff2
// Gold wand ---------------------------------------------------------------- // Gold wand ----------------------------------------------------------------
ACTOR GoldWand : HereticWeapon ACTOR GoldWand : HereticWeapon 9042
{ {
Game Heretic Game Heretic
+BLOODSPLATTER +BLOODSPLATTER
@ -120,6 +120,7 @@ ACTOR GoldWand : HereticWeapon
Weapon.AmmoType "GoldWandAmmo" Weapon.AmmoType "GoldWandAmmo"
Weapon.SisterWeapon "GoldWandPowered" Weapon.SisterWeapon "GoldWandPowered"
Weapon.YAdjust 5 Weapon.YAdjust 5
Inventory.PickupMessage "$TXT_WPNGOLDWAND"
Obituary "$OB_MPGOLDWAND" Obituary "$OB_MPGOLDWAND"
Tag "$TAG_GOLDWAND" Tag "$TAG_GOLDWAND"
@ -127,6 +128,9 @@ ACTOR GoldWand : HereticWeapon
States States
{ {
Spawn:
GWAN A -1
Stop
Ready: Ready:
GWND A 1 A_WeaponReady GWND A 1 A_WeaponReady
Loop Loop

View file

@ -271,6 +271,11 @@ ACTOR PowerFrightener : Powerup native
Powerup.Duration -60 Powerup.Duration -60
} }
ACTOR PowerBuddha : Powerup native
{
Powerup.Duration -60
}
ACTOR PowerScanner : Powerup native ACTOR PowerScanner : Powerup native
{ {
Powerup.Duration -80 Powerup.Duration -80

View file

@ -9,7 +9,7 @@ ACTOR Peasant : StrifeHumanoid
Radius 20 Radius 20
Height 56 Height 56
Monster Monster
+FRIENDLY +NEVERTARGET
-COUNTKILL -COUNTKILL
+NOSPLASHALERT +NOSPLASHALERT
+FLOORCLIP +FLOORCLIP

View file

@ -292,6 +292,8 @@ STSTR_MUS = "Music Change";
STSTR_NOMUS = "IMPOSSIBLE SELECTION"; STSTR_NOMUS = "IMPOSSIBLE SELECTION";
STSTR_DQDON = "Degreelessness Mode ON"; STSTR_DQDON = "Degreelessness Mode ON";
STSTR_DQDOFF = "Degreelessness Mode OFF"; STSTR_DQDOFF = "Degreelessness Mode OFF";
STSTR_DQD2ON = "Ultimate Degreelessness Mode ON";
STSTR_DQD2OFF = "Ultimate Degreelessness Mode OFF";
STSTR_KFAADDED = "Very Happy Ammo Added"; STSTR_KFAADDED = "Very Happy Ammo Added";
STSTR_FAADDED = "Ammo (no keys) Added"; STSTR_FAADDED = "Ammo (no keys) Added";
STSTR_NCON = "No Clipping Mode ON"; STSTR_NCON = "No Clipping Mode ON";
@ -303,6 +305,8 @@ STSTR_CHOPPERS = "... doesn't suck - GM";
STSTR_CLEV = "Changing Level...\n"; STSTR_CLEV = "Changing Level...\n";
TXT_BUDDHAON = "Buddha mode ON"; TXT_BUDDHAON = "Buddha mode ON";
TXT_BUDDHAOFF = "Buddha mode OFF"; TXT_BUDDHAOFF = "Buddha mode OFF";
TXT_BUDDHA2ON = "Ultimate Buddha Mode ON";
TXT_BUDDHA2OFF = "Ultimate Buddha Mode OFF";
TXT_DEFAULTPICKUPMSG = "You got a pickup"; TXT_DEFAULTPICKUPMSG = "You got a pickup";
E1TEXT = E1TEXT =
@ -1242,6 +1246,7 @@ TXT_AMMOPHOENIXROD2 = "INFERNO ORB";
// Weapons // Weapons
TXT_WPNGOLDWAND = "GOLD WAND";
TXT_WPNMACE = "FIREMACE"; TXT_WPNMACE = "FIREMACE";
TXT_WPNCROSSBOW = "ETHEREAL CROSSBOW"; TXT_WPNCROSSBOW = "ETHEREAL CROSSBOW";
TXT_WPNBLASTER = "DRAGON CLAW"; TXT_WPNBLASTER = "DRAGON CLAW";

View file

@ -1,3 +1,8 @@
Gameinfo
{
CheatKey = "maparrows/key.txt"
EasyKey = "maparrows/ravenkey.txt"
}
Intermission Inter_Titlescreen Intermission Inter_Titlescreen
{ {

View file

@ -1300,6 +1300,7 @@ OptionMenu "CompatibilityOptions"
Option "Ignore Y offsets on masked midtextures", "compat_MASKEDMIDTEX", "YesNo" Option "Ignore Y offsets on masked midtextures", "compat_MASKEDMIDTEX", "YesNo"
Option "Cannot travel straight NSEW", "compat_badangles", "YesNo" Option "Cannot travel straight NSEW", "compat_badangles", "YesNo"
Option "Use Doom's floor motion behavior", "compat_floormove", "YesNo" Option "Use Doom's floor motion behavior", "compat_floormove", "YesNo"
Option "Sounds stop when actor vanishes", "compat_soundcutoff", "YesNo"
Class "CompatibilityMenu" Class "CompatibilityMenu"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

After

Width:  |  Height:  |  Size: 377 B