vkdoom_m/src/g_doom/a_painelemental.cpp
Christoph Oelckers 062574b726 - fixed damage handling in A_BetaSkullAttack. For unknown reasons this completely bypassed the normal damage function semantics and even multiplied that with a random value.
- made some tests about calling script code from native functions.

 * scriptified A_SkullAttack to have something to test
 * changed the A_SkullAttack call in A_PainShootSkull.
 * use a macro to declare the function pointer. Using local static variable init directly results in hideous code for the need of being thread-safe (which, even if the engine was made multithreaded is not needed here.)
 * Importsnt node here: Apparently passing an actor pointer to the VMValue constructor results in the void * version being called, not the DObject * version.
2016-11-06 11:36:12 +01:00

158 lines
3.9 KiB
C++

/*
#include "actor.h"
#include "info.h"
#include "p_enemy.h"
#include "p_local.h"
#include "a_action.h"
#include "templates.h"
#include "m_bbox.h"
#include "vm.h"
#include "doomstat.h"
*/
enum PA_Flags
{
PAF_NOSKULLATTACK = 1,
PAF_AIMFACING = 2,
PAF_NOTARGET = 4,
};
//
// A_PainShootSkull
// Spawn a lost soul and launch it at the target
//
void A_PainShootSkull (VMFrameStack *stack, AActor *self, DAngle Angle, PClassActor *spawntype, int flags = 0, int limit = -1)
{
AActor *other;
double prestep;
if (spawntype == NULL) spawntype = PClass::FindActor("LostSoul");
assert(spawntype != NULL);
if (self->DamageType == NAME_Massacre) return;
// [RH] check to make sure it's not too close to the ceiling
if (self->Top() + 8 > self->ceilingz)
{
if (self->flags & MF_FLOAT)
{
self->Vel.Z -= 2;
self->flags |= MF_INFLOAT;
self->flags4 |= MF4_VFRICTION;
}
return;
}
// [RH] make this optional
if (limit == -1 && (i_compatflags & COMPATF_LIMITPAIN))
limit = 21;
if (limit)
{
// count total number of skulls currently on the level
// if there are already 21 skulls on the level, don't spit another one
int count = limit;
FThinkerIterator iterator (spawntype);
DThinker *othink;
while ( (othink = iterator.Next ()) )
{
if (--count == 0)
return;
}
}
// okay, there's room for another one
prestep = 4 + (self->radius + GetDefaultByType(spawntype)->radius) * 1.5;
// NOTE: The following code contains some advance work for line-to-line portals which is currenty inactive.
DVector2 dist = Angle.ToVector(prestep);
DVector3 pos = self->Vec3Offset(dist.X, dist.Y, 8., true);
DVector3 src = self->Pos();
for (int i = 0; i < 2; i++)
{
// 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(src.X, pos.X), MIN(src.Y, pos.Y), MAX(src.X, pos.X), MAX(src.Y, pos.Y));
FBlockLinesIterator it(box);
line_t *ld;
bool inportal = false;
while ((ld = it.Next()))
{
if (ld->isLinePortal() && i == 0)
{
if (P_PointOnLineSidePrecise(src, ld) == 0 &&
P_PointOnLineSidePrecise(pos, ld) == 1)
{
// crossed a portal line from front to back, we need to repeat the check on the other side as well.
inportal = true;
}
}
else if (!(ld->flags & ML_TWOSIDED) ||
(ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS | ML_BLOCKEVERYTHING)))
{
if (box.inRange(ld))
{
if (P_PointOnLineSidePrecise(src, ld) != P_PointOnLineSidePrecise(pos, ld))
return; // line blocks trajectory // ^
}
}
}
if (!inportal) break;
// recalculate position and redo the check on the other side of the portal
pos = self->Vec3Offset(dist.X, dist.Y, 8.);
src.X = pos.X - dist.X;
src.Y = pos.Y - dist.Y;
}
other = Spawn (spawntype, pos, 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->Top() > other->Sector->HighestCeilingAt(other) ||
other->Z() < other->Sector->LowestFloorAt(other))
{
// kill it immediately
P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);// ^
return; // |
} // phares
// Check for movements.
if (!P_CheckPosition (other, other->Pos()))
{
// kill it immediately
P_DamageMobj (other, self, self, TELEFRAG_DAMAGE, NAME_None);
return;
}
// [RH] Lost souls hate the same things as their pain elementals
other->CopyFriendliness (self, !(flags & PAF_NOTARGET));
if (!(flags & PAF_NOSKULLATTACK))
{
DECLARE_VMFUNC(AActor, A_SkullAttack);
CallAction(stack, A_SkullAttack, other);
}
}
DEFINE_ACTION_FUNCTION(AActor, A_PainShootSkull)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(spawntype, AActor);
PARAM_FLOAT(angle);
PARAM_INT_DEF(flags);
PARAM_INT_DEF(limit);
A_PainShootSkull(stack, self, angle, spawntype, flags, limit);
return 0;
}