diff --git a/src/events.cpp b/src/events.cpp index 68088a307..3fb90dcbb 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -259,6 +259,15 @@ void E_WorldThingRevived(AActor* actor) handler->WorldThingRevived(actor); } +void E_WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle) +{ + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->WorldThingDamaged(actor, inflictor, source, damage, mod, flags, angle); +} + void E_WorldThingDestroyed(AActor* actor) { // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. @@ -290,7 +299,11 @@ DEFINE_FIELD_X(RenderEvent, DRenderEvent, Camera); DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsSaveGame); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Thing); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Inflictor); - +DEFINE_FIELD_X(WorldEvent, DWorldEvent, Damage); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageSource); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageType); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageFlags); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageAngle); DEFINE_ACTION_FUNCTION(DEventHandler, Create) { @@ -409,6 +422,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldUnloaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDied) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingRevived) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDamaged) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDestroyed) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) @@ -427,6 +441,11 @@ static DWorldEvent* E_SetupWorldEvent() e->IsSaveGame = savegamerestore; e->Thing = nullptr; e->Inflictor = nullptr; + e->Damage = 0; + e->DamageAngle = 0.0; + e->DamageFlags = 0; + e->DamageSource = 0; + e->DamageType = NAME_None; return e; } @@ -499,6 +518,25 @@ void DStaticEventHandler::WorldThingRevived(AActor* actor) } } +void DStaticEventHandler::WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle) +{ + IFVIRTUAL(DStaticEventHandler, WorldThingDamaged) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldThingDamaged_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + e->Thing = actor; + e->Damage = damage; + e->DamageSource = source; + e->DamageType = mod; + e->DamageFlags = flags; + e->DamageAngle = angle; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + void DStaticEventHandler::WorldThingDestroyed(AActor* actor) { IFVIRTUAL(DStaticEventHandler, WorldThingDestroyed) diff --git a/src/events.h b/src/events.h index 0bebcfc88..73fd5e401 100755 --- a/src/events.h +++ b/src/events.h @@ -31,6 +31,8 @@ void E_WorldThingSpawned(AActor* actor); void E_WorldThingDied(AActor* actor, AActor* inflictor); // called after AActor::Revive. void E_WorldThingRevived(AActor* actor); +// called before P_DamageMobj and before AActor::DamageMobj virtuals. +void E_WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle); // called before AActor::Destroy of each actor. void E_WorldThingDestroyed(AActor* actor); // same as ACS SCRIPT_Lightning @@ -89,6 +91,7 @@ public: virtual void WorldThingSpawned(AActor*); virtual void WorldThingDied(AActor*, AActor*); virtual void WorldThingRevived(AActor*); + virtual void WorldThingDamaged(AActor*, AActor*, AActor*, int, FName, int, DAngle); virtual void WorldThingDestroyed(AActor*); virtual void WorldLightning(); virtual void WorldTick(); @@ -136,18 +139,6 @@ public: FracTic = 0; Camera = nullptr; } - - // serialization handler for our local stuff - void Serialize(FSerializer& arc) override - { - Super::Serialize(arc); - arc("ViewPos", ViewPos); - arc("ViewAngle", ViewAngle); - arc("ViewPitch", ViewPitch); - arc("ViewRoll", ViewRoll); - arc("FracTic", FracTic); - arc("Camera", Camera); - } }; class DWorldEvent : public DBaseEvent @@ -160,20 +151,21 @@ public: AActor* Thing; // for thingdied AActor* Inflictor; // can be null + // for damagemobj + int Damage; + AActor* DamageSource; // can be null + FName DamageType; + int DamageFlags; + DAngle DamageAngle; DWorldEvent() { IsSaveGame = false; Thing = nullptr; Inflictor = nullptr; - } - - void Serialize(FSerializer& arc) override - { - Super::Serialize(arc); - arc("IsSaveGame", IsSaveGame); - arc("Thing", Thing); - arc("Inflictor", Inflictor); + Damage = 0; + DamageSource = nullptr; + DamageFlags = 0; } }; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index fbdac3f8f..b9c72e128 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1597,7 +1597,12 @@ DEFINE_ACTION_FUNCTION(AActor, DamageMobj) PARAM_NAME(mod); PARAM_INT_DEF(flags); PARAM_FLOAT_DEF(angle); - ACTION_RETURN_INT(DamageMobj(self, inflictor, source, damage, mod, flags, angle)); + + // [ZZ] event handlers need the result. + int realdamage = DamageMobj(self, inflictor, source, damage, mod, flags, angle); + if (!realdamage) ACTION_RETURN_INT(0); + E_WorldThingDamaged(self, inflictor, source, realdamage, mod, flags, angle); + ACTION_RETURN_INT(realdamage); } int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, DAngle angle) @@ -1611,7 +1616,14 @@ int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, GlobalVMStack.Call(func, params, 7, &ret, 1, nullptr); return retval; } - else return DamageMobj(target, inflictor, source, damage, mod, flags, angle); + else + { + int realdamage = DamageMobj(target, inflictor, source, damage, mod, flags, angle); + if (!realdamage) return 0; + // [ZZ] event handlers only need the resultant damage (they can't do anything about it anyway) + E_WorldThingDamaged(target, inflictor, source, realdamage, mod, flags, angle); + return realdamage; + } } diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index cedee667a..a1029ff93 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -18,6 +18,12 @@ class WorldEvent : BaseEvent native native readonly Actor Thing; // for thingdied. can be null native readonly Actor Inflictor; + // for thingdamaged. + native readonly int Damage; + native readonly Actor DamageSource; + native readonly Name DamageType; + native readonly EDmgFlags DamageFlags; + native readonly double DamageAngle; } class StaticEventHandler : Object native @@ -37,6 +43,7 @@ class StaticEventHandler : Object native virtual native void WorldThingSpawned(WorldEvent e); virtual native void WorldThingDied(WorldEvent e); virtual native void WorldThingRevived(WorldEvent e); + virtual native void WorldThingDamaged(WorldEvent e); virtual native void WorldThingDestroyed(WorldEvent e); virtual native void WorldLightning(WorldEvent e); // for the sake of completeness. virtual native void WorldTick(WorldEvent e);