- Added a compatibility option to restore the original behavior of the Invisibility

powerup.
- Changed: Weapons are no longer checked for the EXTREMEDEATH and NOEXTREMEDEATH flags.
  For all damage related actions it will always be the projectile (or puff for hitscan
  attacks) that is treated as the damage inflictor.
- Fixed: Hexen's fourth weapons made extreme death depend on the weapon the player
  is holding, not the projectile that did the kill. The WIF_EXTREME_DEATH flag
  no longer exists as a result.
- Expanded PowerSpeed so that subclasses can be derived that alter the speed factor.
- Added an MF5_USESPECIAL flag that allows using things to execute their specials.
- added MF4_FORCERADIUSDMG flag so that exploding items can be created which
  are able to hurt boss monsters.
- moved ML_BLOCK_PLAYERS to the value 0x4000 to bring it in line with Skulltag's 
  implementation.


SVN r530 (trunk)
This commit is contained in:
Christoph Oelckers 2007-05-12 11:14:09 +00:00
parent d60a5ee1b9
commit a6a5821f04
22 changed files with 876 additions and 676 deletions

View file

@ -1,3 +1,19 @@
May 12, 2007 (Changes by Graf Zahl)
- Added a compatibility option to restore the original behavior of the Invisibility
powerup.
- Changed: Weapons are no longer checked for the EXTREMEDEATH and NOEXTREMEDEATH flags.
For all damage related actions it will always be the projectile (or puff for hitscan
attacks) that is treated as the damage inflictor.
- Fixed: Hexen's fourth weapons made extreme death depend on the weapon the player
is holding, not the projectile that did the kill. The WIF_EXTREME_DEATH flag
no longer exists as a result.
- Expanded PowerSpeed so that subclasses can be derived that alter the speed factor.
- Added an MF5_USESPECIAL flag that allows using things to execute their specials.
- added MF4_FORCERADIUSDMG flag so that exploding items can be created which
are able to hurt boss monsters.
- moved ML_BLOCK_PLAYERS to the value 0x4000 to bring it in line with Skulltag's
implementation.
May 9, 2007 (Changes by Graf Zahl)
- added Skulltag's custom F1 help screen MAPINFO option.

View file

@ -255,7 +255,7 @@ enum
MF4_CANUSEWALLS = 0x00000200, // Can activate 'use' specials
MF4_MISSILEMORE = 0x00000400, // increases the chance of a missile attack
MF4_MISSILEEVENMORE = 0x00000800, // significantly increases the chance of a missile attack
// unused flag
MF4_FORCERADIUSDMG = 0x00001000, // if put on an object it will override MF3_NORADIUSDMG
MF4_DONTFALL = 0x00002000, // Doesn't have NOGRAVITY disabled when dying.
MF4_SEESDAGGERS = 0x00004000, // This actor can see you striking with a dagger
MF4_INCOMBAT = 0x00008000, // Don't alert others when attacked by a dagger
@ -289,6 +289,7 @@ enum
MF5_DEHEXPLOSION = 0x00000400, // Use the DEHACKED explosion options when this projectile explodes
MF5_PIERCEARMOR = 0x00000800, // Armor doesn't protect against damage from this actor
MF5_NOBLOODDECALS = 0x00001000, // Actor bleeds but doesn't spawn blood decals
MF5_USESPECIAL = 0x00002000, // Actor executes its special when being 'used'.
// --- mobj.renderflags ---

View file

@ -400,6 +400,7 @@ CVAR (Flag, compat_dehhealth, compatflags, COMPATF_DEHHEALTH);
CVAR (Flag, compat_trace, compatflags, COMPATF_TRACE);
CVAR (Flag, compat_dropoff, compatflags, COMPATF_DROPOFF);
CVAR (Flag, compat_boomscroll, compatflags, COMPATF_BOOMSCROLL);
CVAR (Flag, compat_invisibility,compatflags, COMPATF_INVISIBILITY);
//==========================================================================
//

View file

@ -162,12 +162,11 @@ typedef enum
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,
CF_REGENERATION = 0x20000, // Player owns a regeneration artifact
CF_HIGHJUMP = 0x40000, // more Skulltag flags. Implemetation not guaranteed though. ;)
CF_REFLECTION = 0x80000,
CF_PROSPERITY = 0x100000,
CF_DOUBLEFIRINGSPEED= 0x200000,
} cheat_t;
#define WPIECE1 1

View file

@ -151,6 +151,7 @@ static inline int GET_SPAC (int flags)
// [RH] Monsters (as well as players) can active the line
#define ML_MONSTERSCANACTIVATE 0x2000
#define ML_BLOCK_PLAYERS 0x4000
// [RH] BOOM's ML_PASSUSE flag (conflicts with ML_REPEATSPECIAL)
#define ML_PASSUSE_BOOM 0x0200
@ -175,7 +176,6 @@ static inline int GET_SPAC (int flags)
#define ML_BLOCK_FLOATERS 0x00040000
#define ML_CLIP_MIDTEX 0x00080000 // Automatic for every Strife line
#define ML_WRAP_MIDTEX 0x00100000
#define ML_BLOCK_PLAYERS 0x00200000
// Sector definition, from editing
typedef struct

View file

@ -275,6 +275,7 @@ enum
COMPATF_TRACE = 1 << 13, // Trace ignores lines with the same sector on both sides
COMPATF_DROPOFF = 1 << 14, // Monsters cannot move when hanging over a dropoff
COMPATF_BOOMSCROLL = 1 << 15, // Scrolling sectors are additive like in Boom
COMPATF_INVISIBILITY = 1 << 16, // Monsters can see semi-invisible players
};
// phares 3/20/98:

View file

@ -198,7 +198,7 @@ IMPLEMENT_ACTOR (ACWeapWraithverge, Hexen, -1, 0)
PROP_SpawnState (0)
PROP_Weapon_SelectionOrder (3000)
PROP_Weapon_Flags (WIF_PRIMARY_USES_BOTH | WIF_EXTREME_DEATH)
PROP_Weapon_Flags (WIF_PRIMARY_USES_BOTH)
PROP_Weapon_AmmoUse1 (18)
PROP_Weapon_AmmoUse2 (18)
PROP_Weapon_AmmoGive1 (0)
@ -238,6 +238,7 @@ IMPLEMENT_ACTOR (AHolyMissile, Hexen, -1, 0)
PROP_Damage (4)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT)
PROP_Flags4 (MF4_EXTREMEDEATH)
PROP_SpawnState (0)
PROP_DeathState (4)
@ -322,6 +323,7 @@ IMPLEMENT_ACTOR (AHolySpirit, Hexen, -1, 0)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT|MF2_RIP|MF2_IMPACT|MF2_PCROSS|MF2_SEEKERMISSILE)
PROP_Flags3 (MF3_FOILINVUL|MF3_SKYEXPLODE|MF3_NOEXPLODEFLOOR|MF3_CANBLAST)
PROP_Flags4 (MF4_EXTREMEDEATH)
PROP_RenderStyle (STYLE_Translucent)
PROP_Alpha (HX_ALTSHADOW)

View file

@ -188,7 +188,7 @@ IMPLEMENT_ACTOR (AFWeapQuietus, Hexen, -1, 0)
PROP_SpawnState (0)
PROP_Weapon_SelectionOrder (2900)
PROP_Weapon_Flags (WIF_PRIMARY_USES_BOTH | WIF_EXTREME_DEATH)
PROP_Weapon_Flags (WIF_PRIMARY_USES_BOTH)
PROP_Weapon_AmmoUse1 (14)
PROP_Weapon_AmmoUse2 (14)
PROP_Weapon_AmmoGive1 (0)
@ -242,6 +242,7 @@ IMPLEMENT_ACTOR (AFSwordMissile, Hexen, -1, 0)
PROP_Damage (8)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS)
PROP_Flags4 (MF4_EXTREMEDEATH)
PROP_RenderStyle (STYLE_Add)
PROP_SpawnState (S_FSWORD_MISSILE1)

View file

@ -218,7 +218,7 @@ IMPLEMENT_ACTOR (AMWeapBloodscourge, Hexen, -1, 0)
PROP_SpawnState (0)
PROP_Weapon_SelectionOrder (3100)
PROP_Weapon_Flags (WIF_PRIMARY_USES_BOTH | WIF_EXTREME_DEATH)
PROP_Weapon_Flags (WIF_PRIMARY_USES_BOTH)
PROP_Weapon_AmmoUse1 (15)
PROP_Weapon_AmmoUse2 (15)
PROP_Weapon_UpState (S_MSTAFFUP)
@ -274,6 +274,7 @@ IMPLEMENT_ACTOR (AMageStaffFX2, Hexen, -1, 0)
PROP_DamageType (NAME_Fire)
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS|MF2_SEEKERMISSILE)
PROP_Flags4 (MF4_EXTREMEDEATH)
PROP_SpawnState (S_MSTAFF_FX2_1)
PROP_DeathState (S_MSTAFF_FX2_X1)

View file

@ -281,6 +281,7 @@ static const char *MapInfoMapLevel[] =
"compat_trace",
"compat_dropoff",
"compat_boomscroll",
"compat_invisibility",
"bordertexture",
"f1", // [RC] F1 help
NULL
@ -415,6 +416,7 @@ MapHandlers[] =
{ MITYPE_COMPATFLAG, COMPATF_TRACE},
{ MITYPE_COMPATFLAG, COMPATF_DROPOFF},
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_COMPATFLAG, COMPATF_INVISIBILITY},
{ MITYPE_LUMPNAME, lioffset(bordertexture), 0 },
{ MITYPE_F1, lioffset(f1), 0, },
};

View file

@ -1163,19 +1163,21 @@ void APlayerSpeedTrail::Tick ()
// Speed Powerup -------------------------------------------------------------
IMPLEMENT_STATELESS_ACTOR (APowerSpeed, Any, -1, 0)
PROP_SpeedFixed(3*FRACUNIT/2)
PROP_Powerup_EffectTics (SPEEDTICS)
PROP_Inventory_Icon ("SPBOOT0")
END_DEFAULTS
//===========================================================================
//
// APowerSpeed :: InitEffect
// APowerSpeed :: GetSpeedFactor
//
//===========================================================================
void APowerSpeed::InitEffect ()
fixed_t APowerSpeed ::GetSpeedFactor ()
{
Owner->player->cheats |= CF_SPEED;
if (Inventory != NULL) return FixedMul(Speed, Inventory->GetSpeedFactor());
else return Speed;
}
//===========================================================================
@ -1194,6 +1196,10 @@ void APowerSpeed::DoEffect ()
if (level.time & 1)
return;
// check if another speed item is present to avoid multiple drawing of the speed trail.
if (Inventory != NULL && Inventory->GetSpeedFactor() > FRACUNIT)
return;
if (P_AproxDistance (Owner->momx, Owner->momy) <= 12*FRACUNIT)
return;
@ -1219,20 +1225,6 @@ void APowerSpeed::DoEffect ()
}
}
//===========================================================================
//
// APowerSpeed :: EndEffect
//
//===========================================================================
void APowerSpeed::EndEffect ()
{
if (Owner != NULL && Owner->player != NULL)
{
Owner->player->cheats &= ~CF_SPEED;
}
}
// Minotaur (aka Dark Servant) powerup ---------------------------------------
IMPLEMENT_STATELESS_ACTOR (APowerMinotaur, Any, -1, 0)

View file

@ -170,9 +170,8 @@ class APowerSpeed : public APowerup
{
DECLARE_STATELESS_ACTOR (APowerSpeed, APowerup)
protected:
void InitEffect ();
void DoEffect ();
void EndEffect ();
fixed_t GetSpeedFactor();
};
class APowerMinotaur : public APowerup

View file

@ -783,6 +783,24 @@ void AInventory::ModifyDamage (int damage, FName damageType, int &newdamage, boo
}
}
//===========================================================================
//
// AInventory :: GetSpeedFactor
//
//===========================================================================
fixed_t AInventory::GetSpeedFactor ()
{
if (Inventory != NULL)
{
return Inventory->GetSpeedFactor();
}
else
{
return FRACUNIT;
}
}
//===========================================================================
//
// AInventory :: AlterWeaponSprite

View file

@ -153,6 +153,7 @@ public:
virtual void AbsorbDamage (int damage, FName damageType, int &newdamage);
virtual void ModifyDamage (int damage, FName damageType, int &newdamage, bool passive);
virtual fixed_t GetSpeedFactor();
virtual int AlterWeaponSprite (vissprite_t *vis);
virtual PalEntry GetBlend ();
@ -265,7 +266,7 @@ enum
WIF_ALT_USES_BOTH = 0x00000100, // alternate fire uses both ammo
WIF_WIMPY_WEAPON = 0x00000200, // change away when ammo for another weapon is replenished
WIF_POWERED_UP = 0x00000400, // this is a tome-of-power'ed version of its sister
WIF_EXTREME_DEATH = 0x00000800, // weapon always causes an extreme death
WIF_NO_AUTO_SWITCH = 0x00001000, // never switch to this weapon when it's picked up
WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback

View file

@ -1024,6 +1024,7 @@ static menuitem_t CompatibilityItems[] = {
{ bitflag, "DEH health settings like Doom2.exe", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_DEHHEALTH} },
{ bitflag, "Self ref. sectors don't block shots", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_TRACE} },
{ bitflag, "Monsters get stuck over dropoffs", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_DROPOFF} },
{ bitflag, "Monsters see invisible players", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_INVISIBILITY} },
{ bitflag, "Boom scrollers are additive", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_BOOMSCROLL} },
{ discrete, "Interpolate monster movement", {&nomonsterinterpolation}, {2.0}, {0.0}, {0.0}, {NoYes} },

View file

@ -1512,8 +1512,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
continue; // behind back
}
}
if (player->mo->RenderStyle == STYLE_Translucent ||
player->mo->RenderStyle == STYLE_OptFuzzy)
if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
player->mo->flags3 & MF3_GHOST)
{
if ((P_AproxDistance (player->mo->x - actor->x,
player->mo->y - actor->y) > 2*MELEERANGE)

View file

@ -629,8 +629,7 @@ void AActor::Die (AActor *source, AActor *inflictor)
}
if (diestate == NULL)
{
int flags4 = !inflictor ? 0 : inflictor->player && inflictor->player->ReadyWeapon ?
inflictor->player->ReadyWeapon->flags4 : inflictor->flags4;
int flags4 = inflictor == NULL ? 0 : inflictor->flags4;
int gibhealth = -abs(GetClass()->Meta.GetMetaInt (AMETA_GibHealth,
gameinfo.gametype == GAME_Doom ? -GetDefault()->health : -GetDefault()->health/2));
@ -904,7 +903,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
// Handle passive damage modifiers (e.g. PowerProtection)
if (target->Inventory != NULL)
{
int olddam = damage;
int olddam = damage;
target->Inventory->ModifyDamage(olddam, mod, damage, true);
if (olddam != damage && damage <= 0) return;
}
@ -1127,12 +1126,6 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
source = source->tracer;
}
}
if (source && (source->player) && source->player->ReadyWeapon != NULL &&
(source->player->ReadyWeapon->WeaponFlags & WIF_EXTREME_DEATH))
{
// Always extreme death from fourth weapon
target->health = -target->GetDefault()->health * 3;
}
target->Die (source, inflictor);
return;
}

View file

@ -3267,10 +3267,10 @@ bool PTR_UseTraverse (intercept_t *in)
if (usething==in->d.thing) return true;
// Check thing
// Check for puzzle item use
if (in->d.thing->special == USE_PUZZLE_ITEM_SPECIAL)
// Check for puzzle item use or USESPECIAL flag
if (in->d.thing->flags5 & MF5_USESPECIAL || in->d.thing->special == USE_PUZZLE_ITEM_SPECIAL)
{
if (LineSpecials[USE_PUZZLE_ITEM_SPECIAL] (NULL, usething, false,
if (LineSpecials[in->d.thing->special] (NULL, usething, false,
in->d.thing->args[0], in->d.thing->args[1], in->d.thing->args[2],
in->d.thing->args[3], in->d.thing->args[4]))
return false;
@ -3565,7 +3565,7 @@ bool PIT_RadiusAttack (AActor *thing)
// Boss spider and cyborg and Heretic's ep >= 2 bosses
// take no damage from concussion.
if (thing->flags3 & MF3_NORADIUSDMG)
if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG))
return true;
if (!DamageSource && thing == bombsource)

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))
{
// Freeze player for about .5 sec
if (!(thing->player->cheats & CF_SPEED))
if (thing->Inventory == NULL || thing->Inventory->GetSpeedFactor() <= FRACUNIT)
thing->reactiontime = 18;
}
if (thing->flags & MF_MISSILE)

View file

@ -1120,10 +1120,11 @@ void APlayerPawn::TweakSpeeds (int &forward, int &side)
side = FixedMul (side, SideMove2);
}
if ((player->cheats & CF_SPEED) && !player->morphTics)
{ // Adjust for a player with a speed artifact
forward = (3*forward)>>1;
side = (3*side)>>1;
if (!player->morphTics && Inventory != NULL)
{
fixed_t factor = Inventory->GetSpeedFactor ();
forward = FixedMul(forward, factor);
side = FixedMul(side, factor);
}
}

View file

@ -195,6 +195,7 @@ static flagdef ActorFlags[]=
DEFINE_FLAG(MF4, CANUSEWALLS, AActor, flags4),
DEFINE_FLAG(MF4, MISSILEMORE, AActor, flags4),
DEFINE_FLAG(MF4, MISSILEEVENMORE, AActor, flags4),
DEFINE_FLAG(MF4, FORCERADIUSDMG, AActor, flags4),
DEFINE_FLAG(MF4, DONTFALL, AActor, flags4),
DEFINE_FLAG(MF4, SEESDAGGERS, AActor, flags4),
DEFINE_FLAG(MF4, INCOMBAT, AActor, flags4),
@ -227,6 +228,7 @@ static flagdef ActorFlags[]=
DEFINE_FLAG(MF5, DEHEXPLOSION, AActor, flags5),
DEFINE_FLAG(MF5, PIERCEARMOR, AActor, flags5),
DEFINE_FLAG(MF5, NOBLOODDECALS, AActor, flags5),
DEFINE_FLAG(MF5, USESPECIAL, AActor, flags5),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
@ -4467,12 +4469,181 @@ void ParseClass()
}
}
bool ParseFunctionCall(Baggage &bag, FState & state)
{
// Make the action name lowercase to satisfy the gperf hashers
strlwr (sc_String);
FString funcname = sc_String;
int minreq=0;
memset(&state, 0, sizeof(state));
if (DoSpecialFunctions(state, false, &minreq, bag))
{
return true;
}
PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (FName(sc_String, true), true);
if (sym != NULL && sym->SymbolType == SYM_ActionFunction)
{
PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym);
state.Action = afd->Function;
if (!afd->Arguments.IsEmpty())
{
const char *params = afd->Arguments.GetChars();
int numparams = (int)afd->Arguments.Len();
int v;
if (!islower(*params))
{
SC_MustGetToken('(');
}
else
{
if (!SC_CheckToken('('))
{
return true;
}
}
int paramindex = PrepareStateParameters(&state, numparams);
int paramstart = paramindex;
bool varargs = params[numparams - 1] == '+';
if (varargs)
{
StateParameters[paramindex++] = 0;
}
while (*params)
{
switch(*params)
{
case 'I':
case 'i': // Integer
SC_MustGetNumber();
v=sc_Number;
break;
case 'F':
case 'f': // Fixed point
SC_MustGetFloat();
v=fixed_t(sc_Float*FRACUNIT);
break;
case 'S':
case 's': // Sound name
SC_MustGetString();
v=S_FindSound(sc_String);
break;
case 'M':
case 'm': // Actor name
case 'T':
case 't': // String
SC_MustGetString();
v = (int)(sc_String[0] ? FName(sc_String) : NAME_None);
break;
case 'L':
case 'l': // Jump label
SC_ScriptError("You cannot use state jump calls in action functions (%s tries to call %s)\n",
funcname.GetChars(), afd->SymbolName.GetChars());
break;
case 'C':
case 'c': // Color
SC_MustGetString ();
if (SC_Compare("none"))
{
v = -1;
}
else
{
int c = V_GetColor (NULL, sc_String);
// 0 needs to be the default so we have to mark the color.
v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
}
break;
case 'X':
case 'x':
v = ParseExpression (false, bag.Info->Class);
break;
case 'Y':
case 'y':
v = ParseExpression (true, bag.Info->Class);
break;
default:
assert(false);
v = -1;
break;
}
StateParameters[paramindex++] = v;
params++;
if (varargs)
{
StateParameters[paramstart]++;
}
if (*params)
{
if (*params == '+')
{
if (SC_CheckString(")"))
{
return true;
}
params--;
v = 0;
StateParameters.Push(v);
}
else if ((islower(*params) || *params=='!') && SC_CheckString(")"))
{
return true;
}
SC_MustGetStringName (",");
}
}
SC_MustGetStringName(")");
}
else
{
SC_MustGetString();
if (SC_Compare("("))
{
SC_ScriptError("You cannot pass parameters to '%s'\n",funcname.GetChars());
}
SC_UnGet();
}
return true;
}
return false;
}
void ParseActionFunction()
{
FState state;
Baggage bag;
bag.Info=RUNTIME_CLASS(AActor)->ActorInfo;
// for now only void functions with no parameters
SC_MustGetToken(TK_Void);
SC_MustGetString();
FName funcname = sc_String;
SC_MustGetToken('(');
SC_MustGetToken(')');
SC_MustGetToken('{');
// All this can do for the moment is parse a list of simple function calls, nothing more
while (SC_MustGetString(), sc_TokenType != '}');
{
ParseFunctionCall(bag, state);
SC_MustGetToken(';');
// Todo: Take the state's content and make a list of it.
}
}

File diff suppressed because it is too large Load diff