Author Topic: non-integer expressions in for-loops ?  (Read 436 times)

Legacy_MrZork

  • Hero Member
  • *****
  • Posts: 1643
  • Karma: +0/-0
non-integer expressions in for-loops ?
« on: June 05, 2011, 04:02:19 pm »


               Is there a problem in using non-integer expressions in a for-loop? I was writing some test code and ran across some trouble getting the following to work

// check afteer fPeriod seconds and every fPeriod after 
// until no more than fTotTime secs have passed.
void ScheduleEquipReporting(object oCreature, int InventorySlot, float fPeriod, float fTotTime)
    {
    float fTime;
    for (fTime=fPeriod; fTime<=fTotTime; fTime=fTime+fPeriod)
        DelayCommand(fTime,ReportEquip(oCreature,InventorySlot));
    }

It causes the Toolset to generate a "NON INTGNON INTEGER EXPRESSION WHERE INTEGER REQUIRED" error on the line with the for statement. I also tried that line as
for (fTime=fPeriod; IntToFloat(fTime<=fTotTime); fTime=fTime+fPeriod)
and got the same error.

But the following works fine

// check afteer fPeriod seconds and every fPeriod after 
// until no more than fTotTime secs have passed.
void ScheduleEquipReporting(object oCreature, int InventorySlot, float fPeriod, float fTotTime)
    {
    int i;
    for (i=1; i<=FloatToInt(fTotTime/fPeriod); i++)
        DelayCommand(i*fPeriod,ReportEquip(oCreature,InventorySlot));
    }

There doesn't really seem to be any functional difference except that the second version (which is slightly less readable, for my purposes) is more integer-centric. I didn't see any special notes in the Lexicon indicating restrictions on the data types used in for-loop expressions. What am I missing here?
               
               

               


                     Modifié par MrZork, 05 juin 2011 - 03:05 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #1 on: June 05, 2011, 05:11:18 pm »


               Short answer, yes. If you want do to this you'll need the PRC compiler, which allows more freedom in for loops, for example:


    for (oPC = GetFirstPC(); GetIsObjectValid(oPC); oPC = GetNextPC()) {

You can find it here. It is superior to the toolset compiler in just about every way:

Linkage

Very handy for mass compiling limited script sets at a single go. I wrote up a tutorial on using it here:

Tutorial

Funky
               
               

               


                     Modifié par FunkySwerve, 05 juin 2011 - 04:11 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #2 on: June 05, 2011, 05:21:05 pm »


               Yes there is a Problem. The code that checks the for loop condition only use the EFLAGS Register on the CPU. when you start useing Floats it is the register on the FPU that are being set for the comapirsions. NWscript has not been expanded in order to handel the situation.
               
               

               


                     Modifié par Lightfoot8, 05 juin 2011 - 04:21 .
                     
                  


            

Legacy_MrZork

  • Hero Member
  • *****
  • Posts: 1643
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #3 on: June 05, 2011, 07:10:22 pm »


               FunkySwerve, thanks for the batch file setup link. I use nwnnsscomp regularly, though I didn't know that it compiled code differently than the Toolset compiler. (I mostly use it because I edit in Notepad++ and want to be able to do other stuff with the toolset while coding.) Is there any further documentation for nwnnsscomp, or a thread discussing differences between it and the toolset compiler.

Lightfoot8, thanks for the explanation. That fits perfectly with what I am seeing.

Do I take these two replies together to imply that nwnnsscomp will compile for loops with floating point conditional expressions? I understand that I would still be inviting possible problems if the need arises for me to compile using the toolset's compiler. (I am not currently in the position to do so, but would be a little hesitant to post mods or other add-ons that wouldn't compile for people in the toolset...)
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #4 on: June 05, 2011, 07:46:20 pm »


               

MrZork wrote...
Do I take these two replies together to imply that nwnnsscomp will compile for loops with floating point conditional expressions?


I have never used it, My guess it that it will. 

MrZork wrote...

 (I mostly use it because I edit in Notepad++ and want to be able to do other stuff with the toolset while coding.)


One note here.  If you wanted to make sure that all of your scripts can be compiled by the NW script compiler.  You could just use the command line compiler that came with the game instead of useing a third party compiler. 

it is in your 'utils' directory of your nwn install.  when it is ran without any comand line options it gives the following simple instructions. 

From clcpmpile.exe.....

clcompile:  BioWare's Command-Line Compiler
Copyright © 2003, BioWare Corp.
 
Usage:  clcompile infile [outfile]
 
infile will default to the current directory if no path is given.
outfile will default to the current directory if this is missing.
 
clcompile ..\\my_dir\\*
will compile all the .nss files in the ..\\my_dir directory.
 
clcompile myfile_*.nss
will compile myfile_1.nss if it resides in the current
directory, but not x0_i0_generic.nss (it doesn't match the
file pattern, nor will it compile myfile_2.nss if it is
outside of the current directory.


               
               

               


                     Modifié par Lightfoot8, 05 juin 2011 - 06:49 .
                     
                  


            

Legacy_MrZork

  • Hero Member
  • *****
  • Posts: 1643
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #5 on: June 05, 2011, 07:51:21 pm »


               Good to know. Thanks again. '<img'>
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #6 on: June 05, 2011, 08:13:23 pm »


               

MrZork wrote...


Do I take these two replies together to imply that nwnnsscomp will compile for loops with floating point conditional expressions? I understand that I would still be inviting possible problems if the need arises for me to compile using the toolset's compiler. (I am not currently in the position to do so, but would be a little hesitant to post mods or other add-ons that wouldn't compile for people in the toolset...)


Yes. We've used effects, objects, ints, and even a partial float in for loops with success. To test the full float (in each section) for, I test compiled this:


void main() {
    float i;
    for (i = 1.1; (i * 60.0) < 986.3; i+=1.1) {
        SpeakString("Blah");
    }
}
It compiles, though it would still not let me use ++ with a float, only +=.

Funky
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #7 on: June 05, 2011, 08:24:43 pm »


               

Lightfoot8 wrote...

One note here.  If you wanted to make sure that all of your scripts can be compiled by the NW script compiler.  You could just use the command line compiler that came with the game instead of useing a third party compiler. 


It's not exactly a third party compiler, just a version of the NWN compiler improved on by Torlack, who moved on to work for Bioware (though in fairness, he himself refers to his utilities as 'third party'). Not sure how much the PRC altered it after that, if at all.

Good info on the command line compiler, thank you. Now to try wiring my toolset to use the prc compiler... '<img'>

Funky
               
               

               


                     Modifié par FunkySwerve, 05 juin 2011 - 07:25 .
                     
                  


            

Legacy_Axe_Murderer

  • Full Member
  • ***
  • Posts: 199
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #8 on: June 06, 2011, 06:16:44 am »


               While loops are less picky. You could also switch your floating point version to a while loop.
               
               

               
            

Legacy_CID-78

  • Sr. Member
  • ****
  • Posts: 261
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #9 on: June 06, 2011, 09:11:27 am »


               I would also have gone for a while loop here, but honestly i wouldn't even setup multiple delays like that at all. I would simply used a External Toogle and having the ReportEquiptment (or a wrapper function) calling itself after a delay. that way i can use the toogle to terminate it at anytime, instead of buffering up a number of calls once in a while, and have no way of terminating it prematurly
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #10 on: June 06, 2011, 04:14:19 pm »


               We like for loops for the added utility of continue; - it allows for much neater flow control with fewer brackets. Also possible with while, but not as handy. Comes down to personal taste I suppose.'<img'>

As for the actual content of this loop, it'd be better done recursively, so that there's only one delay running at a time, as CID is suggesting.

By way of example:



void ForceJump (object oTarget, location lTarget, int bClearCombat=TRUE, int bForceCommandable=FALSE) {
    if (!GetIsObjectValid(oTarget) || GetObjectType(oTarget) != OBJECT_TYPE_CREATURE)
        return;

    if (!GetIsObjectValid(GetArea(oTarget))) {
        DelayCommand(5.0, ForceJump(oTarget, lTarget, bClearCombat, bForceCommandable));
        return;
    }

    if (GetIsDead(oTarget)) {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), oTarget);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(GetMaxHitPoints(oTarget)), oTarget);

        effect eBad = GetFirstEffect(oTarget);
        while (GetIsEffectValid(eBad)) {
            if (GetEffectIsNegative(eBad))
                RemoveEffect(oTarget, eBad);

            eBad = GetNextEffect(oTarget);
        }

        if (GetIsPC(oTarget))
            AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));

        DelayCommand(0.1, ForceJump(oTarget, lTarget, bClearCombat, bForceCommandable));
    } else if (!GetCommandable(oTarget)) {
        if (bForceCommandable) {
            AssignCommand(oTarget, SetCommandable(TRUE));

            if (bForceCommandable >= 5)
                WriteTimestampedLogEntry("FORCEJUMP : " + GetPCPlayerName(oTarget) + " : " +
                    GetName(oTarget) + " : more than 5 attempts to force commandable jumping to " +
                    GetResRef(GetAreaFromLocation(lTarget)));
        }

        DelayCommand(1.0, ForceJump(oTarget, lTarget, bClearCombat, ++bForceCommandable));
    } else {
        AssignCommand(oTarget, ClearAllActions(bClearCombat));

        AssignCommand(oTarget, ActionJumpToLocation(lTarget));
        AssignCommand(oTarget, ActionDoCommand(SetCommandable(TRUE)));
        AssignCommand(oTarget, SetCommandable(FALSE));
    }
}

Or, if you have a set number or period in mind, you can configure that as well, and just have a counter tick down to zero, terminating the loop when < 0.

Funky
               
               

               


                     Modifié par FunkySwerve, 06 juin 2011 - 03:29 .
                     
                  


            

Legacy_CID-78

  • Sr. Member
  • ****
  • Posts: 261
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #11 on: June 06, 2011, 06:11:28 pm »


               continue work just fine in "while" and "do while" loops, I can't recall that it's diffrent in NWN than regular C or C++ in this department.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #12 on: June 06, 2011, 06:32:55 pm »


               It isn't. It's just not as convenient to control iterations with as it is with for loops. As I said, largely a matter of taste. Probably 80-90% of the loops we use continue with are for loops. By contrast, we don't have a single do loop in our module.

Funky
               
               

               
            

Legacy_MrZork

  • Hero Member
  • *****
  • Posts: 1643
  • Karma: +0/-0
non-integer expressions in for-loops ?
« Reply #13 on: June 07, 2011, 05:15:46 am »


               Thanks, guys. I actually thought of doing this as a recursive call, but it wasn't worth it for the present purpose. I was running some test code to check reliability of a bunch of commands to equip items (on NPCs, so I couldn't use the PlayerOnEquip event) and see what the delay was for those characters in certain situations. If it were for production code, I certainly wouldn't set up (or rely on) a 100 msec timed sink running, even just for a few seconds, if it actually did anything besides check whether an item was in an inventory slot.

Either way, in this case, there is no advantage to a
while
loop over a
for
loop besides personal taste and I started out using the
for
loop before knowing about the limitation of the Toolset's compiler. In the future, I am leaning toward
while
loops because it's sounding like the Toolset implementation deviates less from the C model for
while
loops than for
for
.