This has to be an engine quirk, my code is good

Post » Sat Nov 17, 2012 7:47 am

Ok I'm trying to set a variable in a quest through a magic effect. I've done it before in this same quest and it works fine. What its doing is setting the variable DetectLIfeToggleVar to 1, and then immediately setting it to 0 every time I cast it. I know I am sucessfully setting the variable, because I commented out the line in the if statement PlayerVampireQuest.DetectLifeToggleVar = 0 and it stayed at 1 and my spell stayed toggled on.

Is there some quirk about setting a quest variable in the same frame or something? I tried a utility.wait(1) command but it didn't help.

Scriptname DetectLifeVampireToggleScript extends ActiveMagicEffect  Spell Property VampireDetectLifeToggleSpell autoPlayerVampireQuestScript Property PlayerVampireQuest  Auto  Event OnEffectStart(Actor akTarget, Actor akCaster)    if(akCaster == Game.GetPlayer())        if PlayerVampireQuest.DetectLifeToggleVar == 1        debug.notification ("detect life was on, turning it off by setting it to 0");            ; turn the toggle to 0 to disable the effect            PlayerVampireQuest.DetectLifeToggleVar = 0        else            ; turn the toggle to 1 to keep the effect looping AND cast the spell            PlayerVampireQuest.DetectLifeToggleVar = 1            debug.notification("detect life was not on, so we are turning it on to 1")            VampireDetectLifeToggleSpell.Cast(akCaster,akCaster)        endif    endifendEvent
User avatar
Beat freak
 
Posts: 3403
Joined: Thu Dec 14, 2006 6:04 am

Post » Sat Nov 17, 2012 11:24 am

I'm not very familiar with game variables and magicEffects, but I can't find where DetectLifeToggleVar is declared.. is it something you defined or is it a game/quest/script variable you're referencing? If it's the latter, you may not be able to set it manually - only read it. If not, it may be that your fragment or other scripting that isn't setting it properly.

Something I noticed is that when the var is 1, it's immediately set back to 0. This may be the problem if the magicEffect is recurring, such as a constant or concentration type effect. I fairly certain that detectLife magic must keep firing to work - about once every second or so as I recall.. if that's true, then the above script will always set that var to 0 until the next effectStart (which may not happen if the effect is removed by that 0 var).
User avatar
c.o.s.m.o
 
Posts: 3419
Joined: Sat Aug 12, 2006 9:21 am

Post » Sat Nov 17, 2012 8:00 am


Is there some quirk about setting a quest variable in the same frame or something? I tried a utility.wait(1) command but it didn't help.


I don't have experience with Quest Variables either, but do you have to update them with http://www.creationkit.com/UpdateCurrentInstanceGlobal_-_Quest like when using globals?
User avatar
Janette Segura
 
Posts: 3512
Joined: Wed Aug 22, 2007 12:36 am

Post » Sat Nov 17, 2012 2:28 pm

Are you certain that the variable is not getting set? The first thing I'd do after setting it, for debugging, is to fire a message telling me what the value of the var is.

If the variable is not getting set correctly, try handling it with a function inside the PlayerVampireQuestScript.

If the var IS getting set correctly, your problem might be where you cast the spell
VampireDetectLifeToggleSpell.Cast(akCaster, akCaster)

Personally, I don't like to hit quest variables directly from outside the script. I like to use a function to handle those kinds of things, but if directly manipulating the variables isn't actually the problem for you then... this statement... is kind of moot :(
User avatar
Joey Avelar
 
Posts: 3370
Joined: Sat Aug 11, 2007 11:11 am

Post » Sat Nov 17, 2012 4:48 am

Is it a quest variable or a property? I've had success with gobals and properties to set them

bool _foo_flag = false conditionalbool property foo_flag    function set(bool value)	    _foo_flag = value    endfunction    bool get()	    return _foo_flag     endfunctionendproperty

Admittedly, the only reason I did it that way was because Papyrus complained if I made an auto property condtional. But it seemed to work just fine when I accessed and set the value via a property from scripts.
User avatar
Mari martnez Martinez
 
Posts: 3500
Joined: Sat Aug 11, 2007 9:39 am

Post » Sat Nov 17, 2012 8:31 am

First, you should be using a boolean instead of 1 or 0.

If I'm reading your code right, is this true?

event OnEffectStart()	if togglevar == true		togglevar = false	elseif togglevar == false		togglevar = true		cast spell	endifendEvent

If that's true, then here's what's happening:
  • You cast your spell. We receive OnEffectStart event and fire script.
  • togglevar is false, so we set it to true. Then we immediately cast the spell again.
  • We receive OnEffectStart event again because we recast the spell. Togglevar is true, so we immediately set it back to false.
I think that's what's happening.
User avatar
xx_Jess_xx
 
Posts: 3371
Joined: Thu Nov 30, 2006 12:01 pm

Post » Sat Nov 17, 2012 10:12 am

First, you should be using a boolean instead of 1 or 0.

Good point Chesko!

If this is the problem, good paying attention ;)
User avatar
Laura Shipley
 
Posts: 3564
Joined: Thu Oct 26, 2006 4:47 am

Post » Sat Nov 17, 2012 5:29 am

First, you should be using a boolean instead of 1 or 0.

If I'm reading your code right, is this true?

event OnEffectStart()	if togglevar == true		togglevar = false	elseif togglevar == false		togglevar = true		cast spell	endifendEvent

If that's true, then here's what's happening:
  • You cast your spell. We receive OnEffectStart event and fire script.
  • togglevar is false, so we set it to true. Then we immediately cast the spell again.
  • We receive OnEffectStart event again because we recast the spell. Togglevar is true, so we immediately set it back to false.
I think that's what's happening.
I think you are right. But I always thought elseif's only run when your previous if was false? Or do all elseifs process, if somehow they are true?

So how do I declare it as a boolean?

In my quest its defined as such:

Int Property DetectLifeToggleVar Auto

Would it just be Bool DetectLiftToggleVar Auto ?

Lets say I change it to the boolean, how would it change how the code is going to behave?
User avatar
Nancy RIP
 
Posts: 3519
Joined: Mon Jan 29, 2007 5:42 am

Post » Sat Nov 17, 2012 9:39 am

I think you are right. But I always thought elseif's only run when your previous if was false? Or do all elseifs process, if somehow they are true?

No, the first "If" will process and if false, it will then fall to the first "ElseIf"... even if all the conditions are true, it's going to stop at the first true condition. Are you thinking because Chesko used:
elseif togglevar == false
that somehow If/ElseIf doesn't work as you thought? Since there are only two allowed values for Bool, the "if togglevar==false" isn't really needed. (Though some languages allow for a null bool, pretty sure Papyrus does not.)

So how do I declare it as a boolean?
Yes, Bool is the keyword for boolean.

Lets say I change it to the boolean, how would it change how the code is going to behave?
It isn't really going to change your code logic, just give you the correct checking that you thought you were using in the first place. Besides, True & False are much easier to read anyway, which makes for easier to understand code and less bugs. :smile:
User avatar
Peter lopez
 
Posts: 3383
Joined: Mon Sep 10, 2007 5:55 pm

Post » Sat Nov 17, 2012 2:36 am

True / false and 1 / 0 is really a semantics change, but is more legible and may compile into a more efficient set of code.

I think you are right. But I always thought elseif's only run when your previous if was false? Or do all elseifs process, if somehow they are true?


In your code, you put "if / else". If the "if" statement is false, it will fall into the else block no matter what.

In my pseudocode, I specified elseif, which was probably unnecessary. The elseif would not be stepped into unless the elseif condition were true.

In a boolean if / else block, an "elseif" would be redundant. Sorry for the confusion.

Would it just be Bool DetectLiftToggleVar Auto ?

Yes.

Lets say I change it to the boolean, how would it change how the code is going to behave?

Assuming you replace your 1 with True, it won't change it a bit.

The real sticky wicket here is that I think you're firing your OnEffectStart() condition twice because you are recasting the spell in your Else block. That needs to be removed, or conditionalized out.

Edit: is the spell being cast in the Else block and the spell this script is attached to two separate spells?
User avatar
Alisia Lisha
 
Posts: 3480
Joined: Tue Dec 05, 2006 8:52 pm

Post » Sat Nov 17, 2012 1:35 pm

Thanks a ton. I got it working with this code:

Scriptname DetectLifeVampireToggleScript extends ActiveMagicEffect  Spell Property VampireDetectLifeToggleSpell autoPlayerVampireQuestScript Property PlayerVampireQuest  Auto  Event OnEffectStart(Actor akTarget, Actor akCaster)    if(akCaster == Game.GetPlayer())        if PlayerVampireQuest.DetectLifeToggleVar == false        debug.notification ("detect life was off, turning it on by setting it to true")            PlayerVampireQuest.DetectLifeToggleVar = true            VampireDetectLifeToggleSpell.Cast(akCaster,akCaster)        else            PlayerVampireQuest.DetectLifeToggleVar = false        endif    endifendEvent

However, the glow on nearby life is sporadic. It glows for a second or two, then shuts off, the spell recasts, sometimes it works, sometimes it doesn't.

Here is my code from the life detect spell:

Scriptname DetectLifeVampireDummyScript extends activemagiceffect  PlayerVampireQuestScript Property PlayerVampireQuest  Auto  Spell Property VampireDetectLifeToggleSpell auto;this is a property to the effects mother spell;old codeEvent OnEffectFinish(Actor akTarget, Actor akCaster)    if PlayerVampireQuest.DetectLifeToggleVar == true        Debug.notification("var was true, keeping the spell alive")        VampireDetectLifeToggleSpell.Cast(akCaster, akTarget)    else    debug.notification("dummy spell did not stay alive")    endif    endEvent

The spell VampireDetectLifeToggleSpell has the dummy script as an effect, and the 4 detect life magic effects:

DetectLIfeEnemyInteriorSelfFF
DetectLIfeEnemyExteriorSelfFF
DetectLIfeFriendInteriorSelfFF
DetectLIfeFriendExteriorSelfFF

I have magnitude set to 0, area 150 and a duration of 5. I upped the 5 to 15 but it didn't help.

Any clues? All I want to do is make a life detect spell you can toggle on/off like you could do with Oblivion.
User avatar
Rob Smith
 
Posts: 3424
Joined: Wed Oct 03, 2007 5:30 pm

Post » Sat Nov 17, 2012 8:28 am

Is it something to do with quest priority? In the example mod I looked at "ring of spell and sense life" by mofomojo (I think that's his name) he used a global variable instead of a quest variable. Would that have anything to do with how fast its reading the spells script?
User avatar
Sasha Brown
 
Posts: 3426
Joined: Sat Jan 20, 2007 4:46 pm

Post » Sat Nov 17, 2012 12:00 am

Well I had spoken too soon. Chesko was right. All I did was reverse the code, now it stays on even when I shut it off. The reason for this is the spell calls itself if that variable is true. So even if I turn it off, the spell comes back and turns it back on.

So I need another variable or something. I tried using IsSpellTarget but a I get errors, that condition isn't as easy to use as it was with Oblivion.

I'd like to just check if the player is spell target of the main spell, then let the other one use the variable that says if its on or not.
User avatar
Doniesha World
 
Posts: 3437
Joined: Sun Jan 07, 2007 5:12 pm

Post » Sat Nov 17, 2012 1:13 pm

I find toggles are easier to make with two spells. One of them is an always on ability while the other one is FF and either adds the ability if absent or removes it if present.

Slightly more complicated, but you get none of these recast issues.
User avatar
Lance Vannortwick
 
Posts: 3479
Joined: Thu Sep 27, 2007 5:30 pm

Post » Sat Nov 17, 2012 12:40 pm

That quest ring is so old at this point. Toggle's especially if they have clean up code and such to perform, are much better implemented now with two spells than one as DocClox mentions. Here's how I would approach this.

Make a sense spell an ability with constant effect that points to a cloak based effect that is constant effect, and points another spell for the apply.
Next spell is your apply spell, it will be a fire and forget, target, 5 seconds for instance. This is what the cloak spell applies to anyone that meets the conditions for what you are sensing (which should be placed here), setup the effect shader to whatever you wish to see and make for FXPersist is set. I suggest in the conditions that you check HasMagicEffect against it's self so it doesn't re-apply unless it run sout. Now when you get far enough away, the sensing shader effect will drop out after five secons.
Finally your toggle spell. OnEffectStart should check if the caster, you, hasspell whateveryourcloak spell is. IF so, remove it. If not, add it.
Done.

-MM
User avatar
James Wilson
 
Posts: 3457
Joined: Mon Nov 12, 2007 12:51 pm

Post » Sat Nov 17, 2012 2:13 am

That quest ring is so old at this point. Toggle's especially if they have clean up code and such to perform, are much better implemented now with two spells than one as DocClox mentions. Here's how I would approach this. Make a sense spell an ability with constant effect that points to a cloak based effect that is constant effect, and points another spell for the apply.

This is part is confusing. Are you saying to make a spell which is an ability that has a magic effect archetype of script that then casts another spell which has an archetype of cloak with a constant effect?

Do I need three spells or just two?

This is said after another two hours trying to do what you said, but I can't get my magic effect to ring true.

Here is what I have:

A spell that is given to the player called VampireDetectLife that they cast. It is an ability spell which uses a magic effect that is a cloak with a constant effect. It has a script as follows:

Scriptname DetectLifeVampireToggleScript extends ActiveMagicEffect  MagicEffect Property DetectLifeVampireToggle AutoSpell Property VampireDetectLifeToggleSpell autoGlobalVariable Property VampireDetectLifeGlobal AutoEvent OnEffectStart(Actor akTarget, Actor akCaster)    if(akCaster == Game.GetPlayer())        if Game.GetPlayer().HasMagicEffect (DetectLifeVampireToggle) == true            Debug.notification("Detect life vampire dummy effect is active")            ; turn the toggle to off to disable the effect            VampireDetectLifeGlobal.SetValue(0)                    else            ; turn the toggle to 1 to keep the effect looping AND cast the spell            VampireDetectLifeGlobal.SetValue(1)                debug.notification("Global was off, gimme da goods so I can find some mortal munchables")            VampireDetectLifeToggleSpell.Cast(akCaster,akCaster)        endif    endifendEvent

The problem is my if condition if Game.GetPlayer().HasMagicEffect (DetectLifeVampireToggle) == true is never true. Just for clarification the main spell's magic effect is this DetectLifeVampireToggle. At this point I'd be happy to get the first step done, make a spell I can toggle on and off, then I can get the life detect part to work I am sure.
User avatar
Hella Beast
 
Posts: 3434
Joined: Mon Jul 16, 2007 2:50 am

Post » Sat Nov 17, 2012 7:29 am

I'd just use two spells: the effect and the toggler.

As for detecting if the detect is on. use player_ref.HasSpell(spellprop) rather than player_ref.HasMagicEffect(me_prop), where spell_prop is a reference to the spell that has the detect effect.

I'd be more specific, but I'm away from my dev box and source code until tonight.
User avatar
adam holden
 
Posts: 3339
Joined: Tue Jun 19, 2007 9:34 pm

Post » Sat Nov 17, 2012 3:20 pm

Well I finally got it going. I ended up writing my own script to toggle the spell. Once that was going it was easy to get the fx playing and repeating using OnEffectFinish and then cast it again. I set the duration of each effect to 1 second so it updates every second revealing new life as you move about, and it kills the effect within a second too when you dispell it. I must have spent 40 hours trying to borrow someones idea, and then I code it in myself in 10 minutes. I learned a lot though, mostly that spells are very finicky.

I initially was going to do it all from one script but for some reason I was unable to get registerforsingleupdate to work at all on my magic effect. Does that have anything to do with the casting type?
User avatar
Céline Rémy
 
Posts: 3443
Joined: Sat Apr 07, 2007 12:45 am


Return to V - Skyrim