diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 0ed2b90cf..d14f04a2f 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,14 @@ November 26, 2006 (Changes by Graf Zahl) +- Converted Ettin and Centaur to DECORATE. +- Made the Ettin's and Centaur's howling sound an actor property. +- Added A_CustomComboAttack function to finally have something that can + replace the old A_ComboAttack function. +- Added A_SpawnItemEx function that removes the problems with A_SpawnItem + and which also should make most of the A_CustomMissile abuse unnecessary. +- Added A_QueueCorpse to the list of DECORATE code pointers. +- Made the size of Hexen's corpse queue configurable by CVAR + (sv_corpsequeuesize.) Setting this CVAR to -1 will disable corpse + queuing completely so that even in Hexen all corpses will stay forever. - Added random2 function to DECORATE's expression evaluator. This is to better emulate some calculation of internal code pointers. - Added named RNG support to DECORATE's expression evaluator. Just use diff --git a/src/actor.h b/src/actor.h index 4cf4c8658..5ec51fadd 100644 --- a/src/actor.h +++ b/src/actor.h @@ -418,6 +418,7 @@ enum AMETA_FastSpeed, // Speed in fast mode AMETA_RDFactor, // Radius damage factor AMETA_CameraHeight, // Height of camera when used as such + AMETA_HowlSound, // Sound being played when electrocuted or poisoned }; // Map Object definition. @@ -476,7 +477,8 @@ public: virtual int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); // Centaurs and ettins squeal when electrocuted, poisoned, or "holy"-ed - virtual void Howl (); + // Made a metadata property so no longer virtual + void Howl (); // Called by A_NoBlocking in case the actor wants to drop some presents virtual void NoBlockingSet (); @@ -504,9 +506,6 @@ public: // Called by RoughBlockCheck virtual bool IsOkayToAttack (AActor *target); - virtual void ChangeSpecial (int special, int data1, int data2, - int data3, int data4, int data5); - // Plays the actor's ActiveSound if its voice isn't already making noise. void PlayActiveSound (); diff --git a/src/g_hexen/a_centaur.cpp b/src/g_hexen/a_centaur.cpp index 8d1d79d38..18f3311f9 100644 --- a/src/g_hexen/a_centaur.cpp +++ b/src/g_hexen/a_centaur.cpp @@ -1,326 +1,10 @@ #include "actor.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" #include "p_enemy.h" #include "a_action.h" #include "m_random.h" -#include "a_hexenglobal.h" static FRandom pr_centaurdefend ("CentaurDefend"); -static FRandom pr_reflect ("CentaurDeflect"); -static FRandom pr_centaurattack ("CentaurAttack"); -static FRandom pr_centaurdrop ("CentaurDrop"); - -void A_CentaurDefend (AActor *); -void A_CentaurAttack (AActor *); -void A_CentaurAttack2 (AActor *); -void A_CentaurDropStuff (AActor *); - -// Centaur ------------------------------------------------------------------ - -FState ACentaur::States[] = -{ -#define S_CENTAUR_LOOK1 0 - S_NORMAL (CENT, 'A', 10, A_Look , &States[S_CENTAUR_LOOK1+1]), - S_NORMAL (CENT, 'B', 10, A_Look , &States[S_CENTAUR_LOOK1]), - -#define S_CENTAUR_WALK1 (S_CENTAUR_LOOK1+2) - S_NORMAL (CENT, 'A', 4, A_Chase , &States[S_CENTAUR_WALK1+1]), - S_NORMAL (CENT, 'B', 4, A_Chase , &States[S_CENTAUR_WALK1+2]), - S_NORMAL (CENT, 'C', 4, A_Chase , &States[S_CENTAUR_WALK1+3]), - S_NORMAL (CENT, 'D', 4, A_Chase , &States[S_CENTAUR_WALK1]), - -#define S_CENTAUR_PAIN1 (S_CENTAUR_WALK1+4) - S_NORMAL (CENT, 'G', 6, A_Pain , &States[S_CENTAUR_PAIN1+1]), - S_NORMAL (CENT, 'G', 6, A_SetReflectiveInvulnerable, &States[S_CENTAUR_PAIN1+2]), - S_NORMAL (CENT, 'E', 15, A_CentaurDefend , &States[S_CENTAUR_PAIN1+3]), - S_NORMAL (CENT, 'E', 15, A_CentaurDefend , &States[S_CENTAUR_PAIN1+4]), - S_NORMAL (CENT, 'E', 15, A_CentaurDefend , &States[S_CENTAUR_PAIN1+5]), - S_NORMAL (CENT, 'E', 1, A_UnSetReflectiveInvulnerable, &States[S_CENTAUR_WALK1]), - -#define S_CENTAUR_ATK1 (S_CENTAUR_PAIN1+6) - S_NORMAL (CENT, 'H', 5, A_FaceTarget , &States[S_CENTAUR_ATK1+1]), - S_NORMAL (CENT, 'I', 4, A_FaceTarget , &States[S_CENTAUR_ATK1+2]), - S_NORMAL (CENT, 'J', 7, A_CentaurAttack , &States[S_CENTAUR_WALK1]), - -#define S_CENTAUR_MISSILE1 (S_CENTAUR_ATK1+3) - S_NORMAL (CENT, 'E', 10, A_FaceTarget , &States[S_CENTAUR_MISSILE1+1]), - S_BRIGHT (CENT, 'F', 8, A_CentaurAttack2 , &States[S_CENTAUR_MISSILE1+2]), - S_NORMAL (CENT, 'E', 10, A_FaceTarget , &States[S_CENTAUR_MISSILE1+3]), - S_BRIGHT (CENT, 'F', 8, A_CentaurAttack2 , &States[S_CENTAUR_WALK1]), - -#define S_CENTAUR_DEATH1 (S_CENTAUR_MISSILE1+4) - S_NORMAL (CENT, 'K', 4, NULL , &States[S_CENTAUR_DEATH1+1]), - S_NORMAL (CENT, 'L', 4, A_Scream , &States[S_CENTAUR_DEATH1+2]), - S_NORMAL (CENT, 'M', 4, NULL , &States[S_CENTAUR_DEATH1+3]), - S_NORMAL (CENT, 'N', 4, NULL , &States[S_CENTAUR_DEATH1+4]), - S_NORMAL (CENT, 'O', 4, A_NoBlocking , &States[S_CENTAUR_DEATH1+5]), - S_NORMAL (CENT, 'P', 4, NULL , &States[S_CENTAUR_DEATH1+6]), - S_NORMAL (CENT, 'Q', 4, NULL , &States[S_CENTAUR_DEATH1+7]), - S_NORMAL (CENT, 'R', 4, A_QueueCorpse , &States[S_CENTAUR_DEATH1+8]), - S_NORMAL (CENT, 'S', 4, NULL , &States[S_CENTAUR_DEATH1+9]), - S_NORMAL (CENT, 'T', -1, NULL , NULL), - -#define S_CENTAUR_DEATH_X1 (S_CENTAUR_DEATH1+10) - S_NORMAL (CTXD, 'A', 4, NULL , &States[S_CENTAUR_DEATH_X1+1]), - S_NORMAL (CTXD, 'B', 4, A_NoBlocking , &States[S_CENTAUR_DEATH_X1+2]), - S_NORMAL (CTXD, 'C', 4, A_CentaurDropStuff , &States[S_CENTAUR_DEATH_X1+3]), - S_NORMAL (CTXD, 'D', 3, A_Scream , &States[S_CENTAUR_DEATH_X1+4]), - S_NORMAL (CTXD, 'E', 4, A_QueueCorpse , &States[S_CENTAUR_DEATH_X1+5]), - S_NORMAL (CTXD, 'F', 3, NULL , &States[S_CENTAUR_DEATH_X1+6]), - S_NORMAL (CTXD, 'G', 4, NULL , &States[S_CENTAUR_DEATH_X1+7]), - S_NORMAL (CTXD, 'H', 3, NULL , &States[S_CENTAUR_DEATH_X1+8]), - S_NORMAL (CTXD, 'I', 4, NULL , &States[S_CENTAUR_DEATH_X1+9]), - S_NORMAL (CTXD, 'J', 3, NULL , &States[S_CENTAUR_DEATH_X1+10]), - S_NORMAL (CTXD, 'K', -1, NULL , NULL), - -#define S_CENTAUR_ICE1 (S_CENTAUR_DEATH_X1+11) - S_NORMAL (CENT, 'U', 5, A_FreezeDeath , &States[S_CENTAUR_ICE1+1]), - S_NORMAL (CENT, 'U', 1, A_FreezeDeathChunks , &States[S_CENTAUR_ICE1+1]), - -}; - -IMPLEMENT_ACTOR (ACentaur, Hexen, 107, 1) - PROP_SpawnHealth (200) - PROP_PainChance (135) - PROP_SpeedFixed (13) - PROP_HeightFixed (64) - PROP_Mass (120) - PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL) - PROP_Flags2 (MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL|MF2_MCROSS) - PROP_Flags4 (MF4_SHIELDREFLECT) - - PROP_SpawnState (S_CENTAUR_LOOK1) - PROP_SeeState (S_CENTAUR_WALK1) - PROP_PainState (S_CENTAUR_PAIN1) - PROP_MeleeState (S_CENTAUR_ATK1) - PROP_DeathState (S_CENTAUR_DEATH1) - PROP_XDeathState (S_CENTAUR_DEATH_X1) - PROP_IDeathState (S_CENTAUR_ICE1) - - PROP_SeeSound ("CentaurSight") - PROP_AttackSound ("CentaurAttack") - PROP_PainSound ("CentaurPain") - PROP_DeathSound ("CentaurDeath") - PROP_ActiveSound ("CentaurActive") -END_DEFAULTS - -void ACentaur::Howl () -{ - int howl = S_FindSound ("PuppyBeat"); - if (!S_GetSoundPlayingInfo (this, howl)) - { - S_SoundID (this, CHAN_BODY, howl, 1, ATTN_NORM); - } -} - -// Centaur Leader ----------------------------------------------------------- - -class ACentaurLeader : public ACentaur -{ - DECLARE_STATELESS_ACTOR (ACentaurLeader, ACentaur) -}; - -IMPLEMENT_STATELESS_ACTOR (ACentaurLeader, Hexen, 115, 2) - PROP_SpawnHealth (250) - PROP_PainChance (96) - PROP_SpeedFixed (10) - - PROP_MissileState (S_CENTAUR_MISSILE1) -END_DEFAULTS - -// Mashed centaur ----------------------------------------------------------- -// -// The mashed centaur is only placed through ACS. Nowhere in the game source -// is it ever referenced. - -class ACentaurMash : public ACentaur -{ - DECLARE_STATELESS_ACTOR (ACentaurMash, ACentaur) -}; - -IMPLEMENT_STATELESS_ACTOR (ACentaurMash, Hexen, -1, 103) - PROP_FlagsSet (MF_NOBLOOD) - PROP_Flags2Set (MF2_BLASTED) - PROP_Flags2Clear (MF2_TELESTOMP) - PROP_Flags4Set(MF4_NOICEDEATH) - PROP_RenderStyle (STYLE_Translucent) - PROP_Alpha (HX_ALTSHADOW) - - PROP_DeathState (~0) - PROP_XDeathState (~0) - PROP_IDeathState (~0) -END_DEFAULTS - -// Centaur projectile ------------------------------------------------------- - -class ACentaurFX : public AActor -{ - DECLARE_ACTOR (ACentaurFX, AActor) -}; - -FState ACentaurFX::States[] = -{ -#define S_CENTAUR_FX1 0 - S_BRIGHT (CTFX, 'A', -1, NULL , NULL), - -#define S_CENTAUR_FX_X1 (S_CENTAUR_FX1+1) - S_BRIGHT (CTFX, 'B', 4, NULL , &States[S_CENTAUR_FX_X1+1]), - S_BRIGHT (CTFX, 'C', 3, NULL , &States[S_CENTAUR_FX_X1+2]), - S_BRIGHT (CTFX, 'D', 4, NULL , &States[S_CENTAUR_FX_X1+3]), - S_BRIGHT (CTFX, 'E', 3, NULL , &States[S_CENTAUR_FX_X1+4]), - S_BRIGHT (CTFX, 'F', 2, NULL , NULL), -}; - -IMPLEMENT_ACTOR (ACentaurFX, Hexen, -1, 0) - PROP_SpeedFixed (20) - PROP_Damage (4) - PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE) - PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS) - PROP_RenderStyle (STYLE_Add) - - PROP_SpawnState (S_CENTAUR_FX1) - PROP_DeathState (S_CENTAUR_FX_X1) - - PROP_DeathSound ("CentaurMissileExplode") -END_DEFAULTS - -// Centaur shield (debris) -------------------------------------------------- - -class ACentaurShield : public AActor -{ - DECLARE_ACTOR (ACentaurShield, AActor) -}; - -FState ACentaurShield::States[] = -{ -#define S_CENTAUR_SHIELD1 0 - S_NORMAL (CTDP, 'A', 3, NULL , &States[S_CENTAUR_SHIELD1+1]), - S_NORMAL (CTDP, 'B', 3, NULL , &States[S_CENTAUR_SHIELD1+2]), - S_NORMAL (CTDP, 'C', 3, NULL , &States[S_CENTAUR_SHIELD1+3]), - S_NORMAL (CTDP, 'D', 3, NULL , &States[S_CENTAUR_SHIELD1+4]), - S_NORMAL (CTDP, 'E', 3, NULL , &States[S_CENTAUR_SHIELD1+5]), - S_NORMAL (CTDP, 'F', 3, NULL , &States[S_CENTAUR_SHIELD1+2]), - -#define S_CENTAUR_SHIELD_X1 (S_CENTAUR_SHIELD1+6) - S_NORMAL (CTDP, 'G', 4, NULL , &States[S_CENTAUR_SHIELD_X1+1]), - S_NORMAL (CTDP, 'H', 4, A_QueueCorpse , &States[S_CENTAUR_SHIELD_X1+2]), - S_NORMAL (CTDP, 'I', 4, NULL , &States[S_CENTAUR_SHIELD_X1+3]), - S_NORMAL (CTDP, 'J', -1, NULL , NULL), -}; - -IMPLEMENT_ACTOR (ACentaurShield, Hexen, -1, 0) - PROP_Flags (MF_DROPOFF|MF_CORPSE) - PROP_Flags2 (MF2_NOTELEPORT) - - PROP_SpawnState (S_CENTAUR_SHIELD1) - PROP_CrashState (S_CENTAUR_SHIELD_X1) -END_DEFAULTS - -// Centaur sword (debris) --------------------------------------------------- - -class ACentaurSword : public AActor -{ - DECLARE_ACTOR (ACentaurSword, AActor) -}; - -FState ACentaurSword::States[] = -{ -#define S_CENTAUR_SWORD1 0 - S_NORMAL (CTDP, 'K', 3, NULL , &States[S_CENTAUR_SWORD1+1]), - S_NORMAL (CTDP, 'L', 3, NULL , &States[S_CENTAUR_SWORD1+2]), - S_NORMAL (CTDP, 'M', 3, NULL , &States[S_CENTAUR_SWORD1+3]), - S_NORMAL (CTDP, 'N', 3, NULL , &States[S_CENTAUR_SWORD1+4]), - S_NORMAL (CTDP, 'O', 3, NULL , &States[S_CENTAUR_SWORD1+5]), - S_NORMAL (CTDP, 'P', 3, NULL , &States[S_CENTAUR_SWORD1+6]), - S_NORMAL (CTDP, 'Q', 3, NULL , &States[S_CENTAUR_SWORD1+2]), - -#define S_CENTAUR_SWORD_X1 (S_CENTAUR_SWORD1+7) - S_NORMAL (CTDP, 'R', 4, NULL , &States[S_CENTAUR_SWORD_X1+1]), - S_NORMAL (CTDP, 'S', 4, A_QueueCorpse , &States[S_CENTAUR_SWORD_X1+2]), - S_NORMAL (CTDP, 'T', -1, NULL , NULL), -}; - -IMPLEMENT_ACTOR (ACentaurSword, Hexen, -1, 0) - PROP_Flags (MF_DROPOFF|MF_CORPSE) - PROP_Flags2 (MF2_NOTELEPORT) - - PROP_SpawnState (S_CENTAUR_SWORD1) - PROP_CrashState (S_CENTAUR_SWORD_X1) -END_DEFAULTS - -//============================================================================ -// -// A_CentaurAttack -// -//============================================================================ - -void A_CentaurAttack (AActor *actor) -{ - if (!actor->target) - { - return; - } - if (actor->CheckMeleeRange ()) - { - int damage = pr_centaurattack()%7+3; - P_DamageMobj (actor->target, actor, actor, damage, NAME_Melee); - P_TraceBleed (damage, actor->target, actor); - } -} - -//============================================================================ -// -// A_CentaurAttack2 -// -//============================================================================ - -void A_CentaurAttack2 (AActor *actor) -{ - if (!actor->target) - { - return; - } - P_SpawnMissileZ (actor, actor->z + 45*FRACUNIT, - actor->target, RUNTIME_CLASS(ACentaurFX)); - S_Sound (actor, CHAN_WEAPON, "CentaurLeaderAttack", 1, ATTN_NORM); -} - -//============================================================================ -// -// A_CentaurDropStuff -// -// Spawn shield/sword sprites when the centaur pulps -//============================================================================ - -void A_CentaurDropStuff (AActor *actor) -{ - const PClass *const DropTypes[] = - { - RUNTIME_CLASS(ACentaurSword), - RUNTIME_CLASS(ACentaurShield) - }; - - for (int i = countof(DropTypes)-1; i >= 0; --i) - { - AActor *mo; - - mo = Spawn (DropTypes[i], actor->x, actor->y, actor->z+45*FRACUNIT, ALLOW_REPLACE); - if (mo) - { - angle_t angle = actor->angle + (i ? ANGLE_90 : ANGLE_270); - mo->momz = FRACUNIT*8+(pr_centaurdrop()<<10); - mo->momx = FixedMul(((pr_centaurdrop()-128)<<11)+FRACUNIT, - finecosine[angle>>ANGLETOFINESHIFT]); - mo->momy = FixedMul(((pr_centaurdrop()-128)<<11)+FRACUNIT, - finesine[angle>>ANGLETOFINESHIFT]); - mo->target = actor; - } - } -} - //============================================================================ // // A_CentaurDefend diff --git a/src/g_hexen/a_ettin.cpp b/src/g_hexen/a_ettin.cpp deleted file mode 100644 index 6dac9f7a5..000000000 --- a/src/g_hexen/a_ettin.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "actor.h" -#include "info.h" -#include "p_local.h" -#include "s_sound.h" -#include "p_enemy.h" -#include "a_action.h" -#include "m_random.h" - -static FRandom pr_ettinatk ("EttinAttack"); -static FRandom pr_dropmace ("DropMace"); - -// Ettin -------------------------------------------------------------------- - -void A_EttinAttack (AActor *); -void A_DropMace (AActor *); - -class AEttin : public AActor -{ - DECLARE_ACTOR (AEttin, AActor) -public: - void Howl (); -}; - -FState AEttin::States[] = -{ -#define S_ETTIN_LOOK 0 - S_NORMAL (ETTN, 'A', 10, A_Look , &States[S_ETTIN_LOOK+1]), - S_NORMAL (ETTN, 'A', 10, A_Look , &States[S_ETTIN_LOOK+0]), - -#define S_ETTIN_CHASE (S_ETTIN_LOOK+2) - S_NORMAL (ETTN, 'A', 5, A_Chase , &States[S_ETTIN_CHASE+1]), - S_NORMAL (ETTN, 'B', 5, A_Chase , &States[S_ETTIN_CHASE+2]), - S_NORMAL (ETTN, 'C', 5, A_Chase , &States[S_ETTIN_CHASE+3]), - S_NORMAL (ETTN, 'D', 5, A_Chase , &States[S_ETTIN_CHASE+0]), - -#define S_ETTIN_PAIN (S_ETTIN_CHASE+4) - S_NORMAL (ETTN, 'H', 7, A_Pain , &States[S_ETTIN_CHASE+0]), - -#define S_ETTIN_ATK1 (S_ETTIN_PAIN+1) - S_NORMAL (ETTN, 'E', 6, A_FaceTarget , &States[S_ETTIN_ATK1+1]), - S_NORMAL (ETTN, 'F', 6, A_FaceTarget , &States[S_ETTIN_ATK1+2]), - S_NORMAL (ETTN, 'G', 8, A_EttinAttack , &States[S_ETTIN_CHASE+0]), - -#define S_ETTIN_DEATH1 (S_ETTIN_ATK1+3) - S_NORMAL (ETTN, 'I', 4, NULL , &States[S_ETTIN_DEATH1+1]), - S_NORMAL (ETTN, 'J', 4, NULL , &States[S_ETTIN_DEATH1+2]), - S_NORMAL (ETTN, 'K', 4, A_Scream , &States[S_ETTIN_DEATH1+3]), - S_NORMAL (ETTN, 'L', 4, A_NoBlocking , &States[S_ETTIN_DEATH1+4]), - S_NORMAL (ETTN, 'M', 4, A_QueueCorpse , &States[S_ETTIN_DEATH1+5]), - S_NORMAL (ETTN, 'N', 4, NULL , &States[S_ETTIN_DEATH1+6]), - S_NORMAL (ETTN, 'O', 4, NULL , &States[S_ETTIN_DEATH1+7]), - S_NORMAL (ETTN, 'P', 4, NULL , &States[S_ETTIN_DEATH1+8]), - S_NORMAL (ETTN, 'Q', -1, NULL , NULL), - -#define S_ETTIN_DEATH2 (S_ETTIN_DEATH1+9) - S_NORMAL (ETTB, 'A', 4, NULL , &States[S_ETTIN_DEATH2+1]), - S_NORMAL (ETTB, 'B', 4, A_NoBlocking , &States[S_ETTIN_DEATH2+2]), - S_NORMAL (ETTB, 'C', 4, A_DropMace , &States[S_ETTIN_DEATH2+3]), - S_NORMAL (ETTB, 'D', 4, A_Scream , &States[S_ETTIN_DEATH2+4]), - S_NORMAL (ETTB, 'E', 4, A_QueueCorpse , &States[S_ETTIN_DEATH2+5]), - S_NORMAL (ETTB, 'F', 4, NULL , &States[S_ETTIN_DEATH2+6]), - S_NORMAL (ETTB, 'G', 4, NULL , &States[S_ETTIN_DEATH2+7]), - S_NORMAL (ETTB, 'H', 4, NULL , &States[S_ETTIN_DEATH2+8]), - S_NORMAL (ETTB, 'I', 4, NULL , &States[S_ETTIN_DEATH2+9]), - S_NORMAL (ETTB, 'J', 4, NULL , &States[S_ETTIN_DEATH2+10]), - S_NORMAL (ETTB, 'K', 4, NULL , &States[S_ETTIN_DEATH2+11]), - S_NORMAL (ETTB, 'L', -1, NULL , NULL), - -#define S_ETTIN_ICE (S_ETTIN_DEATH2+12) - S_NORMAL (ETTN, 'R', 5, A_FreezeDeath , &States[S_ETTIN_ICE+1]), - S_NORMAL (ETTN, 'R', 1, A_FreezeDeathChunks , &States[S_ETTIN_ICE+1]) -}; -IMPLEMENT_ACTOR (AEttin, Hexen, 10030, 4) - PROP_SpawnHealth (175) - PROP_RadiusFixed (25) - PROP_HeightFixed (68) - PROP_Mass (175) - PROP_SpeedFixed (13) - PROP_Damage (3) - PROP_PainChance (60) - PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL) - PROP_Flags2 (MF2_FLOORCLIP|MF2_PUSHWALL|MF2_MCROSS|MF2_TELESTOMP) - - PROP_SpawnState (S_ETTIN_LOOK) - PROP_SeeState (S_ETTIN_CHASE) - PROP_PainState (S_ETTIN_PAIN) - PROP_MeleeState (S_ETTIN_ATK1) - PROP_DeathState (S_ETTIN_DEATH1) - PROP_XDeathState (S_ETTIN_DEATH2) - PROP_IDeathState (S_ETTIN_ICE) - - PROP_SeeSound ("EttinSight") - PROP_AttackSound ("EttinAttack") - PROP_PainSound ("EttinPain") - PROP_DeathSound ("EttinDeath") - PROP_ActiveSound ("EttinActive") -END_DEFAULTS - -void AEttin::Howl () -{ - int howl = S_FindSound ("PuppyBeat"); - if (!S_GetSoundPlayingInfo (this, howl)) - { - S_SoundID (this, CHAN_BODY, howl, 1, ATTN_NORM); - } -} - -// Ettin mace --------------------------------------------------------------- - -class AEttinMace : public AActor -{ - DECLARE_ACTOR (AEttinMace, AActor) -}; - -FState AEttinMace::States[] = -{ - S_NORMAL (ETTB, 'M', 5, NULL , &States[1]), - S_NORMAL (ETTB, 'N', 5, NULL , &States[2]), - S_NORMAL (ETTB, 'O', 5, NULL , &States[3]), - S_NORMAL (ETTB, 'P', 5, NULL , &States[0]), - - S_NORMAL (ETTB, 'Q', 5, NULL , &States[5]), - S_NORMAL (ETTB, 'R', 5, A_QueueCorpse , &States[6]), - S_NORMAL (ETTB, 'S', -1, NULL , NULL) -}; - -IMPLEMENT_ACTOR (AEttinMace, Hexen, -1, 0) - PROP_RadiusFixed (5) - PROP_HeightFixed (5) - PROP_Flags (MF_DROPOFF|MF_CORPSE) - PROP_Flags2 (MF2_NOTELEPORT|MF2_FLOORCLIP) - - PROP_SpawnState (0) - PROP_CrashState (4) -END_DEFAULTS - -// Ettin mash --------------------------------------------------------------- - -class AEttinMash : public AEttin -{ - DECLARE_STATELESS_ACTOR (AEttinMash, AEttin) -}; - -IMPLEMENT_STATELESS_ACTOR (AEttinMash, Hexen, -1, 102) - PROP_FlagsSet (MF_NOBLOOD) - PROP_Flags2Set (MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_MCROSS|MF2_PUSHWALL|MF2_BLASTED) - PROP_Flags4Set(MF4_NOICEDEATH) - PROP_RenderStyle (STYLE_Translucent) - PROP_Alpha (HX_ALTSHADOW) - - PROP_DeathState (~0) - PROP_XDeathState (~0) - PROP_IDeathState (~0) -END_DEFAULTS - -//============================================================================ -// Ettin AI -//============================================================================ - -void A_EttinAttack (AActor *actor) -{ - if (actor->CheckMeleeRange()) - { - int damage = pr_ettinatk.HitDice (2); - P_DamageMobj (actor->target, actor, actor, damage, NAME_Melee); - P_TraceBleed (damage, actor->target, actor); - } -} - - -void A_DropMace (AActor *actor) -{ - AEttinMace *mo; - - mo = Spawn (actor->x, actor->y, - actor->z + (actor->height>>1), ALLOW_REPLACE); - if (mo) - { - mo->momx = (pr_dropmace()-128) << 11; - mo->momy = (pr_dropmace()-128) << 11; - mo->momz = FRACUNIT*10+(pr_dropmace()<<10); - mo->target = actor; - } -} - diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h index 6219c4be1..9720ffdf2 100644 --- a/src/g_hexen/a_hexenglobal.h +++ b/src/g_hexen/a_hexenglobal.h @@ -52,13 +52,6 @@ public: void BeginPlay (); }; -class ACentaur : public AActor -{ - DECLARE_ACTOR (ACentaur, AActor) -public: - void Howl (); -}; - class AFourthWeaponPiece : public AInventory { DECLARE_STATELESS_ACTOR (AFourthWeaponPiece, AInventory) diff --git a/src/g_hexen/a_korax.cpp b/src/g_hexen/a_korax.cpp index ea3ec734a..4e56dbf23 100644 --- a/src/g_hexen/a_korax.cpp +++ b/src/g_hexen/a_korax.cpp @@ -683,10 +683,6 @@ AActor *P_SpawnKoraxMissile (fixed_t x, fixed_t y, fixed_t z, z -= source->floorclip; th = Spawn (type, x, y, z, ALLOW_REPLACE); - if (th->SeeSound) - { - S_SoundID (th, CHAN_BODY, th->SeeSound, 1, ATTN_NORM); - } th->target = source; // Originator an = R_PointToAngle2(x, y, dest->x, dest->y); if (dest->flags & MF_SHADOW) diff --git a/src/g_hexen/a_magelightning.cpp b/src/g_hexen/a_magelightning.cpp index e6ca1e355..3c96a98db 100644 --- a/src/g_hexen/a_magelightning.cpp +++ b/src/g_hexen/a_magelightning.cpp @@ -130,7 +130,11 @@ int ALightning::SpecialMissileHit (AActor *thing) if ((!thing->player && !(thing->flags2&MF2_BOSS)) || !(level.time&1)) { - if (thing->IsKindOf(RUNTIME_CLASS(ACentaur))) + // There needs to be a better way to do this... + static const PClass *centaur=NULL; + if (!centaur) centaur = PClass::FindClass("Centaur"); + + if (thing->IsKindOf(centaur)) { // Lightning does more damage to centaurs P_DamageMobj(thing, this, target, 9, NAME_Electric); } diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index 72817a549..a707a42a5 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -321,7 +321,6 @@ void A_FreezeDeathChunks (AActor *actor) //---------------------------------------------------------------------------- // Corpse queue for monsters - this should be saved out -#define CORPSEQUEUESIZE 64 class DCorpsePointer : public DThinker { @@ -340,7 +339,23 @@ private: IMPLEMENT_POINTY_CLASS(DCorpsePointer) DECLARE_POINTER(Corpse) END_POINTERS - + +CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO) +{ + if (self > 0) + { + TThinkerIterator iterator (STAT_CORPSEPOINTER); + DCorpsePointer *first = iterator.Next (); + while (first != NULL && first->Count > (DWORD)self) + { + DCorpsePointer *next = iterator.Next (); + next->Count = first->Count; + first->Destroy (); + first = next; + } + } +} + DCorpsePointer::DCorpsePointer (AActor *ptr) : DThinker (STAT_CORPSEPOINTER), Corpse (ptr) @@ -354,7 +369,7 @@ DCorpsePointer::DCorpsePointer (AActor *ptr) if (first != this) { - if (first->Count >= CORPSEQUEUESIZE) + if (first->Count >= (DWORD)sv_corpsequeuesize) { DCorpsePointer *next = iterator.Next (); next->Count = first->Count; @@ -399,7 +414,8 @@ void DCorpsePointer::Serialize (FArchive &arc) // throw another corpse on the queue void A_QueueCorpse (AActor *actor) { - new DCorpsePointer (actor); + if (sv_corpsequeuesize > 0) + new DCorpsePointer (actor); } // Remove an actor from the queue (for resurrection) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8e5455fe2..f3d0df263 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2319,6 +2319,11 @@ int AActor::GetMissileDamage (int mask, int add) void AActor::Howl () { + int howl = GetClass()->Meta.GetMetaInt(AMETA_HowlSound); + if (!S_GetSoundPlayingInfo (this, howl)) + { + S_SoundID (this, CHAN_BODY, howl, 1, ATTN_NORM); + } } void AActor::NoBlockingSet () @@ -2433,17 +2438,6 @@ bool AActor::IsOkayToAttack (AActor *link) return false; } -void AActor::ChangeSpecial (int special, int data1, int data2, - int data3, int data4, int data5) -{ - this->special = special; - args[0] = data1; - args[1] = data2; - args[2] = data3; - args[3] = data4; - args[4] = data5; -} - void AActor::SetShade (DWORD rgb) { PalEntry *entry = (PalEntry *)&rgb; diff --git a/src/sdl/i_main.cpp b/src/sdl/i_main.cpp index 4f416cc53..86ebb0f6e 100644 --- a/src/sdl/i_main.cpp +++ b/src/sdl/i_main.cpp @@ -140,6 +140,9 @@ static int DoomSpecificInfo (char *buffer, char *end) int main (int argc, char **argv) { + printf("ZDoom v%s - SVN revision %s - SDL version\nCompiled on %s\n\n", + DOTVERSIONSTR_NOREV,SVN_REVISION_STRING,__DATE__); + { int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS }; cc_install_handlers(4, s, "zdoom-crash.log", DoomSpecificInfo); diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 314e1c465..1c215bc77 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -348,7 +348,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad) { int i; - printf ("Please select a game wad:\n"); + printf ("Please select a game wad (or 0 to exit):\n"); for (i = 0; i < numwads; ++i) { const char *filepart = strrchr (wads[i].Path, '/'); diff --git a/src/thingdef.cpp b/src/thingdef.cpp index 14daffb8e..257250916 100644 --- a/src/thingdef.cpp +++ b/src/thingdef.cpp @@ -132,6 +132,7 @@ static flagdef ActorFlags[]= DEFINE_FLAG2(MF2_LOGRAV, LOWGRAVITY, AActor, flags2), DEFINE_FLAG(MF2, WINDTHRUST, AActor, flags2), DEFINE_FLAG(MF2, HERETICBOUNCE , AActor, flags2), + DEFINE_FLAG(MF2, BLASTED, AActor, flags2), DEFINE_FLAG(MF2, FLOORCLIP, AActor, flags2), DEFINE_FLAG(MF2, SPAWNFLOAT, AActor, flags2), DEFINE_FLAG(MF2, NOTELEPORT, AActor, flags2), @@ -477,6 +478,7 @@ ACTOR(LightInverse) ACTOR(GiveInventory) ACTOR(TakeInventory) ACTOR(SpawnItem) +ACTOR(SpawnItemEx) ACTOR(ThrowGrenade) ACTOR(Recoil) ACTOR(SelectWeapon) @@ -506,6 +508,7 @@ ACTOR(TakeFromTarget) ACTOR(JumpIfInTargetInventory) ACTOR(CountdownArg) ACTOR(CustomMeleeAttack) +ACTOR(CustomComboAttack) ACTOR(Light) ACTOR(Burst) ACTOR(SkullPop) @@ -517,6 +520,7 @@ ACTOR(SPosAttackUseAtkSound) ACTOR(Respawn) ACTOR(BarrelDestroy) ACTOR(PlayerSkinCheck) +ACTOR(QueueCorpse) #include "d_dehackedactions.h" @@ -697,6 +701,7 @@ AFuncDesc AFTable[]= FUNC(A_GiveInventory, "Mx" ) FUNC(A_TakeInventory, "Mx" ) FUNC(A_SpawnItem, "Mxxyx" ) + FUNC(A_SpawnItemEx, "Mxxxxxxxx" ) FUNC(A_ThrowGrenade, "Mxxxy" ) FUNC(A_SelectWeapon, "M") FUNC(A_Print, "Txt") @@ -728,12 +733,14 @@ AFuncDesc AFTable[]= FUNC(A_TakeFromTarget, "Mx" ) FUNC(A_CountdownArg, "X") FUNC(A_CustomMeleeAttack, "Xssty" ) + FUNC(A_CustomComboAttack, "MXXsty" ) FUNC(A_Burst, "M") FUNC(A_RadiusThrust, "xxy") {"A_Explode", A_ExplodeParms, "xxy" }, FUNC(A_Stop, NULL) FUNC(A_Respawn, "y") FUNC(A_BarrelDestroy, NULL) + FUNC(A_QueueCorpse, NULL) }; //========================================================================== @@ -2819,6 +2826,15 @@ static void ActorActiveSound (AActor *defaults, Baggage &bag) defaults->ActiveSound=S_FindSound(sc_String); } +//========================================================================== +// +//========================================================================== +static void ActorHowlSound (AActor *defaults, Baggage &bag) +{ + SC_MustGetString(); + bag.Info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(sc_String)); +} + //========================================================================== // //========================================================================== @@ -4138,6 +4154,7 @@ static const ActorProps props[] = { "health.lowmessage", (apf)HealthLowMessage, RUNTIME_CLASS(AHealth) }, { "height", ActorHeight, RUNTIME_CLASS(AActor) }, { "hitobituary", ActorHitObituary, RUNTIME_CLASS(AActor) }, + { "howlsound", ActorHowlSound, RUNTIME_CLASS(AActor) }, { "ice", ActorIceState, RUNTIME_CLASS(AActor) }, { "inventory.amount", (apf)InventoryAmount, RUNTIME_CLASS(AInventory) }, { "inventory.defmaxamount", (apf)InventoryDefMaxAmount, RUNTIME_CLASS(AInventory) }, diff --git a/src/thingdef_codeptr.cpp b/src/thingdef_codeptr.cpp index 72280c567..362f7de91 100644 --- a/src/thingdef_codeptr.cpp +++ b/src/thingdef_codeptr.cpp @@ -844,6 +844,63 @@ void A_CustomMeleeAttack (AActor *self) } } +//========================================================================== +// +// A fully customizable combo attack +// +//========================================================================== +void A_CustomComboAttack (AActor *self) +{ + int index=CheckIndex(6); + if (index<0) return; + + ENamedName MissileName=(ENamedName)StateParameters[index]; + fixed_t SpawnHeight=fixed_t(EvalExpressionF (StateParameters[index+1], self) * FRACUNIT); + int damage = EvalExpressionI (StateParameters[index+2], self); + int MeleeSound = StateParameters[index+3]; + ENamedName DamageType = (ENamedName)StateParameters[index+4]; + bool bleed = EvalExpressionN (StateParameters[index+5], self); + + + if (!self->target) + return; + + A_FaceTarget (self); + if (self->CheckMeleeRange ()) + { + if (DamageType==NAME_None) DamageType = NAME_Melee; // Melee is the default type + if (MeleeSound) S_SoundID (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM); + P_DamageMobj (self->target, self, self, damage, DamageType); + if (bleed) P_TraceBleed (damage, self->target, self); + } + else + { + const PClass * ti=PClass::FindClass(MissileName); + if (ti) + { + // Although there is a P_SpawnMissileZ function its + // aiming is much too bad to be of any use + self->z+=SpawnHeight-32*FRACUNIT; + AActor * missile = P_SpawnMissile (self, self->target, ti); + self->z-=SpawnHeight-32*FRACUNIT; + + if (missile) + { + // automatic handling of seeker missiles + if (missile->flags2&MF2_SEEKERMISSILE) + { + missile->tracer=self->target; + } + // set the health value so that the missile works properly + if (missile->flags4&MF4_SPECTRAL) + { + missile->health=-2; + } + } + } + } +} + //========================================================================== // // State jump function @@ -1228,6 +1285,71 @@ void A_TakeFromTarget(AActor * self) DoTakeInventory(self, self->target); } +//=========================================================================== +// +// Common code for A_SpawnItem and A_SpawnItemEx +// +//=========================================================================== + +static void InitSpawnedItem(AActor *self, AActor *mo, INTBOOL transfer_translation, INTBOOL setmaster) +{ + if (mo) + { + AActor * originator = self; + + if (transfer_translation) + { + mo->Translation = self->Translation; + } + + mo->angle=self->angle; + while (originator && isMissile(originator)) originator = originator->target; + + if (mo->flags3&MF3_ISMONSTER) + { + if (!P_TestMobjLocation(mo)) + { + // The monster is blocked so don't spawn it at all! + if (mo->CountsAsKill()) level.total_monsters--; + mo->Destroy(); + if (pStateCall != NULL) pStateCall->Result=false; // for an inventory iten's use state + return; + } + else if (originator) + { + if (originator->flags3&MF3_ISMONSTER) + { + // If this is a monster transfer all friendliness information + mo->CopyFriendliness(originator, true); + if (setmaster) mo->master = originator; // don't let it attack you (optional)! + } + else if (originator->player) + { + // A player always spawns a monster friendly to him + mo->flags|=MF_FRIENDLY; + mo->FriendPlayer = originator->player-players+1; + + AActor * attacker=originator->player->attacker; + if (attacker) + { + if (!(attacker->flags&MF_FRIENDLY) || + (deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=mo->FriendPlayer)) + { + // Target the monster which last attacked the player + mo->target = attacker; + } + } + } + } + } + else + { + // If this is a missile or something else set the target to the originator + mo->target=originator? originator : self; + } + } +} + //=========================================================================== // // A_SpawnItem @@ -1235,6 +1357,7 @@ void A_TakeFromTarget(AActor * self) // Spawns an item in front of the caller like Heretic's time bomb // //=========================================================================== + void A_SpawnItem(AActor * self) { FState * CallingState; @@ -1276,60 +1399,88 @@ void A_SpawnItem(AActor * self) self->y + FixedMul(distance, finesine[self->angle>>ANGLETOFINESHIFT]), self->z - self->floorclip + zheight, ALLOW_REPLACE); + InitSpawnedItem(self, mo, transfer_translation, useammo); +} + +//=========================================================================== +// +// A_SpawnItemEx +// +// Enhanced spawning function +// +//=========================================================================== +enum SIX_Flags +{ + SIXF_TRANSFERTRANSLATION=1, + SIXF_ABSOLUTEPOSITION=2, + SIXF_ABSOLUTEANGLE=4, + SIXF_ABSOLUTEMOMENTUM=8, + SIXF_SETMASTER=16 +}; + +void A_SpawnItemEx(AActor * self) +{ + FState * CallingState; + int index=CheckIndex(9, &CallingState); + if (index<0) return; + + const PClass * missile= PClass::FindClass((ENamedName)StateParameters[index]); + fixed_t xofs = fixed_t(EvalExpressionF (StateParameters[index+1], self) * FRACUNIT); + fixed_t yofs = fixed_t(EvalExpressionF (StateParameters[index+2], self) * FRACUNIT); + fixed_t zofs = fixed_t(EvalExpressionF (StateParameters[index+3], self) * FRACUNIT); + fixed_t xmom = fixed_t(EvalExpressionF (StateParameters[index+4], self) * FRACUNIT); + fixed_t ymom = fixed_t(EvalExpressionF (StateParameters[index+5], self) * FRACUNIT); + fixed_t zmom = fixed_t(EvalExpressionF (StateParameters[index+6], self) * FRACUNIT); + angle_t Angle= angle_t(EvalExpressionF (StateParameters[index+7], self) * ANGLE_1); + int flags = EvalExpressionI (StateParameters[index+8], self); + + if (!missile) + { + if (pStateCall != NULL) pStateCall->Result=false; + return; + } + + // Don't spawn monsters if this actor has been massacred + if (self->DamageType == NAME_Massacre && GetDefaultByType(missile)->flags3&MF3_ISMONSTER) return; + + fixed_t x,y,z; + + if (!(flags & SIXF_ABSOLUTEANGLE)) + { + Angle += self->angle; + } + + angle_t ang = Angle >> ANGLETOFINESHIFT; + + if (flags & SIXF_ABSOLUTEPOSITION) + { + x = self->x + xofs; + y = self->y + yofs; + } + else + { + // in relative mode negative y values mean 'left' and positive ones mean 'right' + // This is the inverse orientation of the absolute mode! + x = self->x + FixedMul(xofs, finecosine[ang]) + FixedMul(yofs, finesine[ang]); + y = self->y + FixedMul(xofs, finesine[ang]) - FixedMul(yofs, finecosine[ang]); + } + + if (!(flags & SIXF_ABSOLUTEMOMENTUM)) + { + // Same orientation issue here! + fixed_t newxmom = FixedMul(xmom, finecosine[ang]) + FixedMul(ymom, finesine[ang]); + ymom = FixedMul(xmom, finesine[ang]) - FixedMul(ymom, finecosine[ang]); + xmom = newxmom; + } + + AActor * mo = Spawn( missile, x, y, self->z + self->floorclip + zofs, ALLOW_REPLACE); + InitSpawnedItem(self, mo, (flags & SIXF_TRANSFERTRANSLATION), (flags&SIXF_SETMASTER)); if (mo) { - AActor * originator = self; - - if (transfer_translation) - { - mo->Translation = self->Translation; - } - - mo->angle=self->angle; - while (originator && isMissile(originator)) originator = originator->target; - - if (mo->flags3&MF3_ISMONSTER) - { - if (!P_TestMobjLocation(mo)) - { - // The monster is blocked so don't spawn it at all! - if (mo->CountsAsKill()) level.total_monsters--; - mo->Destroy(); - if (pStateCall != NULL) pStateCall->Result=false; // for an inventory iten's use state - return; - } - else if (originator) - { - if (originator->flags3&MF3_ISMONSTER) - { - // If this is a monster transfer all friendliness information - mo->CopyFriendliness(originator, true); - if (useammo) mo->master = originator; // don't let it attack you (optional)! - } - else if (originator->player) - { - // A player always spawns a monster friendly to him - mo->flags|=MF_FRIENDLY; - mo->FriendPlayer = originator->player-players+1; - - AActor * attacker=originator->player->attacker; - if (attacker) - { - if (!(attacker->flags&MF_FRIENDLY) || - (deathmatch && attacker->FriendPlayer!=0 && attacker->FriendPlayer!=mo->FriendPlayer)) - { - // Target the monster which last attacked the player - mo->target = attacker; - } - } - } - } - } - else - { - // If this is a missile or something else set the target to the originator - mo->target=originator? originator : self; - } + mo->momx=xmom; + mo->momy=ymom; + mo->momz=zmom; + mo->angle=Angle; } } diff --git a/tools/updaterevision/updaterevision.vcproj b/tools/updaterevision/updaterevision.vcproj index 50d15744e..ac51fc51a 100644 --- a/tools/updaterevision/updaterevision.vcproj +++ b/tools/updaterevision/updaterevision.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -