- Added Gez's Skulltag feature patch, including:

* BUMPSPECIAL flag: actors with this flag will run their special if collided on by a player
    * WEAPON.NOAUTOAIM flag, though it is restricted to attacks that spawn a missile (it will not affect autoaim settings for a hitscan or railgun, and that's deliberate)
    * A_FireSTGrenade codepointer, extended to be parameterizable
    * The grenade (as the default actor for A_FireSTGrenade)
    * Protective armors à la RedArmor: they work with a DamageFactor; for example to recreate the RedArmor from Skulltag, copy its code from skulltag.pk3 but remove the "native" keyword and add DamageFactor "Fire" 0.1 to its properties.


SVN r1661 (trunk)
This commit is contained in:
Christoph Oelckers 2009-06-09 17:13:03 +00:00
parent 4fcd64d2c1
commit 523cf6acb2
17 changed files with 154 additions and 23 deletions

View File

@ -1,4 +1,13 @@
June 9, 2009 (Changes by Graf Zahl)
- Added Gez's Skulltag feature patch, including:
* BUMPSPECIAL flag: actors with this flag will run their special if collided on by a player
* WEAPON.NOAUTOAIM flag, though it is restricted to attacks that spawn a missile (it will
not affect autoaim settings for a hitscan or railgun, and that's deliberate)
* A_FireSTGrenade codepointer, extended to be parameterizable
* The grenade (as the default actor for A_FireSTGrenade)
* Protective armors à la RedArmor: they work with a DamageFactor; for example to
recreate the RedArmor from Skulltag, copy its code from skulltag.pk3 but remove
the "native" keyword and add DamageFactor "Fire" 0.1 to its properties.
- Fixed: I_ShutdownInput must NULL all pointers because it can be called twice
if an ENDOOM screen is displayed.
- Fixed: R_DrawSkyStriped used frontyScale without initializing it first.

View File

@ -309,6 +309,7 @@ enum
MF6_MTHRUSPECIES = 0x00000004, // Missile passes through actors of its shooter's species.
MF6_FORCEPAIN = 0x00000008, // forces target into painstate (unless it has the NOPAIN flag)
MF6_NOFEAR = 0x00000010, // Not scared of frightening players
MF6_BUMPSPECIAL = 0x00000020, // Actor executes its special when being collided (as the ST flag)
// --- mobj.renderflags ---

View File

@ -361,6 +361,34 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile)
P_SpawnPlayerMissile (self, PClass::FindClass("Rocket"));
}
//
// A_FireSTGrenade: not exactly backported from ST, but should work the same
//
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade)
{
player_t *player;
ACTION_PARAM_START(1);
ACTION_PARAM_CLASS(grenade, 0);
if (grenade == NULL) return;
if (NULL == (player = self->player))
{
return;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return;
}
// Temporarily raise the pitch to send the grenade slightly upwards
fixed_t SavedPlayerPitch = self->pitch;
self->pitch -= (1152 << FRACBITS);
P_SpawnPlayerMissile(self, grenade);
self->pitch = SavedPlayerPitch;
}
//
// A_FirePlasma
//

View File

@ -139,6 +139,7 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
// The armor has become useless
SavePercent = 0;
ArmorType = NAME_None; // Not NAME_BasicArmor.
// Now see if the player has some more armor in their inventory
// and use it if so. As in Strife, the best armor is used up first.
ABasicArmorPickup *best = NULL;
@ -162,6 +163,24 @@ void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
}
damage = newdamage;
}
// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
if ((damage > 0) && (ArmorType != NAME_None)) // BasicArmor is not going to have any damage factor, so skip it.
{
// This code is taken and adapted from APowerProtection::ModifyDamage().
// The differences include not checking for the NAME_None key (doesn't seem appropriate here),
// not using a default value, and of course the way the damage factor info is obtained.
const fixed_t *pdf = NULL;
DmgFactors *df = PClass::FindClass(ArmorType)->ActorInfo->DamageFactors;
if (df != NULL && df->CountUsed() != 0)
{
pdf = df->CheckKey(damageType);
if (pdf != NULL)
{
damage = newdamage = FixedMul(damage, *pdf);
}
}
}
if (Inventory != NULL)
{
Inventory->AbsorbDamage (damage, damageType, newdamage);

View File

@ -1387,7 +1387,7 @@ IMPLEMENT_CLASS (AHealth)
//===========================================================================
//
// AHealth :: TryPickup
// AHealth :: PickupMessage
//
//===========================================================================
const char *AHealth::PickupMessage ()

View File

@ -317,9 +317,10 @@ enum
WIF_POWERED_UP = 0x00000400, // this is a tome-of-power'ed version of its sister
WIF_AMMO_CHECKBOTH = 0x00000800, // check for both primary and secondary fire before switching it off
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 kickba
WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback
WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles)
WIF_CHEATNOTWEAPON = 1<<27, // Give cheat considers this not a weapon (used by Sigil)
WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil)
// Flags used only by bot AI:

View File

@ -2957,7 +2957,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
{
FName p(FBehavior::StaticLookupString(args[0]));
ABasicArmor * armor = (ABasicArmor *) players[args[1]].mo->FindInventory(NAME_BasicArmor);
if (armor->ArmorType == p) return 1;
if (armor && armor->ArmorType == p) return armor->Amount;
}
return 0;
}

View File

@ -826,6 +826,13 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
return false;
}
}
// Check for players touching a thing with MF6_BUMPSPECIAL
// A blind recreation of what the Skulltag code is probably like.
if (tm.thing->player && (thing->flags6 & MF6_BUMPSPECIAL) && thing->special)
{
LineSpecials[thing->special] (NULL, tm.thing, false, thing->args[0],
thing->args[1], thing->args[2], thing->args[3], thing->args[4]);
}
// Check for missile
if (tm.thing->flags & MF_MISSILE)
{

View File

@ -4999,21 +4999,30 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z,
AActor *linetarget;
int vrange = nofreeaim? ANGLE_1*35 : 0;
// see which target is to be aimed at
i = 2;
do
// Note: NOAUTOAIM is implemented only here, and not in the hitscan or rail attack functions.
// That is because it is only justified for projectiles affected by gravity, not for other attacks.
if (source && source->player && source->player->ReadyWeapon && (source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM))
{
an = angle + angdiff[i];
pitch = P_AimLineAttack (source, an, 16*64*FRACUNIT, &linetarget, vrange);
if (source->player != NULL &&
!nofreeaim &&
level.IsFreelookAllowed() &&
source->player->userinfo.GetAimDist() <= ANGLE_1/2)
// Keep exactly the same angle and pitch as the player's own aim
pitch = source->pitch; linetarget = NULL;
}
else // see which target is to be aimed at
{
i = 2;
do
{
break;
}
} while (linetarget == NULL && --i >= 0);
an = angle + angdiff[i];
pitch = P_AimLineAttack (source, an, 16*64*FRACUNIT, &linetarget, vrange);
if (source->player != NULL &&
!nofreeaim &&
level.IsFreelookAllowed() &&
source->player->userinfo.GetAimDist() <= ANGLE_1/2)
{
break;
}
} while (linetarget == NULL && --i >= 0);
}
if (linetarget == NULL)
{

View File

@ -535,12 +535,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfArmorType)
ACTION_PARAM_START(3);
ACTION_PARAM_NAME(Type, 0);
ACTION_PARAM_STATE(JumpOffset, 1);
ACTION_PARAM_INT(amount, 1);
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
ABasicArmor * armor = (ABasicArmor *) self->FindInventory(NAME_BasicArmor);
if (armor && armor->ArmorType == Type)
if (armor && armor->ArmorType == Type && armor->Amount >= amount)
ACTION_JUMP(JumpOffset);
}

View File

@ -214,6 +214,7 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF6, MTHRUSPECIES, AActor, flags6),
DEFINE_FLAG(MF6, FORCEPAIN, AActor, flags6),
DEFINE_FLAG(MF6, NOFEAR, AActor, flags6),
DEFINE_FLAG(MF6, BUMPSPECIAL, AActor, flags6),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
@ -234,9 +235,12 @@ static FFlagDef ActorFlags[]=
DEFINE_DEPRECATED_FLAG(HERETICBOUNCE),
DEFINE_DEPRECATED_FLAG(HEXENBOUNCE),
DEFINE_DEPRECATED_FLAG(DOOMBOUNCE),
DEFINE_DUMMY_FLAG(NONETID),
DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN),
DEFINE_DUMMY_FLAG(CLIENTSIDEONLY),
// Various Skulltag flags that are quite irrelevant to ZDoom
DEFINE_DUMMY_FLAG(NONETID), // netcode-based
DEFINE_DUMMY_FLAG(ALLOWCLIENTSPAWN), // netcode-based
DEFINE_DUMMY_FLAG(CLIENTSIDEONLY), // netcode-based
DEFINE_DUMMY_FLAG(EXPLODEONDEATH), // seems useless
};
static FFlagDef InventoryFlags[] =
@ -281,6 +285,7 @@ static FFlagDef WeaponFlags[] =
DEFINE_FLAG(WIF, CHEATNOTWEAPON, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF, NO_AUTO_SWITCH, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF, AMMO_CHECKBOTH, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF, NOAUTOAIM, AWeapon, WeaponFlags),
DEFINE_DUMMY_FLAG(NOLMS),
};

View File

@ -60,7 +60,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def);
//
// ParseParameter
//
// Parses aparameter - either a default in a function declaration
// Parses a parameter - either a default in a function declaration
// or an argument in a function call.
//
//==========================================================================

View File

@ -1262,6 +1262,14 @@ DEFINE_CLASS_PROPERTY(pickupsound, S, Inventory)
defaults->PickupSound = str;
}
//==========================================================================
// Dummy for Skulltag compatibility...
//==========================================================================
DEFINE_CLASS_PROPERTY(pickupannouncerentry, S, Inventory)
{
PROP_STRING_PARM(str, 0);
}
//==========================================================================
//
//==========================================================================

View File

@ -176,7 +176,7 @@ ACTOR Actor native //: Thinker
action native A_JumpIfHealthLower(int health, state label);
action native A_JumpIfCloser(float distance, state label);
action native A_JumpIfInventory(class<Inventory> itemtype, int itemamount, state label);
action native A_JumpIfArmorType(string Type, state label);
action native A_JumpIfArmorType(string Type, state label, int amount = 1);
action native A_GiveInventory(class<Inventory> itemtype, int amount = 0);
action native A_TakeInventory(class<Inventory> itemtype, int amount = 0);
action native A_SpawnItem(class<Actor> itemtype, float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false);

View File

@ -340,6 +340,45 @@ ACTOR Rocket
}
}
// --------------------------------------------------------------------------
//
// Grenade -- Taken and adapted from Skulltag
//
// --------------------------------------------------------------------------
ACTOR Grenade
{
SpawnID 216
Radius 8
Height 8
Speed 25
Damage 20
Projectile
-NOGRAVITY
+RANDOMIZE
+DEHEXPLOSION
+GRENADETRAIL
BounceType "Doom"
Gravity 0.25
SeeSound "weapons/grenlf"
DeathSound "weapons/grenlx"
BounceSound "weapons/grbnce"
Obituary "$OB_GRENADE"
DamageType Grenade
States
{
Spawn:
SGRN A 1 Bright
Loop
Death:
MISL B 8 Bright A_Explode
MISL C 6 Bright
MISL D 4 Bright
Stop
}
}
// --------------------------------------------------------------------------
//
// Plasma rifle

View File

@ -25,6 +25,7 @@ ACTOR Inventory native
action native A_LoadShotgun2();
action native A_CloseShotgun2();
action native A_FireCGun();
action native A_FireSTGrenade(class<Actor> grenadetype = "Grenade");
action native A_FireMissile();
action native A_FirePlasma();
action native A_FireRailgun();

View File

@ -201,6 +201,9 @@ weapons/plasmax dsfirxpl
weapons/bfgf dsbfg
weapons/bfgx dsrxplod
weapons/railgf railgf1
weapons/grbnce dsbounce
weapons/grenlx dsgrnexp
weapons/grenlf dsglaunc
// Problem: weapons/rocklx needs to be unlimited but
// is also used for the MAP30 brain explosion.