In-app purchases
Some games are free to play and sell extras: a bag of coins, a new costume, no more ads. I talk to the store for you, whichever store it is, so your game asks the same way everywhere.
The store
The things for sale are listed in a file called iap.json, in the game’s
folder. Each has an id your game buys it by, a name, a price, and whether
it’s consumable, bought again and again like coins, or non-consumable,
bought once and kept, like “no more ads”.
{
"version": 1,
"products": [
{ "id": "coins_100", "type": "consumable", "name": "100 Coins",
"price": { "amount": 99, "currency": "usd" },
"apple_product_id": "com.example.coins100",
"google_product_id": "coins_100" },
{ "id": "no_ads", "type": "non_consumable", "name": "No More Ads",
"price": { "amount": 299, "currency": "usd" },
"apple_product_id": "com.example.noads",
"google_product_id": "no_ads" }
],
"providers": { "ios": "apple", "android": "google",
"web": "iap_server", "desktop": "iap_server" },
"iap_server": { "endpoint": "https://example.com/iap" }
}
providers says which store each kind of machine uses:
- On a phone or a tablet, it’s the App Store on iPhone and iPad, and Google Play on Android. A product is only on sale there if it has the id you gave it in that store, and the store shows its own window to pay in.
- In a web browser, and on a PC, it’s an IAP server: a web server of your
own (or one you use) that knows how to sell things. The price in
iap.jsonis the one it shows, and paying happens in the browser.
Is it open?
purchase.available is 1 when the game is talking to a store, and 0 when
there’s no store or it can’t be reached. purchases is the list of what’s
for sale, each with its id, name, description, price and whether it’s
purchased.
SCREEN 320, 240
IF purchase.available
FOR item = purchases
PRINT item.name, item.price, item.purchased
NEXT
ELSE
PRINT "no store here"
END IF
PRINT "the store has", len(purchases), "things"
no store here
the store has 0 things
Here in the book there’s no store at all, so it’s closed, with nothing for sale. A game should always be fine with that: just don’t show the shop.
Buying
PURCHASE NEW and the id of what to buy opens the store’s window, and your
game carries on. When it’s over, I fire the "purchase" event, with the id,
whether it worked (1 or 0), and why not when it didn’t. Have a CALL EVENT
ready for it before anyone can buy.
SCREEN 320, 240
ATOMIC coins = 0
ATOMIC news = "visiting the shop..."
FUNCTION bought(product, ok, why)
IF ok
IF product = "coins_100" THEN coins = coins + 100
news = "thank you!"
ELSE
news = "no sale: " + why
END IF
END FUNCTION
CALL EVENT bought, "purchase"
PURCHASE NEW "coins_100"
// A spinner while the store has its turn.
turn = 0
DO WHILE news = "visiting the shop..."
IF COOLDOWN(1)
MEMORYBUFFER "spinner"
CIRCLE (160 + cos(turn) * 20, 120 + sin(turn) * 20), 5, 14, 14
END MEMORYBUFFER
FRAME
CLS
PUTIMAGE (0, 0), "spinner"
END FRAME
turn = turn + 0.1
END IF
LOOP
PRINT news
PRINT "coins:", coins
no sale: declined
coins: 0
With no store, I can’t sell anything, so the event says no, and why. On a phone, the player would see the store’s window, and the event would come when they’d paid, or changed their mind.
Keeping count
purchased only means something for a non-consumable: it’s 1 once it’s been
bought, and the store remembers. A consumable is always 0, because it can be
bought again, so the store doesn’t keep count of your coins. Your game does:
add them up when the event says they were bought, and save them, the way
Saving your game does.
FUNCTION bought(product, ok, why)
IF ok AND product = "coins_100"
coins = coins + 100
SAVETEXT "coins.txt", str(coins)
END IF
END FUNCTION
Bought it before?
Someone who bought “no more ads” on their old phone wants it on their new
one too. PURCHASE RESTORE asks the store for everything they’ve bought
before, and the "purchase" event comes once for each one. Put it behind a
“Restore purchases” button.
SCREEN 320, 240
ATOMIC ads = TRUE
FUNCTION bought(product, ok, why)
IF ok AND product = "no_ads" THEN ads = FALSE
END FUNCTION
CALL EVENT bought, "purchase"
PURCHASE RESTORE
PRINT "asked the store for what you bought before"
asked the store for what you bought before
Only non-consumables come back: the coins were spent long ago.
Crash-tan’s Tip: Never decide a purchase worked yourself. Wait for the
"purchase"event to say so: the window can be closed, the card can be turned down, and the player can be offline.