mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-08 05:51:09 +00:00
ebd17de30a
P_FindFloorCeiling never did that. - Merged Check_Sides and PIT_CrossLine into A_PainShootSkull. - Replaced P_BlockLinesIterator with FBlockLinesIterator in all places it was used. This also allowed to remove all the global variable saving in P_CreateSecNodeList. - Added a new FBlockLinesIterator class that doesn't need a callback function because debugging the previous bug proved to be a bit annoying because it involved a P_BlockLinesIterator loop. - Fixed: The MBF code to move monsters away from dropoffs did not work as intended due to some random decisions in P_DoNewChaseDir. When in the avoiding dropoff mode these are ignored now. This should cure the problem that monsters hanging over a dropoff tended to drop down. SVN r887 (trunk)
173 lines
4.4 KiB
C++
173 lines
4.4 KiB
C++
#include "actor.h"
|
|
#include "info.h"
|
|
#include "p_enemy.h"
|
|
#include "p_local.h"
|
|
#include "a_doomglobal.h"
|
|
#include "a_action.h"
|
|
#include "templates.h"
|
|
#include "m_bbox.h"
|
|
#include "thingdef/thingdef.h"
|
|
|
|
void A_PainAttack (AActor *);
|
|
void A_PainDie (AActor *);
|
|
|
|
void A_SkullAttack (AActor *self);
|
|
|
|
static const PClass *GetSpawnType()
|
|
{
|
|
const PClass *spawntype = NULL;
|
|
int index=CheckIndex(1, NULL);
|
|
if (index>=0)
|
|
{
|
|
spawntype = PClass::FindClass((ENamedName)StateParameters[index]);
|
|
}
|
|
if (spawntype == NULL) spawntype = PClass::FindClass("LostSoul");
|
|
return spawntype;
|
|
}
|
|
|
|
|
|
//
|
|
// A_PainShootSkull
|
|
// Spawn a lost soul and launch it at the target
|
|
//
|
|
void A_PainShootSkull (AActor *self, angle_t angle, const PClass *spawntype)
|
|
{
|
|
fixed_t x, y, z;
|
|
|
|
AActor *other;
|
|
angle_t an;
|
|
int prestep;
|
|
|
|
if (spawntype == NULL) return;
|
|
if (self->DamageType==NAME_Massacre) return;
|
|
|
|
// [RH] check to make sure it's not too close to the ceiling
|
|
if (self->z + self->height + 8*FRACUNIT > self->ceilingz)
|
|
{
|
|
if (self->flags & MF_FLOAT)
|
|
{
|
|
self->momz -= 2*FRACUNIT;
|
|
self->flags |= MF_INFLOAT;
|
|
self->flags4 |= MF4_VFRICTION;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// [RH] make this optional
|
|
if (i_compatflags & COMPATF_LIMITPAIN)
|
|
{
|
|
// count total number of skulls currently on the level
|
|
// if there are already 20 skulls on the level, don't spit another one
|
|
int count = 20;
|
|
FThinkerIterator iterator (spawntype);
|
|
DThinker *othink;
|
|
|
|
while ( (othink = iterator.Next ()) )
|
|
{
|
|
if (--count == 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
// okay, there's room for another one
|
|
an = angle >> ANGLETOFINESHIFT;
|
|
|
|
prestep = 4*FRACUNIT +
|
|
3*(self->radius + GetDefaultByType(spawntype)->radius)/2;
|
|
|
|
x = self->x + FixedMul (prestep, finecosine[an]);
|
|
y = self->y + FixedMul (prestep, finesine[an]);
|
|
z = self->z + 8*FRACUNIT;
|
|
|
|
// Check whether the Lost Soul is being fired through a 1-sided // phares
|
|
// wall or an impassible line, or a "monsters can't cross" line.// |
|
|
// If it is, then we don't allow the spawn. // V
|
|
|
|
FBoundingBox box(MIN(self->x, x), MIN(self->y, y), MAX(self->x, x), MAX(self->y, y));
|
|
FBlockLinesIterator it(box);
|
|
line_t *ld;
|
|
|
|
while ((ld = it.Next()))
|
|
{
|
|
if (!(ld->flags & ML_TWOSIDED) ||
|
|
(ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS|ML_BLOCKEVERYTHING)))
|
|
{
|
|
if (!(box.Left() > ld->bbox[BOXRIGHT] ||
|
|
box.Right() < ld->bbox[BOXLEFT] ||
|
|
box.Top() < ld->bbox[BOXBOTTOM] ||
|
|
box.Bottom() > ld->bbox[BOXTOP]))
|
|
{
|
|
if (P_PointOnLineSide(self->x,self->y,ld) != P_PointOnLineSide(x,y,ld))
|
|
return; // line blocks trajectory // ^
|
|
}
|
|
}
|
|
}
|
|
|
|
other = Spawn (spawntype, x, y, z, ALLOW_REPLACE);
|
|
|
|
|
|
// Check to see if the new Lost Soul's z value is above the
|
|
// ceiling of its new sector, or below the floor. If so, kill it.
|
|
|
|
if ((other->z >
|
|
(other->Sector->ceilingplane.ZatPoint (other->x, other->y) - other->height)) ||
|
|
(other->z < other->Sector->floorplane.ZatPoint (other->x, other->y)))
|
|
{
|
|
// kill it immediately
|
|
P_DamageMobj (other, self, self, 1000000, NAME_None); // ^
|
|
return; // |
|
|
} // phares
|
|
|
|
// Check for movements.
|
|
|
|
if (!P_CheckPosition (other, other->x, other->y))
|
|
{
|
|
// kill it immediately
|
|
P_DamageMobj (other, self, self, 1000000, NAME_None);
|
|
return;
|
|
}
|
|
|
|
// [RH] Lost souls hate the same things as their pain elementals
|
|
other->CopyFriendliness (self, true);
|
|
|
|
A_SkullAttack (other);
|
|
}
|
|
|
|
|
|
//
|
|
// A_PainAttack
|
|
// Spawn a lost soul and launch it at the target
|
|
//
|
|
void A_PainAttack (AActor *self)
|
|
{
|
|
if (!self->target)
|
|
return;
|
|
|
|
const PClass *spawntype = GetSpawnType();
|
|
A_FaceTarget (self);
|
|
A_PainShootSkull (self, self->angle, spawntype);
|
|
}
|
|
|
|
void A_DualPainAttack (AActor *self)
|
|
{
|
|
if (!self->target)
|
|
return;
|
|
|
|
const PClass *spawntype = GetSpawnType();
|
|
A_FaceTarget (self);
|
|
A_PainShootSkull (self, self->angle + ANG45, spawntype);
|
|
A_PainShootSkull (self, self->angle - ANG45, spawntype);
|
|
}
|
|
|
|
void A_PainDie (AActor *self)
|
|
{
|
|
if (self->target != NULL && self->IsFriend (self->target))
|
|
{ // And I thought you were my friend!
|
|
self->flags &= ~MF_FRIENDLY;
|
|
}
|
|
const PClass *spawntype = GetSpawnType();
|
|
A_NoBlocking (self);
|
|
A_PainShootSkull (self, self->angle + ANG90, spawntype);
|
|
A_PainShootSkull (self, self->angle + ANG180, spawntype);
|
|
A_PainShootSkull (self, self->angle + ANG270, spawntype);
|
|
}
|