diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 31ba7c94f4..1012ddb6a6 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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. diff --git a/src/actor.h b/src/actor.h index 62851f7f48..d36fe321a4 100644 --- a/src/actor.h +++ b/src/actor.h @@ -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 --- diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 39128fdfe8..71ae8cb96a 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -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 // diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp index 61605f86fc..cf3745e2af 100644 --- a/src/g_shared/a_armor.cpp +++ b/src/g_shared/a_armor.cpp @@ -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); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index bdff394f29..9a29d2d38b 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1387,7 +1387,7 @@ IMPLEMENT_CLASS (AHealth) //=========================================================================== // -// AHealth :: TryPickup +// AHealth :: PickupMessage // //=========================================================================== const char *AHealth::PickupMessage () diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index ef100357e7..f48289cbb8 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -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: diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 5f8d42a9c8..903cf1efc0 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -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; } diff --git a/src/p_map.cpp b/src/p_map.cpp index f1ef571afd..27a32e6397 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f838930f10..458997b616 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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) { diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d9a14e4252..02108f7fb7 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -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); } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 9861355926..cf77825a1c 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -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), }; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index bfe1023ee9..68fe77fe29 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -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. // //========================================================================== diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index fc2765a49e..9d56c7d073 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -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); +} + //========================================================================== // //========================================================================== diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index e758214fe0..295672d934 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -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 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 itemtype, int amount = 0); action native A_TakeInventory(class itemtype, int amount = 0); action native A_SpawnItem(class itemtype, float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); diff --git a/wadsrc/static/actors/doom/doomweapons.txt b/wadsrc/static/actors/doom/doomweapons.txt index 3abab7dbf2..be3fa9e322 100644 --- a/wadsrc/static/actors/doom/doomweapons.txt +++ b/wadsrc/static/actors/doom/doomweapons.txt @@ -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 diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 03285eea50..bd084813b2 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -25,6 +25,7 @@ ACTOR Inventory native action native A_LoadShotgun2(); action native A_CloseShotgun2(); action native A_FireCGun(); + action native A_FireSTGrenade(class grenadetype = "Grenade"); action native A_FireMissile(); action native A_FirePlasma(); action native A_FireRailgun(); diff --git a/wadsrc/static/sndinfo.txt b/wadsrc/static/sndinfo.txt index 8a67640433..72912cbf2e 100644 --- a/wadsrc/static/sndinfo.txt +++ b/wadsrc/static/sndinfo.txt @@ -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.