// 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 == “LOADED”) {
// Game just loaded a new license.
} else if (event_type == “UNLOADED”) {
// Game just unloaded a license (currently unlicensed)
} else if (event_type == “SHUTDOWN”) {
// Game was shutdown (rezzer turned off)
} else 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.
}
}
}
}