This article was written on Pragma Engine version 0.0.94.
Purchasing Stackable Items in a Store #
In this article, we’ll take a look at creating an in-game store that buys and sells stackable items in Pragma Engine. If you haven’t already, check out our previous article on creating stackable items.
Pragma Engine’s store system catalogs preexisting items—both stackable and instanced—inside a store for item exchanges with a player. In this tutorial, we’re going to learn how to create a store with a catalog of stackable item exchanges, and then simulate a player buying and selling stackable items with the store using their gold coins.
Understanding Stores #
Most games have some type of item store for players to acquire, sell, and exchange items. A store could be a cosmetic market in a title screen, a shady, traveling merchant found during gameplay, or any other game system that exchanges items with the player. Pragma Engine uses stores to contain a list of possible item exchanges between items. These items go back and forth between the player and the store’s limitless storage via service calls to the engine.
Stores require that items are first created in their respective JSON files. These two files are StackableSpecs.json
for stackable items and InstancedSpecs.json
for instanced items. Since this article only deals with stackable items, we only have to worry about items we’ll create in StackableSpecs.json
.
The next section will show you how to create stackable copper, tin, and iron ore items to buy and sell in a store using the gold coins from the previous article.
Let’s mine for some ore… #
Before we create our stackable ores, make sure you’ve created your 5-ext
directory from the previous Creating Stackable Items article. If not, no worries. Simply follow the previous article to build your 5-ext
directory and the stackable gold coins item.
To create our stackable ores, go to 5-ext/content/src/StackableSpecs.json
and add the following code for copper_ore
, tin_ore
, and iron_ore
. Notice how we’re keeping the gold_coins
from the previous article, as we’ll be using that currency to buy and sell our newly created ores with the store.
[
{
"catalogId": "gold_coins",
"name": "gold coins",
"limit": 1000000,
"tags": ["currency"],
"removeIfNone": false
},
{
"catalogId": "copper_ore",
"name": "copper ore",
"limit": 1000000,
"tags": ["resource"],
"removeIfNone": true
},
{
"catalogId": "tin_ore",
"name": "tin ore",
"limit": 1000000,
"tags": ["resource"],
"removeIfNone": true
},
{
"catalogId": "iron_ore",
"name": "iron ore",
"limit": 1000000,
"tags": ["resource"],
"removeIfNone": true
}
]
Two things are different when comparing the three ores to the gold coins.
First, the tags for the ores are now a resource
instead of a currency
. This new tag helps organize and differentiate ores from gold coins based on their functionality and purpose within the game (in this case, ores are a resource item, and gold coins are a currency item).
Next, the removeIfNone
parameter has a value of true
for our three ores, compared to the coins’ removeIfNone
of false
. This means that when one of these three stacks of ore is depleted in a player’s inventory, the item disappears from the inventory entirely. Of course, a player can still acquire the depleted stackable item again.
Now that we have all of our stackable ores ready, let’s create a store that buys and sells copper, tin, and iron ore for gold coins.
Creating a Store #
Time to start a small metalworking business!
Go to 5-ext/content/src/Stores.json
and add the following code to create a store called shopkeeper
:
[
{
"id": "shopkeeper",
"name": "Shopkeeper",
"storeEntries": []
}
]
Just like how instanced and stackable items have a catalogId
and a name
, stores have their own id
and name
that service calls use to access the store functionalities. Additionally, stores have the parameter storeEntries
which is where you’ll list the item exchanges a store can make.
Once we’ve created our shopkeeper
, let’s write the item transactions that we want the shopkeeper
to be able to make with a player.
Cataloging the store’s item transaction options #
Add the following entries into the storeEntries
brackets to give our shopkeeper
6 possible item transactions:
"storeEntries": [
{
"id": "buy_copper_ore",
"receivedQuantityByCatalogId": {
"copper_ore": 1
},
"costByCatalogId": {
"gold_coins": {
"cost": 30
}
}
},
{
"id": "sell_copper_ore",
"receivedQuantityByCatalogId": {
"gold_coins": 30
},
"costByCatalogId": {
"copper_ore": {
"cost": 1
}
}
},
{
"id": "buy_tin_ore",
"receivedQuantityByCatalogId": {
"tin_ore": 1
},
"costByCatalogId": {
"gold_coins": {
"cost": 20
}
}
},
{
"id": "sell_tin_ore",
"receivedQuantityByCatalogId": {
"gold_coins": 20
},
"costByCatalogId": {
"tin_ore": {
"cost": 1
}
}
},
{
"id": "buy_iron_ore",
"receivedQuantityByCatalogId": {
"iron_ore": 1
},
"costByCatalogId": {
"gold_coins": {
"cost": 10
}
}
},
{
"id": "sell_iron_ore",
"receivedQuantityByCatalogId": {
"gold_coins": 10
},
"costByCatalogId": {
"iron_ore": {
"cost": 1
}
}
}
]
Let’s break down this code block by describing what each parameter for our storeEntries
means:
Parameter | Description |
---|---|
id | The name used to access the transactional entry in our store. If a store buys and sells the same item, make two separate storeEntries for buying and selling that item. |
receivedQuantityByCatalogId | The ID of the item the caller receives |
costByCatalogId | The ID of the item the store receives for the transaction. In other words, the item that the player pays the store for this transaction. |
cost | The amount of the item required from the caller for the transaction |
Even though buying and selling items might appear as two different functions, they operate very similarly in Pragma Engine; the store receives and gives items to the player the same way a player receives and gives items to the store.
It’s important to be thorough with what your store can actually do for the player; whether it’s only going to allow buying or selling transactions, or both. Also, stores don’t have any type of storage or limited number of transactions. This means that a player can buy an unlimited amount of an item(s) from a store as long as they have the item(s) the store needs for the transaction.
Now that our store is fully functional, with a list of storeEntries
for our player to call, let’s apply our content data changes.
Register content changes #
To register the stackables and store we just made, we need to run Pragma Engine with a fresh build and apply our content data changes. Run the following line of code in a terminal using platform
as the working directory:
make ext-contentdata-apply
After we’ve applied our changes, it’s time to make sure our gold_coins
, our 3 different ores, and the store shopkeeper
are ready for business by simulating service calls with Postman.
Testing the Store #
Before we test our store and stackables, make sure you’re running a MySQL database and have Postman installed. If you don’t already have Postman installed, check out our Postman Setup guide in the initial setup README.
Simulating service calls with Postman #
To get started with Postman, enter the following line in a terminal with platform
as our working directory. This command gets the engine up and running so we can run calls against it.
make run
Now that Pragma Engine, MySQL, and Postman are up and running, let’s test our store by authenticating an Operator and a Player, granting some stackable ores and gold coins, and buying and selling our three types of ores with our newly created shopkeeper.
Authenticating Operator and Player logins #
Let’s go shopping!
In the PragmaDev
folder, navigate to the two service calls: Public>Operator - AuthenticateOrCreateV2
and Public>Player - AuthenticateOrCreateV2
. Then click Send for both service calls and check that the response body for each call has given us pragmaTokens
with a filled pragmaGameToken
and pragmaSocialToken
.
Next, we’re going to grant gold coins to a player to be used with our store.
Granting the gold coins and ores #
This step is identical to the previous Creating Stackable Items article where we grant gold_coins
to the player. However, this time around we need to make sure the player has enough currency to purchase our ores from the store.
In the PragmaDev
folder, locate the service call: Game>RPC - Operator>Inventory>GrantItemsOperatorV1
and open the service call’s body.
In the service call’s body, find the stackable
object and replace the stackable’s catalogId
value with gold_coins
after the colon (if gold_coins
isn’t already there from the previous article). To make sure the player has enough currency, fill in the amount with 1000
. This grants 1000 gold coins to the player.
If you want to make sure the player has enough gold coins, go to the service call location: Game>RPC - Operator>Inventory>GetInventoryOperatorV1
and click Send. You can check the response to see if stackables
has gold_coins
with an amount of at least 1000
. You might have more than 1000 gold coins if you completed the previous blog article’s GrantItemsOperatorV1
, and that’s okay.
Once the player has some gold coins, let’s run a service call to purchase some ores and sell them back to the shopkeeper.
Buying and selling ores with the store #
For this tutorial, let’s assume that our player wants to buy some tin, copper, and iron ore. However, once they make their purchase, they realize they accidentally bought too much copper ore and they don’t actually need any iron ore for their plans. After they realize their mistake, they want to sell all the iron ore back to the shopkeeper and sell exactly 2 copper ore. This interaction is entirely possible with Pragma Engine as long as we input the right storeId
and the correct storeEntryId
s in the StorePurchaseV4
service call.
Navigate to Game>RPC - Player>Inventory>StorePurchaseV4
and open the service call’s body. Inside payload
and data
, edit the storeId
to have the value of shopkeeper
so we use the correct store for this call.
Once we’re all set to interact with our shopkeeper, let’s try to buy some ore!
Go to the storeEntryId
and type buy_copper_ore
to purchase some copper_ore
from the shopkeeper
. Then, edit the amount
by giving it a value of 5
. Click Send once you’ve edited the service call’s body and do this process over again by replacing the storeEntryId
with buy_iron_ore
and then buy_tin_ore
.
You can check the player’s inventory for 5 copper_ore
, iron_ore
, and tin_ore
by using the GetInventoryOperatorV1
. If the player’s inventory had 1000 gold_coins
, they should have spent 300 gold_coins
by buying 5
of each ore
and their inventory should now have 700 gold_coins
.
However, the player actually only wants 3 copper ores and none of the 5 iron ore they just bought. So, to fix our player’s mistake, type sell_iron_ore
in the storeEntryId
and click Send. Then, type sell_copper_ore
in the storeEntryId
, change the amount
value to 2
, and click Send.
After our player has fixed their kerfuffle by selling the ores they don’t want to the shopkeeper, let’s check the player’s inventory for 3 copper_ore
, 5 tin_ore
, and no iron_ore
(because our ores have a removeIfNone
value of true
). They should also have gained 110 gold_coins
from selling their ore and should now have 810 gold_coins
in their inventory.
If your player has the correct amount of ores and gold coins, then bravo! You’ve just created a store that can buy and sell stackable items!
For more information, check out the rest of the articles in this series:
Part I: Creating Stackable Items
Part II: Purchasing Stackable Items in a Store (this article)
Part III: Creating a Crafting System Using Stores