Jump to content

Mystery Prize script - problem with timer?


GloriaGlitter
 Share

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

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

Recommended Posts

Hi there - I am working with a 'mystery prize' script that I found in the library that I have simplified to remove unwanted options etc.  The concept is that the script picks a letter at random and selects a random prize.  If someone's names begins or ends with the selected letter, then they can touch the object and collect the mystery prize.  The letter and prize resets after a set period of time.

The script works about 90% of the time but occasionally it will reset itself twice or three times right after each other rather than once.  Also, I've set the interval to be two minutes for the sake of testing but occasionally the interval is only 1 minute and at another time it might be 3 minutes. 

I think perhaps that there is a conflict with the timer. 

Once I get this part working properly, I will try to to add in some extra code to display the amount of time left before the next reset so that avatars can decide whether to stay for the next reset.

Grateful for any suggestions as to why the script appears not to be consistent.  This is the script:

 

integer use_channel_output = 1; //do we want to shout on channels when someone wins a prize?
integer channel = -999; //the channel we will shout on IF we are shouting on channels
integer use_notify_owner = 1; //do we want to tell our owner when we give out prizes?
integer time_reset_minutes = 2; //how often do we need to reset and pick new random credentials?

//------------------------------------------------------------------------------
 
dotouch(key id) //function for when someone touches this prim
{
    integer winner = 0; //we currently do not have a winner
    string out = "\n"; //text output for user
   
        if(llToUpper(llGetSubString(llKey2Name(id),0,0))==name || llToUpper(llGetSubString(llKey2Name(id),-1,-1))==name)
        { //if the person who touched this prim has a first name that starts with the random letter or a last name that ends with the random letter we have a winner
            winner = 1;
        }else
        {
            out += "your name does not start with or end with "+name+"\n";
        }
    

    if(winner == 1)//if we have a winner
    {
        llSay(0,"CONGRATZ!!!!!!!!!!! YOU WIN");//tell the world
        payout(id);//give out the prize
        if(1==1)state get_rand;//refresh our credentials
    }else//if not tell the user they didnt win and why
    {
        llSay(0,"Sorry but"+out);
    }
}
 
 
dorandletter()//function to pick a random character
{
    integer purely_random = 0;
    integer i = 0;
   
        do{
            llSetText("PICKING A RANDOM LETTER....\n["+llGetSubString(charmap,purely_random,purely_random)+"]",<1,1,1>,1);
            purely_random = llFloor(llFrand(llStringLength(charmap)));
            i++;
        }while(i < 100);
        name = llGetSubString(charmap,purely_random,purely_random);
}


dorandominventory()//function to pick a random inventory item to give out.
{
    integer purely_random = 0;
    integer i = 0;
    do{
        purely_random = llFloor(llFrand(llGetInventoryNumber(INVENTORY_ALL)));
        string n = llGetInventoryName(INVENTORY_ALL,purely_random);
        if(n!=llGetScriptName() && n!="_config")
        {
            llSetText("PICKING A RANDOM ITEM \n["+n+"]",<1,1,1>,1);
            item = n;
        }
        i++;
    }while(i < 100);
}
string name;//the letter we have picked at random
string item;//the random inventory item we are giving away
string charmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";//list of characters in the form of a string.


random_contains()//fetch all our randomness
{
    dorandletter();//get the letter
    dorandominventory();//grab an item
    string sep = "\n";
    string line1 = "If your Name Starts OR Ends with the Letter "+name;
    string line4 = "Touch me for the Mystery Prize inside.";
    string out;
           out += line1+sep;
   
     out += line4+sep;
    //create the text and float it
    llSetText(out,<1,1,1>,1);
}

payout(key id)//function to give out the item to the winner.
{
   
    llGiveInventory(id,item);//give the item to the winner
    llSleep(3.0);//take a short break
    llParticleSystem([]);//kill the particles
    if(use_channel_output == 1)//if we are allowed to talk on channels do that now
    {
        llSay(channel,"MYSTERY_PAYOUT|"+(string)id);
    }
 
    if(use_notify_owner)//if we are allowed to tell our owner about the winner do that now
    {
        llInstantMessage(llGetOwner(),"gave "+item+" to "+llKey2Name(id));
    }
}


default
{
    on_rez(integer sp)
    {
        llResetScript();
    }
    changed(integer c)
    {
        if(c & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
    state_entry()
    {
       llSetText("CONFIGURING MYSTERY SYSTEM...",<1,1,1>,1);
       state get_rand;
    }
    
}
state get_rand
{
    on_rez(integer sp)
    {
        llResetScript();
    }
    changed(integer c)
    {
        if(c & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
    state_entry()
    {
       
        random_contains();
        state running;
    }
}
state running
{
    on_rez(integer sp)
    {
        llResetScript();
    }
    changed(integer c)
    {
        if(c & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
    state_entry()
    {
        llResetTime();
        llSetTimerEvent(1.0);
        llSay(0, "**reset**"); //for debug so I can check how often the timer is reset
    }
    
    timer()
    {
        float time = llGetTime();
        if((integer)time % (60*time_reset_minutes) == 0)
        {
            state get_rand;
        }
    }
    touch_start(integer total_number)
    {
        dotouch(llDetectedKey(0));
    }
}

 

Link to comment
Share on other sites

Just using the script with some test full perm objects as prizes but still getting some inconsistent behaviours such as multiple resetting after the elapsed time.  Is there something obvious with the timer that is causing this or another reason why it triggers multiple times every few cycles?  Thanks.

Link to comment
Share on other sites

5 hours ago, GloriaGlitter said:

Just using the script with some test full perm objects as prizes but still getting some inconsistent behaviours such as multiple resetting after the elapsed time.  Is there something obvious with the timer that is causing this or another reason why it triggers multiple times every few cycles?  Thanks.

Simplify the script by not using state, I would say, it is an overkill to use states for, what the prize script does.

For example when using state: "This means if the new state has a timer event, and the previous state has a timer set, the timer event in the new state will be triggered on the interval set in the previous state."

It can make a lot sense to use state ( aka Finite-state machine like an automata), but it is a balance between the logic on what is intended to be done and the handling of.

Below you can see an example of your script without states, cleaner and easier to understand. We just use a timer period and handle updating winner letter, winner item and touch within this.

I set time_reset_seconds to 20 seconds for testing, remember to change this to a more appropriate value in whole seconds, for example 15x60=900 for update every 15 minute or 3600 for once an hour.

// mystery prize script
integer use_channel_output = 1; //do we want to shout on channels when someone wins a prize?
integer channel = -999; //the channel we will shout on IF we are shouting on channels
integer use_notify_owner = 1; //do we want to tell our owner when we give out prizes?
integer time_reset_seconds = 20; //how often do we need to reset and pick new random credentials?
float time;string name;//the letter we have picked at random
string item;//the random inventory item we are giving away
string charmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";//list of characters in the form of a string.

//------------------------------------------------------------------------------
 
dotouch(key id) //function for when someone touches this prim
{
    string out = "\n"; //text output for user
    
    if(llToUpper(llGetSubString(llKey2Name(id),0,0))==name || llToUpper(llGetSubString(llKey2Name(id),-1,-1))==name)
    {
        //if the person who touched this prim has a first name that starts with the random letter or a last name that ends with the random letter we have a winner
    
        //tell the world
        llSay(0,"CONGRATZ!!!!!!!!!!! YOU WIN");
        
        //give out the prize
        payout(id);
        
        //refresh our credentials
        time = llGetTime();
        random_contains();
    }
    else
    {
        out += "your name does not start with or end with "+name+"\n";
        llSay(0,"Sorry but"+out);
    }
}
 
dorandletter()//function to pick a random character
{
    integer purely_random = 0;
    integer i = 0;
   
        do{
            llSetText("PICKING A RANDOM LETTER....\n["+llGetSubString(charmap,purely_random,purely_random)+"]",<1,1,1>,1);
            purely_random = llFloor(llFrand(llStringLength(charmap)));
            i++;
        }while(i < 100);
        name = llGetSubString(charmap,purely_random,purely_random);
}

dorandominventory()//function to pick a random inventory item to give out.
{
    integer purely_random = 0;
    integer i = 0;
    do{
        purely_random = llFloor(llFrand(llGetInventoryNumber(INVENTORY_ALL)));
        string n = llGetInventoryName(INVENTORY_ALL,purely_random);
        if(n!=llGetScriptName() && n!="_config")
        {
            llSetText("PICKING A RANDOM ITEM \n["+n+"]",<1,1,1>,1);
            item = n;
        }
        i++;
    }while(i < 100);
}

random_contains()//fetch all our randomness
{
    dorandletter();//get the letter
    dorandominventory();//grab an item
    string sep = "\n";
    string line1 = "If your Name Starts OR Ends with the Letter "+name;
    string line4 = "Touch me for the Mystery Prize inside.";
    string out;
           out += line1+sep;
   
     out += line4+sep;
    //create the text and float it
    llSetText(out,<1,1,1>,1);
}

payout(key id)//function to give out the item to the winner.
{
   
    llGiveInventory(id,item);//give the item to the winner
    llSleep(3.0);//take a short break
    llParticleSystem([]);//kill the particles
    if(use_channel_output == 1)//if we are allowed to talk on channels do that now
    {
        llSay(channel,"MYSTERY_PAYOUT|"+(string)id);
    }
 
    if(use_notify_owner)//if we are allowed to tell our owner about the winner do that now
    {
        llInstantMessage(llGetOwner(),"gave "+item+" to "+llKey2Name(id));
    }
}

default
{
    state_entry()
    {
       llSetText("CONFIGURING MYSTERY SYSTEM...",<1,1,1>,1);
       
        llResetTime();
        time = llGetTime();

        llSetTimerEvent(1.0);
        random_contains();
    }
    
    on_rez(integer sp)
    {
        llResetScript();
    }

    changed(integer c)
    {
        if(c & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }

    touch_start(integer total_number)
    {
        dotouch(llDetectedKey(0));
    }

    timer()
    {
        if (llGetTime()-time>time_reset_seconds)
        {
            time = llGetTime();
            
            //for debug so I can check how often the timer is reset
            llSay(0, "**reset** at "+ llGetTimestamp());
            
            random_contains();
        }
    }
}

 

Edited by Rachel1206
  • Thanks 1
Link to comment
Share on other sites

is always interesting about when and when not to use states. Some thoughts

in the OP script the use of states prevents the script from receiving user touches when the script is updating the prize criteria for the next round

state running -> state get_rand(random_contains(dorandletter(), dorandominventory()) -> state running

which is not necessarily a bad thing and can be a good thing when a script is giving out prizes to players

working this thru

suppose our game machine shows a red dress. We click and win! but we get a black dress. Without a state (or a linear coding switch) to prevent touches while updating this can happen when we Touch while the machine is updating from red dress to black dress

when we prevent touching in the updating state, the player gets nothing. As they should, because the red dress was for winning letter A, and the black dress is for winning letter B. A should not win a prize intended for B


on the OP script. Some more thoughts

the way the timer is coded is little bit overkill. This type of prize giving script doesn't need an effort to synchronise with realtime on a short timer like 1 second, given that the prize is only going to be updated on some much longer minutes interval

there is a place for realtime synchronisation on a fast timer. Like when moving objects for example. When a prize machine need only update itself every X minutes then not so much, so fire the timer event on that X

in OP script case, a example mod of the timer code

// take this out
// integer time_reset_minutes = 2;  

// use absolute X time
float time_reset_seconds = 120.0;

state running
{
   state_entry()
   {
      llSetTimerEvent(time_reset_seconds);
   }
    
   touch_start(integer total_number)
   {
       dotouch(llDetectedKey(0));
   }

   timer()
   {
       state get_rand;
   }

   state_exit()
   {
      llSetTimerEvent(0.0);
   }
}

 

  • Thanks 1
Link to comment
Share on other sites

So I've been running my script in my mystery prize giver about a week now - I've modified it a bit since so for instance it advises me when the no-copy prizes are running low and if the next mystery prize is the same as the previous random one then it selects another.  Also, a person can only collect a gift once in every time period e.g. every 5 minutes, and if they try again within the time period, they will get a message saying 'sorry you have already collected 'item'.....

I thought it had been running well but I have discovered a problem today that I do not know how to fix - which is that if person A has collected the gift and then person B comes along and clicks on the vendor, person B gets the message saying sorry you have already collected the gift when it was person A that got it.  I had assumed that the variable 'received' which gets set to 'y' after a gift has been given would only relate to the person that touched the object and not the next toucher.  This seems to be the bit that is going wrong - the script seems to remember the variable value from the previous toucher - any advice on how to fix this would be appreciated - I'll post my complete code below so you might be able to spot my issue - thanks in advance for any suggestions:

 // mystery prize script
string group_id="82d18b8d-82e9-d5fa-5b3b-57d6abfaf34a";
integer time_reset_seconds = 300; //how often do we need to reset and pick new random item
float time;

string item;//the random inventory item we are giving away

float t1=1;
float t2=1;
float t3=1;
vector color =<1,1,1>;
string received="n";
string olditem;
integer objectcount;

//------------------------------------------------------------------------------
integer rand(integer min, integer max)
{
    return min + (integer)(llFrand(max - min + 1));
}

string FormatDecimal(float number, integer precision)
{    
    float roundingValue = llPow(10, -precision)*0.5;
    float rounded;
    if (number < 0) rounded = number - roundingValue;
    else            rounded = number + roundingValue;
 
    if (precision < 1) // Rounding integer value
    {
        integer intRounding = (integer)llPow(10, -precision);
        rounded = (integer)rounded/intRounding*intRounding;
        precision = -1; // Don't truncate integer value
    }
 
    string strNumber = (string)rounded;
    return llGetSubString(strNumber, 0, llSubStringIndex(strNumber, ".") + precision);
}

countobjects()
{
   objectcount= llGetInventoryNumber( INVENTORY_OBJECT );
}

dorandominventory()//function to pick a random inventory item to give out.
{
    integer purely_random = 0;
    integer i = 0;
    countobjects();
    if (objectcount==0) return;
    
    do{
        purely_random = llFloor(llFrand(llGetInventoryNumber(INVENTORY_ALL)));
        string n = llGetInventoryName(INVENTORY_ALL,purely_random);
        if(n!=llGetScriptName() )
        {
         //   llSetText("PICKING A RANDOM ITEM \n["+n+"]",color,1);
            item = n;
        }
        i++;
    }while(i < 100);
   // llOwnerSay(item);
    if (objectcount==1) return;
    
     if (item==olditem)  
     {
    //  llOwnerSay("duplicate");   
      dorandominventory();
    
     }
}

random_contains()//fetch all our randomness
{
 t1= rand(0, 2); t1=t1/2; t2= rand(0, 2); t2=t2/2; t3= rand(0, 2); t3=t3/2; color=<t1,t2,t3>;
 
   if (t1 == 0 && t2 == 0 && t3 == 0) random_contains(); // since the initial texture is a white ? on black background, the color changer has effect of just changing the color of the ? - therefore I dont want a black ? on a black background
 
   llSetColor(color,4);
   dorandominventory();//grab an item
}


default
{
    state_entry()
    {
       llSetTexture("75514350-0a83-9207-a6ce-9e4d174b10b9",4);//question mark texture
       llResetTime();
       time = llGetTime();
       llSetTimerEvent(1.0);
       random_contains();
    }
    
    on_rez(integer sp)
    {
        llResetScript();
    }

   
    touch_start(integer total_number)
    {
        key target = llDetectedKey(0);
        string Name = llKey2Name(target);
        float time_left = (time_reset_seconds-(llGetTime()-time))/60;
        countobjects();
        if (objectcount==0)
        {
           llRegionSayTo(target, 0, "Sorry "+Name+", but the Mystery Gift Vendor is empty - the Owner has been informed.");
           return;
        }
        
         if (llDetectedGroup(0) )
        {
           if (received =="y")
           {
             llRegionSayTo(target, 0, "Sorry "+Name+", you have already collected a '"+item+"'. The next random gift will be available to collect in "+FormatDecimal(time_left, 2) +" minutes (when the ? in the middle of the picture changes color).");   
           }
           else
           {
         llRegionSayTo(target, 0,"Congatulations "+Name+ ", you have received a '"+item+"'. The next random gift will be available to collect in "+FormatDecimal(time_left, 2) +" minutes (when the ? in the middle of the picture changes color).");
         llGiveInventory(target,item);//give the item
         received = "y";
         countobjects();
       if (objectcount<10) llOwnerSay("Mystery Gift Giver has "+(string)objectcount+" items left");
         
           }
        }
        else
        {
        llRegionSayTo(target, 0, "Sorry "+Name+", you are showing the wrong active group! To get the mystery gift, either change the active group tag if you are already a member of secondlife:///app/group/" + group_id + "/about group, or click the link to join the group or click the Group Joiner, which is on the wall here or by the reception desk.");  
       }
    }

    timer()
    {
           if (llGetTime()-time>time_reset_seconds)
        {
            time = llGetTime();
            olditem=item;
            random_contains();
            received = "n";
          }
    }
}

Link to comment
Share on other sites

save into a list the uuids of the last X number of people to have received a gift

then when a person touches the machine, check to see if they are in the list, if so then "Sorry, you have" else Ok, give them a gift

example
 

list givento;

touch_start(...)
{
   key target = llDetectedKey(0);
   if (~llListFindList(givento, [target])
   {
       .. sorry you already have a gift ...
   }
   else
   {
       // add target to givento list
       // removing the most aged person when necessary
       // so to not run out of script memory  
       
       if (llGetListLength(givento) == 40) // change 40 to whichever
       {
          givento = llDeleteSubList(givento, 0, 0);
       }
       givento += [target];
       
       ... give gift to target ...
   }
}

 

Link to comment
Share on other sites

Thanks Mollymews for quick reply - I'll work on this in the morning when I get back on my PC - one thought though, a person is allowed to collect the next gift after the 5 minutes has passed, it is just that they are not allowed to collect the same gift more than once within the 5 minutes - will this amendment stop them collecting more than one gift in total?

Link to comment
Share on other sites

1 hour ago, GloriaGlitter said:

Thanks Mollymews for quick reply - I'll work on this in the morning when I get back on my PC - one thought though, a person is allowed to collect the next gift after the 5 minutes has passed, it is just that they are not allowed to collect the same gift more than once within the 5 minutes - will this amendment stop them collecting more than one gift in total?

make it so that the givento list is cleared/emptied on gift change. So that a person can not get more than one of the same gift, which changes every 5 minutes

  • Thanks 1
Link to comment
Share on other sites

Thanks Mollymews - that worked a treat - what I've learnt from this is that the variables are associated with the object running the script rather than the individual toucher.

But this has now revealed that I've got a bigger problem that might need a bit of a rethink.  In one of my mystery gift vendors the gifts are no-copy.  There are eight different dress designs of which I have been given about 50 copies of each by the designer.  So these are numbered dressA1, dressA2, dressA3.........dressA50, dressB1, dressB2, .....etc.  Suppose the next random gift is dressA20 which Person1 collects.  Person2 comes along within the time period and clicks the vendor - the vendor wants to give dressA20 but it is not there any more and so an error is displayed in the debug window. 

The easiest solution would be to try and persuade the designer to give me the items full perm but failing that, I think I have to rewrite part of the script so that the vendor gives a random item each touch from the items left but that a particular toucher is prevented from collecting another gift until the time is reset.  Also, to prevent the same item being given twice in a row, I'll try to match the previous item name to the next item name by comparing the item names minus the last 3 characters.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1548 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...