jags78 Posted January 27, 2020 Share Posted January 27, 2020 Hi guys and gals I'm making some tests with dynamic script attachments. I chose the 2 quest method, but I stuck somewhere... I'm simply trying to punch a dude in the face and trigger the OnHit() event notifying me "I hit a human..." Here is what I got: Quest 1 - Alias Quest Human02-10 where duplicated from Human01 Human01 Reference Alias test:Human Code Scriptname test:Human extends ReferenceAlias Actor Property PlayerRef Auto Const Event OnHit(ObjectReference akTarget, ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, \ bool abSneakAttack, bool abBashAttack, bool abHitBlocked, string apMaterial) If akAggressor == PlayerRef Debug.Notification("I hit a human...") EndIf EndEvent Quest 2 - Update Quest In the Script tap I added a script called test:updatealias... here the code Scriptname test:updatealias extends Quest Quest Property jags_aliasquest Auto Const Event OnQuestInit() StartTimer(0.5, 42) EndEvent Event OnTimer(int aiTimerID) If aiTimerID == 42 jags_aliasquest.Stop() ; loop prevention Int c = 0 While !jags_aliasquest.IsStopped() && c < 50 Utility.Wait(0.1) c += 1 EndWhile Debug.Notification("aliasquest stopped") jags_aliasquest.Start() ; loop prevention c = 0 If !jags_aliasquest.IsRunning() && c < 50 Utility.Wait(0.1) c += 1 EndIf Debug.Notification("aliasquest started") StartTimer(10, 42) EndIf EndEvent All properties are "attached" to the CK-Objects and the scripts compile fine. Test-envirement is an empty cell (from the mod 'white test room')console commands:killallplayer.placeatme 20749 10 (spawns 10 raiders) Here the problem... I only get the notifications "aliasquest stopped" and "aliasquest started" in a loop as intended, but never a notification "I hit a human..." when I punch or shoot a raider. Forums read for this test-mod:http://www.zombiewalkers.net/2016/09/dynamic-script-attachment.htmlhttp://forums.bethsoft.com/topic/1349649-dynamically-attaching-scripts-to-actors-near-the-player/https://www.creationkit.com/index.php?title=Dynamically_Attaching_Scriptshttp://www.gamesas.com/dynamically-attaching-scripts-actors-near-the-player-t255702.html Has anyone have a clue what I'm doing wrong?? Thx in advanced. Link to comment Share on other sites More sharing options...
SKKmods Posted January 27, 2020 Share Posted January 27, 2020 OnHit is a ScriptObject event, not an Actor or ObjectReference event, so the ObjectReference quest alias attached scripts will never receive them. You need a script to RegisterForHitEvent for each actor reference and then listen for the OnHit events which is a total pain the the arse https://www.creationkit.com/fallout4/index.php?title=RegisterForHitEvent_-_ScriptObject Self.RegisterForHitEvent(akTarget = ThisActor, akAggressorFilter = pPlayerREF, abmatch = true) Self.RegisterForHitEvent(akTarget = pPlayerREF, akAggressorFilter = ThisActor, abmatch = true) And then you have to manage unregistrations when the targets OnUnload() or OnDeath() if OnHit has not triggered to avoid building up a dirty load of orphan event registrations on the script: Self.UnRegisterForHitEvent(pPlayerREF, ThisActor) Self.UnRegisterForHitEvent(ThisActor, pPlayerREF) I have found that using a RefCollectionAlias for akTarget or akAggressorFilter to try and cut down on actor management is inconsistent for hit detection, even when the system is lightly loaded. Wherever possible I avoid the pain of managing RegisterForHitEvent+OnHit and try to use the Perk Entry point ApplyCombatHitSpell attached to actors to trigger a script. Link to comment Share on other sites More sharing options...
DieFeM Posted January 27, 2020 Share Posted January 27, 2020 The quest that holds the aliases is marked as "Run Once", but you are restarting it, so I think that what actually happens is that the counter (c < 50) stops the while loops instead of the quest stopping or starting. Link to comment Share on other sites More sharing options...
jags78 Posted January 27, 2020 Author Share Posted January 27, 2020 The quest that holds the aliases is marked as "Run Once", but you are restarting it, so I think that what actually happens is that the counter (c < 50) stops the while loops instead of the quest stopping or starting.Hmm... Never had a problem to restart a quest although this flag was set. I'll remove it and try again. OnHit is a ScriptObject event, not an Actor or ObjectReference event, so the alias attached scripts will never receive them. You need a script to RegisterForHitEvent for each actor reference and then listen for the OnHit events which is a total pain the the arse https://www.creationkit.com/fallout4/index.php?title=RegisterForHitEvent_-_ScriptObject Wherever possible I avoid using RegisterForHitEvent+OnHit and try to use the Perk Entry point ApplyCombatHitSpell attached to actors to trigger a script. I'm actually using the Perk Entry Point ApplyCombatHitSpell on the mod I'm writing... It works for Melee, Guns, Bashing... but NOT for Grenades, right?? That's why I even started testing with the dynamic script attachements... If I'm right with the Grenade thingy, I'll have to wrap my head around your suggested "pain in the arse" approach... Do you know of any example online? I'm not really grasping how to approach that method. Link to comment Share on other sites More sharing options...
jags78 Posted January 27, 2020 Author Share Posted January 27, 2020 BTW - Thanks for the hint with the RegisterForHitEvent... I didn't know that Event-Registration existed. Makes somewhat more sense that it didn't work now. Link to comment Share on other sites More sharing options...
SKKmods Posted January 27, 2020 Share Posted January 27, 2020 This is a script which prevents actors spawned out of the players line of sight taking or dealing damage until the player can see them to spectate or participate in the fight. It registers a separate script to receive the events to avoid script queues and bottlenecks. The spawning script function: If (pPlayerREF.GetDistance(ThisActor) > 3000) && (pPlayerREF.HasDirectLOS(ThisActor) == FALSE) ;(ThisActor as Actor).SetGhost(True) ; no, need OnHit events to fire (ThisActor as Actor).AddPerk(pSKK_REMNoDamagePerk) (pSKK_REM as SKK_REMCombatScript).RegisterForDirectLOSGain((pPlayerREF as Actor), akTarget = ThisActor) (pSKK_REM as SKK_REMCombatScript).RegisterForDistanceLessThanEvent(pPlayerREF, ThisActor, 1542) (pSKK_REM as SKK_REMCombatScript).RegisterForHitEvent(akTarget = ThisActor, akAggressorFilter = pPlayerREF, abmatch = true) (pSKK_REM as SKK_REMCombatScript).RegisterForHitEvent(akTarget = pPlayerREF, akAggressorFilter = ThisActor, abmatch = true) EndIf This is the SKK_REMCombatScript event handling script function. RegisterForHitEvent is only for one hit, so if conditions are not met then you must re-register. The highly specific registrations SHOULD prevent any hits that do not involve the player from triggering, but, guess what ... they can. So a quality script should be defensive and allow re-registrations for unwanted hit conditions: Event OnHit(ObjectReference akTarget, ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked, string apMaterial) If (akTarget as Actor).HasPerk(pSKK_REMNoDamagePerk) && (akAggressor == pPlayerREF) EnableCombat(akTarget) ElseIf (akAggressor as Actor).HasPerk(pSKK_REMNoDamagePerk) && (akTarget == pPlayerREF) EnableCombat(akAggressor) ElseIf (akTarget as Actor).HasPerk(pSKK_REMNoDamagePerk) ;Player is not yet involved Self.RegisterForHitEvent(akTarget = akTarget, akAggressorFilter = pPlayerREF, abmatch = true) Self.RegisterForHitEvent(akTarget = pPlayerREF, akAggressorFilter = akTarget, abmatch = true) ElseIf (akAggressor as Actor).HasPerk(pSKK_REMNoDamagePerk) ;Player is not yet involved Self.RegisterForHitEvent(akTarget = akAggressor, akAggressorFilter = pPlayerREF, abmatch = true) Self.RegisterForHitEvent(akTarget = pPlayerREF, akAggressorFilter = akAggressor, abmatch = true) EndIf EndEvent Link to comment Share on other sites More sharing options...
jags78 Posted January 27, 2020 Author Share Posted January 27, 2020 (edited) Your snippets are VERY usefull. Thank you very much!! To be honest, I already failed much earlier in the process... I didn't realize that there was an entier ReferenceAlias functions collection. For some reason I thought the ReferenceAlias within the CK was just a Placeholder for the Object-Type given to the RefAlias Script. I thought it just had to match the defined conditions. I was wrong. Some reading and playing around later and I found following functions that triggered an action on the raiders found close to the player:OnAliasInit()GetActorReference()GetReference()Here a working code example Event OnAliasInit() Actor Human = GetActorRef() as Actor ; cast probably not needed Human.UnequipAll() EndEvent 1 second after spawning the raiders, all stood there in their undies... :smile: I'll post my finding about the grenades in here if I remember to... Edited January 27, 2020 by jags78 Link to comment Share on other sites More sharing options...
jags78 Posted January 27, 2020 Author Share Posted January 27, 2020 I got the OnHit() Event working on a minimal state (no filtering appart the akTarget). I've added a eventhandler script to the second quest (the update quest): Scriptname test:EventHandler extends Quest ObjectReference Human ; copied this method of passing a script from 'Stealthy Takedowns', I really like his approach EventHandler Function GetScript() Global return (Game.GetFormFromFile(0x00000F9A, "jags78_aliastest.esp") as Quest) as EventHandler EndFunction Function RegisterHuman(ObjectReference akHuman) Human = akHuman RegisterForHitEvent(Human) EndFunction Event OnHit(ObjectReference akTarget, ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked, string apMaterial) Debug.Notification("OnHit()") RegisterForHitEvent(Human) EndEvent And here the the RefAlias Script: Scriptname test:Human extends ReferenceAlias Event OnAliasInit() ObjectReference oRef = GetReference() test:EventHandler.GetScript().RegisterHuman(oRef) EndEvent I diminished the timer on the update quest script to 1 second... IMPORTANT: DieFeM was right, you have to remove the "Run Once" flag on the alias quest... Works for me, thx to you two for your help. :thumbsup: Link to comment Share on other sites More sharing options...
Recommended Posts