When do we use 'for' statement scripting?
'for' statement and flow control
#1
Posté 24 décembre 2014 - 07:55
#2
Posté 24 décembre 2014 - 08:12
to keep the statement going until it becomes false. Stuff like sustained effects I guess
- WhiteTiger aime ceci
#3
Posté 24 décembre 2014 - 08:23
When you need to repeat one or more statements usually for a set number of times is the short answer. The longer answer is whenever you need to. Whole chapters could be written to answer this.
TR
- WhiteTiger et Verilazic aiment ceci
#4
Posté 24 décembre 2014 - 08:37
Like 'while'?
#5
Posté 24 décembre 2014 - 09:12
For loops are generally used when you have a known (or fixed) number of iterations to do. For example if you know you can effect casterlevel creatures with an effect you could use a for loop from 1 to casterlevel. While is generally used when you don't know the number of iterations (there are lots of examples in the lexicon of using while to say look at each item in inventory etc) or when there are multiple conditions. These are not fast rules of course. You can pretty much make a while loop do anything a for loop can do and vice versa. I believe there is a tutorial on loops in the lexicon.
- Squatting Monk et WhiteTiger aiment ceci
#6
Posté 24 décembre 2014 - 11:01
As the scripting language for NwN is based on the C family (C, C++, C#, etc.) of programming languages, it is worth pointing out that in this family the for loop is regarded as just a specialised form of the while loop.
TR
- WhiteTiger aime ceci
#7
Posté 24 décembre 2014 - 11:47
It's a matter of preference. Personally, I tend to use "while" rather than "for", as it's clear, simple and easy to remember (especially if you use many different languages), but that's just me.
- WhiteTiger aime ceci
#8
Posté 25 décembre 2014 - 01:49
Heh, I thought I hedged enough with "generally" and "not fast rules" that what I was saying was more helpful than controversial, apparently I was wrong ![]()
Fwiw, "for" is more than just shorthand for a "while" loop with a counter. Consider the use of the continue statement. Also "for" loops (in other languages than NWNscript) do not require counters.
Edit: Not trying to turn this into argument though. Happy Holidays fellow NWNers!
- WhiteTiger aime ceci
#9
Posté 25 décembre 2014 - 08:54
(For) is good for running the same action over a set number of times. For example in my skinning system. I have a skill check for each meat you can get off a creature. The number meats being based off the size of the creature and with ( for loop) I can run it really easy.
- WhiteTiger aime ceci
#10
Posté 25 décembre 2014 - 11:18
Examples guys? I would but I've got to wrestle a dead ostrich (well that's what it looks like not the turkey it actually is) into an oven (that looks) too small for it.
TR
- WhiteTiger aime ceci
#11
Posté 25 décembre 2014 - 07:45
// Check to see if the player has at least five goblin ears
int StartingConditional()
{
int nCount;
object oPC = GetPCSpeaker();
object oItem = GetFirstItemInInventory(oPC);
while (GetIsObjectValid(oItem))
{
if (GetTag(oItem) == "goblin_ear")
nCount++;
oItem = GetNextItemInInventory(oPC);
}
return nCount >= 5;
}
// Create five goblin ears in the player's inventory
void main()
{
int i;
object oPC = GetPCSpeaker();
for (i = 0; i < 5; i++)
{
CreateItemOnObject("goblin_ear", oPC);
}
}
- meaglyn et WhiteTiger aiment ceci
#12
Posté 26 décembre 2014 - 09:48
That's a good stuff, thanks folks
#13
Posté 30 décembre 2014 - 03:24
I think it might be achieveable with nwnx - but it would be very hacky.
Eg:
Create a list in memory
add object references to it
and each time you call a method like NWNX_GetNext("ContainerName") - it increments the index of the current selection - until it reaches the end of the list.
for(NWNX_GetNext("ContainerName") != FALSE){
object o = NWNX_GetCurrentObject("ContainerName");
//Do something
}
Of course - this could in theory be done in nwscript too- with use of Set/GetLocalObjectJust do a wrapper method around them, and make it return TRUE if the next item in the list is valid, FALSE if not - and then on a TRUE condition, set another LocalVar to be the actual object reference.
Its alot of work to get a simple - ForEach statement working.
It might be easier to use
for(i=0;i<=MAX_SIZE;i++)
{
}
The obvious benefits of a foreach is that it doesnt require you to know the amount of items in the listWith the SetLocal/GetLocal approach - you are going to sorta need to know that information :
If you are just checking to see if an object is not OBJECT_INVALID - then you will run into issues when object 5 out of 15 (a creature), dies and gets cleaned up by his body disappearing.
Object 5 becomes OBJECT_INVALID, and it would break the loop - preventing progression to objects 6-15 etc
- WhiteTiger aime ceci
#14
Posté 30 décembre 2014 - 12:26
To some extent you can have behaviour that is similar to the For Each command that you desire. The restrictions are that the things that you wish to step through must all be objects and they must all have the same, identical tag. Here is a simple example taken from my Deadly Candles submission to October's (Ravenloft) custom content challenge.
// ExtinguishAllCandles steps through all candles, extiguishing those that are
// lit and telling them they are unlit. Also empties the string "sAllLitCandles"
void ExtinguishAllCandles()
{
int iCandleNum = 0;
object oWayPoint = GetNearestObjectByTag("WP_HereBeMonsters");
object oCandle = GetObjectByTag("TrapCandle", iCandleNum);
while(GetIsObjectValid(oCandle))
{
if(GetLocalInt(oCandle, "bAmAlight"))
{
AssignCommand(oCandle, PlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE));
SetLocalInt(oCandle, "bAmAlight", FALSE);
}
oCandle = GetObjectByTag("TrapCandle", ++iCandleNum);
}
SetLocalString(oWayPoint, "sAllLitCandles", "");
}
This works because GetObjectByTag has 2 parameters and not just the 1 normally used.
TR
- WhiteTiger aime ceci
#15
Posté 30 décembre 2014 - 11:06
Heh, I thought I hedged enough with "generally" and "not fast rules" that what I was saying was more helpful than controversial, apparently I was wrong
Fwiw, "for" is more than just shorthand for a "while" loop with a counter. Consider the use of the continue statement. Also "for" loops (in other languages than NWNscript) do not require counters.
Edit: Not trying to turn this into argument though. Happy Holidays fellow NWNers!
First let me state that I am not wanting to turn this into an argument either.
It sounds like you are trying to say that the FOR control structure is not just a glorified while loop. That due to the assumption that it does not have a 'continue' statement as part of the control structure it is entirely different. Where both the 'continue' and the 'break' statements will work in either loop.
Try this sample code in the OnUse of a placeable.
const int DO_FOREVER =1;
void main()
{
int x;
while (DO_FOREVER)
{
x++;
if (x&1) continue;
SpeakString( IntToString(x));
if (x>20) break;
}
}
To me the matter of 'For' vs. 'while' is a matter of convention. Both compile to pretty much the same thing, With the 'while' loop giving more control over where in the loop the continuation data gets modified. Even with the the choice between the two has more to do with which one is easier for the writer of the script to use or any intended audience to read. It is kind of like having a long debate on using 'i' or 'n' in front of your integers.
Just to sum this up. The 'for' loop is nothing more then a while loop with a 'preloop statment' and a 'endloop statement' added to the control structure. You can in fact write any 'for' loop as a while loop. Both loops below will compile to the same thing.
for ('preloop statment'; 'conditional statement';'endloop statement')
{
SpeakString.....bla bla bla.
}
'preloop statment';
while ('conditional statement')
{
SpeakString.....bla bla bla.
'endloop statement';
}
- Squatting Monk et WhiteTiger aiment ceci
#16
Posté 31 décembre 2014 - 02:02
It sounds like you are trying to say that the FOR control structure is not just a glorified while loop. That due to the assumption that it does not have a 'continue' statement as part of the control structure it is entirely different. Where both the 'continue' and the 'break' statements will work in either loop.
I was not saying that the continue statement did not work in while loops. But because of the way for loops have the loop end statement already built in you get your state changed automatically without having to make sure you increment x (or whatever) before any continue statements. Notice in your example how you put the x++ right at the top of your while loop body so you could use continue safely. Most while loops in NWN don't do that (oItem = GetNextItemInInventory anyone?). So to use the continue statement you need to do extra work which is done for you in a for loop. A for loop is not just a while loop with a counter... (of course you can't do inventory walk loops in NWNScript in a for loop as such to take advantage of that but that's a different discussion).
And yes I said you can do anything with a for loop you can do with a while loop and vice-versa.
Just to sum this up. The 'for' loop is nothing more then a while loop with a 'preloop statment' and a 'endloop statement' added to the control structure. You can in fact write any 'for' loop as a while loop. Both loops below will compile to the same thing.
Right, and now drop a continue statement in each loop. The for loop terminates properly and the while loop does not, because the endloop statement is executed automatically in the for loop. When the things you are doing inside the loop get more interesting than these toy examples that can matter. Cleaner easier code with fewer bugs is a Good Thing.
for ('preloop statment'; 'conditional statement';'endloop statement')
{
continue;
SpeakString.....bla bla bla.
}
'preloop statment';
while ('conditional statement')
{
continue;
SpeakString.....bla bla bla.
'endloop statement';
}
My point was that the automatic execution of the "endloop statement" can be useful and is more than just a different way of writing the loop. Now if NWNScript allowed non-integer expressions in preloop and endloop statements this would be even more useful. E.g. for(object oItem = GetFirstItemInINventory(oPC); GetIsObjectValid(oItem); oItem = GetNextObjectInIntory(oPC)) would be really handy (or the foreach mentioned earlier in the thread).
- Squatting Monk et WhiteTiger aiment ceci
#17
Guest_TrillClinton_*
Posté 31 décembre 2014 - 02:30
Guest_TrillClinton_*
I generally tend to keep a rule by Robert C Martin, who emphasizes on code.
He states that for every for statement, I should only have one statement in it. Example,
for(int index=0;index<size;index++)
{
doSomething();
}
doSomething(); gives me the ability to reduce the dependency on that for statement and increases my change for re-usability. Also, never use magic numbers. Here is an example,
for(int index=0;index<9;index++)
{
doSomething();
}
the above for statement reduces the chance of variable re-usability,easier to change and can be used throughout the system without having to repopulate them throughout your system in terms of a problem.
Typically for statements are used for iteration of ranges. For a procedure that requires iteration based on condition, I would use a while loop.
while(Inventory.isEmpty())
{
removeInventoryItem();
}
Again, not a scripter. I just love to program
- WhiteTiger aime ceci
#18
Posté 31 décembre 2014 - 04:31
It is kind of like having a long debate on using 'i' or 'n' in front of your integers
Oh no, do not mention the integer wars so many deaths so much pain!
![]()
- Lightfoot8 et Squatting Monk aiment ceci
#19
Posté 31 décembre 2014 - 07:27
In a hobby environment, where there are no agreed standards, the most important aspect is the outcome, i.e. if it works, it's good.
Good style makes our code more maintainable, and more legible to other community members, but there's no absolute measure of right and wrong, only opinion.
Following Bioware convention helps (because we're familiar with it). Structured code is easier to read. The rest is a matter of preference.
- Squatting Monk, GhostOfGod et WhiteTiger aiment ceci
#20
Posté 31 décembre 2014 - 03:22
@proleric, agreed (except for some of the Bioware convention - which I find painful to read), I was just trying to clear up Lightfoot's misunderstanding of the point I was trying to make, not to argue that people should use for loops more...
Personally I like a tab-width indentation (8 characters) and so the use of continue in those loops can help keep the code from being indented all the way across the screen, thus making it more readable.
#21
Posté 31 décembre 2014 - 10:53
I kinda wish nwnscript had a real implimentation of a foreach statement.
I think it might be achieveable with nwnx - but it would be very hacky.
[snip]
The obvious benefits of a foreach is that it doesnt require you to know the amount of items in the list
With the SetLocal/GetLocal approach - you are going to sorta need to know that information :
If you are just checking to see if an object is not OBJECT_INVALID - then you will run into issues when object 5 out of 15 (a creature), dies and gets cleaned up by his body disappearing.
Object 5 becomes OBJECT_INVALID, and it would break the loop - preventing progression to objects 6-15 etc
My solution to this was to make wrapper functions to deal with lists that handle keeping count of the number of items in the list. An example loop might look like this:
object oObject;
int i, nCount = GetObjectListCount(OBJECT_SELF, "SomeList");
for (i = 0; i < nCount; i++)
{
oObject = GetObjectListItemByIndex(OBJECT_SELF, i, "SomeList");
// Do stuff to oObject
}
What would really be magical is to be able to pass functions as parameters. Then you could make a foreach function and have it use the function on each item in the list. As is, you could do something similar to this by making your foreach function call ExecuteScript() or SignalEvent() on the object. That could be unnecessarily heavy depending on what you're looking to do, though.





Retour en haut







