Jump to content

Carrying Variables Across Events


reeveskd
 Share

You are about to reply to a thread that has been inactive for 3458 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I am absolutely brand new to scripting, and I confess both noobness and ineptitude in Googling / forum-surfing for this, so my apologies in advance.

I am attempting to build a script by which an avatar (non-perm non-owner) drops three objects onto a prim, and the prim reacts (gives messages / inventory items) based on the unique combinations of those three objects. At the moment, I'm early in the project, trying to establish a test prim onto which inventory items are dropped. The prim then detects the name of the item, stores that name as a variable, and awaits a second (then a third) dropped item, ultimately destroying the three items. (ideally it would reject any item that was not an object and reset, but that comes later.)

My trouble at the moment, as I attempt to learn LSL, is storing the dropped-in object names as variables from one event to the next. Here's what I have so far:

---

default
{
state_entry()
{
llAllowInventoryDrop(TRUE); // Allows non-owners to drop inventory into prim
}

changed(integer change)
{
if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY)) 
{
llSay(0, "Inventory changed.");

integer index;
integer craftingStage;
string itemName = llGetInventoryName(INVENTORY_ALL, index);
integer itemType = llGetInventoryType(itemName);

llSay(0, "The value craftingStage is " + (string)craftingStage);
llSay(0, "The value itemName is " + itemName);
llSay(0, "The value itemType is " + (string)itemType);
llSleep(0.1);
craftingStage = craftingStage + 1;
llSay(0, "The new value craftingStage is " + (string)craftingStage);
llSay(0, "Removing item called " + itemName);
llRemoveInventory(itemName);
}
}
}

---

This script tests well, taking the object, identifying the name and type, regurgitating that information into local, adding 1 to the craftingStage variable, and then deleting the original object, leaving the test prim free of clutter.

However, as I understand it, in this script, I've created the variable "craftingStage" only after the change of inventory event has triggered. While the craftingStage variable is increased by one, I'm unsure how to get this variable to persist (so I can repeat this process another two times, adding +1 to the craftingStage variable each time) across item drops.

My thought was originally that I could use craftingStage as an ordinal number variable so I could ultimately define itemName1, itemName2, and itemName3 into a [list], and then use some if/else statements to say "if the list reads "red red blue" then give the avatar X item, and if the list reads "red blue blue" then give the avatar Y item, but if the list reads anything else, tell the avatar to go pound salt."

That's the ultimate goal: An avatar drags three items onto a prim. If any of those items aren't an object, it pukes and destroys everything (except the script) and resets. If all three items are objects, the test prim compares the names of those items to a list, and if the "recipe" of items matches any set of conditions, the avatar is rewarded with a resulting item, and the "ingredient" items are destroyed and the item resets. If the items don't match a "recipe," the prim pukes and destroys everything and resets. The result is a prim that won't take non-objects, and will take three objects and act accordingly. (How I make sure the objects are "authentic" and not just wooden blocks the avatar named him/herself is another task entirely, I understand, but this is a learning project. Presumably that gets into a database of keys or something, and iono LOL.)

However, this idea of craftingStage as the "what step am I on" variable doesn't seem feasible as a solution if the variable doesn't persist across events, and I'm a total noob and dunno how to do that. I've visited a few script tutorial sims and have done some reading, but if the answer is spelled out in either venue, I'm too bleary to see it.

Thanks in advance for any help any of the experts can provide! ^_^

Cheers,

Loren

Link to comment
Share on other sites

Any variable is defined for use within a specific scope.  Think of "scope" in a practical sense as "a region between curly brackets."  So if you write

touch_start(integer num){    integer i;    while (i < 5 )    {        integer p = 4 + i;        llSay(0, (string)p);        ++i;    }}

 the variable p only has meaning inside the curly brackets of the while loop. The variable i, on the other hand, is outside those brackets and therefore defined for the larger scope of the touch_start event, which has its own curly brackets.  If I moved the llSay statement outside of the while loop, therefore, I would get an error message, telling me that p has no value there.  I can ask about the value of i anywhere in the touch_start event, however, because I will be asking within its scope.

Extend this reasoning beyond the touch_start event and you'll see that there has to be a way to define a scope that is as large as the entire script, so that you can use the same variable anywhere.  When you do that, you have imagined a global variable.  You declare those outside of your default state, usually at the top of the script.  Any time you give a global variable a value in any part of the script, it holds that value so you can use it anywhere else.

string gMyName;default{    state_entry()    {        gMy_name = "Rolig";    }    touch_start(integer num)    {        llSay(0,gMyName);  // Will say Rolig.        state Next;    }}state Next{    touch_start(integer num)    {        llSay(0,gMyName);  // Will say Rolig here too        state default;    }}

So, you need to define global variables to hold and carry values from one event or state to another in your script, and then be sure that you keep track of how those values change and how you will need to reset them when you want to start fresh after completing a process.

 

 

 

   

  • Like 1
Link to comment
Share on other sites

Rolig:

Thank you very much for taking the time to reply with your examples. I will experiment with global variables to keep some of these values from state to state, and see if I can figure out the next stage independently! I appreciate it!

Cheers,

Loren

Link to comment
Share on other sites

Making progress!

Next issue: I would like three sets of "changed" events. (Each time the avatar drags an object onto the prim, I want each object name stored as a separate variable, for later use in generating the "recipe" "ingredient" list.

I tried this using while and a dynamic variable, but failed in the attempt.

I seem to have the trouble now that I can't use more than one "changed" event while in a given state. Do I need to separate the states here, to avoid the "Name previously declared within scope" error?

---

integer craftingStage;
string item1;
string item2;
string item3;

default
{
state_entry() // Initial Settings
{
integer craftingStage=0; // Crafting Stage starts at Zero
string item1 = "None"; // Placeholder variable for "item1"
string item2 = "None"; // Placeholder variable for "item2"
string item3 = "None"; // Placeholder variable for "item3"
llSetText("Click to start crafting", <1.0, 1.0, 1.0>, 1.0); // Set initial hover text
llAllowInventoryDrop(TRUE); // Allows non-owners to drop inventory into prim
} // Closes state_entry

touch_start(integer num_detected) // Touching the prim starts the Crafting loop
{
llSetText("Stage: "+(string)craftingStage+"\n Item 1: "+(string)item1+"\n Item 2: "+(string)item2+"\n Item 3: "+(string)item3, <1.0, 1.0, 1.0>, 1.0); // Set hover text to Crafting format
} // Closes touch_start

 

// <--- Do I need to separate states here, and again after each changed(integer change) event?

 

// Crafting Stage 1
changed(integer change)
{

if (change & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY)) // If non-owner adds item or owner adds item...
{
llSay(0, "Inventory changed."); //Say in local that the inventory has changed

integer index;
string itemName = llGetInventoryName(INVENTORY_ALL, index);
integer itemType = llGetInventoryType(itemName);

llSay(0, "The value craftingStage is " + (string)craftingStage);
llSay(0, "The value itemName is " + itemName);
llSay(0, "The value itemType is " + (string)itemType);
llSleep(0.1);
craftingStage = craftingStage + 1;
llSay(0, "The new value craftingStage is " + (string)craftingStage);

if ((integer)craftingStage == 1) { item1 = itemName; }
else if ((integer)craftingStage == 2) { item2 = itemName; }
else if ((integer)craftingStage == 3) { item3 = itemName; }
else { llSay(0, "Crafting Stage Error"); }

llSleep(0.1);
llSetText("Stage: "+(string)craftingStage+"\n Item 1: "+(string)item1+"\n Item 2: "+(string)item2+"\n Item 3: "+(string)item3, <1.0, 1.0, 1.0>, 1.0);
} // Closes if
} // Closes changed

 

// <-- Another place to change states?

 

// Crafting Stage 2
changed(integer change2)
{

if (change2 & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY)) // If non-owner adds item or owner adds item...
{
llSay(0, "Inventory changed."); //Say in local that the inventory has changed

integer index;
string itemName = llGetInventoryName(INVENTORY_ALL, index);
integer itemType = llGetInventoryType(itemName);

llSay(0, "The value craftingStage is " + (string)craftingStage);
llSay(0, "The value itemName is " + itemName);
llSay(0, "The value itemType is " + (string)itemType);
llSleep(0.1);
craftingStage = craftingStage + 1;
llSay(0, "The new value craftingStage is " + (string)craftingStage);

if ((integer)craftingStage == 1) { item1 = itemName; }
else if ((integer)craftingStage == 2) { item2 = itemName; }
else if ((integer)craftingStage == 3) { item3 = itemName; }
else { llSay(0, "Crafting Stage Error"); }

llSleep(0.1);
llSetText("Stage: "+(string)craftingStage+"\n Item 1: "+(string)item1+"\n Item 2: "+(string)item2+"\n Item 3: "+(string)item3, <1.0, 1.0, 1.0>, 1.0);
} // Closes if
} // Closes changed

 

// <-- Another place to change states?

 

// Crafting Stage 3
changed(integer change3)
{

if (change3 & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY)) // If non-owner adds item or owner adds item...
{
llSay(0, "Inventory changed."); //Say in local that the inventory has changed

integer index;
string itemName = llGetInventoryName(INVENTORY_ALL, index);
integer itemType = llGetInventoryType(itemName);

llSay(0, "The value craftingStage is " + (string)craftingStage);
llSay(0, "The value itemName is " + itemName);
llSay(0, "The value itemType is " + (string)itemType);
llSleep(0.1);
craftingStage = craftingStage + 1;
llSay(0, "The new value craftingStage is " + (string)craftingStage);

if ((integer)craftingStage == 1) { item1 = itemName; }
else if ((integer)craftingStage == 2) { item2 = itemName; }
else if ((integer)craftingStage == 3) { item3 = itemName; }
else { llSay(0, "Crafting Stage Error"); }

llSleep(0.1);
llSetText("Stage: "+(string)craftingStage+"\n Item 1: "+(string)item1+"\n Item 2: "+(string)item2+"\n Item 3: "+(string)item3, <1.0, 1.0, 1.0>, 1.0);
} // Closes if
} // Closes changed

 

// <-- Another place (last place) to change states?


// Cleanup Stage
state_exit()
{
llSay(0, "Cleanup Stage");
llSay(0, "Removing Item 1: " + item1);

if (item1!="inv_receivedetectrespond_protected") {
llRemoveInventory(item1);
} else {
llSay(0, "Protecting script from deletion!");
}
llSay(0, "Removing Item 2: " + item2);

if (item2!="inv_receivedetectrespond_protected") {
llRemoveInventory(item2);
} else {
llSay(0, "Protecting script from deletion!");
}
llSay(0, "Removing Item 3: " + item3);

if (item3!="inv_receivedetectrespond_protected") {
llRemoveInventory(item3);
} else {
llSay(0, "Protecting script from deletion!");
}
} // Closes state_entry
} // Closes default

 

 

Link to comment
Share on other sites

You're creating a monster.  :smileyvery-happy:

I was responding to your OP, concerning global variables, without paying much attention to the context of your specific scripting challenge.  What you're doing is collecting three objects, checking to see whether they are among the objects that you expect, and then performing a rewarding task if they are.  You don't need to do this with multiple states.  In fact, you create a lot of duplicated code (and a headache of chasing variables around) if you do it that way.  Map out the logic of the task.....

1. User drops something into your box.  (Additive A)

2. ++ Number of Objects Added.

    a. Is Number of Objects Added == 3?

        a.1  No >>> Proceed to Step 3

        a.2  Yes >>> Skip to step 8

3.  Is Additive A on the accepted list?

    a. No.>>> Delete Additive A, reset Number of Objects Added, and start over.

    b. Yes >>> Prompt user to add another object

4. User drops something else into your box (Additive B)

5.  Repeat steps 2 and 3. 

    a. If Yes >>> Is the combination of Additive A and Additive B going to lead to a possible prize?

        a.1   No. >>>> Delete Additives A and B, reset Number of Objects Added, and start over.

        a.2  Yes  >>>> Prompt user to add another object and proceed to Step 6

    b. If No >>> Delete Additives A and B, reset Number of Objects Added, and start over.

6.  ++Number of Objects Added.

    a.  Is Number of Objects Added == 3?

        a.1    No. >>> Proceed to step 7

        a.2    Yes >>> Skip to step 8

7. User drops a new object into your box (Additive C)

8.  Repeat steps 2 and 3.

    a. If Yes >>> Is the combination of Additive A and Additive B and Additive C going to lead to a possible prize?

        a.1   No >>> Delete Additives A and B and C, send condolences, reset Number of Objects Added, and start over.

        a.2  Yes  >>>> AWARD PRIZE, delate all objects, reset Number of Objects Added, and start over

   b. If No >>> Delete all additives, reset Number of Objects Added, and start over

9. End.

You can do all of that in a single state.  Each time someone drops a new object into your box, it triggers a changed event and your script is either at step 1, step 4, or step 8 in the schematic flow of logic.  You only need one changed event in one state, because there's no way you can be at more than one step in the logical flow at the same time.  And you always know which step you're at because you have kept track of Number of Objects Added (a global variable).

That's only a rough schematic, (hastily sketched, so I have probably done something inconsistent) but it's the sort of design you need to have created somewhere (in your head if not on paper) before you start writing a script.   Once you have that much done, then you can go back and add the important safeguards (What if some other Bozo comes along and drops something in?  What if THIS bozo gives up and walks away after dropping only one object in? What if this bozo waits too long to drop anything in? And so on and so on....)

 

  • Like 1
Link to comment
Share on other sites

Outstanidng!

I had a map on my whiteboard, so I'm glad to know that's appropriate for large-scale scripting, but I see some logical inconsistencies in my design as I read your analysis, and I think I understand!

I've made several changes to my prototype script in world, and I'm happy to report it's working as intended!

I was missing some key understandings about differentiating different variables, and most critically wasn't looking properly at the correct items in my llGetInventoryName and llGetInventoryType actions. I've made several major changes to both my approach and design, and I now have a script that is successfully identifying each prim as it comes in, storing its information, and deleting the prim to keep it empty and ready for the next thing.

Your help has been tremendous! Thank you!

You're right, of course, that there are safeguards that will need to be developed that are immediately apparent even to me: Bozo is right! I suppose I should look into keying the avatar with the initial click and rejecting anything coming from anybody else right in that state, thereby preventing "contamination" of the recipe. Additionally, a timeout is a GREAT idea, and I'll have to start looking into things like that...

...because after all, I started this project to learn! :D I'm excited. Thank you again, Rolig!

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3458 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...