• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

AAC Znote missing table Points

roriscrave

Advanced OT User
Joined
Dec 7, 2011
Messages
1,188
Solutions
34
Reaction score
200
Hi!
Recently I am migrating to the best of grade, and encounter some difficulties.
I'm testing the game shop, but only says that I have 0 points, but looking at the account, does not display the table points, how should I add?
1568259402805.png
edit: i see it have 2 table accounts, players and others its correct or i did something wrong?
1568260531381.png
 
Last edited:
Solution
You should not alter the original tables that TFS uses. Znote AAC uses supplementary tables prefixed by znote_.

Etc account points are stored in znote_accounts.
When finding the correct row to edit in znote_accounts, keep in mind that znote_accounts.id column is not the same as account_id, you need to use znote_accounts.account_id.

Instead of modifying the tables directly in phpmyadmin, I recommend you to use the admin page in Znote AAC instead.

To gain access to this, add your admin account name in config.php: $config['page_admin_access']
Then login and access the admin.php page.
Here you can, among other things, give shop points to a player.

If the player you wish to send shop points to didnt register their account...
I'm not sure how it works...

But here is the SQL code to add a new entry for points;
SQL:
ALTER TABLE `accounts` ADD COLUMN `points` INT(11) DEFAULT '0' NOT NULL;
 
You should not alter the original tables that TFS uses. Znote AAC uses supplementary tables prefixed by znote_.

Etc account points are stored in znote_accounts.
When finding the correct row to edit in znote_accounts, keep in mind that znote_accounts.id column is not the same as account_id, you need to use znote_accounts.account_id.

Instead of modifying the tables directly in phpmyadmin, I recommend you to use the admin page in Znote AAC instead.

To gain access to this, add your admin account name in config.php: $config['page_admin_access']
Then login and access the admin.php page.
Here you can, among other things, give shop points to a player.

If the player you wish to send shop points to didnt register their account using Znote AAC, this won't work. Before you can send them shop points, you need to convert their account to be compatible with Znote AAC, you can do this by accessing /special/database2znoteaac.php page. As it will repair old accounts to work with Znote AAC.
 
Solution
You should not alter the original tables that TFS uses. Znote AAC uses supplementary tables prefixed by znote_.

Etc account points are stored in znote_accounts.
When finding the correct row to edit in znote_accounts, keep in mind that znote_accounts.id column is not the same as account_id, you need to use znote_accounts.account_id.

Instead of modifying the tables directly in phpmyadmin, I recommend you to use the admin page in Znote AAC instead.

To gain access to this, add your admin account name in config.php: $config['page_admin_access']
Then login and access the admin.php page.
Here you can, among other things, give shop points to a player.

If the player you wish to send shop points to didnt register their account using Znote AAC, this won't work. Before you can send them shop points, you need to convert their account to be compatible with Znote AAC, you can do this by accessing /special/database2znoteaac.php page. As it will repair old accounts to work with Znote AAC.
as always clarified the doubts very well.
thank you very much!
 
Have you done what znote told? Just add your account number and login in site
thanks for repling, in fact i dont even know what site they talking bout, theres no reference at all, they say add your admin account name in config.php, but what config.php? there r many lol, next they say: Then login and access the admin.php page, they talkin bout login to phpmyadmin? nothing is clear, speakin greek i cant understand, if u can gime references please cuz all archives they say have plenty of in the folders lol how i would know which one is to edit?!
 
thanks for repling, in fact i dont even know what site they talking bout, theres no reference at all, they say add your admin account name in config.php, but what config.php? there r many lol, next they say: Then login and access the admin.php page, they talkin bout login to phpmyadmin? nothing is clear, speakin greek i cant understand, if u can gime references please cuz all archives they say have plenty of in the folders lol how i would know which one is to edit?!
Simples, aqui fala sobre znoteacc, se você não está usando esse então desconsidera qualquer coisa, se for znote, na pasta www já tem o config.php, só mudar aquela parte onde o próprio znote diz para fazer e colocar sua conta ali, exemplo de conta: $config['page_admin_access'] = '888888', então é só colocar ali, depois ir no site normal, e fazer login com sua conta que do lado vai aparecer as opções de admin

Simple, here it talks about znoteacc, if you are not using that one then disregard anything, if it is znote, the www folder already has the config.php, just change that part where znote itself says to do it and put your account there, example account: $config['page_admin_access'] = '888888', so just put it there, then go to the normal website, and log in with your account that will show the admin options on the side
 
Simples, aqui fala sobre znoteacc, se você não está usando esse então desconsidera qualquer coisa, se for znote, na pasta www já tem o config.php, só mudar aquela parte onde o próprio znote diz para fazer e colocar sua conta ali, exemplo de conta: $config['page_admin_access'] = '888888', então é só colocar ali, depois ir no site normal, e fazer login com sua conta que do lado vai aparecer as opções de admin

Simple, here it talks about znoteacc, if you are not using that one then disregard anything, if it is znote, the www folder already has the config.php, just change that part where znote itself says to do it and put your account there, example account: $config['page_admin_access'] = '888888', so just put it there, then go to the normal website, and log in with your account that will show the admin options on the side
vlw por responder mano nem vi q tu era br, cara eu nao tenho a pasta znote acc mas dentro da minha db tem esse znote la e em um script de pontos precisa atualizar uma tabela de lá mas nao consigo atualizar isso, na real já até rodei uma query la que atualiza mas nao adianta nada
 
vlw por responder mano nem vi q tu era br, cara eu nao tenho a pasta znote acc mas dentro da minha db tem esse znote la e em um script de pontos precisa atualizar uma tabela de lá mas nao consigo atualizar isso, na real já até rodei uma query la que atualiza mas nao adianta nada
Lua:
-- BETA VERSION, net tested yet
-- Instruction:
-- creaturescripts.xml      <event type="extendedopcode" name="Shop" script="shop.lua" />
-- and in login.lua         player:registerEvent("Shop")
-- create sql table shop_history
-- set variables
-- set up function init(), add there items and categories, follow examples
-- set up callbacks at the bottom to add player item/outfit/whatever you want

local SHOP_EXTENDED_OPCODE = 201
local SHOP_OFFERS = {}
local SHOP_CALLBACKS = {}
local SHOP_CATEGORIES = nil
local SHOP_BUY_URL = "http://otland.net" -- can be empty
local SHOP_AD = { -- can be nil
  image = "https://s3.envato.com/files/62273611/PNG%20Blue/Banner%20blue%20468x60.png",
  url = "http://************",
  text = ""
}
local MAX_PACKET_SIZE = 50000

--[[ SQL TABLE
CREATE TABLE `shop_history` (
  `id` int(11) NOT NULL,
  `account` int(11) NOT NULL,
  `player` int(11) NOT NULL,
  `date` datetime NOT NULL,
  `title` varchar(100) NOT NULL,
  `cost` int(11) NOT NULL,
  `details` varchar(500) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `shop_history`
  ADD PRIMARY KEY (`id`);
ALTER TABLE `shop_history`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
]]--

function init()
  --  print(json.encode(g_game.getLocalPlayer():getOutfit())) -- in console in otclient, will print current outfit and mount
 
  SHOP_CATEGORIES = {}

  local category1 = addCategory({
    type="item",
    item=ItemType(2160):getClientId(),
    count=100,
    name="Items"
  })
  local category2 = addCategory({
    type="outfit",
    name="Outfits",
    outfit={
        mount=0,
        feet=114,
        legs=114,
        body=116,
        type=143,
        auxType=0,
        addons=3,
        head=2,
        rotating=true
    }
  })
  local category3 = addCategory({
    type="image",
    image="http://************/images/137.png",
    name="Category with http image"
  })
  local category4 = addCategory({
    type="image",
    image="/data/images/game/states/electrified.png",
    name="Category with local image"
  })
 
 
  category1.addItem(1, 2160, 1, "1 Crystal coin", "description of cristal coin")
  category1.addItem(5, 2160, 5, "5 Crystal coin", "description of cristal coin")
  category1.addItem(50, 2160, 50, "50 Crystal coin", "description of cristal coin")
  category1.addItem(90, 2160, 100, "100 Crystal coin", "description of cristal coin")
  category1.addItem(200, 2493, 1, "Demon helmet1", "woo\ndemon helmet\nnice, you should buy it")
  category1.addItem(1, 2160, 1, "1 Crystal coin1", "description of cristal coin")
  category1.addItem(5, 2160, 5, "5 Crystal coin1", "description of cristal coin")
  category1.addItem(50, 2160, 50, "50 Crystal coin1", "description of cristal coin")
  category1.addItem(90, 2160, 100, "100 Crystal coin1", "description of cristal coin")
  category1.addItem(200, 2493, 1, "Demon helmet2", "woo\ndemon helmet\nnice, you should buy it")
  category1.addItem(1, 2160, 1, "1 Crystal coin3", "description of cristal coin")
  category1.addItem(5, 2160, 5, "5 Crystal coin3", "description of cristal coin")
  category1.addItem(50, 2160, 50, "50 Crystal coin3", "description of cristal coin")
  category1.addItem(90, 2160, 100, "100 Crystal coin3", "description of cristal coin")
  category1.addItem(200, 2493, 1, "Demon helmet3", "wooxD\ndemon helmet\nnice, you should buy it")
 
  category2.addOutfit(500, {
        mount=0,
        feet=114,
        legs=114,
        body=116,
        type=143,
        auxType=0,
        addons=3,
        head=2,
        rotating=true
    }, "title of this cool outfit or whatever", "this is your new cool outfit. You can buy it here.\nsrlsy")
    category2.addOutfit(100, {
        mount=682,
        feet=0,
        legs=0,
        body=0,
        type=143,
        auxType=0,
        addons=0,
        head=0,
        rotating=true
    }, "MOUNT!!!", "DOUBLE CLICK TO BUY THIS MOUNT. IDK NAME")
    
    category2.addOutfit(100, {
        mount=0,
        feet=0,
        legs=0,
        body=0,
        type=35,
        auxType=0,
        addons=0,
        head=0,
        rotating=true
    }, "Demon outfit", "Want be a demon?\nNo problem")
    category2.addOutfit(100, {
        mount=0,
        feet=0,
        legs=0,
        body=0,
        type=35,
        auxType=0,
        addons=0,
        head=0,
        rotating=false
    }, "Demon outfit2", "This one is not rotating")
    
    category4.addImage(10000, "/data/images/game/states/haste.png", "Offer with local image", "another local image\n/data/images/game/states/haste.png")
    category4.addImage(10000, "http://************/images/freezing.png", "Offer with remote image and custom buy action", "blalasdasd image\nhttp://************/images/freezing.png", customImageBuyAction)
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
  }
end

function getPoints(player)
  local points = 0
  local resultId = db.storeQuery("SELECT `points` FROM `znote_accounts` WHERE `id` = " .. player:getAccountId())
  if resultId ~= false then
    points = result.getDataInt(resultId, "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
  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) -- refresh categories, maybe invalid
    return sendMessage(player, "Error!", "Invalid offer")     
  end
  local points = getPoints(player)
  if not offer['cost'] or offer['cost'] > points or points < 1 then
    return sendMessage(player, "Error!", "You don't have enough points to buy " .. offer['title'] .."!", true)   
  end
  local status = callback(player, offer)
  if status == true then   
    db.query("UPDATE `znote_accounts` set `points` = `points` - " .. offer['cost'] .. " WHERE `id` = " .. player:getAccountId())
    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 sendMessage(player, "Success!", "You bought " .. offer['title'] .."!", true)
  end
  if status == nil or status == false then
    status = "Unknown error while buying " .. offer['title']
  end
  sendMessage(player, "Error!", status)
end

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"] = "Bought on " .. result.getDataString(resultId, "date") .. " for " .. result.getDataInt(resultId, "cost") .. " points."
    until not result.next(resultId)
    result.free(resultId)
    end
 
  sendJSON(player, "history", history)
end

-- BUY CALLBACKS
-- May be useful: print(json.encode(offer))

function defaultItemBuyAction(player, offer)
  -- todo: check if has capacity
  if player:addItem(offer["itemId"], offer["count"], false) then
    return true
  end
  return "Can't add item! Do you have enough space?"
end

function defaultOutfitBuyAction(player, offer)
  return "default outfit buy action is not implemented"
end

function defaultImageBuyAction(player, offer)
  return "default image buy action is not implemented"
end

function customImageBuyAction(player, offer)
  return "custom image buy action is not implemented. Offer: " .. offer['title']
end
 
Lua:
-- BETA VERSION, net tested yet
-- Instruction:
-- creaturescripts.xml      <event type="extendedopcode" name="Shop" script="shop.lua" />
-- and in login.lua         player:registerEvent("Shop")
-- create sql table shop_history
-- set variables
-- set up function init(), add there items and categories, follow examples
-- set up callbacks at the bottom to add player item/outfit/whatever you want

local SHOP_EXTENDED_OPCODE = 201
local SHOP_OFFERS = {}
local SHOP_CALLBACKS = {}
local SHOP_CATEGORIES = nil
local SHOP_BUY_URL = "http://otland.net" -- can be empty
local SHOP_AD = { -- can be nil
  image = "https://s3.envato.com/files/62273611/PNG%20Blue/Banner%20blue%20468x60.png",
  url = "http://************",
  text = ""
}
local MAX_PACKET_SIZE = 50000

--[[ SQL TABLE
CREATE TABLE `shop_history` (
  `id` int(11) NOT NULL,
  `account` int(11) NOT NULL,
  `player` int(11) NOT NULL,
  `date` datetime NOT NULL,
  `title` varchar(100) NOT NULL,
  `cost` int(11) NOT NULL,
  `details` varchar(500) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `shop_history`
  ADD PRIMARY KEY (`id`);
ALTER TABLE `shop_history`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
]]--

function init()
  --  print(json.encode(g_game.getLocalPlayer():getOutfit())) -- in console in otclient, will print current outfit and mount
 
  SHOP_CATEGORIES = {}

  local category1 = addCategory({
    type="item",
    item=ItemType(2160):getClientId(),
    count=100,
    name="Items"
  })
  local category2 = addCategory({
    type="outfit",
    name="Outfits",
    outfit={
        mount=0,
        feet=114,
        legs=114,
        body=116,
        type=143,
        auxType=0,
        addons=3,
        head=2,
        rotating=true
    }
  })
  local category3 = addCategory({
    type="image",
    image="http://************/images/137.png",
    name="Category with http image"
  })
  local category4 = addCategory({
    type="image",
    image="/data/images/game/states/electrified.png",
    name="Category with local image"
  })
 
 
  category1.addItem(1, 2160, 1, "1 Crystal coin", "description of cristal coin")
  category1.addItem(5, 2160, 5, "5 Crystal coin", "description of cristal coin")
  category1.addItem(50, 2160, 50, "50 Crystal coin", "description of cristal coin")
  category1.addItem(90, 2160, 100, "100 Crystal coin", "description of cristal coin")
  category1.addItem(200, 2493, 1, "Demon helmet1", "woo\ndemon helmet\nnice, you should buy it")
  category1.addItem(1, 2160, 1, "1 Crystal coin1", "description of cristal coin")
  category1.addItem(5, 2160, 5, "5 Crystal coin1", "description of cristal coin")
  category1.addItem(50, 2160, 50, "50 Crystal coin1", "description of cristal coin")
  category1.addItem(90, 2160, 100, "100 Crystal coin1", "description of cristal coin")
  category1.addItem(200, 2493, 1, "Demon helmet2", "woo\ndemon helmet\nnice, you should buy it")
  category1.addItem(1, 2160, 1, "1 Crystal coin3", "description of cristal coin")
  category1.addItem(5, 2160, 5, "5 Crystal coin3", "description of cristal coin")
  category1.addItem(50, 2160, 50, "50 Crystal coin3", "description of cristal coin")
  category1.addItem(90, 2160, 100, "100 Crystal coin3", "description of cristal coin")
  category1.addItem(200, 2493, 1, "Demon helmet3", "wooxD\ndemon helmet\nnice, you should buy it")
 
  category2.addOutfit(500, {
        mount=0,
        feet=114,
        legs=114,
        body=116,
        type=143,
        auxType=0,
        addons=3,
        head=2,
        rotating=true
    }, "title of this cool outfit or whatever", "this is your new cool outfit. You can buy it here.\nsrlsy")
    category2.addOutfit(100, {
        mount=682,
        feet=0,
        legs=0,
        body=0,
        type=143,
        auxType=0,
        addons=0,
        head=0,
        rotating=true
    }, "MOUNT!!!", "DOUBLE CLICK TO BUY THIS MOUNT. IDK NAME")
   
    category2.addOutfit(100, {
        mount=0,
        feet=0,
        legs=0,
        body=0,
        type=35,
        auxType=0,
        addons=0,
        head=0,
        rotating=true
    }, "Demon outfit", "Want be a demon?\nNo problem")
    category2.addOutfit(100, {
        mount=0,
        feet=0,
        legs=0,
        body=0,
        type=35,
        auxType=0,
        addons=0,
        head=0,
        rotating=false
    }, "Demon outfit2", "This one is not rotating")
   
    category4.addImage(10000, "/data/images/game/states/haste.png", "Offer with local image", "another local image\n/data/images/game/states/haste.png")
    category4.addImage(10000, "http://************/images/freezing.png", "Offer with remote image and custom buy action", "blalasdasd image\nhttp://************/images/freezing.png", customImageBuyAction)
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
  }
end

function getPoints(player)
  local points = 0
  local resultId = db.storeQuery("SELECT `points` FROM `znote_accounts` WHERE `id` = " .. player:getAccountId())
  if resultId ~= false then
    points = result.getDataInt(resultId, "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
  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) -- refresh categories, maybe invalid
    return sendMessage(player, "Error!", "Invalid offer")    
  end
  local points = getPoints(player)
  if not offer['cost'] or offer['cost'] > points or points < 1 then
    return sendMessage(player, "Error!", "You don't have enough points to buy " .. offer['title'] .."!", true)  
  end
  local status = callback(player, offer)
  if status == true then  
    db.query("UPDATE `znote_accounts` set `points` = `points` - " .. offer['cost'] .. " WHERE `id` = " .. player:getAccountId())
    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 sendMessage(player, "Success!", "You bought " .. offer['title'] .."!", true)
  end
  if status == nil or status == false then
    status = "Unknown error while buying " .. offer['title']
  end
  sendMessage(player, "Error!", status)
end

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"] = "Bought on " .. result.getDataString(resultId, "date") .. " for " .. result.getDataInt(resultId, "cost") .. " points."
    until not result.next(resultId)
    result.free(resultId)
    end
 
  sendJSON(player, "history", history)
end

-- BUY CALLBACKS
-- May be useful: print(json.encode(offer))

function defaultItemBuyAction(player, offer)
  -- todo: check if has capacity
  if player:addItem(offer["itemId"], offer["count"], false) then
    return true
  end
  return "Can't add item! Do you have enough space?"
end

function defaultOutfitBuyAction(player, offer)
  return "default outfit buy action is not implemented"
end

function defaultImageBuyAction(player, offer)
  return "default image buy action is not implemented"
end

function customImageBuyAction(player, offer)
  return "custom image buy action is not implemented. Offer: " .. offer['title']
end
yes bro im using exactly this opcode code, what im in need is to the points inside it work to bu the offers, nothing that i did added points to it, only to the site :(
 
Back
Top