Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added WorldHitscanFired and WorldHitscanPreFired #2432

Merged
merged 2 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 83 additions & 1 deletion src/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,36 @@ void EventManager::WorldThingDied(AActor* actor, AActor* inflictor)
handler->WorldThingDied(actor, inflictor);
}

bool EventManager::WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
if (actor->ObjectFlags & OF_EuthanizeMe)
return false;

bool ret = false;
if (ShouldCallStatic(true)) ret = staticEventManager.WorldHitscanPreFired(actor, angle, distance, pitch, damage, damageType, pufftype, flags, sz, offsetforward, offsetside);

if (!ret)
{
for (DStaticEventHandler* handler = FirstEventHandler; handler && ret == false; handler = handler->next)
ret = handler->WorldHitscanPreFired(actor, angle, distance, pitch, damage, damageType, pufftype, flags, sz, offsetforward, offsetside);
}

return ret;
}

void EventManager::WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
if (actor->ObjectFlags & OF_EuthanizeMe)
return;

if (ShouldCallStatic(true)) staticEventManager.WorldHitscanFired(actor, AttackPos, DamagePosition, Inflictor, flags);

for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->WorldHitscanFired(actor, AttackPos, DamagePosition, Inflictor, flags);
}

void EventManager::WorldThingGround(AActor* actor, FState* st)
{
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
Expand Down Expand Up @@ -1026,6 +1056,14 @@ DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamagePosition);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageIsRadius);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, NewDamage);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, CrushedState);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackPos);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackAngle);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackPitch);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackDistance);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackOffsetForward);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackOffsetSide);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackZ);
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackPuffType);

DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, PlayerNumber);
DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, IsReturn);
Expand Down Expand Up @@ -1729,6 +1767,51 @@ void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor)
}
}

bool DStaticEventHandler::WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside)
{
IFVIRTUAL(DStaticEventHandler, WorldHitscanPreFired)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return false;
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
e.AttackAngle = angle;
e.AttackPitch = pitch;
e.AttackDistance = distance;
e.Damage = damage;
e.DamageType = damageType;
e.AttackPuffType = pufftype;
e.AttackOffsetForward = offsetforward;
e.AttackOffsetSide = offsetside;
e.AttackZ = sz;
e.DamageFlags = flags;
int processed;
VMReturn results[1] = { &processed };
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, results, 1);
return !!processed;
}

return false;
}

void DStaticEventHandler::WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags)
{
IFVIRTUAL(DStaticEventHandler, WorldHitscanFired)
{
// don't create excessive DObjects if not going to be processed anyway
if (isEmpty(func)) return;
FWorldEvent e = owner->SetupWorldEvent();
e.Thing = actor;
e.AttackPos = AttackPos;
e.DamagePosition = DamagePosition;
e.Inflictor = Inflictor;
e.DamageFlags = flags;
VMValue params[2] = { (DStaticEventHandler*)this, &e };
VMCall(func, params, 2, nullptr, 0);
}
}

void DStaticEventHandler::WorldThingGround(AActor* actor, FState* st)
{
IFVIRTUAL(DStaticEventHandler, WorldThingGround)
Expand All @@ -1743,7 +1826,6 @@ void DStaticEventHandler::WorldThingGround(AActor* actor, FState* st)
}
}


void DStaticEventHandler::WorldThingRevived(AActor* actor)
{
IFVIRTUAL(DStaticEventHandler, WorldThingRevived)
Expand Down
14 changes: 14 additions & 0 deletions src/events.h
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ class DStaticEventHandler : public DObject // make it a part of normal GC proces
void WorldThingRevived(AActor* actor);
void WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle);
void WorldThingDestroyed(AActor* actor);
bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside);
void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags);
void WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate);
void WorldLineActivated(line_t* line, AActor* actor, int activationType);
int WorldSectorDamaged(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius);
Expand Down Expand Up @@ -393,6 +395,14 @@ struct FWorldEvent
bool DamageIsRadius; // radius damage yes/no
int NewDamage = 0; // sector/line damaged. allows modifying damage
FState* CrushedState = nullptr; // custom crush state set in thingground
DVector3 AttackPos; //hitscan point of origin
DAngle AttackAngle;
DAngle AttackPitch;
double AttackDistance = 0;
double AttackOffsetForward = 0;
double AttackOffsetSide = 0;
double AttackZ = 0;
PClassActor* AttackPuffType = nullptr;
};

struct FPlayerEvent
Expand Down Expand Up @@ -467,6 +477,10 @@ struct EventManager
void WorldThingSpawned(AActor* actor);
// called after AActor::Die of each actor.
void WorldThingDied(AActor* actor, AActor* inflictor);
// called when a hitscan attack is fired (can be overridden to block it)
bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside);
// called when a hitscan attack has been fired
void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags);
// called inside AActor::Grind just before the corpse is destroyed
void WorldThingGround(AActor* actor, FState* st);
// called after AActor::Revive.
Expand Down
52 changes: 38 additions & 14 deletions src/playsim/p_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
#include "r_utility.h"
#include "p_blockmap.h"
#include "p_3dmidtex.h"
#include "events.h"
#include "vm.h"
#include "d_main.h"

Expand Down Expand Up @@ -4620,6 +4621,12 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage,
double sz, double offsetforward, double offsetside)
{
if (t1->Level->localEventManager->WorldHitscanPreFired(t1, angle, distance, pitch, damage, damageType, pufftype, flags, sz, offsetforward, offsetside))
{
return nullptr;
}


bool nointeract = !!(flags & LAF_NOINTERACT);
DVector3 direction;
double shootz;
Expand All @@ -4634,6 +4641,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
if (flags & LAF_NORANDOMPUFFZ)
puffFlags |= PF_NORANDOMZ;


if (victim != NULL)
{
memset(victim, 0, sizeof(*victim));
Expand Down Expand Up @@ -4724,6 +4732,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
// LAF_ABSOFFSET: Ignore the angle.

DVector3 tempos;
DVector3 puffpos;

if (flags & LAF_ABSPOSITION)
{
Expand Down Expand Up @@ -4759,7 +4768,8 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,

if (nointeract || (puffDefaults && puffDefaults->flags3 & MF3_ALWAYSPUFF))
{ // Spawn the puff anyway
puff = P_SpawnPuff(t1, pufftype, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget, 2, puffFlags);
puffpos = trace.HitPos;
puff = P_SpawnPuff(t1, pufftype, puffpos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget, 2, puffFlags);

if (nointeract)
{
Expand Down Expand Up @@ -4789,7 +4799,8 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
if (nointeract || trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky))
{
DVector2 pos = t1->Level->GetPortalOffsetPosition(trace.HitPos.X, trace.HitPos.Y, -trace.HitVector.X * 4, -trace.HitVector.Y * 4);
puff = P_SpawnPuff(t1, pufftype, DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4), trace.SrcAngleFromTarget,
puffpos = DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4);
puff = P_SpawnPuff(t1, pufftype, puffpos, trace.SrcAngleFromTarget,
trace.SrcAngleFromTarget - DAngle::fromDeg(90), 0, puffFlags);
puff->radius = 1/65536.;

Expand Down Expand Up @@ -4836,6 +4847,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
{
// Hit a thing, so it could be either a puff or blood
DVector3 bleedpos = trace.HitPos;
puffpos = bleedpos;
// position a bit closer for puffs/blood if using compatibility mode.
if (trace.Actor->Level->i_compatflags & COMPATF_HITSCAN)
{
Expand Down Expand Up @@ -4928,6 +4940,9 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
SpawnDeepSplash(t1, trace, puff);
}
}

t1->Level->localEventManager->WorldHitscanFired(t1, tempos, puffpos, puff, flags);

if (killPuff && puff != NULL)
{
puff->Destroy();
Expand Down Expand Up @@ -5378,16 +5393,30 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
//==========================================================================
void P_RailAttack(FRailParams *p)
{
DVector3 start;
FTraceResults trace;
AActor *source = p->source;

PClassActor *puffclass = p->puff;
if (puffclass == NULL)
{
puffclass = PClass::FindActor(NAME_BulletPuff);
}
assert(puffclass != NULL); // Because we set it to a default above
AActor *puffDefaults = GetDefaultByType(puffclass->GetReplacement(source->Level)); //Contains all the flags such as FOILINVUL, etc.
FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType;

int flags;

// disabled because not complete yet.
flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? TRACE_ReportPortals : TRACE_PCross | TRACE_Impact | TRACE_ReportPortals;

if (source->Level->localEventManager->WorldHitscanPreFired(source, source->Angles.Yaw + p->angleoffset, p->distance, source->Angles.Pitch + p->pitchoffset, p->damage, damagetype, puffclass, flags, p->offset_z, 0, p->offset_xy))
{
return;
}

DVector3 start;
FTraceResults trace;

AActor *source = p->source;
DAngle pitch = source->Angles.Pitch + p->pitchoffset;
DAngle angle = source->Angles.Yaw + p->angleoffset;

Expand Down Expand Up @@ -5416,13 +5445,6 @@ void P_RailAttack(FRailParams *p)
start.Y = xy.Y;
start.Z = shootz;

int flags;

assert(puffclass != NULL); // Because we set it to a default above
AActor *puffDefaults = GetDefaultByType(puffclass->GetReplacement(source->Level)); //Contains all the flags such as FOILINVUL, etc.

// disabled because not complete yet.
flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? TRACE_ReportPortals : TRACE_PCross | TRACE_Impact | TRACE_ReportPortals;
rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true;
rail_data.MThruSpecies = ((puffDefaults->flags6 & MF6_MTHRUSPECIES)) ? true : false;

Expand Down Expand Up @@ -5459,8 +5481,7 @@ void P_RailAttack(FRailParams *p)

// Hurt anything the trace hit
unsigned int i;
FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType;


for (i = 0; i < rail_data.RailHits.Size(); i++)
{
bool spawnpuff;
Expand Down Expand Up @@ -5548,6 +5569,9 @@ void P_RailAttack(FRailParams *p)
}
}
}

source->Level->localEventManager->WorldHitscanFired(source, start, trace.HitPos, thepuff, flags);

if (thepuff != NULL)
{
if (trace.Crossed3DWater || trace.CrossedWater)
Expand Down
10 changes: 10 additions & 0 deletions wadsrc/static/zscript/events.zs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ struct WorldEvent native play version("2.4")
native readonly bool DamageIsRadius;
native int NewDamage;
native readonly State CrushedState;
native readonly double AttackAngle;
native readonly double AttackPitch;
native readonly double AttackDistance;
native readonly vector3 AttackPos;
native readonly double AttackOffsetForward;
native readonly double AttackOffsetSide;
native readonly double AttackZ;
native readonly class<Actor> AttackPuffType;
}

struct PlayerEvent native play version("2.4")
Expand Down Expand Up @@ -155,6 +163,8 @@ class StaticEventHandler : Object native play version("2.4")
virtual void WorldThingRevived(WorldEvent e) {}
virtual void WorldThingDamaged(WorldEvent e) {}
virtual void WorldThingDestroyed(WorldEvent e) {}
virtual bool WorldHitscanPreFired(WorldEvent e) { return false; }
virtual void WorldHitscanFired(WorldEvent e) {}
virtual void WorldLinePreActivated(WorldEvent e) {}
virtual void WorldLineActivated(WorldEvent e) {}
virtual void WorldSectorDamaged(WorldEvent e) {}
Expand Down