local ExtendedEvent = CreatureEvent("GameStoreExtended")
function ExtendedEvent.onExtendedOpcode(player, opcode, buffer)
if opcode == CODE_GAMESTORE then
if not GAME_STORE then
gameStoreInitialize()
addEvent(refreshPlayersPoints, 10 * 1000)
end
local status, json_data =
pcall(
function()
return json.decode(buffer)
end
)
if not status then
return
end
local action = json_data.action
local data = json_data.data
if not action or not data then
return
end
if action == "fetch" then
gameStoreFetch(player)
elseif action == "purchase" then
gameStorePurchase(player, data)
elseif action == "gift" then
gameStorePurchaseGift(player, data)
end
end
end
function gameStoreFetch(player)
local sex = player:getSex()
player:sendExtendedOpcode(CODE_GAMESTORE, json.encode({action = "fetchBase", data = {categories = GAME_STORE.categories, url = DONATION_URL}}))
for category, offersTable in pairs(GAME_STORE.offers) do
local offers = {}
for i = 1, #offersTable do
local offer = offersTable[i]
local data = {
type = offer.type,
title = offer.title,
description = offer.description,
price = offer.price
}
if offer.count then
data.count = offer.count
end
if offer.clientId then
data.clientId = offer.clientId
end
if sex == PLAYERSEX_MALE then
if offer.outfitMale then
data.outfit = offer.outfitMale
end
else
if offer.outfitFemale then
data.outfit = offer.outfitFemale
end
end
if offer.data then
data.data = offer.data
end
table.insert(offers, data)
end
player:sendExtendedOpcode(CODE_GAMESTORE, json.encode({action = "fetchOffers", data = {category = category, offers = offers}}))
end
gameStoreUpdatePoints(player)
gameStoreUpdateHistory(player)
end
function gameStoreUpdatePoints(player)
if type(player) == "number" then
player = Player(player)
end
player:sendExtendedOpcode(CODE_GAMESTORE, json.encode({action = "points", data = getPoints(player)}))
end
function gameStoreUpdateHistory(player)
if type(player) == "number" then
player = Player(player)
end
local history = {}
local resultId = db.storeQuery("SELECT * FROM `shop_history` WHERE `account` = " .. player:getAccountId() .. " order by `id` DESC")
if resultId ~= false then
repeat
local desc = "Bought " .. result.getDataString(resultId, "title")
local count = result.getDataInt(resultId, "count")
if count > 0 then
desc = desc .. " (x" .. count .. ")"
end
local target = result.getDataString(resultId, "target")
if target ~= "" then
desc = desc .. " on " .. result.getDataString(resultId, "date") .. " for " .. target .. " for " .. result.getDataInt(resultId, "price") .. " points."
else
desc = desc .. " on " .. result.getDataString(resultId, "date") .. " for " .. result.getDataInt(resultId, "price") .. " points."
end
table.insert(history, desc)
until not result.next(resultId)
result.free(resultId)
end
player:sendExtendedOpcode(CODE_GAMESTORE, json.encode({action = "history", data = history}))
end
function gameStorePurchase(player, offer)
local offers = GAME_STORE.offers[offer.category]
if not offers then
return errorMsg(player, "Something went wrong, try again or contact server admin [#1]!")
end
for i = 1, #offers do
if offers[i].title == offer.title and offers[i].price == offer.price then
local callback = offers[i].callback
if not callback then
return errorMsg(player, "Something went wrong, try again or contact server admin [#2]!")
end
local points = getPoints(player)
if offers[i].price > points then
return errorMsg(player, "You don't have enough points!")
end
local status = callback(player, offers[i])
if status ~= true then
return errorMsg(player, status)
end
local aid = player:getAccountId()
local escapeTitle = db.escapeString(offers[i].title)
local escapePrice = db.escapeString(offers[i].price)
local escapeCount = offers[i].count and db.escapeString(offers[i].count) or 0
db.query("UPDATE `accounts` set `premium_points` = `premium_points` - " .. offers[i].price .. " WHERE `id` = " .. aid)
db.asyncQuery(
"INSERT INTO `shop_history` VALUES (NULL, '" ..
aid .. "', '" .. player:getGuid() .. "', NOW(), " .. escapeTitle .. ", " .. escapePrice .. ", " .. escapeCount .. ", NULL)"
)
addEvent(gameStoreUpdateHistory, 1000, player:getId())
addEvent(gameStoreUpdatePoints, 1000, player:getId())
return infoMsg(player, "You've bought " .. offers[i].title .. "!", true)
end
end
return errorMsg(player, "Something went wrong, try again or contact server admin [#4]!")
end
function gameStorePurchaseGift(player, offer)
local offers = GAME_STORE.offers[offer.category]
if not offers then
return errorMsg(player, "Something went wrong, try again or contact server admin [#1]!")
end
if not offer.target then
return errorMsg(player, "Target player not found!")
end
for i = 1, #offers do
if offers[i].title == offer.title and offers[i].price == offer.price then
local callback = offers[i].callback
if not callback then
return errorMsg(player, "Something went wrong, try again or contact server admin [#2]!")
end
local points = getPoints(player)
if offers[i].price > points then
return errorMsg(player, "You don't have enough points!")
end
local targetPlayer = Player(offer.target)
if not targetPlayer then
return errorMsg(player, "Target player not found!")
end
local status = callback(targetPlayer, offers[i])
if status ~= true then
return errorMsg(player, status)
end
local aid = player:getAccountId()
local escapeTitle = db.escapeString(offers[i].title)
local escapePrice = db.escapeString(offers[i].price)
local escapeCount = offers[i].count and db.escapeString(offers[i].count) or 0
local escapeTarget = db.escapeString(targetPlayer:getName())
db.query("UPDATE `accounts` set `premium_points` = `premium_points` - " .. offers[i].price .. " WHERE `id` = " .. aid)
db.asyncQuery(
"INSERT INTO `shop_history` VALUES (NULL, '" ..
aid .. "', '" .. player:getGuid() .. "', NOW(), " .. escapeTitle .. ", " .. escapePrice .. ", " .. escapeCount .. ", " .. escapeTarget .. ")"
)
addEvent(gameStoreUpdateHistory, 1000, player:getId())
addEvent(gameStoreUpdatePoints, 1000, player:getId())
return infoMsg(player, "You've bought " .. offers[i].title .. " for " .. targetPlayer:getName() .. "!", true)
end
end
return errorMsg(player, "Something went wrong, try again or contact server admin [#4]!")
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 errorMsg(player, msg)
player:sendExtendedOpcode(CODE_GAMESTORE, json.encode({action = "msg", data = {type = "error", msg = msg}}))
end
function infoMsg(player, msg, close)
if not close then
close = false
end
player:sendExtendedOpcode(CODE_GAMESTORE, json.encode({action = "msg", data = {type = "info", msg = msg, close = close}}))
end
function addCategory(title, description, iconType, iconData)
if iconType == "item" then
iconData = ItemType(iconData):getClientId()
end
table.insert(
GAME_STORE.categories,
{
title = title,
description = description,
iconType = iconType,
iconData = iconData
}
)
end
function addItem(category, title, description, itemId, count, price, callback)
if not GAME_STORE.offers[category] then
GAME_STORE.offers[category] = {}
end
if not callback then
callback = defaultItemCallback
end
table.insert(
GAME_STORE.offers[category],
{
type = "item",
title = title,
description = description,
itemId = itemId,
count = count,
price = price,
clientId = ItemType(itemId):getClientId(),
callback = callback
}
)
end
function addOutfit(category, title, description, outfitMale, outfitFemale, price, callback)
if not GAME_STORE.offers[category] then
GAME_STORE.offers[category] = {}
end
if not callback then
callback = defaultOutfitCallback
end
table.insert(
GAME_STORE.offers[category],
{
type = "outfit",
title = title,
description = description,
outfitMale = outfitMale,
outfitFemale = outfitFemale,
price = price,
callback = callback
}
)
end
function addShader(category, title, description, outfitMale, outfitFemale, price, callback)
if not GAME_STORE.offers[category] then
GAME_STORE.offers[category] = {}
end
if not callback then
callback = defaultShaderCallback
end
table.insert(
GAME_STORE.offers[category],
{
type = "outfit",
title = title,
description = description,
outfitMale = outfitMale,
outfitFemale = outfitFemale,
price = price,
callback = callback
}
)
end
function defaultShaderCallback(player, offer)
if player:hasShader(offer.outfitMale.shader) then
return "You already have this shader."
end
player:addShader(offer.outfitMale.shader)
return true
end
function addMount(category, title, description, mountId, clientId, price, callback)
if not GAME_STORE.offers[category] then
GAME_STORE.offers[category] = {}
end
if not callback then
callback = defaultMountCallback
end
table.insert(
GAME_STORE.offers[category],
{
type = "mount",
title = title,
description = description,
mount = mountId,
clientId = clientId,
price = price,
callback = callback
}
)
end
function addWings(category, title, description, wingsId, clientId, price, callback)
if not GAME_STORE.offers[category] then
GAME_STORE.offers[category] = {}
end
if not callback then
callback = defaultWingsCallback
end
table.insert(
GAME_STORE.offers[category],
{
type = "wings",
title = title,
description = description,
wings = wingsId,
clientId = clientId,
price = price,
callback = callback
}
)
end
function addAura(category, title, description, auraId, clientId, price, callback)
if not GAME_STORE.offers[category] then
GAME_STORE.offers[category] = {}
end
if not callback then
callback = defaultAuraCallback
end
table.insert(
GAME_STORE.offers[category],
{
type = "aura",
title = title,
description = description,
aura = auraId,
clientId = clientId,
price = price,
callback = callback
}
)
end
function defaultWingsCallback(player, offer)
if player:hasWings(offer.wings) then
return "You already have these wings."
end
player:addWings(offer.wings)
return true
end
function defaultAuraCallback(player, offer)
if player:hasAura(offer.aura) then
return "You already have this aura."
end
player:addAura(offer.aura)
return true
end
function addCustom(category, type, title, description, data, count, price, callback)
if not GAME_STORE.offers[category] then
GAME_STORE.offers[category] = {}
end
if not callback then
error("[Game Store] addCustom " .. title .. " without callback")
return
end
table.insert(
GAME_STORE.offers[category],
{
type = type,
title = title,
description = description,
data = data,
price = price,
count = count,
callback = callback
}
)
end
function defaultItemCallback(player, offer)
if player:getFreeCapacity() < ItemType(offer.itemId):getWeight(offer.count) then
return "This item is too heavy for you!"
end
local storeInbox = player:getStoreInbox()
if not storeInbox then
return "Store Inbox is not available for your character."
end
local item = Game.createItem(offer.itemId, offer.count)
if not item then
return "Something went wrong, item couldn't be created."
end
item:setStoreItem(true)
local result = storeInbox:addItemEx(item)
item:setStoreItem(false)
if result == RETURNVALUE_NOERROR then
return true
elseif result == RETURNVALUE_CONTAINERNOTENOUGHROOM then
return "Your Store Inbox is full. Please remove some items to receive new ones."
else
return "Something went wrong, item couldn't be added."
end
end
function defaultOutfitCallback(player, offer)
if offer.outfitMale.addons > 0 then
if player:hasOutfit(offer.outfitMale.type, offer.outfitMale.addons) then
return "You already have this outfit with addons."
end
player:addOutfitAddon(offer.outfitMale.type, offer.outfitMale.addons)
else
if player:hasOutfit(offer.outfitMale.type) then
return "You already have this outfit."
end
player:addOutfit(offer.outfitMale.type)
end
if offer.outfitFemale.addons > 0 then
player:addOutfitAddon(offer.outfitFemale.type, offer.outfitFemale.addons)
else
player:addOutfit(offer.outfitFemale.type)
end
return true
end
function defaultMountCallback(player, offer)
if player:hasMount(offer.mount) then
return "You already have this mount."
end
player:addMount(offer.mount)
return true
end
function refreshPlayersPoints()
for _, p in ipairs(Game.getPlayers()) do
if p:getIp() > 0 then
gameStoreUpdatePoints(p)
end
end
addEvent(refreshPlayersPoints, 10 * 1000)
end
LoginEvent:type("login")
LoginEvent:register()
ExtendedEvent:type("extendedopcode")
ExtendedEvent:register()