Scripted Spells

Post » Sat Jan 29, 2011 7:00 am

My Script is below. I know it doesn't work and it isn't even close. This isn't how I originally had it, but this is how it ended up.

When I cast the spell on the target corpse a messagebox is supposed to open up and ask you what you want to do. The problem I'm having is that the message box result isn't processed before the spell is over even though the spells duration is 20 seconds. When I cast the spell again, it randomly picks a messagebox answer and assigns it.

How do I get message boxes to function correctly when they are brought up with a spell? I'd like the player to be able to interact with the corpse through a single spell, rather than clogging up the spellbook.

Perhaps giving me an example or explaining how scripteffectstart/update/finish process in relation to message boxes?

I've been to the wiki and I've been toying with it for hours but I can't seem to get it to work, so please explain in your own words. Thank you!









SCN AAPrepareCorpse

Short SoulButton

begin scripteffectstart

Set soulbutton to getbuttonpressed
Messagebox "What would you like to do?", "Capture the soul.", "Nothing."

end


Begin Scripteffectupdate


if ( SoulButton == 0 && GetDead==1 && Getitemcount AASoulStopper == 0)
additem AASoulStopper 1
player.additem BlackSoulGemFilled 1
Messagebox "You manage to capture the soul!"

Elseif ( SoulButton == 0 && GetDead==0 && Getitemcount AASoulStopper == 0)
Messagebox "The spell fizzles. Perhaps you should kill your intended victim first."

Elseif (soulbutton ==1)
Messagebox "You leave the corpse alone for now."

Else
Endif
Endif

End


Begin Scripteffectfinish




; Maybe it should be down here? It didn't work when it was. I tried it up top too. :-(


end
User avatar
Craig Martin
 
Posts: 3395
Joined: Wed Jun 06, 2007 4:25 pm

Post » Sat Jan 29, 2011 11:54 am

Ok well, part of my problem is the fact that the buttons numbers are wrong. it starts at 0 from the left and goes to the right - so 0 1 2 3 - but the fact that the message box isn't displayed even though the soulgem is added, still baffles me.
User avatar
Flesh Tunnel
 
Posts: 3409
Joined: Mon Sep 18, 2006 7:43 pm

Post » Sat Jan 29, 2011 4:00 pm

Here is my new script.



SCN AAPrepareCorpse

Short SoulButton
Short Check
Short Choice



Begin ScriptEffectStart
Set Choice to -1

end




Begin ScriptEffectUpdate


; This will always fire.

If ( Choice == -1 && GetItemCount AASoulStopper == 0 && GetDead == 1 )
Set SoulButton to GetButtonPressed
Messagebox "What would you like to do?", "Capture the soul.", "Nothing."
Set choice to 1
Endif

; This will NEVER show up for some reason. EVER
If (Choice == -1 && GetItemCount AASoulStopper == 1 && GetDead == 1)
Messagebox "You've already captured this victims soul"
Set choice to 2
endif
;This doesn't happen the first time I cast the spell, although if i Cast the spell again it will happen.
If (choice == 1 && SoulButton == 0 )
additem AASoulStopper 1
player.additem BlackSoulGemFilled 1
Set SoulButton to GetButtonPressed
Set Choice to -1
Messagebox "You've captured your vitcims soul."


; Even if you select Nothing from the messagebox - this never shows up either. It doesn't matter if you select nothing the first time and cast the spell again. It just doesn't show up.


Elseif (Choice == 1 && SoulButton == 1 )
Messagebox "You leave your victims corpse alone for now and attend to other matters."
Set choice to -1
Set SoulButton to -1
Endif


; if the first box fires and you decide to steal the soul, this message box will pop up the second time you cast the spell on the same corpse - and curiously, your black soulgem is added at the same time.

If (Choice == 2)
Messagebox "What would you like to do?"

Endif

end

Begin ScriptEffectFinish

End




I have absolutely no idea why any of this happens the way it does. I've been playing with this thing for hours and this is the closest i've come to getting it to work right, even though I can't see the sense in it.
User avatar
Sunny Under
 
Posts: 3368
Joined: Wed Apr 11, 2007 5:31 pm

Post » Sat Jan 29, 2011 2:37 pm

Please, please, please use [code][/code] around your code. It's all but impossible to read like that.
User avatar
ezra
 
Posts: 3510
Joined: Sun Aug 12, 2007 6:40 pm

Post » Sat Jan 29, 2011 11:22 am

SCN AAPrepareCorpseShort SoulButtonShort CheckShort ChoiceBegin ScriptEffectStartSet Choice to -1endBegin ScriptEffectUpdate ; This will always fire.If ( Choice == -1 && GetItemCount AASoulStopper == 0 && GetDead == 1 )Set SoulButton to GetButtonPressedMessagebox "What would you like to do?", "Capture the soul.", "Nothing."Set choice to 1Endif; This will NEVER show up for some reason. EVERIf (Choice == -1 && GetItemCount AASoulStopper == 1 && GetDead == 1)Messagebox "You've already captured this victims soul"Set choice to 2endif;This doesn't happen the first time I cast the spell, although if i Cast the spell again it will happen.If (choice == 1 && SoulButton == 0 )additem AASoulStopper 1player.additem BlackSoulGemFilled 1Set SoulButton to GetButtonPressedSet Choice to -1Messagebox "You've captured your vitcims soul."; Even if you select Nothing from the messagebox - this never shows up either. It doesn't matter if you select nothing the first time and cast the spell again. It just doesn't show up.Elseif (Choice == 1 && SoulButton == 1 )Messagebox "You leave your victims corpse alone for now and attend to other matters."Set choice to -1Set SoulButton to -1Endif; if the first box fires and you decide to steal the soul, this message box will pop up the second time you cast the spell on the same corpse - and curiously, your black soulgem is added at the same time.If (Choice == 2)Messagebox "What would you like to do?"EndifendBegin ScriptEffectFinishEnd

User avatar
abi
 
Posts: 3405
Joined: Sat Nov 11, 2006 7:17 am

Post » Sat Jan 29, 2011 6:14 pm

Well, the reason you use the code tags is to preserve indentation. Using indentation is an excellent way to keep code neat, readable, and can actually help you catch errors.

Here's your code with indentation and some clean-up of the spacing (i.e. returns added or removed for readability) (I've changed nothing else at this point, this will function identically to your original)
SCN AAPrepareCorpseShort SoulButtonShort CheckShort ChoiceBegin ScriptEffectStart    Set Choice to -1EndBegin ScriptEffectUpdate     ; This will always fire.    If ( Choice == -1 && GetItemCount AASoulStopper == 0 && GetDead == 1 )        Set SoulButton to GetButtonPressed        Messagebox "What would you like to do?", "Capture the soul.", "Nothing."        Set choice to 1    Endif    ; This will NEVER show up for some reason. EVER    If (Choice == -1 && GetItemCount AASoulStopper == 1 && GetDead == 1)        Messagebox "You've already captured this victims soul"        Set choice to 2    Endif    ;This doesn't happen the first time I cast the spell, although if i Cast the spell again it will happen.    If (choice == 1 && SoulButton == 0 )        additem AASoulStopper 1        player.additem BlackSoulGemFilled 1        Set SoulButton to GetButtonPressed        Set Choice to -1        Messagebox "You've captured your vitcims soul."    ; Even if you select Nothing from the messagebox - this never shows up either. It doesn't matter if you    ; select nothing the first time and cast the spell again. It just doesn't show up.    Elseif (Choice == 1 && SoulButton == 1 )        Messagebox "You leave your victims corpse alone for now and attend to other matters."        Set choice to -1        Set SoulButton to -1    Endif    ; if the first box fires and you decide to steal the soul, this message box will pop up the second time    ; you cast the spell on the same corpse - and curiously, your black soulgem is added at the same time.    If (Choice == 2)        Messagebox "What would you like to do?"    EndifEndBegin ScriptEffectFinishEnd
The first thing I see is an empty ScriptEffectFinish block; you don't need that. Second, you could probably speed this up a bit by using elseif more instead of separate blocks. Nested ifs could also help. Here's a first pass through with those changes:
SCN AAPrepareCorpseShort SoulButtonShort CheckShort ChoiceBegin ScriptEffectStart    Set Choice to -1EndBegin ScriptEffectUpdate     ; This will always fire.    If ( Choice == -1 && GetDead ) ; without == 1 here, it will be the same as != 0        If ( GetItemCount AASoulStopper == 0 )            Set SoulButton to GetButtonPressed            Messagebox "What would you like to do?", "Capture the soul.", "Nothing."            Set Choice to 1        Else            Messagebox "You've already captured this victim's soul." ; "victim's" is the possessive            Set Choice to 2        Endif    ;This doesn't happen the first time I cast the spell, although if i Cast the spell again it will happen.    Elseif ( Choice == 1 )        If ( SoulButton == 0 )            additem AASoulStopper 1            player.additem BlackSoulGemFilled 1            Set SoulButton to GetButtonPressed            Set Choice to -1            Messagebox "You've captured your vitcim's soul."        ; Even if you select Nothing from the messagebox - this never shows up either. It doesn't matter if you        ; select nothing the first time and cast the spell again. It just doesn't show up.        Elseif ( SoulButton == 1 )            Messagebox "You leave your victims corpse alone for now and attend to other matters."            Set Choice to -1            Set SoulButton to -1        Endif    ; if the first box fires and you decide to steal the soul, this message box will pop up the second time    ; you cast the spell on the same corpse - and curiously, your black soulgem is added at the same time.    Elseif ( Choice == 2)        Messagebox "What would you like to do?"    EndifEnd
These changes, again, shouldn't affect the functioning of your script (other than making it run a bit faster and make its function a bit clearer because mutually exclusive options are within if/elseif/else blocks).

Anyway, now that it's cleaned up and I can read it more easily, I think I see the problem (or at least a problem) - you're calling GetButtonPressed before the MessageBox. That doesn't work. You need to call MessageBox, and then have a separate block while the script is waiting for input with GetButtonPressed. As is, GetButtonPressed will always return -1 (player doesn't even have buttons yet to press!), and then it doesn't get called again. I recommend http://cs.elderscrolls.com/constwiki/index.php/MessageBox_Tutorial for using the MessageBox; it's quite thorough (read: long), but working with MessageBoxes is a bit tricky, so that's generally a good thing.

In general, MessageBox/GetButtonPressed work... awkwardly in script effects. Because of the limited duration on the script, if the player takes too long to answer, the script may stop running before he does - that's not good. I recommend changing this so you have a Quest script that handles the MessageBox and adding/removing the items, and the script effect just sets that Quest script running by passing the reference of the target to the Quest script. Something like this:
scn MagicEffectScriptBegin ScriptEffectScript    set Quest.refVar to GetSelf    set Quest.fQuestDelayTime to 0.01End
And then:
scn QuestScriptref refVarshort choiceshort checkshort SoulButtonfloat fQuestDelayTimeBegin GameMode    if ( refVar )        ; MessageBox and related code.        set refVar to 0        set fQuestDelayTime to 0    endifEnd
fQuestDelayTime controls how often a Quest script is run. During the MessageBox time, you want it to be running every frame, so it's set to 0.01, but otherwise it's set to 0 so the script will use the default (once every ~5 seconds). You could alternatively use StartQuest/StopQuest or whatever those functions are called, but I didn't feel like looking up exactly how they work for such a miniscule performance boost.
User avatar
chinadoll
 
Posts: 3401
Joined: Tue Aug 22, 2006 5:09 am

Post » Sat Jan 29, 2011 10:12 pm

In general, MessageBox/GetButtonPressed work... awkwardly in script effects. Because of the limited duration on the script.


Actually Script Timers do not run while in MenuMode so a 2 second timer on a spell will never reach its duration as long as your in MenuMode, although opening and closing new menu's will eat some duration because it has to reiterate to open a new menu -> only really a problem if you need several levels of menu options and in this case a Quest work better then a single spell but I often just use different spells each controlling each seperate menu level to avoid Quests that are always on wasting resources -> and even if your turn them off your now stuck with needing to use another source to control when to turn them on and off its just a huge hasstle for very little benefit... at least to me.

Pretty much all of my Oblivion mods use Spells for menu options or any option really -> AM is my only released sample of how this works without any issues, all of the AM timers are set to a few seconds only.
User avatar
james reed
 
Posts: 3371
Joined: Tue Sep 18, 2007 12:18 am

Post » Sat Jan 29, 2011 6:36 pm

I appreciate the help and apologize for leaving such messy posts. I don't frequent forums very often and was unaware of the scripting etiquette.

Can you use the gamemode block in a scripted spell? Also I was under the impression that a messagebox or menumode would halt the scripts processing for some reason but I suppose that isn't true.

I find it kind of strange that you have to declare GetButtonPressed before the messagebox, even though the script seems to react while the player is in menu mode making a choice? but I suppose it makes sense given the fact that when I cast the spell again the effect I want to happen finally does.

I'll make these changes and rearrange the script to the best of my understanding and post the product again. Thank you for your time.


PS.

Is this supposed to be run as a spell script? or is the spell script supposed to call this script into effect?

Is that possible?
User avatar
Nadia Nad
 
Posts: 3391
Joined: Thu Aug 31, 2006 3:17 pm

Post » Sat Jan 29, 2011 11:03 am

Actually Script Timers do not run while in MenuMode so a 2 second timer on a spell will never reach its duration as long as your in MenuMode, although opening and closing new menu's will eat some duration because it has to reiterate to open a new menu -> only really a problem if you need several levels of menu options and in this case a Quest work better then a single spell but I often just use different spells each controlling each seperate menu level to avoid Quests that are always on wasting resources -> and even if your turn them off your now stuck with needing to use another source to control when to turn them on and off its just a huge hasstle for very little benefit... at least to me.

Pretty much all of my Oblivion mods use Spells for menu options or any option really -> AM is my only released sample of how this works without any issues, all of the AM timers are set to a few seconds only.

At least last I checked, most preferred items to spells, and most that do use spells use them to trigger quests. Yes, you are correct, however I tend to greatly prefer to do things in a manner such that they are foolproof, so I don't like trusting spell scripts with storing anything important.

In other news, though, hi! :wave: Nice to see you're still around. How are things going?

I appreciate the help and apologize for leaving such messy posts. I don't frequent forums very often and was unaware of the scripting etiquette.

Well, indentation should be used even just for yourself, as it makes things much easier to read. But that's not a problem.

Can you use the gamemode block in a scripted spell? Also I was under the impression that a messagebox or menumode would halt the scripts processing for some reason but I suppose that isn't true.

Not sure on MenuMode, but GameMode and ScriptEffectUpdate are identical. But the block I posted with GameMode is a Quest script, not a Magic Effect script.

I find it kind of strange that you have to declare GetButtonPressed before the messagebox, even though the script seems to react while the player is in menu mode making a choice? but I suppose it makes sense given the fact that when I cast the spell again the effect I want to happen finally does.

You don't. That's what you've done.

What you have to do is this:
if ( stage == 1 )    MessageBox "Question?" "Answer 1" "Answer 2" "Answer 3"    set stage to 2elseif ( stage == 2 )    set button to GetButtonPressed    if ( button != -1 ) ; -1 is used for 'hasn't picked yet'        set stage to 3elseif ( stage == 3 )    if ( button == 0 ) ; "Answer 1"        ; whatever    elseif ( button == 1 ) ; "Answer 2"        ; whatever    elseif ( button ==2 ) ; "Answer 3"        ; whatever    else ; shouldn't happen but I believe in thoroughness        ; error?    endifendif
Here, you call MessageBox and advance to stage 2, where it sits and calls GetButtonPressed over and over until until it gets something other than -1, which is to say, it waits until the player presses something. Once the player's pressed something, it advances to stage 3 where the code does stuff depending on what button is pressed.

I'll make these changes and rearrange the script to the best of my understanding and post the product again. Thank you for your time.

No problem.

Is this supposed to be run as a spell script? or is the spell script supposed to call this script into effect?

Is that possible?

Which is "this script"? The second one I posted with the GameMode block? That's a Quest script, and yes, the spell script is basically "calling" it because everything in the Quest script depends on refVar != 0, which it usually is. The spell sets refVar to GetSelf, so refVar != 0, so the Quest script runs. It then resets itself back to 0 so that it doesn't run anymore until the next time the spell is cast and sets the refVar variable.
User avatar
Ryan Lutz
 
Posts: 3465
Joined: Sun Sep 09, 2007 12:39 pm


Return to IV - Oblivion