How to make a developer product show up when player has no lives left

Hello!

So I’m new to using developer products and want to figure out how to make one of the developer products show up on screen when the player has no lives left. I have a script to record how much lives the player has, and how it loses them. I’m trying to get something like the death mechanic in “Rickey Rat” and “Us Are Toys” by @UmmmOkayWhat . Like after you loose your lives It’ll show the developer product. If you buy it, you will get more lives and continue playing. But if you don’t you will get kicked from the game.

The set up:

Adding lives the the player on join
LivesScript

Code Inside “Lives” Script

game.Players.PlayerAdded:Connect(function(Player)
	local LivesValue = Instance.new("NumberValue", Player)
	LivesValue.Name = "Lives"
	LivesValue.Value = 3
end)

Decrease 1 life every death
DeathScript

Code inside “Death” script

script.Parent.Humanoid.Died:Connect(function()
	local plr = game.Players:GetPlayerFromCharacter(script.Parent)
	
	plr.Lives.Value -= 1
	
	if plr.Lives.Value == 0 then
		plr:Kick("you lost all your lives")
	end
end)

I’ve tried looking at videos on a way to get this to work. But I have gotten no luck. I’d appreciate some help!

(This is my first topic so i’m not sure if this is how you properly do them)

4 Likes

You would first have to make a prompt before you kick them that says “Would you like to buy more lives” with a yes and no button. If they click yes, then you would have to prompt the product and then give the player the lives should they should to purchase it. If they click no, then you kick them.

The local script (found from the DevHub) under the “Yes” Button that prompts the purchase:

local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
 
local productID = 0000000  -- Change this to your developer product ID
 
-- Function to prompt purchase of the developer product
local function promptPurchase()
	local player = Players.LocalPlayer
	MarketplaceService:PromptProductPurchase(player, productID)
end

script.Parent.Mouse1ButtonClick:Connect(promptPurchase)

Then create server script in ServerScriptService and paste this code (also found from the DevHub) inside:

local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
 
-- Data store for tracking purchases that were successfully processed
local purchaseHistoryStore = DataStoreService:GetDataStore("PurchaseHistory")
 
-- Table setup containing product IDs and functions for handling purchases
local productFunctions = {}
-- Replace the 000000 with your developer product ID
productFunctions[000000] = function(receipt, player)

	local Lives = player:FindFirstChild("LivesValue")
	if Lives then
		Lives.Value += 3
		-- Indicate a successful purchase
		return true
	end
end
 
-- The core 'ProcessReceipt' callback function
local function processReceipt(receiptInfo)
 
	-- Determine if the product was already granted by checking the data store  
	local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
	local purchased = false
	local success, errorMessage = pcall(function()
		purchased = purchaseHistoryStore:GetAsync(playerProductKey)
	end)
	-- If purchase was recorded, the product was already granted
	if success and purchased then
		return Enum.ProductPurchaseDecision.PurchaseGranted
	elseif not success then
		error("Data store error:" .. errorMessage)
	end
 
	-- Find the player who made the purchase in the server
	local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not player then
		-- The player probably left the game
		-- If they come back, the callback will be called again
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
	
	-- Look up handler function from 'productFunctions' table above
	local handler = productFunctions[receiptInfo.ProductId]
 
	-- Call the handler function and catch any errors
	local success, result = pcall(handler, receiptInfo, player)
	if not success or not result then
		warn("Error occurred while processing a product purchase")
		print("\nProductId:", receiptInfo.ProductId)
		print("\nPlayer:", player)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
 
	-- Record transaction in data store so it isn't granted again
	local success, errorMessage = pcall(function()
		purchaseHistoryStore:SetAsync(playerProductKey, true)
	end)
	if not success then
		error("Cannot save purchase data: " .. errorMessage)
	end
 
	-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
	return Enum.ProductPurchaseDecision.PurchaseGranted
end
 
-- Set the callback; this can only be done once by one script on the server! 
MarketplaceService.ProcessReceipt = processReceipt

Here’s a relatively primitive approach to your problem, it makes use of a single RemoteFunction instance placed inside the ReplicatedStorage container.

--LOCAL

local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")

script.Parent.Humanoid.Died:Connect(function()
	local plr = game.Players:GetPlayerFromCharacter(script.Parent)

	plr.Lives.Value -= 1

	if plr.Lives.Value == 0 then
		local value = remote:InvokeServer()
		if not value then
			plr:Kick("server timed out")
		end
		task.wait(60) --60 seconds to purchase more lives.
		if plr.Lives.Value == 0 then
			plr:Kick("you lost all your lives")
		end
	end
end)
--SERVER

local players = game:GetService("Players")
local marketplace = game:GetService("MarketplaceService")
local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")

local productId = 0 --Change to ID of product.

marketplace.ProcessReceipt = function(receiptInfo)
	local player = players:GetPlayerByUserId(receiptInfo.PlayerId)
	if player then
		if receiptInfo.ProductId == productId then
			player.Lives.Value += 3
		end
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
	return Enum.ProductPurchaseDecision.NotProcessedYet
end

remote.OnServerInvoke = function(player)
	marketplace:PromptProductPurchase(player, productId)
	return true
end

The server script would go inside the ServerScriptService container.

1 Like

Thank you, it works perfectly. Well until you buy more lives. Once you buy extra lives it’ll add on to how much it had previously. The “Lives” script adds 3 at the beginning, then after buying it adds 3 more. Thus giving the player 6 lives. And it keeps adding on after dying those 6 times (thus resulting to 9 lives).

Before first time running out of lives

After buying lives for the first time

To explain your issue in depth, the player’s lives stat is being set by the client which means that its changes aren’t being replicated to the server (from the server’s perspective the player still has 3 lives, so 3 + 3 = 6 lives), we can circumvent this issue by setting the player’s “lives” stat on the server whenever they die (instead of letting the client decrement the lives stat by 1).

--LOCAL

local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")
local remote2 = replicated:WaitForChild("RemoteEvent")

local players = game:GetService("Players")
local character = script.Parent
local player = players:GetPlayerFromCharacter(character)
local humanoid = character:WaitForChild("Humanoid")

humanoid.Died:Connect(function()
	remote2:FireServer()

	if player.Lives.Value == 0 then
		local value = remote:InvokeServer()
		if not value then
			player:Kick("server timed out")
		end
		task.wait(60) --60 seconds to purchase more lives.
		if player.Lives.Value == 0 then
			player:Kick("you lost all your lives")
		end
	end
end)
--SERVER

local players = game:GetService("Players")
local marketplace = game:GetService("MarketplaceService")
local replicated = game:GetService("ReplicatedStorage")
local remote = replicated:WaitForChild("RemoteFunction")
local remote2 = replicated:WaitForChild("RemoteEvent")

local productId = 0 --Change to ID of product.

marketplace.ProcessReceipt = function(receiptInfo)
	local player = players:GetPlayerByUserId(receiptInfo.PlayerId)
	if player then
		if receiptInfo.ProductId == productId then
			player.Lives.Value += 3
		end
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
	return Enum.ProductPurchaseDecision.NotProcessedYet
end

remote.OnServerInvoke = function(player)
	marketplace:PromptProductPurchase(player, productId)
	return true
end

remote2.OnServerEvent:Connect(function(player)
	player.Lives.Value -= 1
end)

For this implementation we’ll need a RemoteEvent instance placed inside ReplicatedStorage.

1 Like