From 4a81f55fb0763ba3d23abf429292a20984e6106b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 9 Oct 2009 20:54:28 +0000 Subject: [PATCH] - Added Gez's seeker missile submission. SVN r1905 (trunk) --- docs/rh-log.txt | 1 + src/actor.h | 4 +- src/g_hexen/a_clericholy.cpp | 30 ----------- src/g_hexen/a_hexenglobal.h | 1 - src/g_hexen/a_magestaff.cpp | 36 ------------- src/g_raven/a_minotaur.cpp | 43 --------------- src/g_raven/ravenshared.h | 1 - src/p_mobj.cpp | 69 ++++++++++++++++-------- src/thingdef/thingdef_codeptr.cpp | 14 ++++- src/thingdef/thingdef_data.cpp | 6 ++- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 5 ++ wadsrc/static/actors/hexen/magestaff.txt | 1 + 13 files changed, 74 insertions(+), 139 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index db03561a94..08263f0755 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,5 @@ October 9, 2009 (Changes by Graf Zahl) +- Added Gez's seeker missile submission. - Added Gez's thing activation submission. - added a NULL pointer check to fog spawning in unmorphing code. - fixed: frozen corpses need to be treated as solid by z-movement code. diff --git a/src/actor.h b/src/actor.h index f595e5206a..587297f77c 100644 --- a/src/actor.h +++ b/src/actor.h @@ -217,7 +217,7 @@ enum MF3_CRASHED = 0x00200000, // Actor entered its crash state MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles) MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set) - /* = 0x01000000, */ + MF3_SCREENSEEKER = 0x01000000, // Fails the IsOkayToAttack test if potential target is outside player FOV MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact MF3_BLOODLESSIMPACT = 0x08000000, // Projectile does not leave blood @@ -608,7 +608,7 @@ public: virtual bool SpecialBlastHandling (AActor *source, fixed_t strength); // Called by RoughBlockCheck - virtual bool IsOkayToAttack (AActor *target); + bool IsOkayToAttack (AActor *target); // Plays the actor's ActiveSound if its voice isn't already making noise. void PlayActiveSound (); diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 6ad6522c30..01d13931cc 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -145,36 +145,6 @@ bool AHolySpirit::SpecialBlastHandling (AActor *source, fixed_t strength) return true; } -bool AHolySpirit::IsOkayToAttack (AActor *link) -{ - if ((link->flags3&MF3_ISMONSTER || - (link->player && link != target)) - && !(link->flags2&MF2_DORMANT)) - { - if (target != NULL && link->IsFriend(target)) - { - return false; - } - if (!(link->flags & MF_SHOOTABLE)) - { - return false; - } - if (multiplayer && !deathmatch && link->player && target != NULL && target->player) - { - return false; - } - if (link == target) - { - return false; - } - else if (P_CheckSight (this, link)) - { - return true; - } - } - return false; -} - //============================================================================ // // A_CHolyAttack2 diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h index a942998fe9..a20827774a 100644 --- a/src/g_hexen/a_hexenglobal.h +++ b/src/g_hexen/a_hexenglobal.h @@ -9,7 +9,6 @@ class AHolySpirit : public AActor public: bool Slam (AActor *thing); bool SpecialBlastHandling (AActor *source, fixed_t strength); - bool IsOkayToAttack (AActor *link); }; class AFighterWeapon : public AWeapon diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 76610f6932..2316edde32 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -88,7 +88,6 @@ class AMageStaffFX2 : public AActor DECLARE_CLASS(AMageStaffFX2, AActor) public: int SpecialMissileHit (AActor *victim); - bool IsOkayToAttack (AActor *link); bool SpecialBlastHandling (AActor *source, fixed_t strength); }; @@ -106,41 +105,6 @@ int AMageStaffFX2::SpecialMissileHit (AActor *victim) return -1; } -bool AMageStaffFX2::IsOkayToAttack (AActor *link) -{ - if (((link->flags3 & MF3_ISMONSTER) || link->player) && !(link->flags2 & MF2_DORMANT)) - { - if (!(link->flags & MF_SHOOTABLE)) - { - return false; - } - if (multiplayer && !deathmatch && link->player && target->player) - { - return false; - } - if (link == target) - { - return false; - } - if (target != NULL && target->IsFriend(link)) - { - return false; - } - if (P_CheckSight (this, link)) - { - AActor *master = target; - angle_t angle = R_PointToAngle2 (master->x, master->y, - link->x, link->y) - master->angle; - angle >>= 24; - if (angle>226 || angle<30) - { - return true; - } - } - } - return false; -} - bool AMageStaffFX2::SpecialBlastHandling (AActor *source, fixed_t strength) { // Reflect to originator diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 3dc9e141a9..0958edb83c 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -82,49 +82,6 @@ void AMinotaurFriend::Serialize (FArchive &arc) arc << StartTime; } -bool AMinotaurFriend::IsOkayToAttack (AActor *link) -{ - if ((link->flags3 & MF3_ISMONSTER) && (link != tracer)) - { - if (!((link->flags ^ flags) & MF_FRIENDLY)) - { // Don't attack friends - if (link->flags & MF_FRIENDLY) - { - if (!deathmatch || link->FriendPlayer == 0 || FriendPlayer == 0 || - link->FriendPlayer != FriendPlayer) - { - return false; - } - } - else - { - return false; - } - } - if (!(link->flags&MF_SHOOTABLE)) - { - return false; - } - if (link->flags2&MF2_DORMANT) - { - return false; - } - if ((link->flags5 & MF5_SUMMONEDMONSTER) && (link->tracer == tracer)) - { - return false; - } - if (multiplayer && !deathmatch && link->player) - { - return false; - } - if (P_CheckSight (this, link)) - { - return true; - } - } - return false; -} - void AMinotaurFriend::Die (AActor *source, AActor *inflictor) { Super::Die (source, inflictor); diff --git a/src/g_raven/ravenshared.h b/src/g_raven/ravenshared.h index 7afd759478..fb9edf2799 100644 --- a/src/g_raven/ravenshared.h +++ b/src/g_raven/ravenshared.h @@ -20,7 +20,6 @@ class AMinotaurFriend : public AMinotaur public: int StartTime; - bool IsOkayToAttack (AActor *target); void Die (AActor *source, AActor *inflictor); bool OkayToSwitchTarget (AActor *other); void BeginPlay (); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 31972de470..e898fd6870 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -2693,36 +2693,59 @@ void AActor::PlayActiveSound () bool AActor::IsOkayToAttack (AActor *link) { - if (player) // Minotaur looking around player + if (!(player // Original AActor::IsOkayToAttack was only for players + // || (flags & MF_FRIENDLY) // Maybe let friendly monsters use the function as well? + || (flags5 & MF5_SUMMONEDMONSTER) // AMinotaurFriend has its own version, generalized to other summoned monsters + || (flags2 & MF2_SEEKERMISSILE))) // AHolySpirit and AMageStaffFX2 as well, generalized to other seeker missiles + { // Normal monsters and other actors always return false. + return false; + } + // Standard things to eliminate: an actor shouldn't attack itself, + // or a non-shootable, dormant, non-player-and-non-monster actor. + if (link == this) return false; + if (!(link->player||(link->flags3 & MF3_ISMONSTER)))return false; + if (!(link->flags & MF_SHOOTABLE)) return false; + if (link->flags2 & MF2_DORMANT) return false; + + // An actor shouldn't attack friendly actors. The reference depends + // on the type of actor: for a player's actor, itself; for a projectile, + // its target; and for a summoned minion, its tracer. + AActor * Friend = NULL; + if (player) Friend = this; + else if (flags5 & MF5_SUMMONEDMONSTER) Friend = tracer; + else if (flags2 & MF2_SEEKERMISSILE) Friend = target; + else if ((flags & MF_FRIENDLY) && FriendPlayer) Friend = players[FriendPlayer-1].mo; + + // Friend checks + if (link == Friend) return false; + if (Friend == NULL) return false; + if (Friend->IsFriend(link)) return false; + if ((link->flags5 & MF5_SUMMONEDMONSTER) // No attack against minions on the same side + && (link->tracer == Friend)) return false; + if (multiplayer && !deathmatch // No attack against fellow players in coop + && link->player && Friend->player) return false; + if (((flags & link->flags) & MF_FRIENDLY) // No friendly infighting amongst minions + && IsFriend(link)) return false; + + // Now that all the actor checks are made, the line of sight can be checked + if (P_CheckSight (this, link)) { - if ((link->flags3 & MF3_ISMONSTER) || (link->player && (link != this))) + // AMageStaffFX2::IsOkayToAttack had an extra check here, generalized with a flag, + // to only allow the check to succeed if the enemy was in a ~84° FOV of the player + if (flags3 & MF3_SCREENSEEKER) { - if (IsFriend(link)) - { - return false; - } - if (!(link->flags & MF_SHOOTABLE)) - { - return false; - } - if (link->flags2 & MF2_DORMANT) - { - return false; - } - if ((link->flags5 & MF5_SUMMONEDMONSTER) && (link->tracer == this)) - { - return false; - } - if (multiplayer && !deathmatch && link->player) - { - return false; - } - if (P_CheckSight (this, link)) + angle_t angle = R_PointToAngle2(Friend->x, + Friend->y, link->x, link->y) - Friend->angle; + angle >>= 24; + if (angle>226 || angle<30) { return true; } } + // Other actors are not concerned by this check + else return true; } + // The sight check was failed, or the angle wasn't right for a screenseeker return false; } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 39a08cacdd..934a0b9b58 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -342,12 +342,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSoundEx) // Generic seeker missile function // //========================================================================== +static FRandom pr_seekermissile ("SeekerMissile"); +enum +{ + SMF_LOOK = 1, +}; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) { - ACTION_PARAM_START(2); + ACTION_PARAM_START(5); ACTION_PARAM_INT(ang1, 0); ACTION_PARAM_INT(ang2, 1); + ACTION_PARAM_INT(flags, 2); + ACTION_PARAM_INT(chance, 3); + ACTION_PARAM_INT(distance, 4); + if ((flags & SMF_LOOK) && (self->tracer == 0) && (pr_seekermissile()tracer = P_RoughMonsterSearch (self, distance); + } P_SeekerMissile(self, clamp(ang1, 0, 90) * ANGLE_1, clamp(ang2, 0, 90) * ANGLE_1); } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 7c7ee22595..89741fca62 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -92,6 +92,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF, NOLIFTDROP, AActor, flags), DEFINE_FLAG(MF, STEALTH, AActor, flags), DEFINE_FLAG(MF, ICECORPSE, AActor, flags), + DEFINE_FLAG(MF2, DONTREFLECT, AActor, flags2), DEFINE_FLAG(MF2, WINDTHRUST, AActor, flags2), DEFINE_FLAG(MF2, DONTSEEKINVISIBLE, AActor, flags2), @@ -121,6 +122,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF2, DORMANT, AActor, flags2), DEFINE_FLAG(MF2, SEEKERMISSILE, AActor, flags2), DEFINE_FLAG(MF2, REFLECTIVE, AActor, flags2), + DEFINE_FLAG(MF3, FLOORHUGGER, AActor, flags3), DEFINE_FLAG(MF3, CEILINGHUGGER, AActor, flags3), DEFINE_FLAG(MF3, NORADIUSDMG, AActor, flags3), @@ -141,13 +143,15 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF3, NOTARGET, AActor, flags3), DEFINE_FLAG(MF3, DONTGIB, AActor, flags3), DEFINE_FLAG(MF3, NOBLOCKMONST, AActor, flags3), - DEFINE_FLAG(MF3, AVOIDMELEE, AActor, flags3), DEFINE_FLAG(MF3, FULLVOLDEATH, AActor, flags3), + DEFINE_FLAG(MF3, AVOIDMELEE, AActor, flags3), + DEFINE_FLAG(MF3, SCREENSEEKER, AActor, flags3), DEFINE_FLAG(MF3, FOILINVUL, AActor, flags3), DEFINE_FLAG(MF3, NOTELEOTHER, AActor, flags3), DEFINE_FLAG(MF3, BLOODLESSIMPACT, AActor, flags3), DEFINE_FLAG(MF3, NOEXPLODEFLOOR, AActor, flags3), DEFINE_FLAG(MF3, PUFFONACTORS, AActor, flags3), + DEFINE_FLAG(MF4, QUICKTORETALIATE, AActor, flags4), DEFINE_FLAG(MF4, NOICEDEATH, AActor, flags4), DEFINE_FLAG(MF4, RANDOMIZE, AActor, flags4), diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 429038de2a..b80078769e 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -178,7 +178,7 @@ ACTOR Actor native //: Thinker action native A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was... action native A_PlaySoundEx(sound whattoplay, coerce name slot, bool looping = false, int attenuation = 0); action native A_StopSoundEx(coerce name slot); - action native A_SeekerMissile(int threshold, int turnmax); + action native A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); action native A_Jump(int chance = 256, state label, ...); action native A_CustomMissile(class missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0); action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, bool aimfacing = false); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 033920d907..fda6fd5a62 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -76,6 +76,9 @@ const int BF_USEAMMO = 1; const int BF_DONTWARN = 2; const int BF_AFFECTBOSSES = 4; +// Flags for A_SeekerMissile +const int SMF_LOOK = 1; + // Activation flags enum { @@ -97,6 +100,8 @@ const int AF_TriggerTargets = 4; const int AF_MonsterTrigger = 8; const int AF_MissileTrigger = 16; const int AF_ClearSpecial = 32; +const int AF_NoDeathSpecial = 64; +const int AF_TriggerActs = 128; // constants for A_PlaySound enum diff --git a/wadsrc/static/actors/hexen/magestaff.txt b/wadsrc/static/actors/hexen/magestaff.txt index 4b1887f559..e402e57c0b 100644 --- a/wadsrc/static/actors/hexen/magestaff.txt +++ b/wadsrc/static/actors/hexen/magestaff.txt @@ -125,6 +125,7 @@ ACTOR MageStaffFX2 native DamageType "Fire" Projectile +SEEKERMISSILE + +SCREENSEEKER +EXTREMEDEATH DeathSound "MageStaffExplode"