Initialization and Ranking
First, Setting up the Cards
For a game like this to work, we need a way to store the game's cards somewhere where it will be easy to access, manage, and edit them. For this, we'll use the Game Data Service.
Creating a Data Type for Cards
First, we need to create a new Data Type and add index fields to it:
1. Go to Configurator > Game Data and click Add. The Add Data Type Index page opens.
2. Create a new cardTable Data Type:
- Enter a Short Code, Name, and Description.
3. Add the following index fields for the new Data Type:
- attack - Number
- health - Number
- spawnCost - Number
- tier - String
Once you've created the cardTable Data Type, its time to populate it. Each card will be it's own document, and the reasons why will become obvious later on in the tutorial.
Populating the Data Type with Cards
To populate your Data Type:
1. Go to Data Explorer. The new cardTable will be listed on the Data Types panel.
2. Select cardTable and click the Insert tab.
For our example card game, we'll need to create 3 cards as documents belonging to the cardTable Data Type. Each card will have a value for the fields we've indexed for the Data Type and to serve the following purposes:
- The tier.
- The base attack.
- The base health.
- The spawn cost.
3. Insert three documents into the cardTable Data Type for three common cards, as follows:
ID:archer
{
"spawnCost": 1,
"tier": "common",
"attack": 2,
"health": 2
}
ID:warrior
{
"spawnCost": 1,
"tier": "common",
"attack": 1,
"health": 3
}
ID:mage
{
"spawnCost": 1,
"tier": "common",
"attack": 3,
"health": 1
}
Creating a Data Type for Player Decks
It's worth noting that the ID of your card documents is important for finding the cards in a player's deck. Because you'll have to access the cards statistics when you pull it out during the game, then you need a convenient way of getting that card's statistics from the cardTable Data Type.
For this tutorial, we're going to be using the name of the card as the ID. So that means our player's deck will need to have the card's name, identical to the ID of the card's entry in the cardTable Data Type. To do this in the most convenient way, we're going to create a playerDeck Data Type, which is going to save our player's decks. This Data Type will not need any indexes because we're not going to query it. The entry IDs for this Data Type is going to be the player's ID, so it's easy to reference in Cloud Code. Here's an example of one player's entry:
{
"decks": {
"startingDeck": [
"warrior",
"mage",
"archer"
],
"Brute Deck": [
"warrior",
"clubber",
"ogre"
],
"Assassins": [
"dagger",
"rogue",
"archer"
]
},
"currentDeck": "startingDeck"
}
The string value 'currentDeck' just tells the game which deck the player is using at the moment.
You'd get that entry through the player's ID, like so:
var API = Spark.getGameDataService();
var entry = API.getItem("playerDeck",Spark.getPlayer().getPlayerId());
Player Initialization
We'll need to initialize our players once they're registered by creating their starting deck in the playerDeck Data Type and setting a default rank. To do this, we're going to create a new entry for the deck table and set the rank as scriptData for the player for easy access.
Head over to the Configurator > Cloud Code section. Once there, navigate to the Responses tab, expand it, and look for the RegistrationResponse. We'll edit our RegistrationReponse to look like this:
if(!Spark.hasScriptErrors() && Spark.getPlayer() != null){
//
var API = Spark.getGameDataService();
var entry = API.createItem("playerDeck", Spark.getPlayer().getPlayerId());
var data = entry.getData();
var decks = data.decks = {};
decks.startingDeck = ["warrior","mage","archer"];
data.currentDeck = "startingDeck";
var status = entry.persistor().persist().error();
if(status){
Spark.setScriptError("ERROR", status);
Spark.exit();
} else{
Spark.getPlayer().setScriptData("rank", 25);
Spark.getPlayer().setScriptData("stars", 0);
}
}
Our RegistrationResponse will set the player's rank to 25 with no stars. The response will also construct the player's deck by giving the player that registers 3 common tier cards. The deck will also be saved in playerDeck Data Type table instead of scriptData because once the player's deck gets bigger and if later you give your players a chance to make more decks, the player's details will get clogged. So we'll leave the deck in playerDeck table and retrieve it when we want to using an Event.
Ranking
When a player loses or wins in a ranked match, their rank and stars will be affected. So it's only logical to place this logic in the ChallengeWon and ChallengeLost messages, which can be found under the UserMessages tab in the Cloud Code section. Within these messages, we'll be calling a module which will process the ranking after the result of the Challenge.
ChallengeWonMessage:
//If it's a ranked match, process rank
if(Spark.getData().challenge.shortCode === "chalRanked")
{
//This player was victorious so declare the outcome to 'Victory'
var outcome = "victory";
//Depending on the outcome variable the 'processRank' module will either increase rank or decrease player rank
require("processRank");
}
ChallengeLostMessage:
//If it's a ranked match, process rank
if(Spark.getData().challenge.shortCode === "chalRanked")
{
//This player lost so declare the outcome to 'loss'
var outcome = "loss";
//Depending on the outcome variable the 'processRank' module will either increase rank or decrease player rank
require("processRank");
}
The processRank module moves the player up or down depending on the outcome of the Challenge.
The processRank module:
//Retrieve the number of stars the player earned
var currentStars = Spark.getPlayer().getScriptData("stars");
//Retrieve current rank
var currentRank = Spark.getPlayer().getScriptData("rank");
if(outcome === "victory"){
//Because the player just won, add a star
currentStars++;
//Save the number of stars the player has
Spark.getPlayer().setScriptData("stars", currentStars);
//Check for rank range
if(currentRank <= 25 && currentRank >= 21 ){
//Check for number of stars and if they qualify a levelup
if (currentStars >= 2){
//If number is met, level up by descending down towards rank 1
Spark.getPlayer().setScriptData("rank", currentRank - 1);
//Reset and save the number of current stars
Spark.getPlayer().setScriptData("stars", 0);
}
}
else if(currentRank <= 20 && currentRank >= 16 ){
//Check for number of stars and if they qualify a levelup
if (currentStars >= 3){
//If number is met, level up by descending down towards rank 1
Spark.getPlayer().setScriptData("rank", currentRank - 1);
//Reset and save the number of current stars
Spark.getPlayer().setScriptData("stars", 0);
}
}
else if(currentRank <= 15 && currentRank >= 11 ){
//Check for number of stars and if they qualify a levelup
if (currentStars >= 4){
//If number is met, level up by descending down towards rank 1
Spark.getPlayer().setScriptData("rank", currentRank - 1);
//Reset and save the number of current stars
Spark.getPlayer().setScriptData("stars", 0);
}
}
else{
//Don't do anything if player is rank 1 because they can't advance anymore
if(currentRank > 1)
{
//Check for number of stars and if they qualify a levelup
if (currentStars >= 5){
//If number is met, level up by descending down towards rank 1
Spark.getPlayer().setScriptData("rank", currentRank - 1);
//Reset and save the number of current stars
Spark.getPlayer().setScriptData("stars", 0);
}
}
}
}
else{
//Does the player have stars?
if(currentStars > 0){
//Because the player just lost, remove a star
currentStars--;
//Save the number of stars the player has
Spark.getPlayer().setScriptData("stars", currentStars);
}
//Check if player rank is less than 25 because that's the lowest level
if(currentRank < 25){
//If player has 0 stars
if(currentStars < 1){
//Decrease level by 1
Spark.getPlayer().setScriptData("rank", currentRank + 1);
if(currentRank >= 1 && currentRank <= 9){
Spark.getPlayer().setScriptData("stars", 5);
}
if(currentRank >= 10 && currentRank <= 14 ){
Spark.getPlayer().setScriptData("stars", 4);
}
if(currentRank >= 15 && currentRank <= 19){
Spark.getPlayer().setScriptData("stars", 3);
}
if(currentRank >= 20 && currentRank <= 24){
Spark.getPlayer().setScriptData("stars", 2);
}
}
}
}
And that's it for initialization, your game is ready for the Matchmaking.