Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Particle Script attached to a Notecard reader to change color on voice command.

Iria Troell
Bunny of the House
Join date: 30 Jan 2007
Posts: 10
04-09-2007 16:29
AKA, I'm in waaaay over my head.

In short, the script uses an open-source particle emitter. I attempted to add a notecard reader I found somewhere, probably here, but I don't really understand how or why it works. I'm also prolly being innefficient with the listener, but I was able to get the whole thing to compile. The color change wont work though, and it wont give me a response that the listen statement is working. You might ask why in the hell I would throw all this in together. It's a learning experience, s'all.

Oh, and the notecard is alternate line vectors, as you can probably tell. It loads fine, and makes it to the ownersay that the notecard is loaded.

This is my first big project, and I dont really have any previous scripting experience to the few months ive been fiddling with them in SL, so any help would be appreciated.

CODE
//Altered by Iria Troell
//// based on eltee Statosky's Particle Creation Engine 1.2
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
////// Particle System Variables
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////



///////////////////////////////////////////////////////
// Effect Flag Collection variable
///////////////////////////////////////////////////////
integer effectFlags;
integer running=TRUE;

///////////////////////////////////////////////////////
// Color Secelection Variables
///////////////////////////////////////////////////////
// Interpolate between startColor and endColor
integer colorInterpolation;
// Starting color for each particle
vector startColor;
// Ending color for each particle
vector endColor;
// Starting Transparency for each particle (1.0 is solid)
float startAlpha;
// Ending Transparency for each particle (0.0 is invisible)
float endAlpha;
// Enables Absolute color (true) ambient lighting (false)
integer glowEffect;
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
//For colorchange by notecard
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
vector cardcolor;
string strNotecard = "SprayColors";
integer lineCounter = 0;
key dataRequestID = "";
string data = "";
///////////////////////////////////////////////////////
// Size & Shape Selection Variables
///////////////////////////////////////////////////////
// Interpolate between startSize and endSize
integer sizeInterpolation;
// Starting size of each particle
vector startSize;
// Ending size of each particle
vector endSize;
// Turns particles to face their movement direction
integer followVelocity;
// Texture the particles will use ("" for default)
string texture;

///////////////////////////////////////////////////////
// Timing & Creation Variables Variables
///////////////////////////////////////////////////////
// Lifetime of one particle (seconds)
float particleLife;
// Lifetime of the system 0.0 for no time out (seconds)
float SystemLife;
// Number of seconds between particle emissions
float emissionRate;
// Number of particles to releast on each emission
integer partPerEmission;

///////////////////////////////////////////////////////
// Angular Variables
///////////////////////////////////////////////////////
// The radius used to spawn angular particle patterns
float radius;
// Inside angle for angular particle patterns
float innerAngle;
// Outside angle for angular particle patterns
float outerAngle;
// Rotational potential of the inner/outer angle
vector omega;

///////////////////////////////////////////////////////
// Movement & Speed Variables
///////////////////////////////////////////////////////
// The minimum speed a particle will be moving on creation
float minSpeed;
// The maximum speed a particle will be moving on creation
float maxSpeed;
// Global acceleration applied to all particles
vector acceleration;
// If true, particles will be blown by the current wind
integer windEffect;
// if true, particles 'bounce' off of the object's Z height
integer bounceEffect;
// If true, particles spawn at the container object center
integer followSource;
// If true, particles will move to expire at the target
//integer followTarget = TRUE;
// Desired target for the particles (any valid object/av key)
// target Needs to be set at runtime
key target;

///////////////////////////////////////////////////////
//As yet unimplemented particle system flags
///////////////////////////////////////////////////////
integer randomAcceleration = FALSE;
integer randomVelocity = FALSE;
integer particleTrails = FALSE;

///////////////////////////////////////////////////////
// Pattern Selection
///////////////////////////////////////////////////////
integer pattern;



///////////////////////////////////////////////////////
// Particle System Call Function
///////////////////////////////////////////////////////
setParticles()
{
// Here is where to set the current target

// Feel free to insert any other valid key
target="";
// The following block of if statements is used to construct the mask
if (colorInterpolation) effectFlags = effectFlags|PSYS_PART_INTERP_COLOR_MASK;
if (sizeInterpolation) effectFlags = effectFlags|PSYS_PART_INTERP_SCALE_MASK;
if (windEffect) effectFlags = effectFlags|PSYS_PART_WIND_MASK;
if (bounceEffect) effectFlags = effectFlags|PSYS_PART_BOUNCE_MASK;
if (followSource) effectFlags = effectFlags|PSYS_PART_FOLLOW_SRC_MASK;
if (followVelocity) effectFlags = effectFlags|PSYS_PART_FOLLOW_VELOCITY_MASK;
if (target!="") effectFlags = effectFlags|PSYS_PART_TARGET_POS_MASK;
if (glowEffect) effectFlags = effectFlags|PSYS_PART_EMISSIVE_MASK;
llParticleSystem([
PSYS_PART_FLAGS, effectFlags,
PSYS_SRC_PATTERN, pattern,
PSYS_PART_START_COLOR, startColor,
PSYS_PART_END_COLOR, endColor,
PSYS_PART_START_ALPHA, startAlpha,
PSYS_PART_END_ALPHA, endAlpha,
PSYS_PART_START_SCALE, startSize,
PSYS_PART_END_SCALE, endSize,
PSYS_PART_MAX_AGE, particleLife,
PSYS_SRC_ACCEL, acceleration,
PSYS_SRC_TEXTURE, texture,
PSYS_SRC_BURST_RATE, emissionRate,
PSYS_SRC_INNERANGLE, innerAngle,
PSYS_SRC_OUTERANGLE, outerAngle,
PSYS_SRC_BURST_PART_COUNT, partPerEmission,
PSYS_SRC_BURST_RADIUS, radius,
PSYS_SRC_BURST_SPEED_MIN, minSpeed,
PSYS_SRC_BURST_SPEED_MAX, maxSpeed,
PSYS_SRC_MAX_AGE, SystemLife,
PSYS_SRC_TARGET_KEY, target,
PSYS_SRC_OMEGA, omega ]);
}


///////////////////////////////////////////////////////
// Particle Effect Function
// - Edit the values here to change the effect
///////////////////////////////////////////////////////
ParticleFallsEffect()
{
//Color
colorInterpolation = TRUE;
startColor = cardcolor;
endColor = cardcolor;
startAlpha = 0.4;
endAlpha = 0.0;
glowEffect = FALSE;
//Size & Shape
sizeInterpolation = TRUE;
startSize = <0.0, 0.0, 0.0>;
endSize = <0.4, 0.4, 0.4>;
followVelocity = FALSE;
texture = "";
//Timing
particleLife = 1.5;
SystemLife = 0.0;
emissionRate = 0.02;
partPerEmission = 6;
//Emission Pattern
radius = 0.0;
innerAngle = 0.0;
outerAngle = 0.3;
omega = <0.0, 0.0, 0.0>;
pattern = PSYS_SRC_PATTERN_ANGLE_CONE;
// Drop parcles at the container objects' center
// PSYS_SRC_PATTERN_DROP;
// Burst pattern originating at objects' center
// PSYS_SRC_PATTERN_EXPLODE;
// Use 2D angle between innerAngle and outerAngle
// PSYS_SRC_PATTERN_ANGLE;
// Use 3D cone spread between innerAngle and outerAngle
// PSYS_SRC_PATTERN_ANGLE_CONE;
//Movement
minSpeed = 0.5;
maxSpeed = 0.7;
acceleration = <0.0, 0.0, -0.1>;
windEffect = FALSE;
bounceEffect = FALSE;
followSource = FALSE;
target = "";
// llGetKey() targets this script's container object
// llGetOwner() targets the owner of this script
//Particle Call
setParticles();
}

default
{
state_entry()
{
lineCounter = 0;
integer itemtype = llGetInventoryType(strNotecard);
running=TRUE;
llSetText(" ", <0.0, 1.0, 0.0>, 0.5);
ParticleFallsEffect();
if(INVENTORY_NOTECARD == itemtype)
{
dataRequestID = llGetNotecardLine(strNotecard, lineCounter);
llSetTimerEvent(10);
}
else
{
llOwnerSay("Error - configuration notecard missing. Default parameters only");
state listener;

}

}

dataserver(key queryid, string data)
{
//Check to make sure this is the request we are making.
//Remember that when data comes back from the dataserver,
//it goes to *all* scripts in your prim.
//So you have to make sure this is the data you want, and
//not data coming from some other script.

if(dataRequestID == queryid)
{
if(data == EOF)
{
state listener;
}
else
{
lineCounter++;
dataRequestID = llGetNotecardLine(strNotecard, lineCounter);
}
}
}

timer()
{
llOwnerSay("Time out reading notecard.");
llSetTimerEvent(0);
state listener;
}

}
state listener
{
state_entry()
{
llOwnerSay("Notecard Read Complete, State Listener active.");
llListen(1, "", "", "");
}
listen(integer num, string str, key id, string message)
{
//Is triggered if a llMessageLinked with num of 0 and str of of a specific color is passed through the object.
if ((num == 1)&&(str == "black"))
{
llGetNotecardLine(strNotecard, 2);
}
if ((num == 1)&&(str == "white"))
{
llGetNotecardLine(strNotecard, 4);
}
if ((num == 1)&&(str == "red"))
{
llGetNotecardLine(strNotecard, 6);
}
if ((num == 1)&&(str == "blue"))
{
llGetNotecardLine(strNotecard, 8);
}
if ((num == 1)&&(str == "green"))
{
llGetNotecardLine(strNotecard, 10);
llOwnerSay("Recieved green command");
}
if ((num == 1)&&(str == "yellow"))
{
llGetNotecardLine(strNotecard, 12);
}
if ((num == 1)&&(str == "purple"))
{
llGetNotecardLine(strNotecard, 14);
}
if ((num == 1)&&(str == "custom1"))
{
llGetNotecardLine(strNotecard, 16);
}
if ((num == 1)&&(str == "custom2"))
{
llGetNotecardLine(strNotecard, 18);
}
if ((num == 1)&&(str == "custom3"))
{
llGetNotecardLine(strNotecard, 20);
}
}
}
Ravanne Sullivan
Pole Dancer Extraordinair
Join date: 10 Dec 2005
Posts: 674
04-09-2007 17:07
As near as I can figure from the code you posted, all you do is read various lines from the notecard when you issue a "command" but you don't actually do anything with the information received. your if statements should contain code to take the information received and pass it to the relevant function to actually do whatever it is you want done.
_____________________
Ravanne's Dance Poles and Animations

Available at my Superstore and Showroom on Insula de Somni
http://slurl.com/secondlife/Insula de Somni/94/194/27/
RJ Source
Green Sky Labs
Join date: 10 Jan 2007
Posts: 272
04-09-2007 17:09
That's what I got out of it too.

Might help if you posted the contents of the notecard.

Rj
Iria Troell
Bunny of the House
Join date: 30 Jan 2007
Posts: 10
04-09-2007 17:25
I hadn't really thought of that...
The values of the card are supposed to become vector cardcolor

ok, im confused, even though it may call the information, how do I associate that info with a variable?

CODE
::Black::
<0, 0, 0>
::White::
<1, 1, 1>
::Red::
<1, 0, 0>
::Blue::
<0, 0, 1>
::Green::
<0, 1, 0>
::Yellow::
<1, 1, 0>
::Purple::
<1, 0, 1>
::Custom#1::
<0, 0, 0>
::Custom#2::
<0, 0, 0>
::Custom#3::
<0, 0, 0>
Ravanne Sullivan
Pole Dancer Extraordinair
Join date: 10 Dec 2005
Posts: 674
04-09-2007 18:27
All you're doing is telling it to get a line from your notecard, this triggers the dataserver event that then gets the next line in the notecard unless you have reached the end of file. At no point do you actually do anything with the data retrieved. You should have a rountine inside your dataserver event that takes the infromation read from the notecard and either assigns it to a variable or passes it to another function.

http://lslwiki.org/index.php/Dataserver
_____________________
Ravanne's Dance Poles and Animations

Available at my Superstore and Showroom on Insula de Somni
http://slurl.com/secondlife/Insula de Somni/94/194/27/
Iria Troell
Bunny of the House
Join date: 30 Jan 2007
Posts: 10
04-09-2007 18:30
Oh!

So llGetNotecardLine acts like llListen, in that it activates another event!
I had no clue what dataserver was for, hm...
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-10-2007 00:39
As previously posted by both RJ and Ravanne you're not processing any of the data you're receiving in the data server event, but my question is why read the notecard once at start up and then reread it on each look up anyway?

Either read the data at start up and store it, or just read it when triggered and dont bother storing it. Or possibly a bit of both i.e. read when requested but store it so you dont have to reread it again if asked for it a subsequent time.

You should also restructure your code to use nested if's and else if's where appropriate.

I'd also suggest you take a read of the new Scripters Start here sticky it would give you a few more detailed tutorials on some of the structural and syntaxical best practises in LSL.

Here is how I would approach it
CODE

//Altered by Iria Troell
//// based on eltee Statosky's Particle Creation Engine 1.2
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
////// Particle System Variables
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////

// ************* NEWGY ADDED VARIABLES *************
list colours = [ ];
list colourvalues = [ ];

///////////////////////////////////////////////////////
// Effect Flag Collection variable
///////////////////////////////////////////////////////
integer effectFlags;
///////////////////////////////////////////////////////
// Color Secelection Variables
///////////////////////////////////////////////////////
// Interpolate between startColor and endColor
integer colorInterpolation;
// Starting color for each particle
vector startColor;
// Ending color for each particle
vector endColor;
// Starting Transparency for each particle (1.0 is solid)
float startAlpha;
// Ending Transparency for each particle (0.0 is invisible)
float endAlpha;
// Enables Absolute color (true) ambient lighting (false)
integer glowEffect;
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
//For colorchange by notecard
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
vector cardcolor;
string strNotecard = "SprayColors";
integer lineCounter = 0;
key dataRequestID = NULL_KEY;
///////////////////////////////////////////////////////
// Size & Shape Selection Variables
///////////////////////////////////////////////////////
// Interpolate between startSize and endSize
integer sizeInterpolation;
// Starting size of each particle
vector startSize;
// Ending size of each particle
vector endSize;
// Turns particles to face their movement direction
integer followVelocity;
// Texture the particles will use ("" for default)
string texture;

///////////////////////////////////////////////////////
// Timing & Creation Variables Variables
///////////////////////////////////////////////////////
// Lifetime of one particle (seconds)
float particleLife;
// Lifetime of the system 0.0 for no time out (seconds)
float SystemLife;
// Number of seconds between particle emissions
float emissionRate;
// Number of particles to releast on each emission
integer partPerEmission;

///////////////////////////////////////////////////////
// Angular Variables
///////////////////////////////////////////////////////
// The radius used to spawn angular particle patterns
float radius;
// Inside angle for angular particle patterns
float innerAngle;
// Outside angle for angular particle patterns
float outerAngle;
// Rotational potential of the inner/outer angle
vector omega;

///////////////////////////////////////////////////////
// Movement & Speed Variables
///////////////////////////////////////////////////////
// The minimum speed a particle will be moving on creation
float minSpeed;
// The maximum speed a particle will be moving on creation
float maxSpeed;
// Global acceleration applied to all particles
vector acceleration;
// If true, particles will be blown by the current wind
integer windEffect;
// if true, particles 'bounce' off of the object's Z height
integer bounceEffect;
// If true, particles spawn at the container object center
integer followSource;
// If true, particles will move to expire at the target
//integer followTarget = TRUE;
// Desired target for the particles (any valid object/av key)
// target Needs to be set at runtime
key target;

///////////////////////////////////////////////////////
//As yet unimplemented particle system flags
///////////////////////////////////////////////////////
integer randomAcceleration = FALSE;
integer randomVelocity = FALSE;
integer particleTrails = FALSE;

///////////////////////////////////////////////////////
// Pattern Selection
///////////////////////////////////////////////////////
integer pattern;



///////////////////////////////////////////////////////
// Particle System Call Function
///////////////////////////////////////////////////////
setParticles()
{
// Here is where to set the current target

// Feel free to insert any other valid key
target="";
// The following block of if statements is used to construct the mask
if (colorInterpolation) effectFlags = effectFlags|PSYS_PART_INTERP_COLOR_MASK;
if (sizeInterpolation) effectFlags = effectFlags|PSYS_PART_INTERP_SCALE_MASK;
if (windEffect) effectFlags = effectFlags|PSYS_PART_WIND_MASK;
if (bounceEffect) effectFlags = effectFlags|PSYS_PART_BOUNCE_MASK;
if (followSource) effectFlags = effectFlags|PSYS_PART_FOLLOW_SRC_MASK;
if (followVelocity) effectFlags = effectFlags|PSYS_PART_FOLLOW_VELOCITY_MASK;
if (target!="") effectFlags = effectFlags|PSYS_PART_TARGET_POS_MASK;
if (glowEffect) effectFlags = effectFlags|PSYS_PART_EMISSIVE_MASK;
llParticleSystem([
PSYS_PART_FLAGS, effectFlags,
PSYS_SRC_PATTERN, pattern,
PSYS_PART_START_COLOR, startColor,
PSYS_PART_END_COLOR, endColor,
PSYS_PART_START_ALPHA, startAlpha,
PSYS_PART_END_ALPHA, endAlpha,
PSYS_PART_START_SCALE, startSize,
PSYS_PART_END_SCALE, endSize,
PSYS_PART_MAX_AGE, particleLife,
PSYS_SRC_ACCEL, acceleration,
PSYS_SRC_TEXTURE, texture,
PSYS_SRC_BURST_RATE, emissionRate,
PSYS_SRC_INNERANGLE, innerAngle,
PSYS_SRC_OUTERANGLE, outerAngle,
PSYS_SRC_BURST_PART_COUNT, partPerEmission,
PSYS_SRC_BURST_RADIUS, radius,
PSYS_SRC_BURST_SPEED_MIN, minSpeed,
PSYS_SRC_BURST_SPEED_MAX, maxSpeed,
PSYS_SRC_MAX_AGE, SystemLife,
PSYS_SRC_TARGET_KEY, target,
PSYS_SRC_OMEGA, omega ]);
}


///////////////////////////////////////////////////////
// Particle Effect Function
// - Edit the values here to change the effect
///////////////////////////////////////////////////////
ParticleFallsEffect()
{
//Color
colorInterpolation = TRUE;
startColor = cardcolor;
endColor = cardcolor;
startAlpha = 0.4;
endAlpha = 0.0;
glowEffect = FALSE;
//Size & Shape
sizeInterpolation = TRUE;
startSize = <0.0, 0.0, 0.0>;
endSize = <0.4, 0.4, 0.4>;
followVelocity = FALSE;
texture = "";
//Timing
particleLife = 1.5;
SystemLife = 0.0;
emissionRate = 0.02;
partPerEmission = 6;
//Emission Pattern
radius = 0.0;
innerAngle = 0.0;
outerAngle = 0.3;
omega = <0.0, 0.0, 0.0>;
pattern = PSYS_SRC_PATTERN_ANGLE_CONE;
// Drop parcles at the container objects' center
// PSYS_SRC_PATTERN_DROP;
// Burst pattern originating at objects' center
// PSYS_SRC_PATTERN_EXPLODE;
// Use 2D angle between innerAngle and outerAngle
// PSYS_SRC_PATTERN_ANGLE;
// Use 3D cone spread between innerAngle and outerAngle
// PSYS_SRC_PATTERN_ANGLE_CONE;
//Movement
minSpeed = 0.5;
maxSpeed = 0.7;
acceleration = <0.0, 0.0, -0.1>;
windEffect = FALSE;
bounceEffect = FALSE;
followSource = FALSE;
target = "";
// llGetKey() targets this script's container object
// llGetOwner() targets the owner of this script
//Particle Call
setParticles();
}

default
{
state_entry()
{
llSetText(" ", <0.0, 1.0, 0.0>, 0.5);
ParticleFallsEffect();
lineCounter = 0;
integer itemtype = llGetInventoryType(strNotecard);
if(INVENTORY_NOTECARD == itemtype)
{
colours = [ ];
colourvalues = [ ];
dataRequestID = llGetNotecardLine(strNotecard, lineCounter);
llSetTimerEvent(10);
}
else
{
llOwnerSay("Error - configuration notecard missing. Default parameters only");
state listener;

}

}

dataserver(key queryid, string data)
{
//Check to make sure this is the request we are making.
//Remember that when data comes back from the dataserver,
//it goes to *all* scripts in your prim.
//So you have to make sure this is the data you want, and
//not data coming from some other script.

if(dataRequestID == queryid)
{
llSetTimerEvent(0);
if(data == EOF)
{
state listener;
}
else
{
list ldata = llParseString2List(data, ["="], [""]);
string colourname = llList2String(ldata, 0);
string colourvalue = llList2String(ldata, 1);
colours = (colours = []) + colours + [ llToLower(colourname) ];
colourvalues = (colourvalues = []) + colourvalues + [ llToLower(colourvalue) ];

llSetTimerEvent(10);
lineCounter++;
dataRequestID = llGetNotecardLine(strNotecard, lineCounter);
}
}
}

timer()
{
llOwnerSay("Time out reading notecard.");
llSetTimerEvent(0);
state listener;
}

}

state listener
{
state_entry()
{
llOwnerSay("Notecard Read Complete, State Listener active.");
llListen(1, "", NULL_KEY, "");
}
listen(integer num, string str, key id, string message)
{
string lcase = llToLower(message);
integer index = llListFindList(colours, [ lcase ]);

if(index >= 0)
{
cardcolor = (vector)llList2String(colourvalues, index);
ParticleFallsEffect();
}
}
}


It does require a change the format of your notecard.
Instead of
CODE

::Black::
<0, 0, 0>
::White::
<1, 1, 1>


Use
CODE

Black=<0, 0, 0>
White=<1, 1, 1>
RJ Source
Green Sky Labs
Join date: 10 Jan 2007
Posts: 272
04-10-2007 08:24
You may also want to consider just rewriting this all from scratch, since as you seemed to say at the beginning of the thread, this code was over your head. Starting from scratch, a little bit at a time, would help you understand what all is going on and be able to make changes and maintain this into the future.

Another suggestion, which depends on your plans here, is that since you only have a few colors whose values aren't changing, you might consider just dumping the whole notecard approach and hardcode the colors and values into constants in the script. This will make it more straightforward, especially since you're trying to understand it all. Then later on, once you're more comfortable with everything, you can move it to a notecard approach if needed.

Rj
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-10-2007 08:42
From: RJ Source
You may also want to consider just rewriting this all from scratch, since as you seemed to say at the beginning of the thread, this code was over your head. Starting from scratch, a little bit at a time, would help you understand what all is going on and be able to make changes and maintain this into the future.

Another suggestion, which depends on your plans here, is that since you only have a few colors whose values aren't changing, you might consider just dumping the whole notecard approach and hardcode the colors and values into constants in the script. This will make it more straightforward, especially since you're trying to understand it all. Then later on, once you're more comfortable with everything, you can move it to a notecard approach if needed.

Rj


Stepping back from it for a second and RJ's comments are well made.
Notecards aren't difficult to understand/use, but they do introduce a new, and very important , LSL programming concept, that of a requested event.
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
04-10-2007 10:37
Just to insert a minor LSL grumble here, it might help if there were consistency in naming of functions, so that any which trigger a dataserver event begin with llRequest. llGetNumberOfNotecardLines and llGetNotecardLine (by analogy with llGetPos and llGetKey, for example) imply that their return value is the data in question, not a dataserver event UUID key.

On a similar note, I'm constantly typing out llGetStringLength (by analogy with llGetListLength). </grumble>
Iria Troell
Bunny of the House
Join date: 30 Jan 2007
Posts: 10
04-10-2007 23:35
Thank you very much Newgate.

Through your alteration (fixing) of the script, I have learned a great deal about manipulating lists through your use of

CODE
                list ldata = llParseString2List(data, ["="], [""]); 
string colourname = llList2String(ldata, 0);
string colourvalue = llList2String(ldata, 1);
colours = (colours = []) + colours + [ llToLower(colourname) ];
colourvalues = (colourvalues = []) + colourvalues + [ llToLower(colourvalue) ];


and especially the nested if statement through

CODE
integer index = llListFindList(colours, [ lcase ]); 

if(index >= 0)
{
cardcolor = (vector)llList2String(colourvalues, index);


I had no concept for the llList commands before, nor the syntax of using (variabletype eg. vector) to control what comes out. Dissecting them through llSay's to understand the output has helped a lot. And also that src means source, which I hadnt understood before. It has helped immensely in several other test scripts I have been working on, though I still have a long ways to learn to apply nested If's. dataserver has become far more understandable when I looked at it in the context of states such as listen() or linkmessage().

I'm also currently working to understand states through an opensource script defining multi-tiered menus by Tex Armitage, which also helps with lists and what you have shown me.

On the topic of nested ifs, it is very difficult to wrap my head around sequentially, even though after studying the code you provided I can see how it works. I am currently making my way through threads that mention that through search, but do you have any outside documentation that might help me to understand?

Also, is there a good resource to understand the concept of efficiency? I'm far from hitting the scripting limitations because of useless code, but I'd like to learn what is good practice now, rather than later, but the LSL wiki on SL.com is rather sparse on the topic.

Thank you Ravanne, RJ, and Newgate for your advice! :)

I tend to jump into new things head-first on purpose, rather than one step at a time, as I simply learn better that way. Thank you for pointing out my errors.

On the "Why a notecard" subject, its to add the ability for an end user to set their own preferences on color. I saw that on a couple no-mod free vehicles, and it seemed like a really nifty thing to learn for later, when I might be able to apply it to a product.
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-11-2007 00:30
The sticky's at the top of the forum give a list of a few tutorials which may / may not help depending upon your learning style. The various wikki's are invaluable learning tools, as is this forum. A decent editor and lslint are also must haves for any real development.


list are LSL's equivelent of arrays. They are immensly useful but also unfortunately memory hungry. Very memory Hungry. This has led to the rather unintuative syntax :-

CODE
list = (list = []) + list + [ data ]; 


This assigns list the value of itself plus the new data. The emptying of the list is to reclaim memory. Read Strife's post on optimisation for more insight and details.

The code also bypasses a couples of other known problems, namely that llList2vector doesnt work. Hence the use of llList2String and then casting i.e. changing the type , to a vector

CODE
cardcolor = (vector)llList2String(colourvalues, index);


The use of lllistFindList is just to save all of the if checks. For a small number of items a straight IF compare will be quicker, but the speed advatange is lost as the number of checks grows, to say nothing of the reduction in code size and improved clarity of the code.

My question concerning notecards wasn't why use one, just why read it the way you did.
Doing anything more than once is bad, especially if its constant data. The same applies to nesting your IF's. If you are checking the same condition over and over then make it a containing branch rather than repeating it.

As for jumping in with both feet thats fine as long as you can see which bit of the code at a time isnt working. If you add too many 'new' ideas/processes at once you can end up not knowing where to start to debug whats going wrong.

There are several threads which discuss the 'best' approach to script development. Personally I use functional decomposition, breaking each process down into a number of functional tasks and then translate them to code. Its useful as it allows you to stub the code, i.e. add dummy data, so that it always works even if its not actually doing everything yet. But thats just my approach.
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
04-11-2007 10:21
From: Newgate Ludd
...llList2vector doesnt work. Hence the use of llList2String and then casting i.e. changing the type , to a vector
Just to clarify... llList2Vector does work, but only if the list element being referenced is actually a vector. In other words, it doesn't directly typecast to vector from other types. e.g. If you call llList2Integer on a list element which is a string with the value "256", the return would be an integer with the value 256. However, if you call llList2Vector on a list element which is a string with the value "<100,42,47>", the return would be a vector with the value <0,0,0> (ZERO_VECTOR). So you'd call llList2String and cast the result to a vector separately. llList2Rot has the same problem.

When lists are created directly from strings, i.e. using llCSV2List, llParseString2List, or llParseStringKeepNulls, the resulting elements will all be of the string type. This is common when rebuilding lists sent through link_messages or chat channels.