Shoorkill
Active Member
- Joined
- Dec 17, 2018
- Messages
- 153
- Reaction score
- 25
hello friends, I'm using game-store on my server, with SQL charging and in-game currency, if I have 100 in the account per db, and 100 physical points in the backpack, it doesn't interfere, the only problem is that in charging if the The shop item costs 50 points, and if I have 50 points he charges the correct amount, if I have 75 he only charges 50, but if I have 100 (i.e. double) the purchase is duplicate, can someone help me fix this?
LUA:
function addCategory(data)
data['offers'] = {}
table.insert(SHOP_CATEGORIES, data)
table.insert(SHOP_CALLBACKS, {})
local index = #SHOP_CATEGORIES
return {
addItem = function(cost, itemId, count, title, description, callback)
if not callback then
callback = defaultItemBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="item",
item=ItemType(itemId):getClientId(), -- displayed
itemId=itemId,
count=count,
title=title,
description=description
})
table.insert(SHOP_CALLBACKS[index], callback)
end,
addOutfit = function(cost, outfit, title, description, callback)
if not callback then
callback = defaultOutfitBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="outfit",
outfit=outfit,
title=title,
description=description
})
table.insert(SHOP_CALLBACKS[index], callback)
end,
addImage = function(cost, image, title, description, callback)
if not callback then
callback = defaultImageBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="image",
image=image,
title=title,
description=description
})
table.insert(SHOP_CALLBACKS[index], callback)
end,
addPremiumDays = function(cost, image, title, description, count, callback)
if not callback then
callback = defaultPremiumBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="image",
image=image,
title=title,
description=description,
count=count,
})
table.insert(SHOP_CALLBACKS[index], callback)
end
}
end
function addCategory(data)
data['offers'] = {}
table.insert(SHOP_CATEGORIES, data)
table.insert(SHOP_CALLBACKS, {})
local index = #SHOP_CATEGORIES
return {
addItem = function(cost, itemId, count, title, description, callback)
if not callback then
callback = defaultItemBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="item",
item=ItemType(itemId):getClientId(), -- displayed
itemId=itemId,
count=count,
title=title,
description=description
})
table.insert(SHOP_CALLBACKS[index], callback)
end,
addOutfit = function(cost, outfit, title, description, callback)
if not callback then
callback = defaultOutfitBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="outfit",
outfit=outfit,
title=title,
description=description
})
table.insert(SHOP_CALLBACKS[index], callback)
end,
addImage = function(cost, image, title, description, callback)
if not callback then
callback = defaultImageBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="image",
image=image,
title=title,
description=description
})
table.insert(SHOP_CALLBACKS[index], callback)
end,
addPremiumDays = function(cost, image, title, description, count, callback)
if not callback then
callback = defaultPremiumBuyAction
end
table.insert(SHOP_CATEGORIES[index]['offers'], {
cost=cost,
type="image",
image=image,
title=title,
description=description,
count=count,
})
table.insert(SHOP_CALLBACKS[index], callback)
end
}
end
function getPoints(player)
local points = 0
local resultId = db.storeQuery("SELECT `premium_points` FROM `accounts` WHERE `id` = " .. player:getAccountId())
if resultId ~= false then
points = result.getDataInt(resultId, "premium_points")
result.free(resultId)
end
return points
end
function getStatus(player)
local status = {
ad = SHOP_AD,
points = getPoints(player),
buyUrl = SHOP_BUY_URL
}
return status
end
function sendJSON(player, action, data, forceStatus)
local status = nil
init(player)
if not player:getStorageValue(1150001) or player:getStorageValue(1150001) + 10 < os.time() or forceStatus then
status = getStatus(player)
end
player:setStorageValue(1150001, os.time())
local buffer = json.encode({action = action, data = data, status = status})
local s = {}
for i=1, #buffer, MAX_PACKET_SIZE do
s[#s+1] = buffer:sub(i,i+MAX_PACKET_SIZE - 1)
end
local msg = NetworkMessage()
if #s == 1 then
msg:addByte(50)
msg:addByte(SHOP_EXTENDED_OPCODE)
msg:addString(s[1])
msg:sendToPlayer(player)
return
end
-- split message if too big
msg:addByte(50)
msg:addByte(SHOP_EXTENDED_OPCODE)
msg:addString("S" .. s[1])
msg:sendToPlayer(player)
for i=2,#s - 1 do
msg = NetworkMessage()
msg:addByte(50)
msg:addByte(SHOP_EXTENDED_OPCODE)
msg:addString("P" .. s[i])
msg:sendToPlayer(player)
end
msg = NetworkMessage()
msg:addByte(50)
msg:addByte(SHOP_EXTENDED_OPCODE)
msg:addString("E" .. s[#s])
msg:sendToPlayer(player)
end
function sendMessage(player, title, msg, forceStatus)
sendJSON(player, "message", {title=title, msg=msg}, forceStatus)
end
function onExtendedOpcode(player, opcode, buffer)
if opcode ~= SHOP_EXTENDED_OPCODE then
return false
end
local status, json_data = pcall(function() return json.decode(buffer) end)
if not status then
return false
end
local action = json_data['action']
local data = json_data['data']
if not action or not data then
return false
end
if SHOP_CATEGORIES == nil then
init()
end
if action == 'init' then
sendJSON(player, "categories", SHOP_CATEGORIES)
elseif action == 'buy' then
processBuy(player, data)
elseif action == "history" then
sendHistory(player)
end
return true
end
function processBuy(player, data)
local categoryId = tonumber(data["category"])
local offerId = tonumber(data["offer"])
local offer = SHOP_CATEGORIES[categoryId]['offers'][offerId]
local callback = SHOP_CALLBACKS[categoryId][offerId]
if not offer or not callback or data["title"] ~= offer["title"] or data["cost"] ~= offer["cost"] then
sendJSON(player, "categories", SHOP_CATEGORIES) -- Atualiza as categorias, talvez inválido
return sendMessage(player, "AVISO!", "Oferta inválida")
end
-- Verifica a quantidade de moeda física (ID 6527)
local physicalCurrencyId = 6527
local playerCurrency = player:getItemCount(physicalCurrencyId)
local cost = offer['cost'] -- Custo da oferta em moeda física
-- Verifica se o jogador possui moedas suficientes
if playerCurrency < cost then
return sendMessage(player, "AVISO!", "Você não tem moedas suficientes para comprar " .. offer['title'] .."!", true)
end
-- Criar uma mochila para itens comuns
local backpack = nil
if offer['type'] == 'item' then -- Verificar se é um item comum
backpack = player:addItem(28436, 1, false)
if not backpack then
return sendMessage(player, "AVISO!", "Não foi possível criar a mochila.")
end
backpack:setAttribute(ITEM_ATTRIBUTE_NAME, "Store Bag")
end
-- Chama o callback para processar a compra
local status = callback(player, offer, backpack)
-- Se a compra foi bem-sucedida, desconta a moeda física e registra a compra
if status == true then
-- Deduz a quantidade de moeda física (ID 6527) após a compra
player:removeItem(physicalCurrencyId, cost)
-- Registra a compra no histórico
db.asyncQuery("INSERT INTO `shop_history` (`account`, `player`, `date`, `title`, `cost`, `details`) VALUES ('"
.. player:getAccountId() .. "', '" .. player:getGuid() .. "', NOW(), "
.. db.escapeString(offer['title']) .. ", "
.. db.escapeString(offer['cost']) .. ", "
.. db.escapeString(json.encode(offer)) .. ")")
-- Envia a mensagem de sucesso
return sendMessage(player, "Sucesso!", "Você comprou " .. offer['title'] .."!", true)
end
-- Se a compra falhou ou o jogador já possui o item, envia uma mensagem de erro
if status == nil or status == false then
status = "Você já possui este(a) " .. offer['title']
end
-- Envia a mensagem de erro
sendMessage(player, "AVISO!", status)
end
-- Função para enviar o histórico de compras com moeda física
function sendHistory(player)
if player:getStorageValue(1150002) and player:getStorageValue(1150002) + 10 > os.time() then
return -- min 10s delay
end
player:setStorageValue(1150002, os.time())
local history = {}
local resultId = db.storeQuery("SELECT * FROM `shop_history` WHERE `account` = " .. player:getAccountId() .. " order by `id` DESC")
if resultId ~= false then
repeat
local details = result.getDataString(resultId, "details")
local status, json_data = pcall(function() return json.decode(details) end)
if not status then
json_data = {
type = "image",
title = result.getDataString(resultId, "title"),
cost = result.getDataInt(resultId, "cost")
}
end
table.insert(history, json_data)
history[#history]["description"] = "comprado em " .. result.getDataString(resultId, "date") .. " por " .. result.getDataInt(resultId, "cost") .. " moedas físicas."
until not result.next(resultId)
result.free(resultId)
end
sendJSON(player, "history", history)
end
-- Funções de callback
function defaultItemBuyAction(player, offer, backpack)
if not backpack then
return "Erro: mochila não encontrada."
end
local itemId = offer["itemId"]
local itemCount = offer["count"] or 1
local isStackable = isItemStackable(itemId) -- Supondo que esta função verifica se o item é empilhável
if isStackable then
-- Lógica para itens empilháveis
local fullStacks = math.floor(itemCount / 100)
local remainder = itemCount % 100
for i = 1, fullStacks do
local addedItem = backpack:addItem(itemId, 100)
if not addedItem then
return "Não foi possível adicionar o item na mochila."
end
end
if remainder > 0 then
local addedItem = backpack:addItem(itemId, remainder)
if not addedItem then
return "Não foi possível adicionar o item na mochila."
end
end
else
-- Lógica para itens não empilháveis
for i = 1, itemCount do
local addedItem = backpack:addItem(itemId, 1)
if not addedItem then
return "Não foi possível adicionar o item na mochila."
end
end
end
return true
end
function defaultOutfitBuyAction(player, offer)
local outfit = offer['outfit']
local mountId = outfit['mount']
local wingId = outfit['wing']
local auraId = outfit['auras']
local shaderId = outfit['shaderAdd']
if player:getStorageValue(outfit['storage']) > 0 then
local message = "Você já possui esta " .. outfit['name'] .. "!"
player:sendTextMessage(MESSAGE_INFO_DESCR, message)
return false
end
-- Verifica a quantidade de moeda física (ID 6527)
local physicalCurrencyId = 6527
local playerCurrency = player:getItemCount(physicalCurrencyId)
if offer['cost'] > playerCurrency then
player:sendTextMessage(MESSAGE_INFO_DESCR, "Você não possui moedas suficientes para comprar este outfit.")
return false
end
-- Deduz a moeda física (ID 6527)
player:removeItem(physicalCurrencyId, offer['cost'])
if outfit['lookType'] then
local sex = player:getSex()
local lookType = outfit['lookType'][sex + 1]
local addons = outfit['addons']
player:addOutfitAddon(lookType, addons)
player:addOutfit(outfit['type'], addons)
end
player:setStorageValue(outfit['storage'], 1)
local message = "Você comprou o " .. outfit['name'] .. "!"
player:sendTextMessage(MESSAGE_INFO_DESCR, message)
if mountId and mountId > 0 then
player:addMount(mountId)
player:setStorageValue(outfit['storage'], 1)
end
if wingId and wingId > 0 then
player:addWings(wingId)
player:setStorageValue(outfit['storage'], 1)
end
if auraId and auraId > 0 then
player:addAura(auraId)
player:setStorageValue(outfit['storage'], 1)
end
if shaderId and tonumber(shaderId) and tonumber(shaderId) > 0 then
player:addShader(tonumber(shaderId))
player:setStorageValue(outfit['storage'], 1)
end
db.asyncQuery("INSERT INTO `shop_history` (`account`, `player`, `date`, `title`, `cost`, `details`) VALUES ('"
.. player:getAccountId() .. "', '" .. player:getGuid() .. "', NOW(), "
.. db.escapeString(offer['title']) .. ", "
.. db.escapeString(offer['cost']) .. ", "
.. db.escapeString(json.encode(offer)) .. ")")
return true
end
function defaultImageBuyAction(player, offer)
-- Verifica se o jogador tem pontos suficientes
local currentPoints = getPoints(player)
if currentPoints < offer.cost then
sendMessage(player, "Purchase Error", "You do not have enough points to purchase this image.")
return false
end
-- Atualiza os pontos do jogador no banco de dados de forma atômica
local query = string.format("UPDATE `accounts` SET `premium_points` = `premium_points` - %d WHERE `id` = %d AND `premium_points` >= %d", offer.cost, player:getAccountId(), offer.cost)
local updateResult = db.query(query)
if not updateResult then
sendMessage(player, "Purchase Error", "There was an error updating your points. Please try again.")
return false
end
-- Adiciona a imagem ao perfil do jogador
local success = addImageToPlayerProfile(player, offer.image)
if not success then
-- Se houver um erro ao adicionar a imagem, reembolsa os pontos
db.query(string.format("UPDATE `accounts` SET `premium_points` = `premium_points` + %d WHERE `id` = %d", offer.cost, player:getAccountId()))
sendMessage(player, "Purchase Error", "There was an error adding the image to your profile. Your points have been refunded.")
return false
end
-- Envia uma mensagem de confirmação para o jogador
sendMessage(player, "Image Purchased", "You have successfully purchased the image: " .. offer.title)
return true
end
-- Função fictícia para adicionar a imagem ao perfil do jogador
function addImageToPlayerProfile(player, imageUrl)
-- Implemente a lógica para adicionar a imagem ao perfil do jogador aqui
-- Retorne true se a imagem foi adicionada com sucesso, ou false se houve um erro
return true -- Simulando sucesso
end
function customImageBuyAction(player, offer)
return "A acao de compra personalizada de imagem nao esta implementada. Oferta: " .. offer['title']
end
function defaultImageBuyAction(player, offer)
-- Verifica se o jogador tem pontos suficientes
local currentPoints = getPoints(player)
if currentPoints < offer.cost then
sendMessage(player, "Purchase Error", "You do not have enough points to purchase this image.")
return false
end
-- Atualiza os pontos do jogador no banco de dados de forma atômica
local query = string.format("UPDATE `accounts` SET `premium_points` = `premium_points` - %d WHERE `id` = %d AND `premium_points` >= %d", offer.cost, player:getAccountId(), offer.cost)
local updateResult = db.query(query)
if not updateResult then
sendMessage(player, "Purchase Error", "There was an error updating your points. Please try again.")
return false
end
-- Adiciona a imagem ao perfil do jogador
local success = addImageToPlayerProfile(player, offer.image)
if not success then
-- Se houver um erro ao adicionar a imagem, reembolsa os pontos
db.query(string.format("UPDATE `accounts` SET `premium_points` = `premium_points` + %d WHERE `id` = %d", offer.cost, player:getAccountId()))
sendMessage(player, "Purchase Error", "There was an error adding the image to your profile. Your points have been refunded.")
return false
end
-- Envia uma mensagem de confirmação para o jogador
sendMessage(player, "Image Purchased", "You have successfully purchased the image: " .. offer.title)
return true
end
-- Função fictícia para adicionar a imagem ao perfil do jogador
function addImageToPlayerProfile(player, imageUrl)
-- Implemente a lógica para adicionar a imagem ao perfil do jogador aqui
-- Retorne true se a imagem foi adicionada com sucesso, ou false se houve um erro
return true -- Simulando sucesso
end
function customImageBuyAction(player, offer)
return "A acao de compra personalizada de imagem nao esta implementada. Oferta: " .. offer['title']
end