# HG changeset patch # User Adam Kaminski # Date 1638127682 18000 # Sun Nov 28 14:28:02 2021 -0500 # Node ID 8582fccb02f82f77604240d4ed71933bb3d9eb26 # Parent 4b4e53df7d0b389d7daa22f4cbdac64ca2bc0cea Added a variant of GAMEEVENT_ACTOR_DAMAGED that is triggered just before an actor's armor can absorb any damage, called GAMEEVENT_ACTOR_ARMORDAMAGED. diff -r 4b4e53df7d0b -r 8582fccb02f8 src/gamemode.cpp --- a/src/gamemode.cpp Sun Nov 28 13:28:27 2021 -0500 +++ b/src/gamemode.cpp Sun Nov 28 14:28:02 2021 -0500 @@ -1084,6 +1084,8 @@ // LONG GAMEMODE_HandleEvent ( const GAMEEVENT_e Event, AActor *pActivator, const int DataOne, const int DataTwo ) { + bool bRunNow = false; + // [BB] Clients don't start scripts. if ( NETWORK_InClientMode() ) return 1; @@ -1093,7 +1095,8 @@ // actor pointers that were responsible for calling the event // become NULL after one tic. // Also allow chat events to be executed immediately. - bool bRunNow = ( Event == GAMEEVENT_ACTOR_SPAWNED || Event == GAMEEVENT_ACTOR_DAMAGED || Event == GAMEEVENT_CHAT ); + if ( Event == GAMEEVENT_ACTOR_SPAWNED || Event == GAMEEVENT_ACTOR_DAMAGED || Event == GAMEEVENT_ACTOR_ARMORDAMAGED || Event == GAMEEVENT_CHAT ) + bRunNow = true; // [BB] The activator of the event activates the event script. // The first argument is the type, e.g. GAMEEVENT_PLAYERFRAGS, @@ -1111,7 +1114,7 @@ //***************************************************************************** // -bool GAMEMODE_HandleDamageEvent ( AActor *target, AActor *inflictor, AActor *source, int &damage, FName mod ) +bool GAMEMODE_HandleDamageEvent ( AActor *target, AActor *inflictor, AActor *source, int &damage, FName mod, bool bBeforeArmor ) { // [AK] Don't run any scripts if the target doesn't allow executing GAMEEVENT_ACTOR_DAMAGED. if ( target->STFlags & STFL_NODAMAGEEVENTSCRIPT ) @@ -1122,6 +1125,8 @@ if ((( target->STFlags & STFL_USEDAMAGEEVENTSCRIPT ) == false ) && ( gameinfo.bForceDamageEventScripts == false )) return true; + const GAMEEVENT_e DamageEvent = bBeforeArmor ? GAMEEVENT_ACTOR_ARMORDAMAGED : GAMEEVENT_ACTOR_DAMAGED; + // [AK] We somehow need to pass all the actor pointers into the script itself. A simple way // to do this is temporarily spawn a temporary actor and change its actor pointers to the target, // source, and inflictor. We can then use these to initialize the AAPTR_DAMAGE_TARGET, @@ -1133,7 +1138,7 @@ temp->tracer = inflictor; GAMEMODE_SetEventResult( damage ); - damage = GAMEMODE_HandleEvent( GAMEEVENT_ACTOR_DAMAGED, temp, damage, GlobalACSStrings.AddString( mod )); + damage = GAMEMODE_HandleEvent( DamageEvent, temp, damage, GlobalACSStrings.AddString( mod )); // [AK] Destroy the temporary actor after executing all event scripts. temp->Destroy( ); diff -r 4b4e53df7d0b -r 8582fccb02f8 src/gamemode.h --- a/src/gamemode.h Sun Nov 28 13:28:27 2021 -0500 +++ b/src/gamemode.h Sun Nov 28 14:28:02 2021 -0500 @@ -132,6 +132,7 @@ GAMEEVENT_PLAYERCONNECT, GAMEEVENT_ACTOR_SPAWNED, GAMEEVENT_ACTOR_DAMAGED, + GAMEEVENT_ACTOR_ARMORDAMAGED, } GAMEEVENT_e; //***************************************************************************** @@ -213,7 +214,7 @@ GAMESTATE_e GAMEMODE_GetState ( void ); void GAMEMODE_SetState ( GAMESTATE_e GameState ); LONG GAMEMODE_HandleEvent ( const GAMEEVENT_e Event, AActor *pActivator = NULL, const int DataOne = 0, const int DataTwo = 0 ); -bool GAMEMODE_HandleDamageEvent ( AActor *target, AActor *inflictor, AActor *source, int &damage, FName mod ); +bool GAMEMODE_HandleDamageEvent ( AActor *target, AActor *inflictor, AActor *source, int &damage, FName mod, bool bBeforeArmor = false ); LONG GAMEMODE_GetEventResult ( void ); void GAMEMODE_SetEventResult ( LONG lResult ); diff -r 4b4e53df7d0b -r 8582fccb02f8 src/p_acs.cpp --- a/src/p_acs.cpp Sun Nov 28 13:28:27 2021 -0500 +++ b/src/p_acs.cpp Sun Nov 28 14:28:02 2021 -0500 @@ -11721,11 +11721,11 @@ // [TP] We need to store this as activefontname instead. activefontname = "SmallFont"; - // [AK] Check if this is an event script triggered by GAMEEVENT_ACTOR_DAMAGED. This is - // where we initialize the script's target, source, and inflictor pointers by using the - // temporary activator's own pointers. + // [AK] Check if this is an event script triggered by GAMEEVENT_ACTOR_DAMAGED or + // GAMEEVENT_ACTOR_ARMORDAMAGED. This is where we initialize the script's target, + // source, and inflictor pointers by using the temporary activator's own pointers. if (( NETWORK_InClientMode( ) == false ) && ( who != NULL ) && - ( code->Type == SCRIPT_Event ) && ( args[0] == GAMEEVENT_ACTOR_DAMAGED )) + ( code->Type == SCRIPT_Event ) && ( args[0] == GAMEEVENT_ACTOR_DAMAGED || args[0] == GAMEEVENT_ACTOR_ARMORDAMAGED )) { pDamageTarget = who->target; pDamageSource = who->master; diff -r 4b4e53df7d0b -r 8582fccb02f8 src/p_acs.h --- a/src/p_acs.h Sun Nov 28 13:28:27 2021 -0500 +++ b/src/p_acs.h Sun Nov 28 14:28:02 2021 -0500 @@ -1074,8 +1074,8 @@ int InModuleScriptNumber; FString activefontname; // [TP] - // [AK] Pointers to the source, inflictor, and target actors that triggered a GAMEEVENT_ACTOR_DAMAGED event. - // In all other cases, these pointers should be equal to NULL. + // [AK] Pointers to the source, inflictor, and target actors that triggered a GAMEEVENT_ACTOR_DAMAGED or + // GAMEEVENT_ACTOR_ARMORDAMAGED event. In all other cases, these pointers should be equal to NULL. TObjPtr pDamageSource; TObjPtr pDamageInflictor; TObjPtr pDamageTarget; @@ -1121,7 +1121,7 @@ friend class ServerCommands::ReplaceTextures; // [AK] We need to access protected variables from this class when we tell the clients to print a HUD message. friend void SERVERCOMMANDS_PrintACSHUDMessage( DLevelScript *pScript, const char *pszString, float fX, float fY, LONG lType, LONG lColor, float fHoldTime, float fInTime, float fOutTime, fixed_t Alpha, LONG lID, ULONG ulPlayerExtra, ServerCommandFlags flags ); - // [AK] If the current running script is a GAMEEVENT_ACTOR_DAMAGED event, this will return a pointer to the source, inflictor, or target actor. + // [AK] If the current running script is a GAMEEVENT_ACTOR_DAMAGED or GAMEEVENT_ACTOR_ARMORDAMAGED event, this returns a pointer to the source, inflictor, or target actor. friend AActor *ACS_GetScriptDamagePointers( unsigned int pointer ); }; diff -r 4b4e53df7d0b -r 8582fccb02f8 src/p_interaction.cpp --- a/src/p_interaction.cpp Sun Nov 28 13:28:27 2021 -0500 +++ b/src/p_interaction.cpp Sun Nov 28 14:28:02 2021 -0500 @@ -1552,6 +1552,11 @@ if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) { + // [AK] Trigger an event script indicating that the player has taken damage before any damage + // can be absorbed by their armor. If the event returns 0, don't do anything else. + if ( GAMEMODE_HandleDamageEvent( target, inflictor, source, damage, mod, true ) == false ) + return -1; + int newdam = damage; player->mo->Inventory->AbsorbDamage (damage, mod, newdam); damage = newdam; @@ -1647,6 +1652,11 @@ // Armor for monsters. if (!(flags & (DMG_NO_ARMOR|DMG_FORCED)) && target->Inventory != NULL && damage > 0) { + // [AK] Trigger an event script indicating that the actor has taken damage before any damage + // can be absorbed by their armor. If the event returns 0, don't do anything else. + if ( GAMEMODE_HandleDamageEvent( target, inflictor, source, damage, mod, true ) == false ) + return -1; + int newdam = damage; target->Inventory->AbsorbDamage (damage, mod, newdam); damage = newdam;