Difference between revisions of "Prize Server Script (open source)"

From K.R. Engineering Support Wiki
Jump to: navigation, search
(Created page with "<pre> // Prize Server Script for K.R. Engineering Games. // Open source, developed by Karsten Rutledge. // October 6th, 2007 // *** DISCLAIMER *** // As of the writing of thi...")
 
Line 1: Line 1:
 
<pre>
 
<pre>
// Prize Server Script for K.R. Engineering Games.
+
// K.R. Engineering Prize Server Sample Script for Content Creators (full perm)
// Open source, developed by Karsten Rutledge.
+
// Written by Karsten Rutledge
// October 6th, 2007
+
// March 3rd, 2017
  
// *** DISCLAIMER ***
+
// This script is intended to serve both as a framework and as documentation on how to create 3rd-party objects that process and react to game events from K.R. Engineering games.
// As of the writing of this script, it is a violation of the Second Life Terms of Service for this server to award prizes of any value (L$ or objects otherwise considered to have value) to game winners if the winner of that game had to pay a 'consideration' (pay-to-play) to the game in order to participate. K.R. Engineering can not be held liable if the owners of this script and/or server choose to use it in a way that violates this policy.
+
// ******************
+
  
// If there are any suggestions or features you'd like to see added to this game API, please contact Karsten Rutledge.
+
// This script is designed to work with Gaming.SL LIVE enabled games that support the new API Framework.
  
// ========= BEGIN PRIZE SERVER CODE =========
+
// For additional information about the prize server API, please visit our Support Wiki at http://wiki.karstenrutledge.com/
  
// Initialization function.
+
// Default runtime state.
init() {
+
    // We need debit perms to do payouts.
+
    llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
+
}
+
 
+
// Default program state.
+
 
default {
 
default {
     state_entry() {
+
     // Incoming messages from other scripts. Specifically from the Prize Server API script which should also be in the contents of the same object that this script is in.
        // Call init on state entry (compile time) to get debit perms.
+
     link_message(integer sender, integer num, string message, key data) {
        init();
+
        // Only respond to "api event" messages.
    }
+
         if (message == "api event") {
    on_rez(integer param) {
+
             // All API events are in the format of:
        // Call init on on_rez (when the server is rezzed) to get debit perms.
+
             // data = game_uuid|game_name|game_model|game_version|game_license|API|api_event|event_specific_information|...|...|...
        init();
+
    }
+
    // The API Server Module will send us link messages containing information received from the games.
+
     link_message(integer sender, integer num, string message, key id) {
+
         if (message == "game joined") {
+
 
+
             // The value of 'id' is a pipe (|) delimited list of paramters. We can parse it by typecasting it to a string and then splitting it up.
+
             list info = llParseStringKeepNulls((string)id, ["|"], []);
+
            // This shold now be a list of [game table UUID, game type, game version, player name, player UUID];
+
            // For ease of use, let's break these up into single variables.
+
            key    gamekey    = (key)llList2String(info, 0);
+
            string  gamename    = llList2String(info, 1);
+
            float  gameversion = (float)llList2String(info, 2);
+
            string  playername  = llList2String(info, 3);
+
            key    playerkey  = (key)llList2String(info, 4);
+
 
              
 
              
             // Not doing anything here right now.
+
             // First turn the blob of data into a usable list variable that we can index.
 +
            list api_event = llParseStringKeepNulls((string)data, ["|"], []);
 
              
 
              
        } else if (message == "game left") {
+
            // Now break the list up into usable variables.
 +
            // These variables are consistent across all API event types. Other variables can be created based on the specific event type.
 +
            key game_uuid = (key)llList2String(api_event, 0);
 +
            string game_name = llList2String(api_event, 1);
 +
            // ^^^^ "Greedy Greedy", "Simopolis", etc...
 +
            string game_model = llList2String(api_event, 2);
 +
            // ^^^^ As of the time of this writing, the only game model is "Standard", but there may be more in the future.
 +
            string game_version = llList2String(api_event, 3);
 +
            // ^^^^ We're using a string type for version because it is in the format of MAJOR.MINOR.MAINT such as 3.2.12 which is not a float type.
 +
            key game_license = (key)llList2String(api_event, 4);
 +
            // We skip over api_event[5] because that is always just "API".
 +
            string event_type = llList2String(api_event, 6);
 +
            // =============================
 +
           
 +
            // If/elseif structure to determine behaviour based on event_type.
 +
            if (event_type == "STATE") {
 +
                // Game state has changed.
 +
               
 +
                // Set up event-specific variables.
 +
                string game_state = llList2String(api_event, 7);
 +
                // ==========================
 +
               
 +
                if (game_state == "RESET") {
 +
                    // Game was reset.
 +
                } else if (game_state == "STARTED") {
 +
                    // A new game has started.
 +
                } else if (game_state == "ENDED") {
 +
                    // A game is over. We will probably be getting a WON API event following this, dealt with below.
 +
                    // This is not for winning stuff. This is just to say that the game is over and done.
 +
                }
 +
            } else if (event_type == "PLAYER JOIN") {
 +
                // A player has joined the game.
 +
   
 +
                // Set up event-specific variables.
 +
                integer player_index = llList2Integer(api_event, 7);
 +
                // ^^^^ player_index is the position they joined the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
 +
                key player_uuid = (key)llList2String(api_event, 8);
 +
                // ==========================
 +
               
 +
                // Keep track of player data here.
 +
            } else if (event_type == "PLAYER LEFT") {
 +
                // A player has left the game.
 +
   
 +
                // Set up event-specific variables.
 +
                integer player_index = llList2Integer(api_event, 7);
 +
                // ^^^^ player_index is the position they occupied prior to leaving the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
 +
                key player_uuid = (key)llList2String(api_event, 8);
 +
                // ==========================
 +
               
 +
                // Clean up player data here.
 +
            } else if (event_type == "PLAYER SCORE") {
 +
                // A player's score has changed, for better or worse.
  
            // The value of 'id' is a pipe (|) delimited list of paramters. We can parse it by typecasting it to a string and then splitting it up.
+
                // Set up event-specific variables.
             list info = llParseStringKeepNulls((string)id, ["|"], []);
+
                integer player_index = llList2Integer(api_event, 7);
            // This shold now be a list of [game table UUID, game type, game version, player name, player UUID];
+
                // ^^^^ player_index is the position they occupied prior to leaving the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
            // For ease of use, let's break these up into single variables.
+
                key player_uuid = (key)llList2String(api_event, 8);
            key     gamekey    = (key)llList2String(info, 0);
+
                integer player_score = llList2Integer(api_event, 9);
            string gamename    = llList2String(info, 1);
+
                // ==========================
            float  gameversion = (float)llList2String(info, 2);
+
               
            string playername  = llList2String(info, 3);
+
                // Score change stuff here.
            key    playerkey  = (key)llList2String(info, 4);
+
                // In the case of team games, you should receive a separate score change event for each player on the team.
 +
             } else if (event_type == "ACHIEVEMENT") {
 +
                // A player was awarded an achievement.
 +
   
 +
                // Set up event-specific variables.
 +
                key player_uuid = (key)llList2String(api_event, 7);
 +
                string player_name = llList2String(api_event, 8);
 +
                string achievement_name = llList2String(api_event, 9);
 +
                // ==========================
 +
               
 +
                // Hooray, achievement?
 +
            } else if (event_type == "TURN") {
 +
                // The turn has changed.
 +
   
 +
                // Set up event-specific variables.
 +
                integer player_turn = llList2Integer(api_event, 7);
 +
                // ==========================
 +
               
 +
                if (player_turn) {
 +
                    // It is Player (player_turn)'s turn.
 +
                    // Do stuff that should be triggered by turn changes here.
 +
                } else {
 +
                    // A false player turn (player_turn == 0) means that it is currently NOBODY'S TURN.
 +
                    // This probably means nobody is sitting at the game currently, or the game is otherwise waiting for something to happen.
 +
                }
 +
            } else if (event_type == "ROUND") {
 +
                // The round has advanced.
 +
                // Not all games have 'rounds'.
 +
   
 +
                // Set up event-specific variables.
 +
                integer game_round = llList2Integer(api_event, 7);
 +
                // ==========================
 +
               
 +
                // Do stuff that should be triggered on round changes.
 +
                // This event, if applicable, happens when one round has ended and a new one has started.
 +
                // The idea of what is a "round" varies from game to game. For some games it simply means all players have taken a turn and come back
 +
                // to the first player again (Greedy Greedy). For other games, it may mean a specific criteria has been reached to terminate the end of a round (Hearts for example, meaning all cards have been played).
 +
            } else if (event_type == "EVENT") {
 +
                // Amusingly, EVENT is also an event type.
 +
                // The EVENT event happens when something happens to a player in the game.
 +
                // Super descriptive, right?
 +
                // Basically this is a way for the game signal that something good or bad happened to a player, in various degrees of severity.
 +
                // What these events are and what happens during them is entirely up to the game in question, but we try to provide you with enough information here
 +
                // that you could have generic reactions to "good" or "bad" game events, or process specific events for specific games if you wish.
 +
               
 +
                // **************
 +
                // For lists of game-specific events that can be sent, please visit our Support Wiki at http://wiki.karstenrutledge.com/
 +
                // **************
 +
               
 +
                // Set up event-specific variables.
 +
                // player index|player uuid|type|severity|subtype|subtype_specific_details|...|...|...
 +
                integer player_index = llList2Integer(api_event, 7);
 +
                // ^^^^ player_index is the position they occupied prior to leaving the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
 +
                key player_uuid = (key)llList2String(api_event, 8);
 +
                string game_event_type = llList2String(api_event, 9);
 +
                integer game_event_severity = llList2Integer(api_event, 10);
 +
                string game_event_subtype = llList2String(api_event, 11);
 +
                // Other variables can be set up based on the specific subtype.
 +
                // ==========================
 +
               
 +
                if (game_event_type == "GOOD") {
 +
                    // Something good happened to the player.
 +
                    // game_event_severity goes from 1 (a tiny bit good) to 5 (life changing, miraculous, etc.)
 +
                   
 +
                    // Generic good event stuff.
 +
                } else if (game_event_type == "BAD") {
 +
                    // Something bad happened to the player.
 +
                    // game_event_severity goes from 1 (a tiny bit bad) to 5 (catastrophic, suicide-inducing, etc...)
 +
                   
 +
                    // Subtype example for Greedy Greedy.
 +
                    if (game_name == "Greedy Greedy" && game_event_subtype == "BUSTED") {
 +
                        // It was a bad event, and specifically they busted (rolled nothing of value).
 
                          
 
                          
            // Not doing anything here right now.
+
                        // Sub type specific variables.
           
+
                        integer points_lost = llList2Integer(api_event, 12);
        } else if (message == "game reset") {
+
                        // ^^^^ How many points they lost when they busted.
 
+
                        // ==========================
            // The value of 'id' is a pipe (|) delimited list of paramters. We can parse it by typecasting it to a string and then splitting it up.
+
                       
            list info = llParseStringKeepNulls((string)id, ["|"], []);
+
                        // WOMP WOMP.
            // This shold now be a list of [game table UUID, game type, game version];
+
                    } else {
            // For ease of use, let's break these up into single variables.
+
                        // Generic bad event stuff
            key    gamekey    = (key)llList2String(info, 0);
+
                    }
            string  gamename    = llList2String(info, 1);
+
                } else if (game_event_type == "NEUTRAL") {
             float  gameversion = (float)llList2String(info, 2);
+
                    // Something neutral happened to the player.
 
+
                    // game_event_severity doesn't have a whole lot of meaning here, I guess. This is for events that aren't good or bad, but still noteworthy.
            // Not doing anything here right now.
+
                   
 
+
                    // Generic neutral event stuff.
        } else if (message == "game started") {
+
                }
           
+
               
            // This command was added in v1.1 of the prize script, and may not work on older games.
+
             } else if (event_type == "WON") {
 
+
                // One or more players have won the game.
            // The value of 'id' is a pipe (|) delimited list of paramters. We can parse it by typecasting it to a string and then splitting it up.
+
   
            list info = llParseStringKeepNulls((string)id, ["|"], []);
+
                // Set up event-specific variables.
            // This shold now be a list of [game table UUID, game type, game version];
+
                // A lot of this information may be redundant if you've been keeping track of it up until now. This redundancy is carryover from the game uploading end-of-game data to the G.SL server.
            // For ease of use, let's break these up into single variables.
+
                // comma-sep-winners|winners_score|comma-sep-participants|comma-sep-participant-scores|comma-sep-player-counts(final,min,max)|comma-sep-options|duration
            key    gamekey    = (key)llList2String(info, 0);
+
                list winners = llParseString2List(llList2String(api_event, 7), [","], []);
            string  gamename    = llList2String(info, 1);
+
                // The UUID(s) of the winner(s). There can be more than one winner in the case of ties or in the case of teams winning.
            float  gameversion = (float)llList2String(info, 2);
+
                integer winning_score = llList2Integer(api_event, 8);
 
+
                // The score that the winner(s) had at the end of the game. Depending on the game, this might be the lowest score, highest score, or a total nonsense score.
            // Not doing anything here right now.
+
                // This is a single number, even if there are multiple winners, because all winners would have the same score, or else there wouldn't be more than one of them.
 
+
                list all_players = llParseStringKeepNulls(llList2String(api_event, 9), [","], []);
        } else if (message == "game score") {
+
                // UUID list of all players who were playing the game. This includes anyone who LOST at some point during the game.
           
+
                list all_scores = llParseStringKeepNulls(llList2String(api_event, 10), [","], []);
            // Only available on newer game tables, including Greedy v1.95 and newer.
+
                // List of the final scores of all players playing the game. This is index-matched to the all_players list above.
            // The value of 'id' is a pipe (|) delimited list of paramters. We can parse it by typecasting it to a string and then splitting it up.
+
                // index-matched means llList2Integer(all_scores, N) will give you the correct score for llList2Key(all_scores, N) where N is the same for both.
            list info = llParseStringKeepNulls((string)id, ["|"], []);
+
                list player_counts = llParseStringKeepNulls(llList2String(api_event, 11), [","], []);
            // This shold now be a list of [game table UUID, game type, game version, winner name, winner UUID, total buyin on table, total players];
+
                integer final_players = llList2Integer(player_counts, 0);
            // For ease of use, let's break these up into single variables.
+
                // ^^^^ number of players still at the game when it ended.
            key    gamekey    = (key)llList2String(info, 0);
+
                integer min_players = llList2Integer(player_counts, 1);
            string  gamename    = llList2String(info, 1);
+
                // ^^^^ Lowest concurrent number of players during the game's entire duration.
            float  gameversion = (float)llList2String(info, 2);
+
                integer max_players = llList2Integer(player_counts, 2);
            string  playername  = llList2String(info, 3);
+
                // ^^^^ Highest concurrent number of players during the game's entire duration.
            key    playerkey  = (key)llList2String(info, 4);
+
                list game_options = llParseStringKeepNulls(llList2String(api_event, 12), [","], []);
            integer score      = (integer)llList2String(info, 5);
+
                // ^^^^ This is a list of options that the game was played under. These are the same options on the Gaming.SL website for this game. Some games have no options, some have a couple, some have a lot.
           
+
                integer duration = llList2Integer(api_event, 13);
            // Not doing anything here right now. This gets triggered any time a player's score changes, either up or down.
+
                // Duration of the game in seconds.
 
+
                // ==========================
        } else if (message == "game won") {
+
               
           
+
                // Do winner stuff here. Money, hookers, booze! Or whatever, we're not judging.
            // The value of 'id' is a pipe (|) delimited list of paramters. We can parse it by typecasting it to a string and then splitting it up.
+
             } else if (event_type == "LOST") {
            list info = llParseStringKeepNulls((string)id, ["|"], []);
+
                 // A player has lost the game.
            // This shold now be a list of [game table UUID, game type, game version, winner name, winner UUID, total buyin on table, total players];
+
               
            // For ease of use, let's break these up into single variables.
+
                // Not all games will send LOST messages.
            key    gamekey    = (key)llList2String(info, 0);
+
                // LOST messages are for elimination based games where a player can be removed from the game, but other players are still playing.
            string  gamename    = llList2String(info, 1);
+
                // Example of this would be Simopolis (Monopoly) where one player can go bankrupt, thus losing the game, but a final winner hasn't been determined yet.
            float  gameversion = (float)llList2String(info, 2);
+
               
            string  winnername  = llList2String(info, 3);
+
                 // When a WON event is triggered, it is assumed that any remaining players have lost, but no specific LOST events will be called for each loser during a WON event.
            key    winnerkey  = (key)llList2String(info, 4);
+
               
            integer totalfees  = (integer)llList2String(info, 5);
+
                // Set up event-specific variables.
            integer numplayers  = (integer)llList2String(info, 6);
+
                integer player_index = llList2Integer(api_event, 7);
            // These parameters were added in v1.1 of the prize script, and may not work on older games.
+
                // ^^^^ player_index is the position they joined the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
             integer gametime    = 0;
+
                 key player_uuid = (key)llList2String(api_event, 8);
            if (llGetListLength(info) >= 8) {
+
                // ==========================
                 // Only set if the game actually sent that info, because this was added on newer model games.
+
           
                 // This is the total duration of the game in seconds.
+
                // A player lost. Whatever, I guess.
                 gametime        = (integer)llList2String(info, 7);
+
 
             }
 
             }
            integer division    = 1;
 
            if (llGetListLength(info) >= 9) {
 
                // Only set if the game actually sent that info, because this was added on newer model games.
 
                // This is in the case of multiple winners, how many people are we dividing the profits to.
 
                // This should be backwards compatible, for older games that don't send this information
 
                // we will simply assume there is no division (divided by 1).
 
                division        = (integer)llList2String(info, 8);
 
            }
 
            integer winnerscore = -1;
 
            integer winnerbets = -1;
 
            integer winnershare = -1;
 
            if (llGetListLength(info) >= 10) {
 
                // Only available on newer games.
 
                // Winnerscore is, of course, the winner's score at the time of winning.
 
                winnerscore    = (integer)llList2String(info, 9);
 
                // Winnerbets is the total amount of bet money this player put in to the game, does not include pay to play fees, as this information is already available in totalfees.
 
                winnerbets      = (integer)llList2String(info, 10);
 
                // Winnershare is the amount the winner actually got paid by the internal prize server on the game.
 
                winnershare    = (integer)llList2String(info, 11);
 
            }
 
            // Below this line is several examples of ways to 'award' a winner of a game.
 
           
 
 
           
 
                                   
 
            // === BEGIN PRIZE OPTION 1: Give a random object in inventory ===
 
            integer givetype = INVENTORY_OBJECT;
 
            // ^^^ If for some reason you want to give a random notecard, you could change givetype to INVENTORY_NOTECARD.
 
            if (llGetInventoryNumber(givetype)) {
 
                // ^^^ Verify that there's something in our inventory to give first.
 
                integer randprize = (integer)llFrand((float)llGetInventoryNumber(givetype));
 
                // ^^^ random number between 0 and the amount of that type of item we have.
 
                llGiveInventory(winnerkey, llGetInventoryName(givetype, randprize));
 
                // ^^^ pass the winner's UUID from the info variable to llGiveInventory along with the random item name from inventory. They should receive it nearly instantly.
 
            }
 
            // === END PRIZE OPTION 1: Give a random object in inventory ===
 
 
 
 
 
            // === BEGIN PRIZE OPTION 2: Pay the player a portion of the pay-to-play fees collected from the table ===
 
            float prizepercent = 0.9;
 
            // If there were no fees paid into the table, that means the table was free-to-play, no prizes for that.
 
            // ^^^ This can be looked at like a percentage. 0.9 is 90% (default). 1.00 is 100%. 0.0 would be 0%.
 
            // This is the percentage of the total fees that we're going to give to the player. By giving them 90% of the fees,
 
            // That means the 'house' is keeping 10% of what was paid into the table.
 
            // Change prizepercent to 0.0 to disable paying money as a prize.
 
            if (prizepercent != 0.0 && totalfees) {
 
                llGiveMoney(winnerkey, (integer)((float)totalfees * prizepercent) / division);
 
            }
 
            // === END PRIZE OPTION 2: Pay the player a portion of the pay-to-play fees collected from the table ===
 
           
 
 
 
 
            // === BEGIN PRIZE OPTION 3: Pay the player a fixed amount. ===
 
            integer payout = 0;
 
            // ^^^ Change payout variable to something other than 0 if you want this to work.
 
            if (payout && numplayers > 1) {
 
                // ^^^ Only payout if more than 1 person is playing. In other words, no money if they're playing the game repeatedly by themselves just for the money.
 
                llGiveMoney(winnerkey, payout / division);
 
            }
 
            // === END PRIZE OPTION 3: Pay the player a fixed amount. ===
 
 
           
 
                                   
 
           
 
            // ===========================================
 
            // You can of course write your own prize giving routines here, these are just some examples. By default, if you use this script as-is (as it was originally written),
 
            // then it will pay 90% of game earnings to the winner and if there are any objects in the inventory of this server, it will give them a random one. If you don't
 
            // put any objects in the inventory of this server, it will just pay them the 90% and do nothing else.
 
            // ===========================================
 
           
 
 
         }
 
         }
 
     }
 
     }

Revision as of 01:35, 20 June 2018

// K.R. Engineering Prize Server Sample Script for Content Creators (full perm)
// Written by Karsten Rutledge
// March 3rd, 2017

// This script is intended to serve both as a framework and as documentation on how to create 3rd-party objects that process and react to game events from K.R. Engineering games.

// This script is designed to work with Gaming.SL LIVE enabled games that support the new API Framework.

// For additional information about the prize server API, please visit our Support Wiki at http://wiki.karstenrutledge.com/

// Default runtime state.
default {
    // Incoming messages from other scripts. Specifically from the Prize Server API script which should also be in the contents of the same object that this script is in.
    link_message(integer sender, integer num, string message, key data) {
        // Only respond to "api event" messages.
        if (message == "api event") {
            // All API events are in the format of:
            // data = game_uuid|game_name|game_model|game_version|game_license|API|api_event|event_specific_information|...|...|...
            
            // First turn the blob of data into a usable list variable that we can index.
            list api_event = llParseStringKeepNulls((string)data, ["|"], []);
            
            // Now break the list up into usable variables.
            // These variables are consistent across all API event types. Other variables can be created based on the specific event type.
            key game_uuid = (key)llList2String(api_event, 0);
            string game_name = llList2String(api_event, 1);
            // ^^^^ "Greedy Greedy", "Simopolis", etc...
            string game_model = llList2String(api_event, 2);
            // ^^^^ As of the time of this writing, the only game model is "Standard", but there may be more in the future.
            string game_version = llList2String(api_event, 3);
            // ^^^^ We're using a string type for version because it is in the format of MAJOR.MINOR.MAINT such as 3.2.12 which is not a float type.
            key game_license = (key)llList2String(api_event, 4);
            // We skip over api_event[5] because that is always just "API".
            string event_type = llList2String(api_event, 6);
            // =============================
            
            // If/elseif structure to determine behaviour based on event_type.
            if (event_type == "STATE") {
                // Game state has changed.
                
                // Set up event-specific variables.
                string game_state = llList2String(api_event, 7);
                // ==========================
                
                if (game_state == "RESET") {
                    // Game was reset.
                } else if (game_state == "STARTED") {
                    // A new game has started.
                } else if (game_state == "ENDED") {
                    // A game is over. We will probably be getting a WON API event following this, dealt with below.
                    // This is not for winning stuff. This is just to say that the game is over and done.
                }
            } else if (event_type == "PLAYER JOIN") {
                // A player has joined the game.
    
                // Set up event-specific variables.
                integer player_index = llList2Integer(api_event, 7);
                // ^^^^ player_index is the position they joined the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
                key player_uuid = (key)llList2String(api_event, 8);
                // ==========================
                
                // Keep track of player data here.
            } else if (event_type == "PLAYER LEFT") {
                // A player has left the game.
    
                // Set up event-specific variables.
                integer player_index = llList2Integer(api_event, 7);
                // ^^^^ player_index is the position they occupied prior to leaving the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
                key player_uuid = (key)llList2String(api_event, 8);
                // ==========================
                
                // Clean up player data here.
            } else if (event_type == "PLAYER SCORE") {
                // A player's score has changed, for better or worse.

                // Set up event-specific variables.
                integer player_index = llList2Integer(api_event, 7);
                // ^^^^ player_index is the position they occupied prior to leaving the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
                key player_uuid = (key)llList2String(api_event, 8);
                integer player_score = llList2Integer(api_event, 9);
                // ==========================
                
                // Score change stuff here.
                // In the case of team games, you should receive a separate score change event for each player on the team.
            } else if (event_type == "ACHIEVEMENT") {
                // A player was awarded an achievement.
    
                // Set up event-specific variables.
                key player_uuid = (key)llList2String(api_event, 7);
                string player_name = llList2String(api_event, 8);
                string achievement_name = llList2String(api_event, 9);
                // ==========================
                
                // Hooray, achievement?
            } else if (event_type == "TURN") {
                // The turn has changed.
    
                // Set up event-specific variables.
                integer player_turn = llList2Integer(api_event, 7);
                // ==========================
                
                if (player_turn) {
                    // It is Player (player_turn)'s turn.
                    // Do stuff that should be triggered by turn changes here.
                } else {
                    // A false player turn (player_turn == 0) means that it is currently NOBODY'S TURN.
                    // This probably means nobody is sitting at the game currently, or the game is otherwise waiting for something to happen.
                }
            } else if (event_type == "ROUND") {
                // The round has advanced.
                // Not all games have 'rounds'.
    
                // Set up event-specific variables.
                integer game_round = llList2Integer(api_event, 7);
                // ==========================
                
                // Do stuff that should be triggered on round changes.
                // This event, if applicable, happens when one round has ended and a new one has started.
                // The idea of what is a "round" varies from game to game. For some games it simply means all players have taken a turn and come back
                // to the first player again (Greedy Greedy). For other games, it may mean a specific criteria has been reached to terminate the end of a round (Hearts for example, meaning all cards have been played).
            } else if (event_type == "EVENT") {
                // Amusingly, EVENT is also an event type.
                // The EVENT event happens when something happens to a player in the game.
                // Super descriptive, right?
                // Basically this is a way for the game signal that something good or bad happened to a player, in various degrees of severity.
                // What these events are and what happens during them is entirely up to the game in question, but we try to provide you with enough information here
                // that you could have generic reactions to "good" or "bad" game events, or process specific events for specific games if you wish.
                
                // **************
                // For lists of game-specific events that can be sent, please visit our Support Wiki at http://wiki.karstenrutledge.com/
                // **************
                
                // Set up event-specific variables.
                // player index|player uuid|type|severity|subtype|subtype_specific_details|...|...|...
                integer player_index = llList2Integer(api_event, 7);
                // ^^^^ player_index is the position they occupied prior to leaving the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
                key player_uuid = (key)llList2String(api_event, 8);
                string game_event_type = llList2String(api_event, 9);
                integer game_event_severity = llList2Integer(api_event, 10);
                string game_event_subtype = llList2String(api_event, 11);
                // Other variables can be set up based on the specific subtype.
                // ==========================
                
                if (game_event_type == "GOOD") {
                    // Something good happened to the player.
                    // game_event_severity goes from 1 (a tiny bit good) to 5 (life changing, miraculous, etc.)
                    
                    // Generic good event stuff.
                } else if (game_event_type == "BAD") {
                    // Something bad happened to the player.
                    // game_event_severity goes from 1 (a tiny bit bad) to 5 (catastrophic, suicide-inducing, etc...)
                    
                    // Subtype example for Greedy Greedy.
                    if (game_name == "Greedy Greedy" && game_event_subtype == "BUSTED") {
                        // It was a bad event, and specifically they busted (rolled nothing of value).
                        
                        // Sub type specific variables.
                        integer points_lost = llList2Integer(api_event, 12);
                        // ^^^^ How many points they lost when they busted.
                        // ==========================
                        
                        // WOMP WOMP.
                    } else {
                        // Generic bad event stuff
                    }
                } else if (game_event_type == "NEUTRAL") {
                    // Something neutral happened to the player.
                    // game_event_severity doesn't have a whole lot of meaning here, I guess. This is for events that aren't good or bad, but still noteworthy.
                    
                    // Generic neutral event stuff.
                }
                
            } else if (event_type == "WON") {
                // One or more players have won the game.
    
                // Set up event-specific variables.
                // A lot of this information may be redundant if you've been keeping track of it up until now. This redundancy is carryover from the game uploading end-of-game data to the G.SL server.
                // comma-sep-winners|winners_score|comma-sep-participants|comma-sep-participant-scores|comma-sep-player-counts(final,min,max)|comma-sep-options|duration
                list winners = llParseString2List(llList2String(api_event, 7), [","], []);
                // The UUID(s) of the winner(s). There can be more than one winner in the case of ties or in the case of teams winning.
                integer winning_score = llList2Integer(api_event, 8);
                // The score that the winner(s) had at the end of the game. Depending on the game, this might be the lowest score, highest score, or a total nonsense score.
                // This is a single number, even if there are multiple winners, because all winners would have the same score, or else there wouldn't be more than one of them.
                list all_players = llParseStringKeepNulls(llList2String(api_event, 9), [","], []);
                // UUID list of all players who were playing the game. This includes anyone who LOST at some point during the game.
                list all_scores = llParseStringKeepNulls(llList2String(api_event, 10), [","], []);
                // List of the final scores of all players playing the game. This is index-matched to the all_players list above.
                // index-matched means llList2Integer(all_scores, N) will give you the correct score for llList2Key(all_scores, N) where N is the same for both.
                list player_counts = llParseStringKeepNulls(llList2String(api_event, 11), [","], []);
                integer final_players = llList2Integer(player_counts, 0);
                // ^^^^ number of players still at the game when it ended.
                integer min_players = llList2Integer(player_counts, 1);
                // ^^^^ Lowest concurrent number of players during the game's entire duration.
                integer max_players = llList2Integer(player_counts, 2);
                // ^^^^ Highest concurrent number of players during the game's entire duration.
                list game_options = llParseStringKeepNulls(llList2String(api_event, 12), [","], []);
                // ^^^^ This is a list of options that the game was played under. These are the same options on the Gaming.SL website for this game. Some games have no options, some have a couple, some have a lot.
                integer duration = llList2Integer(api_event, 13);
                // Duration of the game in seconds.
                // ==========================
                
                // Do winner stuff here. Money, hookers, booze! Or whatever, we're not judging.
            } else if (event_type == "LOST") {
                // A player has lost the game.
                
                // Not all games will send LOST messages.
                // LOST messages are for elimination based games where a player can be removed from the game, but other players are still playing.
                // Example of this would be Simopolis (Monopoly) where one player can go bankrupt, thus losing the game, but a final winner hasn't been determined yet.
                
                // When a WON event is triggered, it is assumed that any remaining players have lost, but no specific LOST events will be called for each loser during a WON event.
                
                // Set up event-specific variables.
                integer player_index = llList2Integer(api_event, 7);
                // ^^^^ player_index is the position they joined the game. If they sat in the first chair, they are "player 1", if they sat in the second chair, they are "player 2", etc.
                key player_uuid = (key)llList2String(api_event, 8);
                // ==========================
             
                // A player lost. Whatever, I guess.
            }
        }
    }
}