MWSFD Question on variables

Post » Sat Jan 23, 2010 3:38 pm

So i'm currently doing the tutorial for MWSFD about the riddle chest, and in the explanation, I got confused. It says ": we need to declare a variable and use it to make sure the message is only displayed once. Change the script to the following:
Begin my_first_scriptShort controlvarIf ( OnActivate == 1 )If ( controlvar == 0)		MessageBox "Voiceless it cries, wingless flutters, toothless bites, mouthless mutters. What is it?", "Bat", "Old woman", "Wind", "Wraith"	Set controlvar to 1endifendifEnd
"

So for the variable, I can make up any random name and use it? Or does it have to be a specific name? I don't really understand what it's saying here.
User avatar
pinar
 
Posts: 3453
Joined: Thu Apr 19, 2007 1:35 pm

Post » Sat Jan 23, 2010 10:20 am

Yup. For most variables (excluding special ones like OnPcEquip) you can give them any name.

All variables are is a way of storing a bit of information (In this case a number). You could think of it like a box that holds a number with the variable name written on the box. You can set and get the number. However, all you use the name for is knowing which box to get the number from.
User avatar
Damned_Queen
 
Posts: 3425
Joined: Fri Apr 20, 2007 5:18 pm

Post » Sat Jan 23, 2010 10:05 pm

Yup. For most variables (excluding special ones like OnPcEquip) you can give them any name.

Huh. Well then. That greatly reduces my confusion on reading scripts haha :brokencomputer:
User avatar
brenden casey
 
Posts: 3400
Joined: Mon Sep 17, 2007 9:58 pm

Post » Sat Jan 23, 2010 2:54 pm

You can use whatever you want, but try to keep it relevant to it's function. A variable is basically a way to store different states of information. In the tutorial, "controlvar" is likely meant to mean "control variable", that is, a variable that controls. All variables control something. In this case it is controlling the ability to open the chest. You could name it "state", and it would still do the same thing, and is still pretty relevant. You might remember "doOnce", or "done" from an earlier script. They both do the same thing as far as scripts are concerned, and you could likewise replace them with "state".

You can name them anything really, but it's easier if they reflect what they are for. You can't have more than one variable with the same name though, and you shouldn't make them too long. Abbreviate them, like "controlvar". Even better would be "ctrlvar", if only slightly more confusing. Stick to the tutorial conventions unless you are confident that your liberties won't mess it up, though the naming of variables shouldn't. Though not relevant to the tutorial, there is also a problem with using too many variables in one script. Specifically, the 34th variable of the same type ( short, long, float ) doesn't work well. Search "34th variable" in MWSFD to learn more.

Edit: Leave it to someone who actually knows programming to give a simpler explanation than someone who doesn't. =/
User avatar
Stacey Mason
 
Posts: 3350
Joined: Wed Nov 08, 2006 6:18 am

Post » Sat Jan 23, 2010 11:11 am

You can use whatever you want, but try to keep it relevant to it's function. A variable is basically a way to store different states of information. In the tutorial, "controlvar" is likely meant to mean "control variable", that is, a variable that controls. All variables control something. In this case it is controlling the ability to open the chest. You could name it "state", and it would still do the same thing, and is still pretty relevant. You might remember "doOnce", or "done" from an earlier script. They both do the same thing as far as scripts are concerned, and you could likewise replace them with "state".

You can name them anything really, but it's easier if they reflect what they are for. You can't have more than one variable with the same name though, and you shouldn't make them too long. Abbreviate them, like "controlvar". Even better would be "ctrlvar", if only slightly more confusing. Stick to the tutorial conventions unless you are confident that your liberties won't mess it up, though the naming of variables shouldn't. Though not relevant to the tutorial, there is also a problem with using too many variables in one script. Specifically, the 34th variable of the same type ( short, long, float ) doesn't work well. Search "34th variable" in MWSFD to learn more.

Edit: Leave it to someone who actually knows programming to give a simpler explanation than someone who doesn't. =/

I appreciate the info , and I heard about the 34th variable somewhere so now i'm interested in it. But thank you, the people in this forum are so helpful :D and what do you mean with that edit? You and yacoby both seem to know a good bit about it, to me anyways
User avatar
Prohibited
 
Posts: 3293
Joined: Tue Jun 12, 2007 6:13 am

Post » Sat Jan 23, 2010 8:22 am

NEW QUESTION

So, I'm reading up on floats, shorts, and longs, and I am deeply confused. How do you know when to use which? Which functions go with which? I've grasped everything so far, but this is just beyond me in the way the MWSFD explains it. Can anyone stupify it for me?


Question number 2:
begin 01mc_poisonoustrollskinshort donefloat timerif ( OnActivate == 1 )	if ( done == 1 )		return	else		Set done to 1		messageBox "You rip open the skin and a putrid smell arises. It gives you a funny feeling in the back of your throat."		player->addSpell "01mc_poisonioustrollskinn"		Activate	endifendifEnd


I've wrote the above script, but now i need to incorporate a time.
	Set timer to ( timer + GetSecondsPassed )	if timer > 10		Player->RemoveSpell, "01mc_poisonioustrollskinn"	endif


How do i implement that?
User avatar
Melly Angelic
 
Posts: 3461
Joined: Wed Aug 15, 2007 7:58 am

Post » Sat Jan 23, 2010 12:08 pm

I appreciate the info , and I heard about the 34th variable somewhere so now i'm interested in it. But thank you, the people in this forum are so helpful :D and what do you mean with that edit? You and yacoby both seem to know a good bit about it, to me anyways

Except that Yacoby has written programs, and I know nothing outside of TES script and some HTML, if that counts. The edit isn't meant to be negative, only sarcastic. Both of our responses have useful information, with Yacoby's being clearer on that point. I just tend to go into more detail than I probably need to for many things.
User avatar
Jesus Duran
 
Posts: 3444
Joined: Wed Aug 15, 2007 12:16 am

Post » Sat Jan 23, 2010 7:55 pm

Except that Yacoby has written programs, and I know nothing outside of TES script and some HTML, if that counts. The edit isn't meant to be negative, only sarcastic. Both of our responses have useful information, with Yacoby's being clearer on that point. I just tend to go into more detail than I probably need to for many things.


Ohh, I see, yes program writing does sound a bit more in depth haha ;D But then again, being "clearer to the point" and "going into more detail than I need to" are both good quality's, depending on the order they are received :D
User avatar
Nymph
 
Posts: 3487
Joined: Thu Sep 21, 2006 1:17 pm

Post » Sat Jan 23, 2010 8:45 pm

Curse this posting while I'm posting. I don't type fast enough to be a programmer anyway.

So, I'm reading up on floats, shorts, and longs, and I am deeply confused. How do you know when to use which? Which functions go with which? I've grasped everything so far, but this is just beyond me in the way the MWSFD explains it. Can anyone stupify it for me?

Short and long are stored as integers and would be generally used for when exact numbers are needed. Long can hold larger numbers than short, but I have never seen it used outside of MWSE. I'd like more info on it's usefulness as this is a little outside my knowledge. Floats store decimals, and are used when you need to track a value that is not whole or will almost never be exact. How much time has passed is one example since the game counts fractions of seconds. This is why a timer is stored as a float. Distance is another. You probably won't be at 256 units from object x when the part of the script that would detect it runs, so you use > 255 but < 257, which is anywhere from 255.1 to 256.9. Health may look like a whole number for example, but it isn't. You may need to detect if the player has less than < 1 instead of == 0, for example.

I might be a bit off. I don't fully understand why an integer will almost never be true for distance considering how many times the scripts run in a second, but it would seem that it is possible that the integers will fail.

Question number 2:
I've wrote the above script, but now i need to incorporate a time.

How do i implement that?

The tutorial should show you where to put it. What's important is that you understand why it is where it is, and what it is doing.
User avatar
Trey Johnson
 
Posts: 3295
Joined: Thu Oct 11, 2007 7:00 pm

Post » Sat Jan 23, 2010 12:03 pm

Curse this posting while I'm posting. I don't type fast enough to be a programmer anyway.


Short and long are stored as integers and would be generally used for when exact numbers are needed. Long can hold larger numbers than short, but I have never seen it used outside of MWSE. I'd like more info on it's usefulness as this is a little outside my knowledge. Floats store decimals, and are used when you need to track a value that is not whole or will almost never be exact. How much time has passed is one example since the game counts fractions of seconds. This is why a timer is stored as a float. Distance is another. You probably won't be at 256 units from object x when the part of the script that would detect it runs, so you use > 255 but < 257, which is anywhere from 255.1 to 256.9. Health may look like a whole number for example, but it isn't. You may need to detect if the player has less than < 1 instead of == 0, for example.

I might be a bit off. I don't fully understand why an integer will almost never be true for distance considering how many times the scripts run in a second, but it would seem that it is possible that the integers will fail.


The tutorial should show you where to put it. What's important is that you understand why it is where it is, and what it is doing.

Thank you for the lesson on variables, it makes much more sense haha.
But as for the script, I've looked through it and somehow formed this:
begin 01mc_poisonoustrollskinshort doneshort didfloat timerIf ( MenuMode == 1 )	ReturnEndifif ( OnActivate == 1 )	if ( done == 1 )		return	else		Set done to 1		messageBox "You rip open the skin and a putrid smell arises. It gives you a funny feeling in the back of your throat."		player->addSpell "01mc_poisonioustrollskinn"		Activate	     Set timer to ( timer + GetSecondsPassed )           if timer > 10                Player->RemoveSpell, "01mc_poisonioustrollskinn"           endif	endifendifEnd


Allthough, I'm positive it won't work because I wrote it :facepalm:

EDIT: I tested it in game.. Serves to say the curse killed my test character, the timer didn't work :/
User avatar
Andrew Lang
 
Posts: 3489
Joined: Thu Oct 11, 2007 8:50 pm

Post » Sat Jan 23, 2010 4:14 pm

EDIT: I tested it in game.. Serves to say the curse killed my test character, the timer didn't work :/

Okay, I don't know how you got that. Your script should end end up looking like the tutorial. Or did you already complete it? If so, from what I see of your script, it should be almost like the tutorial script in form. Take a good look at the endif and elseif statements near the bottom of the two scripts and see if you can get it. I think you are missing some, so the timer calculation is getting skipped. You could just put the timer in a separate block as well, and it should work.

As for where it goes, it entirely depends. In my experience it's usually gone at the top in a separate block, though it can often function elsewhere. I like it there when practical, because it ensures the timed event is done before the rest of the script checks if it needs to be applied again. Dunno if that is for the better or not, but it works for me. In this case, putting it at the top could keep the rest of the script from even running, since once it is applied it doesn't need to be done again, and the return will stop it from checking. The return I suspect, is also what is keeping the timer from getting checked, since that part of the script isn't getting run because of the missing endif and elseif statements. Returns are useful, but somewhat tricky to use.

I'm going to teach you a bit about debugging. First, is your health enough to survive the curse? It needs to be to be sure that the timer ends. Either heal, or open the console and type "Player->ModHealth 10000" or whatever. Activate your object and let the curse run it's course. If it never ends, reload. If it does, reload anyway. This time activate your object but don't let the curse run it's course. While it is working, open the console and click on whatever the script is attached to. Type "sv", which stands for "show variables". Locate your script in the window. it will probably be at the bottom. Look at the number next to "timer". Press the up arrow to retype your last command, sv, and press enter again. Do this a few times and see if the variable exceeds 10. If so, it's not terminating correctly.

Putting it at the top is probably the best option in my opinion, but try it both ways to get an understanding of how it works.
User avatar
Lance Vannortwick
 
Posts: 3479
Joined: Thu Sep 27, 2007 5:30 pm

Post » Sat Jan 23, 2010 1:58 pm

The timer bit there is the issue. When you have something repeating like that, isolate it out.

short gaveSpellshort runTimerfloat timerif ( OnActivate == 1 ) ; This occurs for 1 frame, serving as an initial trigger    if ( gaveSpell != 1 )        Set gaveSpell To 1        MessageBox "You rip open the skin and a putrid smell arises. It gives you a funny feeling in the back of your throat."        "player"->AddSpell "01mc_poisonioustrollskinn"        Activate        Set runTimer To 1        Set timer To 0 ; Clear the timer    endifendifif ( runTimer == 1 )    Set timer to ( timer + GetSecondsPassed )    if ( timer > 10 )        Set runTimer to 0 ; Stop it from running further        "player"->RemoveSpell "01mc_poisonioustrollskinn"    endifendif


The timer handling code is very simple, you're just waiting for the time to be up, so that's all you check for. Having it within the OnActivate block means it only runs for one frame, and so will never hit the time condition.

Other than that bit, your script looks pretty good. :thumbsup: Tweak it and test in game.

Short and long are stored as integers and would be generally used for when exact numbers are needed. Long can hold larger numbers than short, but I have never seen it used outside of MWSE.

Short is (-2^16, +2^16-1], I believe, with long being (-2^31, +2^31-1]. Longs are just used when you need to count up to 4 billion; they however match the memory model of Morrowind and use MWSE uses them to store C++ pointers (a total hack, which is why it breaks when you save/reload, but it works for a short time).

Floats store decimals, and are used when you need to track a value that is not whole or will almost never be exact. How much time has passed is one example since the game counts fractions of seconds. This is why a timer is stored as a float. Distance is another. You probably won't be at 256 units from object x when the part of the script that would detect it runs, so you use > 255 but < 257, which is anywhere from 255.1 to 256.9. Health may look like a whole number for example, but it isn't. You may need to detect if the player has less than < 1 instead of == 0, for example.

Correct. The "float" in floating point means the decimal place, which appears to float depending on the value and precision. There are some limits to them still, but much larger values are possible.

Unfortunately, the game can in some cases store shorts, longs and floats in floats on disk, which can hurt precision (floats have some rounding errors). If you're interested in the details, check:
http://en.wikipedia.org/wiki/Floating_point
http://en.wikipedia.org/wiki/Integer_(computer_science)

Morrowind uses 16-bit shorts and 32-bit longs and floats.
User avatar
[Bounty][Ben]
 
Posts: 3352
Joined: Mon Jul 30, 2007 2:11 pm

Post » Sat Jan 23, 2010 11:03 am

The timer bit there is the issue. When you have something repeating like that, isolate it out.

In the MWSFD tutorial, I'd place the timer elsewhere in it's own block. It is still isolated though in the tutorial even though it's in the same block, if I understand blocks correctly. It's just not as efficient.

Oh noes, numbers! *runs* I get how Morrowind uses them, I just can't see a practical use for long in the base game. I didn't know about the disk storage though. And floats will only have errors if the decimal place is high, right?

I will certainly read the links. The second one is missing a ")" at the end, by the way. I recall that you like numbers. I don't dislike them, but I know I need to know them better If I'm gonna program anything. Math was never my strong point.
User avatar
BethanyRhain
 
Posts: 3434
Joined: Wed Oct 11, 2006 9:50 am

Post » Sat Jan 23, 2010 9:29 pm

Wikipedia keeps messing with links. It should take you somewhere similar, so... :brokencomputer:

The bit I posted with a simple check around the timer isn't inefficient, although you could tweak it to be just a hair faster:
if ( runTimer != 1 )    returnendifSet timer to ( timer + GetSecondsPassed )if ( timer > 10 )    Set runTimer to 0 ; Stop it from running further    "player"->RemoveSpell "01mc_poisonioustrollskinn"endif


The actual speed differences shouldn't matter, though.

Practical uses for longs... not sure. You could use them for simple comparisons or summing things up. But yes, the issues with floats don't hit until you're way up there, and you aren't likely to have problems in the game.
User avatar
Aliish Sheldonn
 
Posts: 3487
Joined: Fri Feb 16, 2007 3:19 am

Post » Sat Jan 23, 2010 5:43 pm

Okay, I don't know how you got that. Your script should end end up looking like the tutorial. Or did you already complete it? If so, from what I see of your script, it should be almost like the tutorial script in form. Take a good look at the endif and elseif statements near the bottom of the two scripts and see if you can get it. I think you are missing some, so the timer calculation is getting skipped. You could just put the timer in a separate block as well, and it should work.

As for where it goes, it entirely depends. In my experience it's usually gone at the top in a separate block, though it can often function elsewhere. I like it there when practical, because it ensures the timed event is done before the rest of the script checks if it needs to be applied again. Dunno if that is for the better or not, but it works for me. In this case, putting it at the top could keep the rest of the script from even running, since once it is applied it doesn't need to be done again, and the return will stop it from checking. The return I suspect, is also what is keeping the timer from getting checked, since that part of the script isn't getting run because of the missing endif and elseif statements. Returns are useful, but somewhat tricky to use.

I'm going to teach you a bit about debugging. First, is your health enough to survive the curse? It needs to be to be sure that the timer ends. Either heal, or open the console and type "Player->ModHealth 10000" or whatever. Activate your object and let the curse run it's course. If it never ends, reload. If it does, reload anyway. This time activate your object but don't let the curse run it's course. While it is working, open the console and click on whatever the script is attached to. Type "sv", which stands for "show variables". Locate your script in the window. it will probably be at the bottom. Look at the number next to "timer". Press the up arrow to retype your last command, sv, and press enter again. Do this a few times and see if the variable exceeds 10. If so, it's not terminating correctly.

Putting it at the top is probably the best option in my opinion, but try it both ways to get an understanding of how it works.



The timer bit there is the issue. When you have something repeating like that, isolate it out.

short gaveSpellshort runTimerfloat timerif ( OnActivate == 1 ) ; This occurs for 1 frame, serving as an initial trigger    if ( gaveSpell != 1 )        Set gaveSpell To 1        MessageBox "You rip open the skin and a putrid smell arises. It gives you a funny feeling in the back of your throat."        "player"->AddSpell "01mc_poisonioustrollskinn"        Activate        Set runTimer To 1        Set timer To 0 ; Clear the timer    endifendifif ( runTimer == 1 )    Set timer to ( timer + GetSecondsPassed )    if ( timer > 10 )        Set runTimer to 0 ; Stop it from running further        "player"->RemoveSpell "01mc_poisonioustrollskinn"    endifendif


The timer handling code is very simple, you're just waiting for the time to be up, so that's all you check for. Having it within the OnActivate block means it only runs for one frame, and so will never hit the time condition.

Other than that bit, your script looks pretty good. :thumbsup: Tweak it and test in game.


Short is (-2^16, +2^16-1], I believe, with long being (-2^31, +2^31-1]. Longs are just used when you need to count up to 4 billion; they however match the memory model of Morrowind and use MWSE uses them to store C++ pointers (a total hack, which is why it breaks when you save/reload, but it works for a short time).


Correct. The "float" in floating point means the decimal place, which appears to float depending on the value and precision. There are some limits to them still, but much larger values are possible.

Unfortunately, the game can in some cases store shorts, longs and floats in floats on disk, which can hurt precision (floats have some rounding errors). If you're interested in the details, check:
http://en.wikipedia.org/wiki/Floating_point
http://en.wikipedia.org/wiki/Integer_(computer_science)

Morrowind uses 16-bit shorts and 32-bit longs and floats.



In the MWSFD tutorial, I'd place the timer elsewhere in it's own block. It is still isolated though in the tutorial even though it's in the same block, if I understand blocks correctly. It's just not as efficient.

Oh noes, numbers! *runs* I get how Morrowind uses them, I just can't see a practical use for long in the base game. I didn't know about the disk storage though. And floats will only have errors if the decimal place is high, right?

I will certainly read the links. The second one is missing a ")" at the end, by the way. I recall that you like numbers. I don't dislike them, but I know I need to know them better If I'm gonna program anything. Math was never my strong point.



Wikipedia keeps messing with links. It should take you somewhere similar, so... :brokencomputer:

The bit I posted with a simple check around the timer isn't inefficient, although you could tweak it to be just a hair faster:
if ( runTimer != 1 )    returnendifSet timer to ( timer + GetSecondsPassed )if ( timer > 10 )    Set runTimer to 0 ; Stop it from running further    "player"->RemoveSpell "01mc_poisonioustrollskinn"endif


The actual speed differences shouldn't matter, though.

Practical uses for longs... not sure. You could use them for simple comparisons or summing things up. But yes, the issues with floats don't hit until you're way up there, and you aren't likely to have problems in the game.

Wow. I don't even know where to begin. Well I'll start off with what Arsuru said. Thank you for teaching me how to debug and how to find the variables, i didn't know that could be done! And I know it should have ended up looking like the tutorials, but the way the author had wrote the variables in the example script threw me off. I believe i can figure it out now though, I just whizzed through peachykeen's version, seeing what ya'll meant, and i'm gunna try and write it myself off of what i know now. As usual Arsuru, your help is invaluable! And to peachykeen, thank you for writing the script and giving me a reference point, or just the script itself if needbe. I'm trying to learn to do this stuff myself so i don't have to both this forum as much, because i know i do alottttt of bothering haha. And to both of you; thank you for the lessons on variables, i believe i have a far better understanding of them now ;D

You people are awesome. Just sayin. :intergalactic:
User avatar
Jhenna lee Lizama
 
Posts: 3344
Joined: Wed Jun 06, 2007 5:39 am

Post » Sat Jan 23, 2010 1:47 pm

So I have made this from ya'll information and sayings:
begin 01mc_poisonoustrollskinshort doneshort getimerfloat timerif ( OnActivate == 1 )	if ( done == 1 )		return	else		Set done to 1		messageBox "You rip open the skin and a putrid smell arises. It gives you a funny feeling in the back of your throat."		player->addSpell "01mc_poisonioustrollskinn"		Activate		set getimer to 1	    	endifendifIf ( getimer == 1 )	Set timer to ( timer + GetSecondsPassed )		if timer > 10			Player->RemoveSpell, "01mc_poisonioustrollskinn"			set getimer to 0		endifendifEnd


Now, everything works perfectly, except that it doesn't last 10 seconds like it's supposed to. More like only 3 or 4 :/
Anyone know what I did wrong?
User avatar
Jeffrey Lawson
 
Posts: 3485
Joined: Tue Oct 16, 2007 5:36 pm

Post » Sat Jan 23, 2010 3:24 pm

Wow. I don't even know where to begin. Well I'll start off with what Arsuru said. Thank you for teaching me how to debug and how to find the variables, i didn't know that could be done! And I know it should have ended up looking like the tutorials, but the way the author had wrote the variables in the example script threw me off. I believe i can figure it out now though, I just whizzed through peachykeen's version, seeing what ya'll meant, and i'm gunna try and write it myself off of what i know now. As usual Arsuru, your help is invaluable! And to peachykeen, thank you for writing the script and giving me a reference point, or just the script itself if needbe. I'm trying to learn to do this stuff myself so i don't have to both this forum as much, because i know i do alottttt of bothering haha. And to both of you; thank you for the lessons on variables, i believe i have a far better understanding of them now ;D

You people are awesome. Just sayin. :intergalactic:

Haha, no need to quote us on all that. We gotta keep the knowledge going after all. This is like, esoteric stuff, or something. I'll show you a variation of peechykeen's script if you want once you figure it out, or if you can't. I noticed while editing your scripts that you used spaces to indent. Just use the tab key. Much faster, tidier and easier to count. Not sure, but it might use less bytes too as it is one character and scripts have a size limit I think, and each line has a character limit. MWEdit can do it for you, too. MWEdit is great for writing MW scripts. It's error reporting is more accurate too since it tells you exactly where the problem is.

You also left out a comma. MWSFD states that syntax rules are pretty lax, but cautions that you be consistent. So either always use them, or never do. Same with parentheses, and spaces and quotes in certain situations. Some will say to put quotes around "Player" for example, some won't. It's apparently only absolutely needed if the ID contains spaces or begins with an underscore. Read the section on syntax if you haven't, and read it again if you did. Also, it's generally considered best to keep functions named the way Bethesda did, like AddItem, instead of addItem or additem, though in practice they all work. Even ADDITEM should work. It's just for readability, so it's not terribly important.


Now, everything works perfectly, except that it doesn't last 10 seconds like it's supposed to. More like only 3 or 4 :/
Anyone know what I did wrong?

No idea, it looks like it should work fine. Edit this part like so:

Player->RemoveSpell, "01mc_poisonioustrollskinn"MessageBox, "%.0f", timerset getimer to 0

This will show you how long the timer goes. Or you could just type "sv" into the console over and over to see if it terminates.
User avatar
jaideep singh
 
Posts: 3357
Joined: Sun Jul 08, 2007 8:45 pm

Post » Sat Jan 23, 2010 8:01 pm

Haha, no need to quote us on all that. We gotta keep the knowledge going after all. This is like, esoteric stuff, or something. I'll show you a variation of peechykeen's script if you want once you figure it out, or if you can't. I noticed while editing your scripts that you used spaces to indent. Just use the tab key. Much faster, tidier and easier to count. Not sure, but it might use less bytes too as it is one character and scripts have a size limit I think, and each line has a character limit. MWEdit can do it for you, too. MWEdit is great for writing MW scripts. It's error reporting is more accurate too since it tells you exactly where the problem is.

You also left out a comma. MWSFD states that syntax rules are pretty lax, but cautions that you be consistent. So either always use them, or never do. Same with parentheses, and spaces and quotes in certain situations. Some will say to put quotes around "Player" for example, some won't. It's apparently only absolutely needed if the ID contains spaces or begins with an underscore. Read the section on syntax if you haven't, and read it again if you did. Also, it's generally considered best to keep functions named the way Bethesda did, like AddItem, instead of addItem or additem, though in practice they all work. Even ADDITEM should work. It's just for readability, so it's not terribly important.



No idea, it looks like it should work fine. Edit this part like so:

Player->RemoveSpell, "01mc_poisonioustrollskinn"MessageBox, "%.0f", timerset getimer to 0

This will show you how long the timer goes. Or you could just type "sv" into the console over and over to see if it terminates.


Hmm... thank you for pointing out my error, I tried to do my best :D But yes i know with the syntax it's supposed to be all or none to reduce errors, and all that, just finished reading it before i wrote the script, how ironic. And thank you for telling me about MWedit, writing in TESCS is a bit annoying because i'm scared it'll close on me. Thanks, as always!
User avatar
Pawel Platek
 
Posts: 3489
Joined: Sat May 26, 2007 2:08 pm

Post » Sat Jan 23, 2010 4:38 pm

Haha, no need to quote us on all that. We gotta keep the knowledge going after all. This is like, esoteric stuff, or something. I'll show you a variation of peechykeen's script if you want once you figure it out, or if you can't. I noticed while editing your scripts that you used spaces to indent. Just use the tab key. Much faster, tidier and easier to count. Not sure, but it might use less bytes too as it is one character and scripts have a size limit I think, and each line has a character limit. MWEdit can do it for you, too. MWEdit is great for writing MW scripts. It's error reporting is more accurate too since it tells you exactly where the problem is.

Knowledge, yep. There are tons of little things, some not even in SFD.
I personally learn code best by seeing examples, which is why most of my posts will probably have a quick rewrite of whatever script is being discussed. I can skip that bit or add more comments explaining why if you'd like, though.
Tabs are technically smaller than spaces, but I've gotten in teh habit of using 4 spaces in my C++, so it drags over here (takes effort not to end every line with a ';' :P). Matter of preference, not sure it changes anything syntactically, but does save 3/6/9 bytes per line.

You also left out a comma. MWSFD states that syntax rules are pretty lax, but cautions that you be consistent. So either always use them, or never do. Same with parentheses, and spaces and quotes in certain situations. Some will say to put quotes around "Player" for example, some won't. It's apparently only absolutely needed if the ID contains spaces or begins with an underscore. Read the section on syntax if you haven't, and read it again if you did. Also, it's generally considered best to keep functions named the way Bethesda did, like AddItem, instead of addItem or additem, though in practice they all work. Even ADDITEM should work. It's just for readability, so it's not terribly important.

While it is technically choice, there are a few rules that can help prevent crashes/bugs. Using the MWEdit compiler helps already, but other stuff does as well:
  • ALWAYS QUOTE YOUR IDs - They can be one letter or every control character in the ASCII set, put quotes around it! This helps the compiler tell where the ID starts and ends, without any chance of confusion, is good habit, can clarify code and prevent bugs. While Arsuru is correct in that it's only required for certain IDs, I consider it required for all.
    [list]
  • Edit: Oh, and this goes for "player" and "PlayerSaveGame" as well.
  • IDs start with a letter - Can prevent some bugs, especially if you start with initials. "pk_mod1_item" isn't gonna be used as often and is far more descriptive than "01_thing those". Traditional variable naming (which also applies to script variables) says start with a letter. Numbers and underscores are fine, but as the second+ character.
  • Don't reCASE - IDs are technically not case sensitive, but it's still best to use exactly what you see. Less chance for errors when x === y.
  • CamelCaseCommands - Clearer code, not sure if it helps bugs. AddItem is typically easier to read than aDDITem or additem, and becomes more helpful with PositionCell and such.
  • No comma after commands, only params - Matter of personal preference, really. I don't always use commas, but when I do, they don't follow the command.
    AddItem "gold_001", 10 ; Like so

  • Space - Some things need spaces, some don't. For readability and ease of parsing, add spaces between things, and always after commas. Exact spacing around parentheses has been a topic of debate for some years (civilized humans place spaces within their parentheses in vim), but keep it consistent and put them where it makes the line more readable. That's the whole point of whitespace.
  • Simple - The parser and language choke if you do too many things in a single line, especially if those things generate temporary variables. Doing 10 or 15 math operations will probably break, doing 3 with a command in there will for sure, as will some commands inside if statements. This necessitates temporary variables and splitting complex things up (which can actually decrease bugs, so its win/win for the most part).
  • As Arsuru said, consistency. Makes for more readable code and, if you follow good syntax, will keep bugs out.


A lot of it is preference or habit picked up over countless aeons of beating MWScript into something resembling submission, some are just things that might keep the bugs away for a bit longer. You can probably ignore everything I listed, but it will eventually cause a problem (possibly years down the road). ;)
User avatar
XPidgex Jefferson
 
Posts: 3398
Joined: Fri Sep 08, 2006 4:39 pm

Post » Sat Jan 23, 2010 7:21 pm

I hope we aren't confusing you. Even if you don't get into much scripting, it's still useful to know simple things. Once you know the simple things though, the rest just seems to come. If you can stand it that is. ;)

Edit: I'm just going to post my version since I noticed something broken in the script. It needs a MenuMode check. This was covered in the tutorial for this exact reason. You did complete the tutorial, right? :stare:

It's quite short, but the comments are long. You also have two n's in the script/curse name. Just pointing it out if it's not intentional.

Spoiler
begin 01mc_poisonoustrollskinshort doOnceshort donefloat timerif ( MenuMode == 1 )	returnelseif ( done == 1 )	returnendif;You often want a MenuMode check. It keeps the script from running while the menus are up. Without it, in this case if the;player were in their inventory long enough for the curse to expire, it wouldn't harm them at all. Try typing "sv" into the console;with the scripted object selected, with and without the MenuMode part, and notice how the timer behaves. I have changed done;to doOnce to better describe it's function, and made done a variable to effectively terminate the script. Since it is a local script,;it will run anytime the cell it is in is loaded in memory. Putting done here stops the rest of the script from processing, maximizing;performance.if ( doOnce == 1 )	set timer to ( timer + GetSecondsPassed )	if ( timer >= 10 )		"Player"->RemoveSpell, "01mc_poisonioustrollskinn"		set timer to 0		set done to 1	else		return	endifendif;The return here keeps the rest of the script from executing until the timer reaches 10 since it's no longer needed once the;event has passed. It's not of much help in a script this short, and could probably be removed, but it is an example. If doOnce;doesn't equal 1, it will go to the next block. The first condition ( doOnce ) must be true before it can check for the second;( timer >= 10 ). So the second block won't execute before the bottom one. It is often backwards like this.if ( OnActivate == 1 )	 if ( doOnce == 0 )		MessageBox "You rip open the skin and a putrid smell arises. It gives you a funny feeling in the back of your throat."		"Player"->AddSpell, "01mc_poisonioustrollskinn"		Set doOnce to 1		Activate	endifendif;We don't need this last block to run again since this is a one-time event, so it will only execute if doOnce == 0.;This way, on further activations it won't add the curse again. I reordered the actions a bit here. I prefer to set;variables near the end, but I don't think it matters in most cases.End

There are even more ways to do this, but this is the most efficient way I know.

snip

I learn best by a mix, I guess, so I try a bit of both. I don't generally don't like just being handed a script, at least without being able to understand it ( That might change if I get into proper languages though. ), so I try not to do that. However, no matter how much I look at MWSE, it still confuses me. =/

I've been not quoting "player", mostly because most example I see are like that. I guess I'll update my scripts. At least I don't have a whole lot. I use commas after functions for the same reason. It works in any case. I use spaces in parentheses, and am experimenting adopting it to my writing style. It's the norm in France it seems, and I like the look. Most of the time. It's recommended to never use spaces around a fix ( -> ) though, and I've never seen it done that way either.
User avatar
Stephanie I
 
Posts: 3357
Joined: Thu Apr 05, 2007 3:28 pm

Post » Sat Jan 23, 2010 5:11 pm

  • ALWAYS QUOTE YOUR IDs - They can be one letter or every control character in the ASCII set, put quotes around it! This helps the compiler tell where the ID starts and ends, without any chance of confusion, is good habit, can clarify code and prevent bugs. While Arsuru is correct in that it's only required for certain IDs, I consider it required for all.
    [list]
  • Edit: Oh, and this goes for "player" and "PlayerSaveGame" as well.



exception:
do not quote player references when using MWSE. this causes bizarre errors, as i found out to my debugging sorrow.
User avatar
Klaire
 
Posts: 3405
Joined: Wed Sep 27, 2006 7:56 am

Post » Sun Jan 24, 2010 12:14 am

exception:
do not quote player references when using MWSE. this causes bizarre errors, as i found out to my debugging sorrow.

Maybe that issue could be addressed in MWSE, or MGE XE, since Hrnchamd messed with the internal MWSE already. It probably wouldn't hurt to mention it.
User avatar
Queen Bitch
 
Posts: 3312
Joined: Fri Dec 15, 2006 2:43 pm

Post » Sat Jan 23, 2010 12:54 pm

I might be a bit off. I don't fully understand why an integer will almost never be true for distance considering how many times the scripts run in a second, but it would seem that it is possible that the integers will fail.

There are a lot of possible values a floating point number can hold between 255 and 256. The chance that the result from getDistance is a integer is very very small.

Also, there are some integers that cannot be represented by a float. There are also some decimal numbers that you would expect to be representable (like 0.1) that aren't representable.
User avatar
Elena Alina
 
Posts: 3415
Joined: Sun Apr 01, 2007 7:24 am

Post » Sat Jan 23, 2010 1:55 pm

Knowledge, yep. There are tons of little things, some not even in SFD.
I personally learn code best by seeing examples, which is why most of my posts will probably have a quick rewrite of whatever script is being discussed. I can skip that bit or add more comments explaining why if you'd like, though.
Tabs are technically smaller than spaces, but I've gotten in teh habit of using 4 spaces in my C++, so it drags over here (takes effort not to end every line with a ';' :P). Matter of preference, not sure it changes anything syntactically, but does save 3/6/9 bytes per line.


While it is technically choice, there are a few rules that can help prevent crashes/bugs. Using the MWEdit compiler helps already, but other stuff does as well:
  • ALWAYS QUOTE YOUR IDs - They can be one letter or every control character in the ASCII set, put quotes around it! This helps the compiler tell where the ID starts and ends, without any chance of confusion, is good habit, can clarify code and prevent bugs. While Arsuru is correct in that it's only required for certain IDs, I consider it required for all.
    [list]
  • Edit: Oh, and this goes for "player" and "PlayerSaveGame" as well.
  • IDs start with a letter - Can prevent some bugs, especially if you start with initials. "pk_mod1_item" isn't gonna be used as often and is far more descriptive than "01_thing those". Traditional variable naming (which also applies to script variables) says start with a letter. Numbers and underscores are fine, but as the second+ character.
  • Don't reCASE - IDs are technically not case sensitive, but it's still best to use exactly what you see. Less chance for errors when x === y.
  • CamelCaseCommands - Clearer code, not sure if it helps bugs. AddItem is typically easier to read than aDDITem or additem, and becomes more helpful with PositionCell and such.
  • No comma after commands, only params - Matter of personal preference, really. I don't always use commas, but when I do, they don't follow the command.
    AddItem "gold_001", 10 ; Like so

  • Space - Some things need spaces, some don't. For readability and ease of parsing, add spaces between things, and always after commas. Exact spacing around parentheses has been a topic of debate for some years (civilized humans place spaces within their parentheses in vim), but keep it consistent and put them where it makes the line more readable. That's the whole point of whitespace.
  • Simple - The parser and language choke if you do too many things in a single line, especially if those things generate temporary variables. Doing 10 or 15 math operations will probably break, doing 3 with a command in there will for sure, as will some commands inside if statements. This necessitates temporary variables and splitting complex things up (which can actually decrease bugs, so its win/win for the most part).
  • As Arsuru said, consistency. Makes for more readable code and, if you follow good syntax, will keep bugs out.


A lot of it is preference or habit picked up over countless aeons of beating MWScript into something resembling submission, some are just things that might keep the bugs away for a bit longer. You can probably ignore everything I listed, but it will eventually cause a problem (possibly years down the road). ;)



I hope we aren't confusing you. Even if you don't get into much scripting, it's still useful to know simple things. Once you know the simple things though, the rest just seems to come. If you can stand it that is. ;)

Edit: I'm just going to post my version since I noticed something broken in the script. It needs a MenuMode check. This was covered in the tutorial for this exact reason. You did complete the tutorial, right? :stare:

It's quite short, but the comments are long. You also have two n's in the script/curse name. Just pointing it out if it's not intentional.

Spoiler
begin 01mc_poisonoustrollskinshort doOnceshort donefloat timerif ( MenuMode == 1 )	returnelseif ( done == 1 )	returnendif;You often want a MenuMode check. It keeps the script from running while the menus are up. Without it, in this case if the;player were in their inventory long enough for the curse to expire, it wouldn't harm them at all. Try typing "sv" into the console;with the scripted object selected, with and without the MenuMode part, and notice how the timer behaves. I have changed done;to doOnce to better describe it's function, and made done a variable to effectively terminate the script. Since it is a local script,;it will run anytime the cell it is in is loaded in memory. Putting done here stops the rest of the script from processing, maximizing;performance.if ( doOnce == 1 )	set timer to ( timer + GetSecondsPassed )	if ( timer >= 10 )		"Player"->RemoveSpell, "01mc_poisonioustrollskinn"		set timer to 0		set done to 1	else		return	endifendif;The return here keeps the rest of the script from executing until the timer reaches 10 since it's no longer needed once the;event has passed. It's not of much help in a script this short, and could probably be removed, but it is an example. If doOnce;doesn't equal 1, it will go to the next block. The first condition ( doOnce ) must be true before it can check for the second;( timer >= 10 ). So the second block won't execute before the bottom one. It is often backwards like this.if ( OnActivate == 1 )	 if ( doOnce == 0 )		MessageBox "You rip open the skin and a putrid smell arises. It gives you a funny feeling in the back of your throat."		"Player"->AddSpell, "01mc_poisonioustrollskinn"		Set doOnce to 1		Activate	endifendif;We don't need this last block to run again since this is a one-time event, so it will only execute if done == 0.;This way, on further activations it won't add the curse again. I reordered the actions a bit here. I prefer to set;variables near the end, but I don't think it matters in most cases.End

There are even more ways to do this, but this is the most efficient way I know.


I learn best by a mix, I guess, so I try a bit of both. I don't generally don't like just being handed a script, at least without being able to understand it ( That might change if I get into proper languages though. ), so I try not to do that. However, no matter how much I look at MWSE, it still confuses me. =/

I've been not quoting "player", mostly because most example I see are like that. I guess I'll update my scripts. At least I don't have a whole lot. I use commas after functions for the same reason. It works in any case. I use spaces in parentheses, and am experimenting adopting it to my writing style. It's the norm in France it seems, and I like the look. Most of the time. It's recommended to never use spaces around a fix ( -> ) though, and I've never seen it done that way either.

Peachykeen- Thank you for all the tips! I'll be sure to put them to good use. And like you said about learning by seeing examples, I'm kinda the same way. I'll learn it eventually though.

Arsuru- Yes of course i finished the tutorial, that's where i got it from. I thought if you put it in there then it would stop while the player was in the menu? And also, thank you for putting all of the comment and fixing the script, it really helped me understand it. Especially the thing about everything looking backwards, it seems to be just common sense now. =p
Again, thank both of you!
User avatar
Nuno Castro
 
Posts: 3414
Joined: Sat Oct 13, 2007 1:40 am

Post » Sat Jan 23, 2010 4:19 pm

There are a lot of possible values a floating point number can hold between 255 and 256. The chance that the result from getDistance is a integer is very very small.

Also, there are some integers that cannot be represented by a float. There are also some decimal numbers that you would expect to be representable (like 0.1) that aren't representable.

Yeah, I can see that. That last part is interesting.

Peachykeen- Thank you for all the tips! I'll be sure to put them to good use. And like you said about learning by seeing examples, I'm kinda the same way. I'll learn it eventually though.

Arsuru- Yes of course i finished the tutorial, that's where i got it from. I thought if you put it in there then it would stop while the player was in the menu? And also, thank you for putting all of the comment and fixing the script, it really helped me understand it. Especially the thing about everything looking backwards, it seems to be just common sense now. =p
Again, thank both of you!

Yes, it does stop it. It's more like a pause; it resumes as soon as you exit the menus. Sometimes not having it will break a script too, so it really depends, but since both the tutorial and your script use the same device, it is needed. Looks like there is an error in my last comment block. Done should be doOnce. Gonna fix that.

Anyway, glad to be of help.
User avatar
Erich Lendermon
 
Posts: 3322
Joined: Sat Nov 03, 2007 4:20 pm

Next

Return to III - Morrowind