Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Calling functions and syntax errors

Gabriel Lemieux
Consumate Newbie
Join date: 28 Aug 2005
Posts: 18
10-17-2005 08:41
I pestered Ice Brodie with a couple problems, but I think I have a couple of larger questions that I need to put up here...

I want to write two scripts, one with two user-defined functions in it, and one that will call the userdefined functions on a listen event. Can I simply call those functions, even though they're in another script?

I was going to experiment and find out for myself, but here's problem #2:

I'm getting a syntax error in the following script:

CODE
glxChangeColor(string color) {
if (color == "Black") {
llSetColor(<0.0, 0.0, 0.0>, ALL_SIDES);
}
if (color == "Red") {
llSetColor(<0.29, 0.0, 0.0>, ALL_SIDES);
}
if (color == "Blue") {
llSetColor(<0.0, 0.0, 0.29>, ALL_SIDES);
}
if (color == "Purple") {
llSetColor(<0.29, 0.0, 0.29>, ALL_SIDES);
}
if (color == "Orange") {
llSetColor(<0.486, 0.243, 0.0>, ALL_SIDES);
}
if (color == "Green") {
llSetColor(<0.0, 0.29, 0.0>, ALL_SIDES);
}
if (color == "Gold") {
llSetColor(<0.392, 0.392, 0.0>, ALL_SIDES);
}
if (color == "Silver") {
llSetColor(<0.6745, 0.6745, 0.6745>, ALL_SIDES);
}
}

glxChangeMaterial(string material) {
if (material == "Metal") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_METAL]);
llSetAlpha(1.0, ALL_SIDES);
}
if (material == "Glass") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_GLASS]);
llSetAlpha(0.4, ALL_SIDES);
}
if (material == "Light") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]);
llSetAlpha(0.2, ALL_SIDES);
}
}


I'm getting the syntax error right at that very last curly brace.

Can someone please tell me what I'm doing wrong or forgetting?

Thank you for any responses to the dumb newbie questions, and thank you, Ice, for answering my first dumb newbie question. :)

-GLX
Fox Stirling
Certified Lunatic
Join date: 16 Aug 2004
Posts: 120
10-17-2005 09:21
I don't see anything here that would cause a syntax error, of course, I may be overlooking something as well.. Are you defining these before the default state? LSL will throw a syntax error if you don't define these functions globally prior to the default state.

Fox
_____________________
...
Escort DeFarge
Together
Join date: 18 Nov 2004
Posts: 681
10-17-2005 09:51
From: Gabriel Lemieux
Can I simply call those functions, even though they're in another script?

Short answer... no you can't.


*edit* Also the syntax error can be explained by the fact that *end edit* A script must have a default state, and I believe that you compiled without one. Additionally, that default state must have at least one callback defined (e.g. state_entry()).

HTH
_____________________
http://slurl.com/secondlife/Together
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
10-17-2005 09:58
From: Gabriel Lemieux

I want to write two scripts, one with two user-defined functions in it, and one that will call the userdefined functions on a listen event. Can I simply call those functions, even though they're in another script?


Im afraid not, at least not directly. You need to have your scripts link message one another. Here's an example:

CODE

// Script that calls the functions
remote_f(string s, string r) {
// All the scripts in the same prim as this script "hear" this
// link message in their link_message event.
llMessageLinked(LINK_THIS, 0, llDumpList2String([s,r], "$3P"), "f");
}

default {
state_entry() {
remote_f("foo", "bar");
}
}

CODE

f(string s, string r) {
// Do stuff.
}

default {
link_message(integer sender, integer num, string str, key id) {
// A script in this object sent a link message that this script "heard".
if (id == "f") {
list params = llParseString2List(str, ["$3P"], []);
string s = llList2String(params, 0);
string r = llList2String(params, 1);
f(s, r);
}
}
}

For more info, see:
http://secondlife.com/badgeo/wakka.php?wakka=llMessageLinked
http://secondlife.com/badgeo/wakka.php?wakka=link_message
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Gabriel Lemieux
Consumate Newbie
Join date: 28 Aug 2005
Posts: 18
10-17-2005 18:03
Thank you, Christopher!

As I said in a previous post, I'm slogging through the LSL wiki, but my brain can't seem to grasp any of these concepts (such as needing a default state and at least one event call). The llMessageLinked was a perfect example. I looked at it last night, but had very little idea of how it was actually applied. You wouldn't know that I used to know how to program. I certainly feel like I've never done this before.

Anyway, so if I understand this right, the full script should actually be:

CODE

default {

link_message(integer sender, integer num, string str, key id) {
if (str == "Black") {
llSetColor(<0.0, 0.0, 0.0>, ALL_SIDES);
}
if (str == "Red") {
llSetColor(<0.29, 0.0, 0.0>, ALL_SIDES);
}
if (str == "Blue") {
llSetColor(<0.0, 0.0, 0.29>, ALL_SIDES);
}
if (str == "Purple") {
llSetColor(<0.29, 0.0, 0.29>, ALL_SIDES);
}
if (str == "Orange") {
llSetColor(<0.486, 0.243, 0.0>, ALL_SIDES);
}
if (str == "Green") {
llSetColor(<0.0, 0.29, 0.0>, ALL_SIDES);
}
if (str == "Gold") {
llSetColor(<0.392, 0.392, 0.0>, ALL_SIDES);
}
if (str == "Silver") {
llSetColor(<0.6745, 0.6745, 0.6745>, ALL_SIDES);
}
if (str == "Metal") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_METAL]);
llSetAlpha(1.0, ALL_SIDES);
}
if (str == "Glass") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_GLASS]);
llSetAlpha(0.4, ALL_SIDES);
}
if (str == "Light") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]);
llSetAlpha(0.2, ALL_SIDES);
}
}
}


I got rid of the functions... it made more sense to combine them and just pass the string directly.

The main script should then be something like:

CODE
default {
state_entry() {
llListen(7343, "", llGetOwner(), "");
}

listen(integer channel, string name, key id, string message) {
llMessageLinked(LINK_THIS, 0, NULL_KEY, "blah");
}
}


Where "blah" would be all the different options. Is there a way to read through the string and just pass part of it? What I mean is, I'm setting up commands that all start with Change (Change Red, Change Metal, Change Green, etc). Can I set up the program to skip "Change" and just grab the second word?

While typing this, I realize that perhaps it'll probably be easier if I just do the whole thing in the listen() event instead of using a linked message and two scripts. But my above question still stands. How would I go about grabbing only part of a string to pass that value along?

Thank you guys for helping out a newbie who can't seem to get it. The concepts are becoming clearer as I talk this out.

-GLX
Gabriel Lemieux
Consumate Newbie
Join date: 28 Aug 2005
Posts: 18
10-17-2005 22:09
From: Gabriel Lemieux


How would I go about grabbing only part of a string to pass that value along?



Nevermind... I found what I needed in the wiki. It's getting easier to find my way around that thing now.

I'm sure I'll be back in the morning with another question or two.

-GLX

When you don't know what's possible, anything is...
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
10-17-2005 22:18
From: Gabriel Lemieux
Thank you, Christopher!

No problem :D

From: Gabriel Lemieux
Where "blah" would be all the different options. Is there a way to read through the string and just pass part of it? What I mean is, I'm setting up commands that all start with Change (Change Red, Change Metal, Change Green, etc). Can I set up the program to skip "Change" and just grab the second word?


Yup, there are actually many ways to do this.
Method 1
You can use llParseString2List(message, [" "], []); to break the string at its spaces into a list of words ("Hello, world" becomes ["Hello,", "world"], Ill call this list parsedString) That lets you address each word individually, llList2String(parsedString, 1) is "world".

Example:
CODE

listen(integer channel, string name, key id, string message)
{
list parsedMessage = llParseString2List(message, [" "], []); // Split at spaces.
// If first word is "Change"
if (llList2String(parsedMessage, 0) == "Change")
{
string color = llList2String(parsedMessage, 1);
}
}


This method is good for simplicity's sake, but it gets a little complicated when it comes to colors with spaces in their names. Youll end up needing to do some list manipulation, which is about just as difficult as the second method below. This method is also theoretically more inefficiant, as it involves searching the string, rather then looking at specific indicies in the string.

Method 2
An alternative is manipulating the string directly using llGetSubString and llDeleteSubString.
A string's characters are addressed like so:
CODE

String: "Fifteen"
Characters: F i f t e e n
Index: 0 1 2 3 4 5 6

Which means:
llGetSubString("Fifteen", 0, 4) returns "Fifte",
llGetSubString("Fifteen", 3, 4) returns "te",
llDeleteSubString("Fifteen", 4, 6) returns "Fift", and
llDeleteSubString("Fifteen", 3, -1) returns "Fif".
(-1 is a handy shortcut that refers to the last character in the string).

So in your case, you'd have strings like "Change green", "Change " is 7 letters long, indexes 0 through 6 in your string. When you call llDeleteSubString("Change green", 0, 6), it will return "green".

Here's another example:
CODE

listen(integer channel, string name, key id, string message)
{
// If the message starts with "Change "
if (llGetSubString(message, 0, 6) == "Change ")
{
string color = llDeleteSubString(message, 0, 6); // Remove "Change "
// Do stuff...
}
}


Hope this helps :)
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Gabriel Lemieux
Consumate Newbie
Join date: 28 Aug 2005
Posts: 18
10-18-2005 00:45
llParseString2List might come in handy, though I'm not sure where.

I was just looking at the string functions, thus my "nevermind" post, but you just answered all the questions I had while reading up on it, and llDeleteSubString is a much better idea than what I had. I was going to break the command up into two words, much like llParseString2List, and store them into variables, etc etc.. I think you just helped me figure out how to do it without defining any local variables at all (other than the required parameters, that is).

In your second example, using llDeleteSubString, could I replace
CODE
string color = llDeleteSubString(message, 0, 6);
with
CODE
llMessageLinked(LINK_THIS, 0, NULL_KEY, llDeleteSubString(message, 0, 6));
thus making it a call to another script that would do the work?

I remember why I wanted to use llMessageLinked in the first place. I'm setting up the listen commands so I can change all the members of a set at once, but I'm also setting up a llDialog menu so the user can change each member of the set individually (in this case, a set of matching attachments). Instead of lots of duplicate code, I was just going to have both scripts call the one that does all the actual changing.

Thanks again. I think this is really starting to sink in finally. :)
_____________________
-GLX

When you don't know what's possible, anything is...
Gabriel Lemieux
Consumate Newbie
Join date: 28 Aug 2005
Posts: 18
10-18-2005 07:02
Oh dear. I wrote both scripts this morning, the core changing script, and the listening script, and nothing's happening. Yet they both compile successfully, so at least I'm one step in the right direction.

The object in question is a linked pair of horns, one prim each. The code is as follows:

The listening script:
CODE
default {
on_rez(integer start_param) {
llResetScript();
}

state_entry() {
llListen(7343, "", llGetOwner(), "");
}

listen(integer channel, string name, key id, string message) {
if (llToLower(llGetSubString(message, 0, 4)) == "demon") {
llMessageLinked(LINK_SET, 0, NULL_KEY, llToLower(llDeleteSubString(message, 0, 5)));
llSay(0, message);
}
}
}

and the changing script:
CODE
default {

link_message(integer sender_num, integer num, string str, key id) {
if (str == "black") {
llSetColor(<0.0, 0.0, 0.0>, ALL_SIDES);
llSay(0, str);
}
if (str == "red") {
llSetColor(<0.29, 0.0, 0.0>, ALL_SIDES);
}
if (str == "blue") {
llSetColor(<0.0, 0.0, 0.29>, ALL_SIDES);
}
if (str == "purple") {
llSetColor(<0.29, 0.0, 0.29>, ALL_SIDES);
}
if (str == "orange") {
llSetColor(<0.486, 0.243, 0.0>, ALL_SIDES);
}
if (str == "green") {
llSetColor(<0.0, 0.29, 0.0>, ALL_SIDES);
}
if (str == "gold") {
llSetColor(<0.392, 0.392, 0.0>, ALL_SIDES);
}
if (str == "silver") {
llSetColor(<0.6745, 0.6745, 0.6745>, ALL_SIDES);
}
if (str == "metal") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_METAL]);
llSetAlpha(1.0, ALL_SIDES);
}
if (str == "glass") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_GLASS]);
llSetAlpha(0.4, ALL_SIDES);
}
if (str == "light") {
llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]);
llSetAlpha(0.2, ALL_SIDES);
}
}
}


I put a couple of llSay commands in there so I could see what was working. The llSay command in the first script fires. So if I type "/7343 demon black", the horns will say "demon black", but it doesn't do anything else.

So what am I missing?

Thankee very very kindly. :)
_____________________
-GLX

When you don't know what's possible, anything is...
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
10-18-2005 08:35
Just for debug, store llDeleteSubString(message, 0, 5) in a separate variable and have it llSay that as well, so you're sure you pulled the right sub-string out of the message. Then in the other script, put an llSay right at the top and print str, so you know what's coming in, and if it's even getting called.

There might be some subtle bug with llDeleteSubString. I know it returns the modified string, it doesn't actually update the original string. Which is why you usually need to do message = llDeleteSubString(message, ...). But you should be able to use it as a parameter to llToLower. Notice how message is unchanged though, since the llSay occurs after the delete but it still contains teh full message.

Put the extra debug llSay's in, I'm sure you'll find the problem. And it's likely that using the intermediate variable to store the deleted string might fix your problem.
Gabriel Lemieux
Consumate Newbie
Join date: 28 Aug 2005
Posts: 18
10-18-2005 21:33
From: Ziggy Puff
Just for debug, store llDeleteSubString(message, 0, 5) in a separate variable and have it llSay that as well, so you're sure you pulled the right sub-string out of the message. Then in the other script, put an llSay right at the top and print str, so you know what's coming in, and if it's even getting called.

There might be some subtle bug with llDeleteSubString. I know it returns the modified string, it doesn't actually update the original string. Which is why you usually need to do message = llDeleteSubString(message, ...). But you should be able to use it as a parameter to llToLower. Notice how message is unchanged though, since the llSay occurs after the delete but it still contains teh full message.

Put the extra debug llSay's in, I'm sure you'll find the problem. And it's likely that using the intermediate variable to store the deleted string might fix your problem.



But shouldn't llDeleteSubString return the modified string, even if it doesn't actually modify the variable itself? In that case, it should still be passing the modified string, even though the change is not permenant.

I'll do what you suggested and check this out in the morning. Thank you for the tips. :)

As frustrating as this all is, I'm really enjoying the learning process -- despite the fact that I feel like I don't know anything.
_____________________
-GLX

When you don't know what's possible, anything is...
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
10-18-2005 23:04
From: someone
But shouldn't llDeleteSubString return the modified string, even if it doesn't actually modify the variable itself? In that case, it should still be passing the modified string, even though the change is not permenant.


Yes, that's what I would expect too, but it's best to be sure :)

Never mind, I found your bug:

CODE
llMessageLinked(LINK_SET, 0, NULL_KEY, llToLower(llDeleteSubString(message, 0, 5)));


Should be:

CODE
llMessageLinked(LINK_SET, 0, llToLower(llDeleteSubString(message, 0, 5)), NULL_KEY);


You have the key and the string reversed. Since keys are strings internally, you can swap them and the compiler won't complain.
Gabriel Lemieux
Consumate Newbie
Join date: 28 Aug 2005
Posts: 18
10-18-2005 23:54
From: Ziggy Puff

You have the key and the string reversed. Since keys are strings internally, you can swap them and the compiler won't complain.


*sigh* You know, I triple-checked for that very thing and missed it every time. It's the little things that get me. I've gotten paranoid about braces, semi-colons, and making sure I've got all the parameters I need in the right order. And still I miss them.

Thanks for catching it. :D
_____________________
-GLX

When you don't know what's possible, anything is...