foamyesque Posted July 19, 2019 Share Posted July 19, 2019 (edited) There's a variety of possible approaches here, depending on what exactly you *mean* to do. There's nothing wrong with a basketful of if statements, as such, but there are some approaches that would eliminate the need. As currently structured your script doesn't care about spells, it cares about magic effects. The same magic effect can potentially be used in many different spells or spell-like effects (such as enchantments or abilities). It is also set up so any one of the seven magic effects listed will trigger the code execution, so the potential for a race condition exists: If a spell has two of the effects you care about you will set the quest stage four times: It will fire two OnMagicEffectApply() events, both of which will have two successful matches. If you're using a structure like that it is generally best to make it go if-elseif, so that all the branches are mutually exclusive and only one will be chosen. My own setup here would be to use a FormList, so you can add and remove your triggering effects without needing to edit the properties or script code. It also greatly simplifies the code, to this: int property myStage auto Quest property myQuest auto FormList property myEffectList auto Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect) if akCaster == Game.GetPlayer() if myEffectList.HasForm(akEffect) myQuest.setStage(myStage) endif endif endEvent Edited July 19, 2019 by foamyesque Link to comment Share on other sites More sharing options...
foamyesque Posted July 19, 2019 Share Posted July 19, 2019 Note: Strictly, the above code may also generate a race condition (it still has the potential for multiple OnMagicEffectApply() events firing). There's ways to mitigate that if it's relevant, but they're beyond the scope of your question. Link to comment Share on other sites More sharing options...
PeterMartyr Posted July 19, 2019 Share Posted July 19, 2019 every one been so busy solving your Problem I will answer the Question you asked, with a lot of If Statements you use a Nested If Statement If (Stage 1) ElseIf (Stage 2) ElseIf (Stage 3) Else ;final stage EndIf Edit they way python does a Switch is very handy in papyrus too.(independent learning required) Edit 2@foamyesque sorry mate I missed your reference, my bad. Link to comment Share on other sites More sharing options...
npdogg Posted July 19, 2019 Share Posted July 19, 2019 (edited) Instead of directly setting the stage from the magic effects of the 7 spells, have those spells call a function on your quest. This function would have an internal counter that sets the correct stage once it reaches 7. Each magic effect would just need a guard so that it performs the increment once. Very simple and easy to extend or swap the spells in future. Optionally, have the function check a form list to verify that the calling spell is valid, but this is probably overkill for a simple mod (as opposed to a library). You could also use the story manager magic cast event to advance your quest, but that would be more complicated if you aren't familiar with how to use it. maybe next is working for you xyzSampleAliasScript Scriptname xyzSampleAliasScript extends ReferenceAlias; https://forums.nexusmods.com/index.php?/topic/7826293-multiple-if-statements/; https://www.creationkit.com/index.php?title=GetOwningQuest_-_Alias Quest PROPERTY myQuest auto ; the quest, maybe not needed Int PROPERTY myStage auto ; the stage you like to set MagicEffect[] PROPERTY myList auto ; pre-filled array of magicEffects Bool[] PROPERTY myEffect auto Hidden ; fill with Zeros, the same length as effect in array from above; -- EVENT --EVENT OnInit() Debug.Trace(" OnInit() - has been reached.. " +self) ; info only for papyrus loggingENDEVENTEVENT OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)IF (akCaster == Game.GetPlayer() as ObjectReference) myF_TryStage(akEffect)ENDIFENDEVENT; -- FUNCTION --;------------------------------------------FUNCTION myF_TryStage(MagicEffect akEffect);------------------------------------------; "where the stage will only advance if you can perform a certain few spells. 7 to be exact."IF (myQuest) && myQuest.IsRunning() && (myList) && (myEffect.Length == myList.Length)ELSE RETURN ; - STOP - missing quest property OR quest is not running OR different array lengthsENDIF;---------------------int i = myList.Length WHILE (i) ; (i > 0) i = i - 1 IF (myList == akEffect) myEffect = TRUE ; set TRUE for matching effect i = 0 ENDIF ENDWHILEIF (i == 0)ELSE RETURN ; - STOP - current effect is not desired for monitoringENDIF;--------------------- WHILE (i < myEffect.Length) IF myEffect ELSE RETURN ; - STOP - at least one effect is currently not applied ENDIF; ---------------------- i = i + 1 ENDWHILE myQuest.setStage(myStage) ; set stage, if all effects were foundENDFUNCTION There is another way with changing a GlobalVariable, but I would like to prefer above. This is insanely complicated relative to what the OP is trying to achieve. Less is more when it comes to programming. Edited July 19, 2019 by npdogg Link to comment Share on other sites More sharing options...
foamyesque Posted July 19, 2019 Share Posted July 19, 2019 (edited) Instead of directly setting the stage from the magic effects of the 7 spells, have those spells call a function on your quest. This function would have an internal counter that sets the correct stage once it reaches 7. Each magic effect would just need a guard so that it performs the increment once. Very simple and easy to extend or swap the spells in future. Optionally, have the function check a form list to verify that the calling spell is valid, but this is probably overkill for a simple mod (as opposed to a library). You could also use the story manager magic cast event to advance your quest, but that would be more complicated if you aren't familiar with how to use it. maybe next is working for you xyzSampleAliasScript Scriptname xyzSampleAliasScript extends ReferenceAlias; https://forums.nexusmods.com/index.php?/topic/7826293-multiple-if-statements/ ; https://www.creationkit.com/index.php?title=GetOwningQuest_-_Alias Quest PROPERTY myQuest auto ; the quest, maybe not needed Int PROPERTY myStage auto ; the stage you like to set MagicEffect[] PROPERTY myList auto ; pre-filled array of magicEffects Bool[] PROPERTY myEffect auto Hidden ; fill with Zeros, the same length as effect in array from above ; -- EVENT -- EVENT OnInit() Debug.Trace(" OnInit() - has been reached.. " +self) ; info only for papyrus loggingENDEVENT EVENT OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)IF (akCaster == Game.GetPlayer() as ObjectReference) myF_TryStage(akEffect)ENDIFENDEVENT ; -- FUNCTION -- ;------------------------------------------FUNCTION myF_TryStage(MagicEffect akEffect);------------------------------------------; "where the stage will only advance if you can perform a certain few spells. 7 to be exact." IF (myQuest) && myQuest.IsRunning() && (myList) && (myEffect.Length == myList.Length)ELSE RETURN ; - STOP - missing quest property OR quest is not running OR different array lengthsENDIF;---------------------int i = myList.Length WHILE (i) ; (i > 0) i = i - 1 IF (myList == akEffect) myEffect = TRUE ; set TRUE for matching effect i = 0 ENDIF ENDWHILE IF (i == 0)ELSE RETURN ; - STOP - current effect is not desired for monitoringENDIF;--------------------- WHILE (i < myEffect.Length) IF myEffect ELSE RETURN ; - STOP - at least one effect is currently not applied ENDIF; ---------------------- i = i + 1 ENDWHILE myQuest.setStage(myStage) ; set stage, if all effects were foundENDFUNCTION There is another way with changing a GlobalVariable, but I would like to prefer above. This is insanely complicated relative to what the OP is trying to achieve. Less is more when it comes to programming. That logic would be correct if all seven effects were required to advance the stage, but that's not what OP's code looks like they're trying to do. I agree with offloading the stage-setting to the quest proper as a design principle, but if this code is on, say, a quest alias, I'm not sure it matters much. Edited July 19, 2019 by foamyesque Link to comment Share on other sites More sharing options...
npdogg Posted July 19, 2019 Share Posted July 19, 2019 That logic would be correct if all seven effects were required to advance the stage, but that's not what OP's code looks like they're trying to do. I agree with offloading the stage-setting to the quest proper as a design principle, but if this code is on, say, a quest alias, I'm not sure it matters much. Even simpler, no need for the counter and just move the guard to the quest function. Link to comment Share on other sites More sharing options...
TobiaszPL Posted July 20, 2019 Share Posted July 20, 2019 foamyesqueIf you're using a structure like that it is generally best to make it go if-elseif, so that all the branches are mutually exclusive and only onewill be chosen. my code also chose only one :D after Function find first effects it return with TRUE :) It will fire two OnMagicEffectApply() events, both of which will have two successful matches. You can protect from duplicating by adding one more If that check if current state is lower than state we want to set :x#MyUglyEnglish xD im not sure you will understand me xDDD Npdogg have you try my code ? :Pi want to know it works or not xD Link to comment Share on other sites More sharing options...
javaplaza Posted September 23, 2019 Author Share Posted September 23, 2019 zombie blog time - but ive finally come back to this part of the quest.this is the script on my target npc. the formlist has 8 spells and 1 dragon shout.right now im testing with the dragon shout, and the stage isn't changing over in game. considering changing it to onHit ? many thanks Scriptname DFLShoutTrigger extends ReferenceAlias int property myStage auto Quest property myQuest auto FormList property myEffectList auto Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect) if akCaster == Game.GetPlayer() if myEffectList.HasForm(akEffect) myQuest.setStage(myStage) debug.messagebox("Success") endif endif endEvent Link to comment Share on other sites More sharing options...
npdogg Posted September 27, 2019 Share Posted September 27, 2019 (edited) considering changing it to onHit ? Dawnguard uses OnHit to detect when Dexion is charmed during Prophet. Scriptname DLC1VQ03VamprieCharmDexion extends ReferenceAlias {When the player uses a spel on Dexion that has the "vampiremesmerize" effect, display a new objective} Event onHit(objectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) if GetOwningQuest().GetStageDone(6) == 0 if akAggressor == Game.GetPlayer() as ObjectReference Spell sourceSpell = akSource as Spell If sourceSpell != None && GetActorRef().HasMagicEffect(VampireMesmerize) GetOwningQuest().SetObjectiveCompleted(40,1) GetOwningQuest().SetObjectiveDisplayed(45,1) endif endif endif endEvent MagicEffect Property VampireMesmerize Auto Edited September 27, 2019 by npdogg Link to comment Share on other sites More sharing options...
ReDragon2013 Posted September 27, 2019 Share Posted September 27, 2019 (edited) you wrote: "script on my target npc. the formlist has 8 spells and 1 dragon shout."but the OnMagicEffectApply() event has return value of "MagicEffect akEffect", which is whether a spell nor a shout, that means HasForm() is returning always False.Conclusion, move to OnHit() event as follow: Quest PROPERTY myQuest auto Int PROPERTY myStage auto FormList PROPERTY myList auto ;Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) ;endEvent EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProj, Bool b1, Bool b2, Bool b3, Bool b4) IF ((akSource as Spell) || (akSource as Shout)) && myList.HasForm(akSource) ELSE RETURN ; - STOP - not part of formlist ENDIF ;--------------------- IF (akAggressor == Game.GetPlayer() as ObjectReference) ELSE RETURN ; - STOP - not fired by player ENDIF ;--------------------- myQuest.setStage(myStage) Debug.MessageBox("Success") ; *** debugging only *** ENDEVENT Edited September 27, 2019 by ReDragon2013 Link to comment Share on other sites More sharing options...
Recommended Posts