Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

counting backwards properly

Kornscope Komachi
Transitional human
Join date: 30 Aug 2006
Posts: 1,041
09-02-2008 05:25
Ive tried using minus in various places here to select the previous texture. it always goes forward one, before going back and when at zero gives an error as it can't find the texture. What gives?
This should be simple. And probably is when I can see what's wrong.

CODE
//From the script library
//Writen by Strife Onizuka
//http://secondlife.com/badgeo/wakka.php?wakka=LibraryTextureSwitcher

float time = 0; //give me a value if you want time based shifting otherwise set to zero

integer total;
integer counter;

next()
{
string name = llGetInventoryName(INVENTORY_TEXTURE,counter);
if(name == "")
{
total = llGetInventoryNumber(INVENTORY_TEXTURE);
counter = 0;
if(total < 1)
return;
else
name = llGetInventoryName(INVENTORY_TEXTURE,counter);
}
else if(counter + 1 >= total)
total = llGetInventoryNumber(INVENTORY_TEXTURE);
llSetTexture(name ,0);
if(total)
counter ++ % total;
}
prev()
{
string name = llGetInventoryName(INVENTORY_TEXTURE,counter);
if(name == "")
{
total = llGetInventoryNumber(INVENTORY_TEXTURE);
counter = -1;
if(total < 1)
return;
else
name = llGetInventoryName(INVENTORY_TEXTURE,counter);
}
else if(counter + 1 >= total)
total = llGetInventoryNumber(INVENTORY_TEXTURE);
llSetTexture(name ,0);
if(total)
counter -- % total;
}
default
{
state_entry()
{
total = llGetInventoryNumber(INVENTORY_TEXTURE);
//next();
//llSetTimerEvent(time);
//llSetText("\n \n \n \n \n \n"),<0,0,1>, 0.9);
}

link_message(integer sender,integer num,string str,key id)
{
if (str == "Next") next();
if (str == "Prev") prev();
}
timer()
{
llResetScript();
}
}
_____________________
SCOPE Homes, Bangu
-----------------------------------------------------------------
Dora Gustafson
Registered User
Join date: 13 Mar 2007
Posts: 779
09-02-2008 05:38
Be aware that
counter-- % total;
and
--counter % total;
are two different things:)
if you enter the line with 8 the first line will return 8 % total, the second will return 7 % total.
in the first case the variable is decremented after use, in the second it is before.
_____________________
From Studio Dora
Kornscope Komachi
Transitional human
Join date: 30 Aug 2006
Posts: 1,041
09-02-2008 07:49
I cannot work out what % Modulus/Cross product means

* / %
Multiply/Dot-Product, Divide, Modulus/Cross-Product
rollover = (count + 1)%5;

This is not the first time I've googled it either. Can it be explained to a layman?
_____________________
SCOPE Homes, Bangu
-----------------------------------------------------------------
Meade Paravane
Hedgehog
Join date: 21 Nov 2006
Posts: 4,845
09-02-2008 08:10
llOwnerSay is your friend!

The % operator basically gets you the remainder of division..

This little bit of code..

integer i;
for (i = 0; i < 10; ++i)
{
llOwnerSay ("i = " + (string)i + ", i % 3 = " + (string)(i % 3));
}

...results in this:

i = 0, i % 3 = 0
i = 1, i % 3 = 1
i = 2, i % 3 = 2
i = 3, i % 3 = 0
i = 4, i % 3 = 1
i = 5, i % 3 = 2
i = 6, i % 3 = 0
i = 7, i % 3 = 1
i = 8, i % 3 = 2
i = 9, i % 3 = 0

Where you put ++ and -- on a line matters.. If you put it before the variable, the variable is updated and then used. If you put it after the variable, the value is used then the variable is updated.

integer i = 10;

llOwnerSay ("with i starting at 10, --i % 3 = " + (string)(--i % 3));
i = 10;
llOwnerSay ("with i starting at 10, i-- % 3 = " + (string)(i-- % 3));

Gets you:

with i starting at 10, --i % 3 = 0
with i starting at 10, i-- % 3 = 1

In the first case. 1 is subtracted from 'i' before it does the % operator. The remainder of 9/3 = 0.

In the second case, 1 is subtracted from 'i' after the % is evaluated so you get the remainder of 10/3, which is 1.
_____________________
Tired of shouting clubs and lucky chairs? Vote for llParcelSay!!!
- Go here: http://jira.secondlife.com/browse/SVC-1224
- If you see "if you were logged in.." on the left, click it and log in
- Click the "Vote for it" link on the left
Ron Khondji
Entirely unlike.
Join date: 6 Jan 2007
Posts: 224
Easier?
09-02-2008 08:53
Why not simply do:

CODE


next()
{
counter++;
if (counter > total) counter = 0;
set();
}

prev()
{
counter--;
if (counter < 0) counter = total;
set();
}

set()
{
string name = llGetInventoryName(INVENTORY_TEXTURE,counter);
llSetTexture(name ,ALL_SIDES);
}

Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
09-02-2008 11:07
I'm not sure if this is the problem you are running into, but it is my best guess without picking through the logic:

BEWARE negative values with the modulo operator! A negative dividend always results in a negative result (remainder). This is different from the way modular arithmetic works--where, for example -1, 4, and 9 are in the same congruence class modulo 5 (so -1%5, 4%5, and 9%5 should produce the same result, usually 4).

Instead of blindly decrementing:

CODE

counter = (counter-1)%divisor;


you should always add the divisor before taking the modulo to avoid negative dividends:

CODE

counter = (counter-1+divisor)%divisor;


For example:

-1 % 5 = -1
(-1 + 5) % 5 = 4 % 5 = 4
Kornscope Komachi
Transitional human
Join date: 30 Aug 2006
Posts: 1,041
09-02-2008 18:55
Thanks for your help in defining Modulo.
I've re-read this page several times and it does not help me.
I get double capital F's in 1000 point font for FAIL!

It's algebra, and it's as clear as mud. I'll need a few weeks or more to make this sink in. If ever. Can you be dyslexic at math?

Thanks to Ron, I'm taking the easy option on this one. I'm a 'mug scripter'

mug = Aussie slang for not very good.
Thanks for trying to help. Maybe someone else will benefit.

Have a calculus day.
_____________________
SCOPE Homes, Bangu
-----------------------------------------------------------------
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
09-02-2008 19:55
Old School!!!!!
CODE
integer total;
integer counter = 0;

default{
state_entry() {
total = llGetInventoryNumber(INVENTORY_TEXTURE);
--total;
}

link_message(integer sender,integer num,string str,key id) {
if (str == "Next") {
if (counter >= 0 && counter < total) counter++;
else counter = 0;
}
else if (str == "Prev") {
if (counter > 0 && counter <= total) counter--;
else counter = total;
}
string name = llGetInventoryName(INVENTORY_TEXTURE,counter);
llSetTexture(name ,0);
}
changed(integer change) {
if (change & CHANGED_INVENTORY) {
total = llGetInventoryNumber(INVENTORY_TEXTURE);
--total;
}
}
}
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Kornscope Komachi
Transitional human
Join date: 30 Aug 2006
Posts: 1,041
09-02-2008 20:30
Perfect. Thanks Jesse.
Old school is fine with me. More suits my 47 years' brain.
Like I said...You're a champion!
_____________________
SCOPE Homes, Bangu
-----------------------------------------------------------------
Squirrel Wood
Nuteater. Beware!
Join date: 14 Jun 2006
Posts: 471
09-02-2008 23:37
Modulo for dummies:

10 % 3 will take the number 10 and subtract 3 from it until the remaining rest is smaller than 3 but NOT negative.

10 - 3 - 3 - 3 = 1
9 - 3 - 3 - 3 = 0
8 - 3 - 3 = 2

Hope that helps you to understand how modulo operates.
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
09-03-2008 02:43
From: Kornscope Komachi
Can you be dyslexic at math?

Yes, in fact that is the most common form, the human brain is better designed for language than for math and many people have a problem visualising numbers. I have the opposite problem, Math is easy but I cant visualise words. Thank god for Spell Checkers.
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
12-01-2009 02:38
From: Hewee Zetkin
you should always add the divisor before taking the modulo to avoid negative dividends:

CODE

counter = (counter-1+divisor)%divisor;


For example:

-1 % 5 = -1
(-1 + 5) % 5 = 4 % 5 = 4

Apologies for pulling this one out of the archives but I'm wondering if Hewee's advice above would hold for a positive counter also? I understand the reply was to Korscope's issue with a negative counter. I've done both in a script I'm currently chewing over and it certainly sorted the negative counter where I had the same problem but I hadn't a problem with this positive counter, for instance:

CODE

counter = (counter+1)%divisor;


Even so I added the divisor. Just wondering if it makes any difference to performance or, worse, is it a no-no?
Indeterminate Schism
Registered User
Join date: 24 May 2008
Posts: 236
12-01-2009 03:21
Adding the divisor to a positive number won't affect the result so if you're unsure whether the value you're checking will be positive or negative it is at least 'safe' to use.
Adding it where you don't need to is bound to have an impact on performance, simply because the script is doing more work. However, the overhead is minimal and better than having to check first.

That is:
counter = (++counter + total) % total;

is safe and has a lower overhead than:
if (number < 0)
{
counter = (++counter + total) % total;
}
else
{
counter = ++counter % total;
}
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
12-01-2009 03:27
Thanks for that, Indy. I feel I'm a little bit less of a danger to the community now I got that straight.

Just a little.
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
12-01-2009 06:23
The code I'm working on isn't at all like Kornscope's but the principle is the same: I want the option to activate a particle emitter via llSay() at any given stage of the count. The message will vary for different particle emitters depending on the stage of the count.

So this is the counter function:

CODE

Count()
{
Counter = (Counter+1) % 5;
{
if (Counter == 0)
{
llSay(-2001,"3");
}
else if (Counter == 1)
{
llSay(-2001,"6");
}
else if ...
}
}


I tried running an additional 'if' for the particles after each llSay() inside the counter function but they were just ignored - I guess because the Count function has already been called on a linked prim. So the particle emitters are activated via another function, which is where my problem is:

CODE

Particles()
{
if (Count = "0")
{
llSay(-2001,"5");
}
else if (Count = "1")
{
llSay(-2001,"7");
}
else if ...
}


I can't get the Particles function to 'understand' what point the Count function is at. It occurred to me that I could try a listen event for those llSay messages in Count() but I have a notion that isn't a good thing to do since the script would be listening to itself if that is possible. The basic touch event goes something like this:

CODE

touch_end (integer total_number)
{
if (llDetectedLinkNumber(0) == 2)
{
llSay(-2001,"2");
}
else if (llDetectedLinkNumber(0) == 3)
{
llSay(-2001,"3");
}
else if (llGetLinkName(llDetectedLinkNumber(0)) == "4")
{
// Whatever
}
else if (llGetLinkName(llDetectedLinkNumber(0)) == "5")
{
Count();
}
else if (llGetLinkName(llDetectedLinkNumber(0)) == "6")
{
Particles();
}
else if (llGetLinkName(llDetectedLinkNumber(0)) == "7")
{
// Whatever
}
}


I've been up and down the Wikis and all over 'Scripting Tips' looking for an example but no joy apart from the texture/vendor under discussion. Surely it must be possible to do this in a more general way?

I'd be grateful if someone could even point me to a good rundown on using a counter in various contexts.
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
12-01-2009 16:43
if I understand what your doing, you need to store the result of "Count()" in a global variable, and then read that global variable in "Particles()"

and no, a prim cannot listen to itself.

you could replace "Count()" with
integer gIntCount; //-- in the globals
gIntCount = (gIntCount + 1) % 5; //-- in your touch event

and then reference it in "Particles()" as
if (gIntCount == 0){ //-- etc
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
12-02-2009 01:03
Thanks for that, Void. It did the trick and I didn't need either function - just listed my 'else if' controls for the particles under the appropriate detected link touch.

I guess folks got to shake their heads at some of the 'issues' I have with scripting but that one has been plaguing me for a couple of days. As you might have guessed, I was working on a counter following your suggestions on another thread. I got kind of side tracked looking into the modulo thing, which I'm glad about, but I completely lost track of how this was supposed to work.

On a related note, how would I stop the counter so that further clicks are not counted? The reason I'm asking is that I have two counters, like forward and reverse, and they work nicely on a pair of buttons, except that the user has to take note when he or she is at the limit of one button and switch to the other. Otherwise handling of the looping sequence between the two can be somewhat confusing although it isn't a great disaster.

I tried this:
CODE

gIntCount = (gIntCount-1);
{
if (gIntCount == 0)
{
llSay(-2001,"3");
}
else if (gIntCount == 1)
{
...
}
else if (gIntCount == 6)
{
llSay(-2001,"12");
}
else if (gIntCount > 4) return;
}


Although this stops at six, extra clicks are counted on the other button and that will jump through a number of stages according to however many extra clicks were made on this one.
Indeterminate Schism
Registered User
Join date: 24 May 2008
Posts: 236
12-02-2009 04:26
From: Ephraim Kappler

Particles()
{
if (Count = "0";)
{
llSay(-2001,"5";);
}
else if (Count = "1";)
{
llSay(-2001,"7";);
}
else if ...
}


I only read this far so check & test then post again if I missed a question

IF (COUNT == "0";) ... ELSE IF (COUNT == "1";) ... etc

'if (Count = "0";)' is assignment, not evaluation!
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
12-02-2009 05:19
From: Indeterminate Schism
I only read this far so check & test then post again if I missed a question

IF (COUNT == "0";) ... ELSE IF (COUNT == "1";) ... etc

'if (Count = "0";)' is assignment, not evaluation!

Thanks for the clarification, Indy. I've always been vague about the difference between '=' and '==' amongst a thousand other aspects of scripting. The table of operators in the Wiki doesn't seem to penetrate to those parts of my brain that otherwise bright, shiny objects manage to reach with remarkable ease.

As it happens, I had the whole thing completely arseways. In her post above, Void pointed out that I didn't need to assign the counter a function on its own. It surely didn't help that I had assignment and evaluation confused and the value was a string where (I think) it should be an integer. Happily her solution works very nicely.

I don't suppose you could advise me how to stop the counter as I outlined in post #17 above?
Indeterminate Schism
Registered User
Join date: 24 May 2008
Posts: 236
12-02-2009 06:11
1. To be exact - what 'if (Count = "0";)' does is FIRST assign "0" to the variable 'Count' and THEN test if the result of that assignment is 0 (FALSE) or not (TRUE). Sometimes that can be a useful shortcut trick but commonly if ... = ... instead of == is a mistake.

2. It's hard to give you a proper answer without a wider context and not knowing where you're incrementing or decrementing your counter(s) now. On the other hand, just as illustration, you could try using an 'increment' variable as well as a 'counter' one ...

integer Counter = 0;
integer Increment = 1;
integer Max = 6;
integer Min = 0;

LoopCounter()
{
Counter += Increment;
if (Counter < Min) Counter = Max;
else if (Counter > Max) Counter = Min;
}

That'll count up to a limit and then start again. To reverse the counter direction use Increment = -Increment; (NOT Increment -= Increment!). So ... with Increment = 1 it'll keep counting 0 - 6, then again 0 - 6, etc. Use 'Increment = -Increment' (so Increment is now -1) and it'll count backwards 6 - 0, then again 6 - 0, etc. Use 'Increment = -Increment' again and it's back to 1 so the count goes up 0 - 6, 0 - 6 again.

Which brings us to what you, more probably, wanted ...

BounceCounter()
{
Counter += Increment;
if ((Counter == Min) || (Counter == Max)) Increment = -Increment;
}

... Will count 0 - 6 - 0 - 6 - 0, etc.

ETA:
Oops, I should read the posts I'm answering! You have two buttons that control the counter - one that increments and one that decrements? Get them to call this function with either 1 or -1 as appropriate:

LimitCounter(integer Increment)
{
Counter += Increment;
if (Counter < Min) Counter = Min;
if (Counter > Max) Counter = Max;
}
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
12-02-2009 08:19
From: Indeterminate Schism
1. To be exact - what 'if (Count = "0";)' does is FIRST assign "0" to the variable 'Count' and THEN test if the result of that assignment is TRUE. Sometimes that can be a useful shortcut trick but commonly if ... = ... instead of == is a mistake.

That explains why I could only get a response for '0' when I ran an llOwnerSay debug on the script. Up until I read your differentiation between 'assignment' and 'evaluate' above, I had understood that '==' means 'equal to' but I wasn't fully able to understand the significance of '=' in anything but the vaguest sense. Like most amateurs, I'm always grateful for a layman's explanation of coding logic.

As for the Counter itself, I'm trying to achieve something like the two-button functionality of, say, the forward and backward buttons on a cd player. Your BounceCounter function would work nicely if I used a single button. Unfortunately the drawback is that it cycles through all the forward/backward stages, which is inconvenient if, for instance, the user only wants to go back a single stage.

Your first example of the LoopCounter function works the same way as this:

CODE

Count = (Count+1+6) % 6; // Or Count = (Count+1) % 6


Both versions only work in one direction, which I can fix by using a decremented version on the other button. This is why I was looking at the modulo operator yesterday. However, this non-looping version is closer to what I need:

CODE

Count = (Count+1);


The problem is that when the count is finished on a button, further clicks on it will have been counted on the other button when the user gets around to clicking on that. The result is a leap forward or backwards, as the case may be over, several stages.

I have managed to get additional counts on either button not to count on the other button by adding a 'return' which is what I was doing in that piece of code in #17 above. The same idea on a modified version of your LoopCounter looks like this:

CODE

CountUp()
{
Count += Increment;
if (Count < Min) Count = Max;
else if (Count > Max) return;
}


The problem with the 'return' solution in either case is that for each redundant click on a button, an extra click is necessary on the other button before it will begin to count through the various stages. Basically it 'appears' to be temporarily jammed.

I suppose I need the counter on each button to fail silently if it has counted to its limit.

ETA: The solution in your ETA does the trick, Indy. Thanks.
Indeterminate Schism
Registered User
Join date: 24 May 2008
Posts: 236
12-02-2009 15:49
From: Ephraim Kappler
Your first example of the LoopCounter function works the same way as this:

Count = (Count+1+6) % 6; // Or Count = (Count+1) % 6


Yes, all that talk about modulus was how to limit the count. I posted the code as I did, without reference to that, because it's more consistent with the other routines I used. My intention was clarity rather than efficiency, which the % version offers, but I may have confused things by using a different code style in mid-thread, sorry about that.
Glad you're sorted-out now anyway.

BTW - to remember the operators I usually think of the conditionals as 'is' something
x = y ----------- x EQUALS y
if(x == y) ----------- IF x IS equal to y
if(x != y) ----------- IF x IS not equal to y
if(x > y) ----------- IF x IS larger than y
etc.
Might help :-)
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
12-03-2009 01:21
From: Indeterminate Schism
Yes, all that talk about modulus was how to limit the count. I posted the code as I did, without reference to that, because it's more consistent with the other routines I used.

I understood that. I was doing more or less the same by posting modified code to be consistent with the examples you were showing me. What I in fact took from your last solution looks something like this when I added it to the code example I was enquiring about in #17:

CODE

gIntCount = (gIntCount-1); // Count down
{
if (gIntCount < 0) gIntCount = 0;
else if (gIntCount == 0)
{
llSay(-2001,"3");
}
else if (gIntCount == 1)
{
...
}
else if (gIntCount == 6)
{
llSay(-2001,"6");
}
}


And this:

CODE

gIntCount = (gIntCount+1); // Count up
{
if (gIntCount == 0)
{
llSay(-2001,"3");
}
else if (gIntCount == 1)
{
...
}
else if (gIntCount == 6)
{
llSay(-2001,"6");
}
else if (gIntCount > 6) gIntCount = 6;
}


Any amount of clicks beyond the limit of the button has no effect whatsoever and the user has to click on the other button to go forwards or backwards as the case may be. At the same time the counts in between are consistent so that three clicks forward on one button can be reversed by three clicks back on its fellow, for example, which is what I need.

Thanks again to yourself and Void for the pointers.