- Added Gez's seeker missile submission.

SVN r1905 (trunk)
This commit is contained in:
Christoph Oelckers 2009-10-09 20:54:28 +00:00
parent 819158a8fe
commit 4a81f55fb0
13 changed files with 74 additions and 139 deletions

View file

@ -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.

View file

@ -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 ();

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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 ();

View file

@ -2693,36 +2693,59 @@ void AActor::PlayActiveSound ()
bool AActor::IsOkayToAttack (AActor *link)
{
if (player) // Minotaur looking around player
{
if ((link->flags3 & MF3_ISMONSTER) || (link->player && (link != this)))
{
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)
{
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))
{
// 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)
{
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;
}

View file

@ -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()<chance))
{
self->tracer = P_RoughMonsterSearch (self, distance);
}
P_SeekerMissile(self, clamp<int>(ang1, 0, 90) * ANGLE_1, clamp<int>(ang2, 0, 90) * ANGLE_1);
}

View file

@ -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),

View file

@ -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<Actor> 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<Actor> pufftype = "BulletPuff", float range = 0, bool aimfacing = false);

View file

@ -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

View file

@ -125,6 +125,7 @@ ACTOR MageStaffFX2 native
DamageType "Fire"
Projectile
+SEEKERMISSILE
+SCREENSEEKER
+EXTREMEDEATH
DeathSound "MageStaffExplode"