Gummi Gumball Machine

Written by: Headmaster

Found on the Second Life Scripting Library:

// example gummy gumball machine
// version 0.3
// Public Domain January 2015 irihapeti
//
// will give out all the gummys in the machine contents
// in some "random" order and then refill itself
// so that a player wont get 2 gummmys the same in a row
// and if they keep playing will get all the common gummys in
// best case: not less than gbM-1 turns [exactly 1 of each common
//  gummmy] and worst case: not greater than 2*gbM-3 turns
//
// for rares
//   if gbC = 3 and gbM = 5 (which incl. the rare) then rare is
//   guarantee to be given 1 in each set of 13. 3 * 4 + 1
//   altho from a players pov they more likely to play bc can get at
//   least 1 of each common in max 7 turns. 3 + 4 
//   if gbC = 4 and gbM = 5 then is still 7 for the commons. and now
//    4 * 4 + 1 = 17 for rare
//   the shortest period for rare is: 2
//   the longest period is: 1 + (gbM-1) * gbC * gbC
//   e.g: if gbM = 4 and gbC = 2 then 3 * 2 * 2 + 1 = 13 
//         | x123 123 | 123 123x |  where x = rare
//   gbM = 3. gbC = 2. 2 * 2 * 2 + 1 = 9
//         | x12 12 | 12 12x |
         
// usage: reset script after loading the gummys in machine
//        give permission for refunds
//        then just pay to play
 
// change these to whichever
integer gbP = 1;      // L$ price to play gummy gumball
integer gbC = 3;      // number of rounds in which 1 only rare will be given
string  gbN = "rare"; // name of the rare gummy
 
// internals
list    gbL;  // index list of gummys currently in play
list    gbW;  // listcopy of gummys in machine excluding rare
integer gbG;  // this gummy to give
integer gbI;  // indice of this gummy to give
integer gbJ;  // indice of this round
integer gbK;  // indice of rare round
integer gbM;  // total number of gummys in machine
integer gbQ;  // number of gummys for this round
integer gbR;  // indice of the rare gummy
key     gbY;  // key of last player

gbS() // shuffle n pick
{
    if ((++gbI) == gbQ)  // then shuffle
    { 
        if ((++gbJ) == gbC) // rounds exhausted so pick new rare round
        {
            gbK = (integer)llFrand(gbC);
            gbJ = 0;    
        }             

        integer n = llList2Integer(gbL, gbQ-1); // save last item of old list
        
	gbL = gbW;                              // get copy of commons
        if (gbJ == gbK) gbL += [gbR];           // add in rare if rare round  
        gbL = llListRandomize(gbL, 1);          // shuffle
        
	gbQ = llGetListLength(gbL);             // save length of new list
        integer m = llList2Integer(gbL, 0);     // get 1st item of new list    

        if (n == m)  // 1st of new list is same as last of old list so swap it to a later place
        {
            n = 1 + (integer)llFrand(gbQ - 1);
            gbL = [llList2Integer(gbL, n)] + llDeleteSubList(llListReplaceList(gbL, [m], n, n), 0, 0);
        }
        
	gbI = 0;  // reset the list index
    }
    
    // next gummy in list
    gbG = llList2Integer(gbL, gbI);
}

gbA()  // reset machine
{
   gbL = gbW;
   gbQ = gbM;
   gbI = gbQ-1;
   gbJ = gbC-1;    
   gbS();
}    

default
{
   state_entry()
   {
      // set machine

      gbM = llGetInventoryNumber(INVENTORY_OBJECT);
      if (gbM == 0)
      {
         llOwnerSay("is no gummys in machine");
         return;
      }

      // get gummys into list. mark the rare
      gbR = -1;
      gbW = [];
      integer i;
      for (i = 0; i < gbM; i++)
      {
         if (llGetInventoryName(INVENTORY_OBJECT, i) == gbN) 
            gbR = i;
         else
            gbW += [i];        
      }    
      if (gbR == -1)
      {
         llOwnerSay("hmm! cant find the rare: " + gbN 
            + ". check your typing ok");
         return;
      }
       
      // for refunding if SL bork
      llRequestPermissions(llGetOwner(), PERMISSION_DEBIT); 
    }
     
    run_time_permissions(integer perm)
    {
        if(perm & PERMISSION_DEBIT)
            state play;
    }
}
 
state play
{
   state_entry()
   { 
      llSetPayPrice(PAY_HIDE, [gbP, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
      llOwnerSay("gummy gumball is set to play. woohoo!");
   }

   money(key id, integer amount)
   {     
      if (amount != gbP) // shouldnt happen this but might if SL bork. is money so
      {
        if (amount > 0)
        { 
	   llGiveMoney(id, amount);
           llWhisper(0, "eep! you paid the wrong amount. "
              + "so we refund your L$" + (string)amount + " ok");
	}
        // if amount < 0 then is a serious SL serverside error like totally

        return;
      }

      // clocker defend. reset everytime is a new player
      if (id != gbY)
      {
         gbY = id;
         gbA();
      }
          
      // all good. so give gummy     
      llGiveInventory(id, llGetInventoryName(INVENTORY_OBJECT, gbG));
                
      if (gbG == gbR)  // then rare given. add bling here as you like
      {
         llWhisper(0, "woohoo! you got a rare gummy \\o/");
      }
      else // common given
      {
         llWhisper(0, "enjoy your gummy ok (:");
      }

      gbS();  // prep for next play
   }
}