# HG changeset patch # User Adam Kaminski # Date 1632330419 14400 # Wed Sep 22 13:06:59 2021 -0400 # Node ID 9e12d0bb6e3d9d60c8d7183c3a5e86a0b3617266 # Parent 61947626089ddb6e20890252948f736533a59d77 GAMEEVENT_ACTOR_DAMAGED is now triggered just before the actor receives damage. It's now possible to modify how much damage they take by changing the result value of the script during the first tic that it's run. diff -r 61947626089d -r 9e12d0bb6e3d src/actor.h --- a/src/actor.h Tue Sep 21 09:25:50 2021 -0400 +++ b/src/actor.h Wed Sep 22 13:06:59 2021 -0400 @@ -1174,6 +1174,10 @@ // [BB] Last movedir that was sent to the client. BYTE lastMovedir; + // [AK] The final damage this actor takes after executing the first tic of all GAMEEVENT_ACTOR_DAMAGED + // scripts. This is not always the same amount of damage they originally received. + int DamageEventReceived; + // ThingIDs static void ClearTIDHashes (); void AddToHash (); diff -r 61947626089d -r 9e12d0bb6e3d src/gamemode.cpp --- a/src/gamemode.cpp Tue Sep 21 09:25:50 2021 -0400 +++ b/src/gamemode.cpp Wed Sep 22 13:06:59 2021 -0400 @@ -67,6 +67,7 @@ #include "possession.h" #include "p_lnspec.h" #include "p_acs.h" +#include "gi.h" // [BB] The next includes are only needed for GAMEMODE_DisplayStandardMessage #include "sbar.h" #include "v_video.h" @@ -1047,6 +1048,43 @@ //***************************************************************************** // +bool GAMEMODE_HandleDamageEvent ( AActor *target, AActor *inflictor, AActor *source, int &damage, FName mod ) +{ + // [AK] Don't run any scripts if the target doesn't allow executing GAMEEVENT_ACTOR_DAMAGED. + if ( target->STFlags & STFL_NODAMAGEEVENTSCRIPT ) + return true; + + // [AK] Don't run any scripts if the target can't execute GAMEEVENT_ACTOR_DAMAGED unless + // all actors are forced to execute it. + if ((( target->STFlags & STFL_USEDAMAGEEVENTSCRIPT ) == false ) && ( gameinfo.bForceDamageEventScripts == false )) + return true; + + // [AK] We somehow need to pass the source and inflictor actor pointers into the script + // itself. A simple way to do this is temporarily changing the target's pointers to the + // source and inflictor, which we'll then use to initialize AAPTR_DAMAGE_SOURCE and + // AAPTR_DAMAGE_INFLICTOR for the script. + // The source actor is the activator, which we'll use to initialize AAPTR_DAMAGE_TARGET. + AActor *tempMaster = target->master; + AActor *tempTarget = target->target; + target->master = source; + target->target = inflictor; + + // [AK] The amount of damage the target receives can be modified directly inside the + // script using SetResultValue. If the returned value is different to the original, + // then it becomes the new damage. + target->DamageEventReceived = damage; + GAMEMODE_HandleEvent( GAMEEVENT_ACTOR_DAMAGED, target, damage, GlobalACSStrings.AddString( mod )); + damage = target->DamageEventReceived; + + // [AK] Restore the source actor's old pointers. + target->master = tempMaster; + target->target = tempTarget; + + return ( damage > 0 ); +} + +//***************************************************************************** +// void GAMEMODE_DisplayStandardMessage( const char *pszMessage, const bool bInformClients ) { if ( NETWORK_GetState( ) != NETSTATE_SERVER ) diff -r 61947626089d -r 9e12d0bb6e3d src/gamemode.h --- a/src/gamemode.h Tue Sep 21 09:25:50 2021 -0400 +++ b/src/gamemode.h Wed Sep 22 13:06:59 2021 -0400 @@ -216,6 +216,7 @@ GAMESTATE_e GAMEMODE_GetState ( void ); void GAMEMODE_SetState ( GAMESTATE_e GameState ); void 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 ); // [BB] This function doesn't really belong here. Find a better place for it. void GAMEMODE_DisplayStandardMessage( const char *pszMessage, const bool bInformClients = false ); diff -r 61947626089d -r 9e12d0bb6e3d src/p_acs.cpp --- a/src/p_acs.cpp Tue Sep 21 09:25:50 2021 -0400 +++ b/src/p_acs.cpp Wed Sep 22 13:06:59 2021 -0400 @@ -7741,6 +7741,13 @@ switch (state) { + case SCRIPT_Running: + // [AK] If this is an event script triggered by GAMEEVENT_ACTOR_DAMAGED, initialize the + // result value to match the amount of damage the target received. + if (( bIsDamageEvent ) && ( NETWORK_InClientMode( ) == false )) + resultValue = pDamageTarget->DamageEventReceived; + break; + case SCRIPT_Delayed: // Decrement the delay counter and enter state running // if it hits 0 @@ -11595,6 +11602,12 @@ // [AK] We're done running this script so any action or line specials activated now aren't done in ACS. g_pCurrentScript = NULL; + // [AK] For event scripts triggered by GAMEEVENT_ACTOR_DAMAGED, if the result value doesn't match whatever + // damage the target originally received, then it becomes the new damage they will take. This only matters + // during this script's first tic. + if (( bIsDamageEvent ) && ( NETWORK_InClientMode( ) == false ) && ( resultValue != pDamageTarget->DamageEventReceived )) + pDamageTarget->DamageEventReceived = resultValue; + // [BB] Stop the net traffic measurement and add the result to this script's traffic. NETTRAFFIC_AddACSScriptTraffic ( script, NETWORK_StopTrafficMeasurement ( ) ); @@ -11654,8 +11667,8 @@ // where we initialize the script's target, source, and inflictor pointers by using the // activator as the target, and the activator's own master and target, which are the // source and inflictor respectively. - if (( NETWORK_InClientMode( ) == false ) && ( who != NULL ) && - ( code->Type == SCRIPT_Event ) && ( args[0] == GAMEEVENT_ACTOR_DAMAGED )) + bIsDamageEvent = (( code->Type == SCRIPT_Event ) && ( args[0] == GAMEEVENT_ACTOR_DAMAGED )); + if (( NETWORK_InClientMode( ) == false ) && ( who != NULL ) && ( bIsDamageEvent )) { pDamageTarget = who; pDamageSource = who->master; diff -r 61947626089d -r 9e12d0bb6e3d src/p_acs.h --- a/src/p_acs.h Tue Sep 21 09:25:50 2021 -0400 +++ b/src/p_acs.h Wed Sep 22 13:06:59 2021 -0400 @@ -1073,6 +1073,7 @@ FBehavior *activeBehavior; int InModuleScriptNumber; FString activefontname; // [TP] + bool bIsDamageEvent; // [AK] // [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. diff -r 61947626089d -r 9e12d0bb6e3d src/p_interaction.cpp --- a/src/p_interaction.cpp Tue Sep 21 09:25:50 2021 -0400 +++ b/src/p_interaction.cpp Wed Sep 22 13:06:59 2021 -0400 @@ -1508,7 +1508,8 @@ lOldTargetHealth = target->health; if (player) { - + bool bDamageEventHandled = false; // [AK] + // [TIHan/Spleen] Apply factor for damage dealt to players by monsters. ApplyCoopDamagefactor(damage, source); @@ -1553,6 +1554,13 @@ } } + // [AK] Trigger an event script indicating that the player has taken damage, if we can. + // If they don't end up taking damage in the end, do nothing more. + if ( GAMEMODE_HandleDamageEvent( target, inflictor, source, damage, mod ) == false ) + return -1; + + bDamageEventHandled = true; + if (damage >= player->health && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) && !player->morphTics) @@ -1561,6 +1569,11 @@ } } + // [AK] If we haven't done so already, trigger an event script indicating that the player has taken damage. + // If they don't end up taking damage in the end, do nothing more. + if (( bDamageEventHandled == false ) && ( GAMEMODE_HandleDamageEvent( target, inflictor, source, damage, mod ) == false )) + return -1; + player->health -= damage; // mirror mobj health here for Dave // [RH] Make voodoo dolls and real players record the same health target->health = player->mo->health -= damage; @@ -1625,6 +1638,11 @@ } } + // [AK] Trigger an event script indicating that the target actor has taken damage, if we can. + // If they don't end up taking damage in the end, do nothing more. + if ( GAMEMODE_HandleDamageEvent( target, inflictor, source, damage, mod ) == false ) + return -1; + target->health -= damage; } @@ -1665,26 +1683,6 @@ source->player->ulUnrewardedDamageDealt += MIN( (int)lOldTargetHealth, damage ); } - // [AK] Trigger an event script indicating that the target actor has taken damage, if we can. - if ((( target->STFlags & STFL_NODAMAGEEVENTSCRIPT ) == false ) && (( target->STFlags & STFL_USEDAMAGEEVENTSCRIPT ) || ( gameinfo.bForceDamageEventScripts ))) - { - // [AK] We somehow need to pass the source and inflictor actor pointers into the script - // itself. A simple way to do this is temporarily changing the target's pointers to the - // source and inflictor, which we'll then use to initialize AAPTR_DAMAGE_SOURCE and - // AAPTR_DAMAGE_INFLICTOR for the script. - // The source actor is the activator, which we'll use to initialize AAPTR_DAMAGE_TARGET. - AActor *tempMaster = target->master; - AActor *tempTarget = target->target; - target->master = source; - target->target = inflictor; - - GAMEMODE_HandleEvent( GAMEEVENT_ACTOR_DAMAGED, target, damage, GlobalACSStrings.AddString( mod )); - - // [AK] Restore the source actor's old pointers. - target->master = tempMaster; - target->target = tempTarget; - } - // [BC] Tell clients that this thing was damaged. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) {