RomanR Posted August 17, 2022 Share Posted August 17, 2022 @glowplug Is it possible to also use "OnMagicEffectHit" somehow? Is it possible to set event handler for multiple effects? If I write these commands SetEventHandler "OnMagicEffectHit" FnPlayerDispelLight first::PlayerRef second::"NEYE" SetEventHandler "OnMagicEffectHit" FnPlayerDispelNEye first::PlayerRef second::"LGHT" will event handlers be set and work? However, FnDispelConflicts still needs exact editor IDs of spells, I think my approach (although much more complex and with bigger overhead) gives better result. Link to comment Share on other sites More sharing options...
glowplug Posted August 18, 2022 Share Posted August 18, 2022 You're certainly on the right track RomanR, I was forgetting about Dispel by MagicEffect. To be honest, I did not think things through. Unfortunately OnMagicEffectHit doesn't stack, each SetEventHandler "OnMagicEffectHit" removes the previous. The other problem is that the event double fires and fails to interpret refActor.Dispel refSpell.The reason there is no 'elseif' is to ensure all conflicts Dispel.Note: the actual spell is not cast till after the EventHandler - it won't self dispel if it has conflicting effects.Note: MagicItemHasEffectCode passed by long - MagicItemHasEffect passed by string_var won't compile in 'if' statement. scn QstMagicEffectHandlersScript ;Quest script Begin GameMode if GetGameLoaded PlayerRef.SetEventHandler OnSpellCast, FnOnSpellCastActor endif End scn FnOnSpellCastActor ; elseif not used to ensure all desired Dispel occur. ; the actual spell is cast after this EventHandler (it won't self dispel) ref refActor ref refSpell Begin Function { refActor, refSpell } if MagicItemHasEffect LGHT, refSpell call FnActorDispelByMagicEffectCode refActor, (MECodeFromChars "NEYE") endif if MagicItemHasEffect NEYE, refSpell call FnActorDispelByMagicEffectCode refActor, (MECodeFromChars "LGHT") endif if MagicItemHasEffect WABR, refSpell call FnActorDispelByMagicEffectCode refActor, (MECodeFromChars "WAWA") endif if MagicItemHasEffect WAWA, refSpell call FnActorDispelByMagicEffectCode refActor, (MECodeFromChars "WABR") endif End scn FnActorDispelByMagicEffectCode ;Generic function to loop through whichever Actor's spells ;NOTE: MagicItemHasEffectCode using long - MagicItemHasEffect using string_var won't compile int iIndex ref refSpell array_var arrSpells ref refActor long lEffect Begin Function { refActor, lEffect } let arrSpells := refActor.GetSpells while iIndex < ar_Size arrSpells let refSpell := arrSpells[iIndex] if MagicItemHasEffectCode lEffect, refSpell refActor.Dispel refSpell endif let iIndex += 1 loop End Link to comment Share on other sites More sharing options...
glowplug Posted August 18, 2022 Share Posted August 18, 2022 PS I accidentally clicked Cancel on another 'No Quotes' warning then got no warning later, it should be...PlayerRef.SetEventHandler "OnSpellCast", FnOnSpellCastActor...it worked without the quotes but better to get it right. I've tested it by repeating variations of the following with a custom spell called LightNight that has Light+Night-Eye...Night-Eye then Light - Night-Eye Dispelled, Light is castLight then Night-Eye - Light Dispelled, Night-Eye is castLightNight then Light - LightNight Dispelled, Light is castLightNight then Night-Eye - LightNight Dispelled, Night-Eye is castLight then LightNight - Light Dispelled, LightNight is castNight-Eye then LightNight - Night-Eye Dispelled, LightNight is cast...suffice to say that 'elseif' would be wrong and Cast is running after the EventHandler has compeleted. Link to comment Share on other sites More sharing options...
RomanR Posted August 18, 2022 Share Posted August 18, 2022 That's a shame, but I see another event, which seems interesting "OnMagicApply". It looks little overheading, because is invoked on each effect, but documentation says is working for all things which could put some effect on you (spell, enchantment...). I have some free time for a weekend, so I think I will test it. Link to comment Share on other sites More sharing options...
glowplug Posted August 18, 2022 Share Posted August 18, 2022 Remove any of the quotes breaks this... SetEventHandler "OnMagicApply", FnOnMagicApply, "ref"::"LGHT", "ref"::"Player" The parameters have to be ref.Yes, it filters to self but LGHT is ignored (fires for any Self) the entire spell is passed yet it fires for each magic effect. OnMagicCast the same but only fires once for the spell. Edit: I'm guessing that all of the event handlers have the same "add same removes previous" issue. Having an event handler for each effect means the scattered across as many scripts as there are Magic Effect required - if their code needs changing then we've got to make sure to find change and save all of them - I try to avoid that. If OnSpellCast is required for additional/different code then what I put on FnOnSpellCastActor should be factored out. Link to comment Share on other sites More sharing options...
GamerRick Posted August 19, 2022 Author Share Posted August 19, 2022 (edited) Fabulous!!! Thanks glowplug!!! Edited August 19, 2022 by GamerRick Link to comment Share on other sites More sharing options...
RomanR Posted August 19, 2022 Share Posted August 19, 2022 The "onMagicApply" seems the right choice for this and after some testing I can present you practicaly complete framework. First init part: scn RRSetHandlerQuestScript short restart short good short init int size int old_size int count array_var dispelPrefs begin GameMode ; is prefs in order ? let size := ar_Size dispelPrefs if size != old_size set init to 0 endif ; init part if init == 0 if size == -1 let dispelPrefs := ar_Construct array else ar_Resize dispelPrefs 0 endif let dispelPrefs[0] := "NEYE" ; effect we want to check let dispelPrefs[1] := "+" ; block of counter effects begin here let dispelPrefs[2] := "LGHT" ; setting counter effect let dispelPrefs[3] := "-" ; end of counter effects block let dispelPrefs[4] := "LGHT" let dispelPrefs[5] := "+" let dispelPrefs[6] := "NEYE" let dispelPrefs[7] := "-" let size := ar_Size dispelPrefs set old_size to size set init to 1 endif ; setting an event set restart to 0 if GetGameRestarted set restart to 1 endif if restart ;print "Restart detected in game mode." let good := SetEventHandler "OnMagicApply" RRMagicHandlerScript if good == 0 Message "Counter Effect Mod: Creation of event handler failed." endif ; adding token to catch long-term effects before this mod was active (player only) set count to player.GetItemCount RRDispelEffectToken if count == 0 player.AddItemNS RRDispelEffectToken 1 endif set restart to 0 endif end begin MenuMode ; is prefs in order ? let size := ar_Size dispelPrefs if size != old_size set init to 0 endif ; init part if init == 0 if size == -1 let dispelPrefs := ar_Construct array else ar_Resize dispelPrefs 0 endif let dispelPrefs[0] := "NEYE" ; effect we want to check let dispelPrefs[1] := "+" ; block of counter effects begin here let dispelPrefs[2] := "LGHT" ; setting counter effect let dispelPrefs[3] := "-" ; end of counter effect block let dispelPrefs[4] := "LGHT" let dispelPrefs[5] := "+" let dispelPrefs[6] := "NEYE" let dispelPrefs[7] := "-" let size := ar_Size dispelPrefs set old_size to size set init to 1 endif ; setting an event set restart to 0 if GetGameRestarted set restart to 1 endif if restart ;print "Restart detected in menu mode." let good := SetEventHandler "OnMagicApply" RRMagicHandlerScript if good == 0 Message "Counter Effect Mod: Creation of event handler failed." endif ; adding token to catch long-term effects before this mod was active (player only) set count to player.GetItemCount RRDispelEffectToken if count == 0 player.AddItemNS RRDispelEffectToken 1 endif set restart to 0 endif end It's set to always running quest with small priority. I also added token to deal with things like enchantments from rings, so if you're wearing them, the opposite effects from spells will not apply to you until you unequip them. Script for handler: scn RRMagicHandlerScript ref magic_item ref caster ref target short found short argument short counter_on short long_term int size int index int magic_code int count string_var ascii_code string_var check_effect string_var dispel_effect begin function { magic_item, caster } if magic_item != 0 set target to GetSelf if target == player ;print "There was aplied magic effect on "+$player+" now." if RRSetHandlerQuest.init != 0 let size := ar_Size RRSetHandlerQuest.dispelPrefs endif if size > 0 set index to 0 let check_effect := "" let dispel_effect := "" while index < size let ascii_code := RRSetHandlerQuest.dispelPrefs[index] if eval (ascii_code != "+") && eval (ascii_code != "-") set argument to 1 else set argument to 0 endif if eval (ascii_code == "+") set counter_on to 1 endif if eval (ascii_code == "-" ) set counter_on to 0 set found to 0 let dispel_effect := "" endif if argument != 0 && counter_on == 0 let check_effect := ascii_code endif if argument != 0 && counter_on == 0 && found == 0 let magic_code := MECodeFromChars $check_effect let found := MagicItemHasEffectCode magic_code magic_item if found ;print "Desired effect "+$check_effect+" found aplied on "+$target+"." ; adding token to deal with long-term effects (enchant from apparel, ability etc.) if target.IsActor ;print $target+" is actor." set count to target.GetItemCount RRDispelEffectToken if count == 0 target.AddItemNS RRDispelEffectToken 1 ;print "Adding token." endif endif endif endif if argument != 0 && counter_on != 0 && found != 0 let dispel_effect := ascii_code ;print "Trying to find and dispel "+$dispel_effect+"." Call RRFnDispelMagicEffect target dispel_effect endif set index to index + 1 loop endif endif endif sv_Destruct check_effect dispel_effect ascii_code end Quite standard, it goes through dispelPrefs field defined in quest and calls function to dispel defined oppsite effect(s). It also adds a token. Script of function responsible for dispeling effects: scn RRFnDispelMagicEffect array_var activeeffects string_var ascii_code string_var dispel_code int size int index int eff_code int magic_type int temp ref caster ref target short dispel_it begin function { target, dispel_code } let size := ar_Size activeeffects if size == -1 let activeeffects := ar_Construct array endif if target != 0 let activeeffects := target.GetActiveEffectCodes let size := ar_Size activeeffects endif if size > 0 set index to 0 while index < size let eff_code := activeeffects[index] let ascii_code := GetMagicEffectCharsC eff_code ;print $ascii_code if eval (ascii_code == dispel_code) set dispel_it to 0 set caster to 0 let caster := target.GetNthActiveEffectMagicItem index if caster != 0 set magic_type to 0 set temp to 0 let magic_type := GetMagicItemType caster if magic_type != 0 if magic_type == 3 || magic_type == 4 ; alchemy item or ingredient ;print "Alchemy or ingredient." set dispel_it to 1 endif if dispel_it == 0 && magic_type == 2 ; enchantment let temp := GetEnchantmentType caster if temp != 3 ; dispel scrolls, weapons and staffs ;print $temp ;print "Enchantment." set dispel_it to 1 endif endif if dispel_it == 0 && magic_type == 1 ; we want disable spells let magic_type := GetSpellType caster if magic_type == 0 || magic_type == 3 ;disable only normal spell or lesser power ;print "Spell or lesser power." set dispel_it to 1 endif endif endif endif if dispel_it ;print "The opposite effect "+$dispel_code+" will be removed from "+$target+"." target.DispelNthActiveEffect index endif endif set index to index + 1 loop endif ; cleanup sv_Destruct ascii_code dispel_code ar_Resize activeeffects 0 let activeeffects := ar_Null end There are checks to not dispel all effects mindlessly, but it leaves enchantments on apparel, greater powers, diseases and abilities alone. And for token: scn RRDispelEffectTokenScript ref actor ref item int size int prefs_size int index int prefs_index int code int magic_type int temp short remove short argument short block_on short found string_var ascii_code string_var check_code string_var dispel_code array_var effects begin GameMode set remove to 0 let size := ar_Size effects if size == -1 let effects := ar_Construct array endif if actor == 0 set actor to GetContainer endif if actor != 0 && RRSetHandlerQuest.init != 0 let prefs_size := ar_Size RRSetHandlerQuest.dispelPrefs let effects := actor.GetActiveEffectCodes let size := ar_Size effects if prefs_size > 0 && size > 0 ;print "Checking..." set remove to 1 set prefs_index to 0 while prefs_index < prefs_size let ascii_code := RRSetHandlerQuest.dispelPrefs[prefs_index] if eval (ascii_code != "+") && eval (ascii_code != "-") set argument to 1 else set argument to 0 endif if eval (ascii_code == "+") set block_on to 1 endif if eval (ascii_code == "-") set block_on to 0 set found to 0 let dispel_code := "" endif if argument != 0 && block_on == 0 ;print "Token> There is setting for "+$ascii_code+"." set index to 0 while index < size let code := effects[index] let check_code := GetMagicEffectCharsC code if eval (check_code == ascii_code) ; now we check if source of effect is enchantment from apparel (ring, amulet, clothes ...) ; or ability, disease or greater power ;print "Effect found on index "+$index+"." set item to 0 let item := actor.GetNthActiveEffectMagicItem index if item != 0 set magic_type to 0 set temp to 0 let magic_type := GetMagicItemType item if magic_type != 0 if magic_type == 2 ; enchantment let temp := GetEnchantmentType item if temp == 3 ; apparel ;print "Enchatment from apparel." set remove to 0 set found to 1 endif endif if found == 0 && magic_type == 1 ; spell let temp := GetSpellType item if temp != 0 && temp != 3 ;ignore normal spell or lesser power ;print "Power, disease or ability." set remove to 0 set found to 1 endif endif endif endif endif set index to index + 1 loop endif if argument && block_on && found let dispel_code := ascii_code ;print "Trying to remove opposite effect "+$dispel_code+" from "+$actor+"." Call RRFnDispelMagicEffect actor dispel_code endif set prefs_index to prefs_index + 1 loop endif else set remove to 1 endif if remove != 0 ;print "Token> No effect coming from long-term source found, so I will remove." RemoveMe endif sv_Destruct ascii_code check_code dispel_code ar_Resize effects 0 let effects := ar_Null end As it was made to deal with greater powers, enchantments and such it will stay in target's inventory until the last effect of this type is active. After that it will remove itself. Now you can play with it all you like. I hope it will make you happy. Link to comment Share on other sites More sharing options...
RomanR Posted August 19, 2022 Share Posted August 19, 2022 Seems for the last one I forgot to add cleaning commands before RemoveMe command and I also cleaned some weirdness for remove variable. Sorry about that, here's new version: scn RRDispelEffectTokenScript ref actor ref item int size int prefs_size int index int prefs_index int code int magic_type int temp short remove short argument short block_on short found string_var ascii_code string_var check_code string_var dispel_code array_var effects begin GameMode set remove to 1 let size := ar_Size effects if size == -1 let effects := ar_Construct array endif if actor == 0 set actor to GetContainer endif if actor != 0 && RRSetHandlerQuest.init != 0 let prefs_size := ar_Size RRSetHandlerQuest.dispelPrefs let effects := actor.GetActiveEffectCodes let size := ar_Size effects if prefs_size > 0 && size > 0 ;print "Checking..." set remove to 1 set prefs_index to 0 while prefs_index < prefs_size let ascii_code := RRSetHandlerQuest.dispelPrefs[prefs_index] if eval (ascii_code != "+") && eval (ascii_code != "-") set argument to 1 else set argument to 0 endif if eval (ascii_code == "+") set block_on to 1 endif if eval (ascii_code == "-") set block_on to 0 set found to 0 let dispel_code := "" endif if argument != 0 && block_on == 0 ;print "Token> There is setting for "+$ascii_code+"." set index to 0 while index < size let code := effects[index] let check_code := GetMagicEffectCharsC code if eval (check_code == ascii_code) ; now we check if source of effect is enchantment from apparel (ring, amulet, clothes ...) ; or ability, disease or greater power ;print "Effect found on index "+$index+"." set item to 0 let item := actor.GetNthActiveEffectMagicItem index if item != 0 set magic_type to 0 set temp to 0 let magic_type := GetMagicItemType item if magic_type != 0 if magic_type == 2 ; enchantment let temp := GetEnchantmentType item if temp == 3 ; apparel ;print "Enchatment from apparel." set remove to 0 set found to 1 endif endif if found == 0 && magic_type == 1 ; spell let temp := GetSpellType item if temp != 0 && temp != 3 ;ignore normal spell or lesser power ;print "Power, disease or ability." set remove to 0 set found to 1 endif endif endif endif endif set index to index + 1 loop endif if argument && block_on && found let dispel_code := ascii_code ;print "Trying to remove opposite effect "+$dispel_code+" from "+$actor+"." Call RRFnDispelMagicEffect actor dispel_code endif set prefs_index to prefs_index + 1 loop endif endif if remove != 0 ;print "Token> No effect coming from long-term source found, so I will remove." sv_Destruct ascii_code check_code dispel_code ar_Resize effects 0 let effects := ar_Null RemoveMe endif sv_Destruct ascii_code check_code dispel_code ar_Resize effects 0 let effects := ar_Null end Link to comment Share on other sites More sharing options...
Recommended Posts