Jump to content

[LE] Multiple If Statements


Recommended Posts

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 by foamyesque
Link to comment
Share on other sites

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

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 logging
ENDEVENT


EVENT OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)
IF (akCaster == Game.GetPlayer() as ObjectReference)
myF_TryStage(akEffect)
ENDIF
ENDEVENT


; -- 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 lengths
ENDIF
;---------------------
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 monitoring
ENDIF
;---------------------
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 found
ENDFUNCTION

 

 

 

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 by npdogg
Link to comment
Share on other sites

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 logging

ENDEVENT

 

 

EVENT OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)

IF (akCaster == Game.GetPlayer() as ObjectReference)

myF_TryStage(akEffect)

ENDIF

ENDEVENT

 

 

; -- 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 lengths

ENDIF

;---------------------

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 monitoring

ENDIF

;---------------------

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 found

ENDFUNCTION

 

 

 

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 by foamyesque
Link to comment
Share on other sites

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

foamyesque

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 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 ? :P

i want to know it works or not xD

Link to comment
Share on other sites

  • 2 months later...

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

 

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 by npdogg
Link to comment
Share on other sites

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 by ReDragon2013
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...