Skip to content

Commit 99c058d

Browse files
authored
Added WorldHitscanFired and WorldHitscanPreFired (ZDoom#2432)
* Added WorldHitscan events * DVector3 → const DVector3&
1 parent c31f45c commit 99c058d

File tree

4 files changed

+145
-15
lines changed

4 files changed

+145
-15
lines changed

src/events.cpp

+83-1
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,36 @@ void EventManager::WorldThingDied(AActor* actor, AActor* inflictor)
701701
handler->WorldThingDied(actor, inflictor);
702702
}
703703

704+
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)
705+
{
706+
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
707+
if (actor->ObjectFlags & OF_EuthanizeMe)
708+
return false;
709+
710+
bool ret = false;
711+
if (ShouldCallStatic(true)) ret = staticEventManager.WorldHitscanPreFired(actor, angle, distance, pitch, damage, damageType, pufftype, flags, sz, offsetforward, offsetside);
712+
713+
if (!ret)
714+
{
715+
for (DStaticEventHandler* handler = FirstEventHandler; handler && ret == false; handler = handler->next)
716+
ret = handler->WorldHitscanPreFired(actor, angle, distance, pitch, damage, damageType, pufftype, flags, sz, offsetforward, offsetside);
717+
}
718+
719+
return ret;
720+
}
721+
722+
void EventManager::WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags)
723+
{
724+
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
725+
if (actor->ObjectFlags & OF_EuthanizeMe)
726+
return;
727+
728+
if (ShouldCallStatic(true)) staticEventManager.WorldHitscanFired(actor, AttackPos, DamagePosition, Inflictor, flags);
729+
730+
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
731+
handler->WorldHitscanFired(actor, AttackPos, DamagePosition, Inflictor, flags);
732+
}
733+
704734
void EventManager::WorldThingGround(AActor* actor, FState* st)
705735
{
706736
// don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever.
@@ -1026,6 +1056,14 @@ DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamagePosition);
10261056
DEFINE_FIELD_X(WorldEvent, FWorldEvent, DamageIsRadius);
10271057
DEFINE_FIELD_X(WorldEvent, FWorldEvent, NewDamage);
10281058
DEFINE_FIELD_X(WorldEvent, FWorldEvent, CrushedState);
1059+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackPos);
1060+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackAngle);
1061+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackPitch);
1062+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackDistance);
1063+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackOffsetForward);
1064+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackOffsetSide);
1065+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackZ);
1066+
DEFINE_FIELD_X(WorldEvent, FWorldEvent, AttackPuffType);
10291067

10301068
DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, PlayerNumber);
10311069
DEFINE_FIELD_X(PlayerEvent, FPlayerEvent, IsReturn);
@@ -1729,6 +1767,51 @@ void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor)
17291767
}
17301768
}
17311769

1770+
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)
1771+
{
1772+
IFVIRTUAL(DStaticEventHandler, WorldHitscanPreFired)
1773+
{
1774+
// don't create excessive DObjects if not going to be processed anyway
1775+
if (isEmpty(func)) return false;
1776+
FWorldEvent e = owner->SetupWorldEvent();
1777+
e.Thing = actor;
1778+
e.AttackAngle = angle;
1779+
e.AttackPitch = pitch;
1780+
e.AttackDistance = distance;
1781+
e.Damage = damage;
1782+
e.DamageType = damageType;
1783+
e.AttackPuffType = pufftype;
1784+
e.AttackOffsetForward = offsetforward;
1785+
e.AttackOffsetSide = offsetside;
1786+
e.AttackZ = sz;
1787+
e.DamageFlags = flags;
1788+
int processed;
1789+
VMReturn results[1] = { &processed };
1790+
VMValue params[2] = { (DStaticEventHandler*)this, &e };
1791+
VMCall(func, params, 2, results, 1);
1792+
return !!processed;
1793+
}
1794+
1795+
return false;
1796+
}
1797+
1798+
void DStaticEventHandler::WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags)
1799+
{
1800+
IFVIRTUAL(DStaticEventHandler, WorldHitscanFired)
1801+
{
1802+
// don't create excessive DObjects if not going to be processed anyway
1803+
if (isEmpty(func)) return;
1804+
FWorldEvent e = owner->SetupWorldEvent();
1805+
e.Thing = actor;
1806+
e.AttackPos = AttackPos;
1807+
e.DamagePosition = DamagePosition;
1808+
e.Inflictor = Inflictor;
1809+
e.DamageFlags = flags;
1810+
VMValue params[2] = { (DStaticEventHandler*)this, &e };
1811+
VMCall(func, params, 2, nullptr, 0);
1812+
}
1813+
}
1814+
17321815
void DStaticEventHandler::WorldThingGround(AActor* actor, FState* st)
17331816
{
17341817
IFVIRTUAL(DStaticEventHandler, WorldThingGround)
@@ -1743,7 +1826,6 @@ void DStaticEventHandler::WorldThingGround(AActor* actor, FState* st)
17431826
}
17441827
}
17451828

1746-
17471829
void DStaticEventHandler::WorldThingRevived(AActor* actor)
17481830
{
17491831
IFVIRTUAL(DStaticEventHandler, WorldThingRevived)

src/events.h

100755100644
+14
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ class DStaticEventHandler : public DObject // make it a part of normal GC proces
311311
void WorldThingRevived(AActor* actor);
312312
void WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle);
313313
void WorldThingDestroyed(AActor* actor);
314+
bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside);
315+
void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags);
314316
void WorldLinePreActivated(line_t* line, AActor* actor, int activationType, bool* shouldactivate);
315317
void WorldLineActivated(line_t* line, AActor* actor, int activationType);
316318
int WorldSectorDamaged(sector_t* sector, AActor* source, int damage, FName damagetype, int part, DVector3 position, bool isradius);
@@ -393,6 +395,14 @@ struct FWorldEvent
393395
bool DamageIsRadius; // radius damage yes/no
394396
int NewDamage = 0; // sector/line damaged. allows modifying damage
395397
FState* CrushedState = nullptr; // custom crush state set in thingground
398+
DVector3 AttackPos; //hitscan point of origin
399+
DAngle AttackAngle;
400+
DAngle AttackPitch;
401+
double AttackDistance = 0;
402+
double AttackOffsetForward = 0;
403+
double AttackOffsetSide = 0;
404+
double AttackZ = 0;
405+
PClassActor* AttackPuffType = nullptr;
396406
};
397407

398408
struct FPlayerEvent
@@ -467,6 +477,10 @@ struct EventManager
467477
void WorldThingSpawned(AActor* actor);
468478
// called after AActor::Die of each actor.
469479
void WorldThingDied(AActor* actor, AActor* inflictor);
480+
// called when a hitscan attack is fired (can be overridden to block it)
481+
bool WorldHitscanPreFired(AActor* actor, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, double sz, double offsetforward, double offsetside);
482+
// called when a hitscan attack has been fired
483+
void WorldHitscanFired(AActor* actor, const DVector3& AttackPos, const DVector3& DamagePosition, AActor* Inflictor, int flags);
470484
// called inside AActor::Grind just before the corpse is destroyed
471485
void WorldThingGround(AActor* actor, FState* st);
472486
// called after AActor::Revive.

src/playsim/p_map.cpp

+38-14
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
#include "r_utility.h"
8282
#include "p_blockmap.h"
8383
#include "p_3dmidtex.h"
84+
#include "events.h"
8485
#include "vm.h"
8586
#include "d_main.h"
8687

@@ -4627,6 +4628,12 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
46274628
DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage,
46284629
double sz, double offsetforward, double offsetside)
46294630
{
4631+
if (t1->Level->localEventManager->WorldHitscanPreFired(t1, angle, distance, pitch, damage, damageType, pufftype, flags, sz, offsetforward, offsetside))
4632+
{
4633+
return nullptr;
4634+
}
4635+
4636+
46304637
bool nointeract = !!(flags & LAF_NOINTERACT);
46314638
DVector3 direction;
46324639
double shootz;
@@ -4641,6 +4648,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
46414648
if (flags & LAF_NORANDOMPUFFZ)
46424649
puffFlags |= PF_NORANDOMZ;
46434650

4651+
46444652
if (victim != NULL)
46454653
{
46464654
memset(victim, 0, sizeof(*victim));
@@ -4731,6 +4739,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
47314739
// LAF_ABSOFFSET: Ignore the angle.
47324740

47334741
DVector3 tempos;
4742+
DVector3 puffpos;
47344743

47354744
if (flags & LAF_ABSPOSITION)
47364745
{
@@ -4766,7 +4775,8 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
47664775

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

47714781
if (nointeract)
47724782
{
@@ -4796,7 +4806,8 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
47964806
if (nointeract || trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky))
47974807
{
47984808
DVector2 pos = t1->Level->GetPortalOffsetPosition(trace.HitPos.X, trace.HitPos.Y, -trace.HitVector.X * 4, -trace.HitVector.Y * 4);
4799-
puff = P_SpawnPuff(t1, pufftype, DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4), trace.SrcAngleFromTarget,
4809+
puffpos = DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4);
4810+
puff = P_SpawnPuff(t1, pufftype, puffpos, trace.SrcAngleFromTarget,
48004811
trace.SrcAngleFromTarget - DAngle::fromDeg(90), 0, puffFlags);
48014812
puff->radius = 1/65536.;
48024813

@@ -4843,6 +4854,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
48434854
{
48444855
// Hit a thing, so it could be either a puff or blood
48454856
DVector3 bleedpos = trace.HitPos;
4857+
puffpos = bleedpos;
48464858
// position a bit closer for puffs/blood if using compatibility mode.
48474859
if (trace.Actor->Level->i_compatflags & COMPATF_HITSCAN)
48484860
{
@@ -4935,6 +4947,9 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
49354947
SpawnDeepSplash(t1, trace, puff);
49364948
}
49374949
}
4950+
4951+
t1->Level->localEventManager->WorldHitscanFired(t1, tempos, puffpos, puff, flags);
4952+
49384953
if (killPuff && puff != NULL)
49394954
{
49404955
puff->Destroy();
@@ -5385,16 +5400,30 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
53855400
//==========================================================================
53865401
void P_RailAttack(FRailParams *p)
53875402
{
5388-
DVector3 start;
5389-
FTraceResults trace;
5403+
AActor *source = p->source;
53905404

53915405
PClassActor *puffclass = p->puff;
53925406
if (puffclass == NULL)
53935407
{
53945408
puffclass = PClass::FindActor(NAME_BulletPuff);
53955409
}
5410+
assert(puffclass != NULL); // Because we set it to a default above
5411+
AActor *puffDefaults = GetDefaultByType(puffclass->GetReplacement(source->Level)); //Contains all the flags such as FOILINVUL, etc.
5412+
FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType;
5413+
5414+
int flags;
5415+
5416+
// disabled because not complete yet.
5417+
flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? TRACE_ReportPortals : TRACE_PCross | TRACE_Impact | TRACE_ReportPortals;
5418+
5419+
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))
5420+
{
5421+
return;
5422+
}
5423+
5424+
DVector3 start;
5425+
FTraceResults trace;
53965426

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

@@ -5423,13 +5452,6 @@ void P_RailAttack(FRailParams *p)
54235452
start.Y = xy.Y;
54245453
start.Z = shootz;
54255454

5426-
int flags;
5427-
5428-
assert(puffclass != NULL); // Because we set it to a default above
5429-
AActor *puffDefaults = GetDefaultByType(puffclass->GetReplacement(source->Level)); //Contains all the flags such as FOILINVUL, etc.
5430-
5431-
// disabled because not complete yet.
5432-
flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? TRACE_ReportPortals : TRACE_PCross | TRACE_Impact | TRACE_ReportPortals;
54335455
rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true;
54345456
rail_data.MThruSpecies = ((puffDefaults->flags6 & MF6_MTHRUSPECIES)) ? true : false;
54355457

@@ -5466,8 +5488,7 @@ void P_RailAttack(FRailParams *p)
54665488

54675489
// Hurt anything the trace hit
54685490
unsigned int i;
5469-
FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType;
5470-
5491+
54715492
for (i = 0; i < rail_data.RailHits.Size(); i++)
54725493
{
54735494
bool spawnpuff;
@@ -5555,6 +5576,9 @@ void P_RailAttack(FRailParams *p)
55555576
}
55565577
}
55575578
}
5579+
5580+
source->Level->localEventManager->WorldHitscanFired(source, start, trace.HitPos, thepuff, flags);
5581+
55585582
if (thepuff != NULL)
55595583
{
55605584
if (trace.Crossed3DWater || trace.CrossedWater)

wadsrc/static/zscript/events.zs

+10
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ struct WorldEvent native play version("2.4")
9797
native readonly bool DamageIsRadius;
9898
native int NewDamage;
9999
native readonly State CrushedState;
100+
native readonly double AttackAngle;
101+
native readonly double AttackPitch;
102+
native readonly double AttackDistance;
103+
native readonly vector3 AttackPos;
104+
native readonly double AttackOffsetForward;
105+
native readonly double AttackOffsetSide;
106+
native readonly double AttackZ;
107+
native readonly class<Actor> AttackPuffType;
100108
}
101109

102110
struct PlayerEvent native play version("2.4")
@@ -155,6 +163,8 @@ class StaticEventHandler : Object native play version("2.4")
155163
virtual void WorldThingRevived(WorldEvent e) {}
156164
virtual void WorldThingDamaged(WorldEvent e) {}
157165
virtual void WorldThingDestroyed(WorldEvent e) {}
166+
virtual bool WorldHitscanPreFired(WorldEvent e) { return false; }
167+
virtual void WorldHitscanFired(WorldEvent e) {}
158168
virtual void WorldLinePreActivated(WorldEvent e) {}
159169
virtual void WorldLineActivated(WorldEvent e) {}
160170
virtual void WorldSectorDamaged(WorldEvent e) {}

0 commit comments

Comments
 (0)