diff --git a/config.lua.dist b/config.lua.dist index 9d1ed2fa681..1e3425ac1c7 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -6,6 +6,7 @@ useAnyDatapackFolder = false dataPackDirectory = "data-otservbr-global" -- Don't change this unless you know what you're doing coreDirectory = "data" +tournamentCoinsName = "Tournament Coins" -- Set log level -- It can be trace, debug, info, warning, error, critical, off (default: info). diff --git a/data-otservbr-global/npc/jeronimo.lua b/data-otservbr-global/npc/jeronimo.lua index 5f9fdc122e3..86c6a69e6ab 100644 --- a/data-otservbr-global/npc/jeronimo.lua +++ b/data-otservbr-global/npc/jeronimo.lua @@ -23,10 +23,13 @@ npcConfig.flags = { floorchange = false, } +local tournamentCoinName = configManager.getString(configKeys.TOURNAMENT_COINS_NAME) + npcConfig.voices = { interval = 15000, chance = 50, - { text = "Change your Bar of Gold's for Items here!" }, + { text = "Change your " .. tournamentCoinName .. " for Items here!" }, + { text = "Visit our Game Store -> Tournament Shop to check the offers" }, } local keywordHandler = KeywordHandler:new() @@ -56,15 +59,84 @@ npcType.onCloseChannel = function(npc, creature) npcHandler:onCloseChannel(npc, creature) end --- ID, Count, Price -local eventShopItems = { - ["small stamina refill"] = { 22473, 1, 100 }, - ["zaoan chess box"] = { 18339, 1, 100 }, - ["pannier backpack"] = { 19159, 1, 70 }, - ["green light"] = { 21217, 1, 70 }, - ["blood herb"] = { 3734, 3, 10 }, - ["draken doll"] = { 12044, 1, 70 }, - ["bear doll"] = { 3001, 1, 70 }, +local OfferType = { + ExerciseWeapon = 1, + Doll = 2, + House = 3, + Utils = 4, + Outfit = 5, + Mount = 6, +} + +--local listShopItems = { +-- ["name"] = { id = x, count = 1, value = x, charges = x, type = OfferType.x }, +--} +local listShopItems = { + ["exercise sword"] = { id = 28552, count = 1, value = 700, charges = 1500, type = OfferType.ExerciseWeapon }, + ["exercise axe"] = { id = 28553, count = 1, value = 700, charges = 1500, type = OfferType.ExerciseWeapon }, + ["exercise club"] = { id = 28554, count = 1, value = 700, charges = 1500, type = OfferType.ExerciseWeapon }, + ["exercise bow"] = { id = 28555, count = 1, value = 700, charges = 1500, type = OfferType.ExerciseWeapon }, + ["exercise rod"] = { id = 28556, count = 1, value = 700, charges = 1500, type = OfferType.ExerciseWeapon }, + ["exercise wand"] = { id = 28557, count = 1, value = 700, charges = 1500, type = OfferType.ExerciseWeapon }, + + ["baby brain squid"] = { id = 32909, count = 1, value = 800, wrap = true, type = OfferType.House }, + ["baby vulcongra"] = { id = 32908, count = 1, value = 800, wrap = true, type = OfferType.House }, + ["cerberus champion puppy"] = { id = 31464, count = 1, value = 800, wrap = true, type = OfferType.House }, + ["guzzlemaw grub"] = { id = 32907, count = 1, value = 800, wrap = true, type = OfferType.House }, + ["jousting eagle baby"] = { id = 31462, count = 1, value = 800, wrap = true, type = OfferType.House }, + ["demon doll"] = { id = 32918, count = 1, value = 400, wrap = true, type = OfferType.House }, + ["ogre rowdy doll"] = { id = 32944, count = 1, value = 400, wrap = true, type = OfferType.House }, + ["retching horror doll"] = { id = 32945, count = 1, value = 400, wrap = true, type = OfferType.House }, + ["vexclaw doll"] = { id = 32943, count = 1, value = 400, wrap = true, type = OfferType.House }, + ["draken doll"] = { id = 12044, count = 1, value = 150, wrap = true, type = OfferType.House }, + ["bear doll"] = { id = 3001, count = 1, value = 150, wrap = true, type = OfferType.House }, + + ["gilded blessed shield"] = { id = 37165, count = 1, value = 1500, wrap = true, type = OfferType.House }, + ["gilded crown"] = { id = 34332, count = 1, value = 1500, wrap = true, type = OfferType.House }, + ["gilded horned helmet"] = { id = 38640, count = 1, value = 1500, wrap = true, type = OfferType.House }, + ["gilded magic longsword"] = { id = 36995, count = 1, value = 1500, wrap = true, type = OfferType.House }, + ["gilded warlord sword"] = { id = 39767, count = 1, value = 1500, wrap = true, type = OfferType.House }, + + ["sublime tournament accolade"] = { id = 31472, count = 1, value = 500, wrap = true, type = OfferType.House }, + ["tournament accolade"] = { id = 31470, count = 1, value = 500, wrap = true, type = OfferType.House }, + + ["sublime tournament carpet"] = { id = 31467, count = 1, value = 100, wrap = true, type = OfferType.House }, + ["tournament carpet"] = { id = 31466, count = 1, value = 100, wrap = true, type = OfferType.House }, + + ["carved table"] = { id = 32972, count = 1, value = 100, wrap = true, type = OfferType.House }, + ["carved table centre"] = { id = 32974, count = 1, value = 100, wrap = true, type = OfferType.House }, + ["carved table corner"] = { id = 32969, count = 1, value = 100, wrap = true, type = OfferType.House }, + + ["cozy couch"] = { id = 32948, count = 1, value = 100, wrap = true, type = OfferType.House }, + ["cozy couch left end"] = { id = 32948, count = 1, value = 100, wrap = true, type = OfferType.House }, + ["cozy couch right end"] = { id = 32956, count = 1, value = 100, wrap = true, type = OfferType.House }, + ["cozy couch corner"] = { id = 32964, count = 1, value = 100, wrap = true, type = OfferType.House }, + + ["zaoan chess box"] = { id = 18339, count = 1, value = 200, type = OfferType.Utils }, + ["pannier backpack"] = { id = 19159, count = 1, value = 150, type = OfferType.Utils }, + ["green light"] = { id = 21217, count = 1, value = 80, type = OfferType.Utils }, + ["blood herb"] = { id = 3734, count = 3, value = 30, type = OfferType.Utils }, + + ["full dragon slayer"] = { id = { female = 1289, male = 1288 }, value = 5000, type = OfferType.Outfit }, + ["full lion of war"] = { id = { female = 1207, male = 1206 }, value = 2000, type = OfferType.Outfit }, + ["full veteran paladin"] = { id = { female = 1205, male = 1204 }, value = 2000, type = OfferType.Outfit }, + ["full void master"] = { id = { female = 1203, male = 1202 }, value = 2000, type = OfferType.Outfit }, + + ["cerberus champion"] = { id = 146, value = 4000, type = OfferType.Mount }, + ["jousting eagle"] = { id = 145, value = 1500, type = OfferType.Mount }, +} + +local offersByCategories = { + ["exercise weapons"] = "{exercise sword} (700), {exercise axe} (700), {exercise club} (700), {exercise bow} (700), {exercise rod} (700), {exercise wand} (700). Each one with 1500 charges.", + ["dolls"] = "{baby brain squid} (800), {baby vulcongra} (800), {cerberus champion puppy} (800), {guzzlemaw grub} (800), {jousting eagle baby} (800), {demon doll} (400), {ogre rowdy doll} (400), {retching horror doll} (400), {vexclaw doll} (400), {draken doll} (150), {bear doll} (150).", + ["house decorations"] = "\nGilded: {gilded blessed shield} (1500), {gilded crown} (1500), {gilded horned helmet} (1500), {gilded magic longsword} (1500), {gilded warlord sword} (1500).\n" + .. "Accolade: {sublime tournament accolade} (500), {tournament accolade} (500).\n" + .. "Carpet: {sublime tournament carpet} (100), {tournament carpet} (100).\n" + .. "Table: {carved table} (100), {carved table centre} (100), {carved table corner} (100).\n" + .. "Cozy: {cozy couch} (100), {cozy couch left end} (100), {cozy couch right end} (100), {cozy couch corner} (100).", + ["utils"] = "{zaoan chess box} (200), {pannier backpack} (150), {green light} (80), {blood herb} (30).", + ["outfits"] = "{full lion of war} (2000), {full veteran paladin} (2000), {full void master} (2000), {full dragon slayer} (5000).", + ["mounts"] = "{jousting eagle} (1500), {cerberus champion} (4000).", } local function creatureSayCallback(npc, creature, type, message) @@ -75,43 +147,157 @@ local function creatureSayCallback(npc, creature, type, message) return false end + local amountTournamentCoins = player:getTournamentCoins() or 0 message = string.lower(message) - if message == "event shop" then - npcHandler:say("In our website enter in {Events} => {Events Shop}.", npc, creature) + if message == "help" or message == tournamentCoinName:lower() then + npcHandler:say("In our game store -> Tournament Shop", npc, creature) + return true + elseif message == "balance" then + npcHandler:say(string.format("Your balance is %i %s%s!", amountTournamentCoins, tournamentCoinName:lower(), amountTournamentCoins > 1 and "s" or ""), npc, creature) + return true + elseif MsgContains(message, "categor") then + npcHandler:say("You can see items by category: {Exercise Weapons}, {Dolls}, {House Decorations}, {Utils}, {Outfits} or {Mounts}.", npc, creature) + npcHandler:setTopic(playerId, 1) + return true end - if eventShopItems[message] then + if (npcHandler:getTopic(playerId) == 2 or npcHandler:getTopic(playerId) == 0) and listShopItems[message] == nil then npcHandler:setTopic(playerId, 0) - local itemId, itemCount, itemPrice = eventShopItems[message][1], eventShopItems[message][2], eventShopItems[message][3] - if player:getItemCount(14112) > 0 then - npcHandler:say("You want buy {" .. message .. "} for " .. itemPrice .. "x?", npc, creature) - npcHandler:setTopic(message) - else - npcHandler:say("You don't have " .. itemPrice .. " {Bar of Gold(s)}!", npc, creature) + npcHandler:say("We can't find the item that you want, try again or access our game store to see the offers!", npc, creature) + return true + end + + if npcHandler:getTopic(playerId) == 1 then + npcHandler:setTopic(playerId, 2) + local text = offersByCategories[message] + if text == nil then + text = "We can't find the {category} that you want, try again or access our game store to see the offers!" + npcHandler:setTopic(playerId, 0) + end + npcHandler:say(text, npc, creature) + return true + end + + if (npcHandler:getTopic(playerId) == 2 or npcHandler:getTopic(playerId) == 0) and listShopItems[message] ~= nil then + local selected = listShopItems[message] + if amountTournamentCoins < selected.value then + npcHandler:say(string.format("You don't have %i {%s}!", selected.value, tournamentCoinName), npc, creature) + npcHandler:setTopic(playerId, 0) + npcHandler:setTopic("selected", {}) + npcHandler:setTopic("outfit", {}) + npcHandler:setTopic("mount", {}) return true end + + local descCharge = "" + if selected.type == OfferType.ExerciseWeapon and selected.charges ~= nil then + descCharge = " with " .. selected.charges .. " charges" + end + + if selected.type == OfferType.Outfit then + npcHandler:say(string.format("You want buy %s outfit for %i %s? {yes} or {no}", message, selected.value, tournamentCoinName:lower()), npc, creature) + npcHandler:setTopic("outfit", message) + elseif selected.type == OfferType.Mount then + npcHandler:say(string.format("You want buy %s mount for %i %s? {yes} or {no}", message, selected.value, tournamentCoinName:lower()), npc, creature) + npcHandler:setTopic("mount", message) + else + npcHandler:say(string.format("You want buy %ix %s%s for %i %s? {yes} or {no}", selected.count, message, descCharge, selected.value, tournamentCoinName:lower()), npc, creature) + end + + npcHandler:setTopic(playerId, 3) + npcHandler:setTopic("selected", selected) + + return true end - if eventShopItems[npcHandler:getTopic(playerId)] then - local itemId, itemCount, itemPrice = eventShopItems[npcHandler:getTopic(playerId)][1], eventShopItems[npcHandler:getTopic(playerId)][2], eventShopItems[npcHandler:getTopic(playerId)][3] - if message == "no" then + if npcHandler:getTopic(playerId) == 3 then + if message ~= "yes" then npcHandler:say("So... what you want?", npc, creature) npcHandler:setTopic(playerId, 0) - elseif message == "yes" then - if player:getItemCount(14112) >= itemPrice then - npcHandler:say("You bought {" .. npcHandler:getTopic(playerId) .. "} " .. itemCount .. "x for " .. itemPrice .. " {Bar of Gold(s)}!", npc, creature) - player:removeItem(14112, itemPrice) - player:addItem(itemId, itemCount) - else - npcHandler:say("You don't have enough bar's.", npc, creature) + npcHandler:setTopic("selected", {}) + return true + else + local selected = npcHandler:getTopic("selected") + if not selected or selected == nil then + npcHandler:setTopic(playerId, 0) + npcHandler:setTopic("selected", {}) + logger.error("[jeronimo]: item not selected") return true end + + if selected.type == OfferType.Mount then + if player:hasMount(selected.id) then + npcHandler:say("You already own this mount.", npc, creature) + return true + end + player:updateTournamentCoins(selected.value, "remove") + player:addMount(selected.id) + local mountName = npcHandler:getTopic("mount") + local msg = string.format("You bought %s mount for %i {%s}!", mountName, selected.value, tournamentCoinName) + player:getPosition():sendMagicEffect(CONST_ME_HOLYDAMAGE) + npcHandler:say(msg, npc, creature) + npcHandler:setTopic(playerId, 0) + npcHandler:setTopic("selected", {}) + npcHandler:setTopic("mount", {}) + elseif selected.type == OfferType.Outfit then + local female, male = selected.id.female, selected.id.male + if player:hasOutfit(female) or player:hasOutfit(male) then + npcHandler:say("You already own this outfit.", npc, creature) + return true + end + player:updateTournamentCoins(selected.value, "remove") + player:addOutfitAddon(female, 3) + player:addOutfitAddon(male, 3) + local outfitName = npcHandler:getTopic("outfit") + local msg = string.format("You bought %s outfit for %i %s!", outfitName, selected.value, tournamentCoinName:lower()) + player:getPosition():sendMagicEffect(CONST_ME_HOLYDAMAGE) + npcHandler:say(msg, npc, creature) + npcHandler:setTopic(playerId, 0) + npcHandler:setTopic("selected", {}) + npcHandler:setTopic("outfit", {}) + else + local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX) + local itemT = ItemType(selected.id) + if amountTournamentCoins >= selected.value then + if inbox and inbox:getEmptySlots() > 0 and player:getFreeCapacity() >= itemT:getCapacity() then + player:updateTournamentCoins(selected.value, "remove") + + if selected.charges ~= nil and selected.charges > 0 then + local addedItem = player:addItem(selected.id, selected.count, true) + addedItem:setAttribute("charges", selected.charges) + else + selected.charges = 0 + if selected.wrap then + local decoKit = inbox:addItem(ITEM_DECORATION_KIT, 1) + if decoKit then + decoKit:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, "Unwrap it in your own house to create a <" .. itemT:getName() .. ">.") + decoKit:setCustomAttribute("unWrapId", selected.id) + decoKit:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime()) + player:sendUpdateContainer(inbox) + end + else + player:addItem(selected.id, selected.count) + end + end + local descCharge = selected.charges > 0 and " with " .. selected.charges .. " charges" or "" + local msg = string.format("You bought %ix %s%s for %i {%s} and received in your store inbox!", selected.count, itemT:getName(), descCharge, selected.value, tournamentCoinName) + player:getPosition():sendMagicEffect(CONST_ME_HOLYDAMAGE) + npcHandler:say(msg, npc, creature) + npcHandler:setTopic(playerId, 0) + npcHandler:setTopic("selected", {}) + else + npcHandler:say("You need to have capacity and empty slots to receive.", npc, creature) + end + else + npcHandler:say(string.format("You don't have enough {%s}.", tournamentCoinName), npc, creature) + end + end end end + return true end +npcHandler:setMessage(MESSAGE_GREET, "Welcome |PLAYERNAME|! You can see my offers by {categories} or if you want to change your " .. tournamentCoinName:lower() .. " to items, just say the item name! If you want help, say {help}! Or do you want know your {balance}?") npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback) npcHandler:addModule(FocusModule:new(), npcConfig.name, true, true, true) - --- npcType registering the npcConfig table npcType:register(npcConfig) diff --git a/data-otservbr-global/scripts/actions/custom/tournament_tokens.lua b/data-otservbr-global/scripts/actions/custom/tournament_tokens.lua new file mode 100644 index 00000000000..5aef9deaf67 --- /dev/null +++ b/data-otservbr-global/scripts/actions/custom/tournament_tokens.lua @@ -0,0 +1,17 @@ +local token = Action() + +local tokenId = 14112 -- bar of gold (if you don't use custom item, you need to verify all drops in monsters) + +function token.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:getItemCount(tokenId) > 0 then + local tournamentCoins = player:getItemCount(tokenId) + db.query("UPDATE `accounts` SET `tournament_coins` = `tournament_coins` + '" .. tournamentCoins .. "' WHERE `id` = '" .. player:getAccountId() .. "';") + player:sendTextMessage(MESSAGE_INFO_DESCR, string.format("You added %d %s to your account.", tournamentCoins, configManager.getString(configKeys.TOURNAMENT_COINS_NAME):lower())) + player:removeItem(tokenId, tournamentCoins) + player:getPosition():sendMagicEffect(CONST_ME_HOLYAREA) + end + return true +end + +token:id(tokenId) +token:register() diff --git a/data-otservbr-global/scripts/globalevents/vip/online_coins.lua b/data-otservbr-global/scripts/globalevents/vip/online_coins.lua index f249752397d..af25471ee28 100644 --- a/data-otservbr-global/scripts/globalevents/vip/online_coins.lua +++ b/data-otservbr-global/scripts/globalevents/vip/online_coins.lua @@ -8,7 +8,7 @@ local config = { -- per hour | system will calculate how many coins will be given and when -- put 0 in coinsPerHour.free to disable free from receiving coins coinsPerHour = { - free = 1, + free = 0, vip = 5, }, @@ -43,8 +43,8 @@ function onlineCoinsEvent.onThink(interval) player:setStorageValue(config.storage, coins * 10000000) if coins >= config.awardOn then local coinsMath = math.floor(coins) - player:addTibiaCoins(coinsMath, true) - player:sendTextMessage(MESSAGE_FAILURE, string.format("Congratulations %s!\z You have received %d %s for being online.", player:getName(), coinsMath, "tibia coins")) + player:addTibiaCoins(coinsMath) + player:sendTextMessage(MESSAGE_STATUS_SMALL, string.format("Congratulations %s!\z You have received %d %s for being online.", player:getName(), coinsMath, "tibia coins")) player:setStorageValue(config.storage, (coins - coinsMath) * 10000000) end end diff --git a/data-otservbr-global/scripts/globalevents/vip/online_tokens.lua b/data-otservbr-global/scripts/globalevents/vip/online_tokens.lua index 656039dfe66..4a0a86ca58d 100644 --- a/data-otservbr-global/scripts/globalevents/vip/online_tokens.lua +++ b/data-otservbr-global/scripts/globalevents/vip/online_tokens.lua @@ -3,9 +3,9 @@ local config = { storage = Storage.VipSystem.OnlineTokensGain, checkDuplicateIps = false, - tokenItemId = 14112, -- bar of gold + tokenItemId = 14112, -- bar of gold (if you don't use custom item, you need to verify all drops in monsters) - interval = 60 * 1000, + interval = 60 * 1000, -- 1 hora -- per hour | system will calculate how many tokens will be given and when -- put 0 in tokensPerHour.free to disable free from receiving tokens @@ -30,6 +30,7 @@ function onlineTokensEvent.onThink(interval) return true end + local tournamentCoinName = configManager.getString(configKeys.TOURNAMENT_COINS_NAME) local checkIp = {} for _, player in pairs(players) do if player:getGroup():getId() > GROUP_TYPE_SENIORTUTOR then @@ -46,7 +47,7 @@ function onlineTokensEvent.onThink(interval) local tokensMath = math.floor(tokens) local item = player:addItem(config.tokenItemId, tokensMath) if item then - player:sendTextMessage(MESSAGE_FAILURE, string.format("Congratulations %s!\z You have received %d %s for being online.", player:getName(), tokensMath, "tokens")) + player:sendTextMessage(MESSAGE_STATUS_SMALL, string.format("Congratulations %s!\z You have received %d %s for being online.", player:getName(), tokensMath, tournamentCoinName)) end player:setStorageValue(config.storage, (tokens - tokensMath) * 10000000) end diff --git a/data/modules/scripts/gamestore/gamestore.lua b/data/modules/scripts/gamestore/gamestore.lua index f000c4079af..e05b5459774 100644 --- a/data/modules/scripts/gamestore/gamestore.lua +++ b/data/modules/scripts/gamestore/gamestore.lua @@ -2675,7 +2675,7 @@ GameStore.Categories = { { icons = { "Outfit_Veteran_Paladin_Male_Addon_3.png", "Outfit_Veteran_Paladin_Female_Addon_3.png" }, name = "Full Veteran Paladin Outfit", - price = 750, + price = 2000, sexId = { female = 1205, male = 1204 }, addon = 3, description = "{character}\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nA Veteran Paladin has mastered the art of distance fighting. No matter how far away his prey may be, a marksman like the Veteran Paladin will always hit with extraordinary precision. No one can escape his keen hawk-eyed vision and even small stones become deadly weapons in his hands.", @@ -2684,7 +2684,7 @@ GameStore.Categories = { { icons = { "Outfit_Void_Master_Male_Addon_3.png", "Outfit_Void_Master_Female_Addon_3.png" }, name = "Full Void Master Outfit", - price = 750, + price = 2000, sexId = { female = 1203, male = 1202 }, addon = 3, description = "{character}\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nAccording to ancient rumours, the pulsating orb that the Void Master balances skilfully on the tip of his staff consists of powerful cosmic spheres. If you gaze too long into the infinite emptiness inside the orb, its powers will absorb your mind.", @@ -6455,31 +6455,220 @@ GameStore.Categories = { -- Tournament { icons = { "Category_Tournament.png" }, - name = "Tournament", + name = "Tournament Shop", rookgaard = true, - subclasses = { "Tickets", "Exclusive Offers" }, + subclasses = { "TS-Exercise Weapons", "TS-Outfits", "TS-Mounts", "TS-Dolls", "TS-House Furniture" }, }, -- Tournament ~ Tickets + --{ + -- icons = { "Category_Tickets.png" }, + -- parent = "Tournament", + -- name = "Tickets", + -- rookgaard = true, + -- offers = { + -- { + -- icons = { "Tournament_Restricted.png" }, + -- name = "Restricted Tournament Ticket", + -- price = 500, + -- }, + -- }, + --}, { - icons = { "Category_Tickets.png" }, - parent = "Tournament", - name = "Tickets", + icons = { "Category_ExerciseWeapons.png" }, + name = "TS-Exercise Weapons", + parent = "Tournament Shop", rookgaard = true, offers = { { - icons = { "Tournament_Restricted.png" }, - name = "Restricted Tournament Ticket", - price = 500, + icons = { "Exercise_Sword.png" }, + name = "Exercise Sword", + price = 700, + itemtype = 28552, + charges = 1500, + description = "Use it to train your sword fighting skill on an exercise dummy!\n\n{character}\n{storeinbox}\n{info} use it on an exercise dummy to train your sword fighting skill\n{info} usable 1500 times a piece\n{info} this item cannot be traded and cannot be moved", + type = GameStore.OfferTypes.OFFER_TYPE_CHARGES, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Exercise_Axe.png" }, + name = "Exercise Axe", + price = 700, + itemtype = 28553, + charges = 1500, + description = "Use it to train your axe fighting skill on an exercise dummy!\n\n{character}\n{storeinbox}\n{info} use it on an exercise dummy to train your axe fighting skill\n{info} usable 1500 times a piece\n{info} this item cannot be traded and cannot be moved", + type = GameStore.OfferTypes.OFFER_TYPE_CHARGES, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Exercise_Club.png" }, + name = "Exercise Club", + price = 700, + itemtype = 28554, + charges = 1500, + description = "Use it to train your club fighting skill on an exercise dummy!\n\n{character}\n{storeinbox}\n{info} use it on an exercise dummy to train your club fighting skill\n{info} usable 1500 times a piece\n{info} this item cannot be traded and cannot be moved", + type = GameStore.OfferTypes.OFFER_TYPE_CHARGES, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Exercise_Bow.png" }, + name = "Exercise Bow", + price = 700, + itemtype = 28555, + charges = 1500, + description = "Use it to train your distance fighting skill on an exercise dummy!\n\n{character}\n{storeinbox}\n{info} use it on an exercise dummy to train your distance fighting skill\n{info} usable 1500 times a piece\n{info} this item cannot be traded and cannot be moved", + type = GameStore.OfferTypes.OFFER_TYPE_CHARGES, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Exercise_Rod.png" }, + name = "Exercise Rod", + price = 700, + itemtype = 28556, + charges = 1500, + description = "Use it to train your magic level on an exercise dummy!\n\n{character}\n{storeinbox}\n{info} use it on an exercise dummy to train your magic level\n{info} usable 1500 times a piece\n{info} this item cannot be traded and cannot be moved", + type = GameStore.OfferTypes.OFFER_TYPE_CHARGES, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Exercise_Wand.png" }, + name = "Exercise Wand", + price = 700, + itemtype = 28557, + charges = 1500, + description = "Use it to train your magic level on an exercise dummy!\n\n{character}\n{storeinbox}\n{info} use it on an exercise dummy to train your magic level\n{info} usable 1500 times a piece", + type = GameStore.OfferTypes.OFFER_TYPE_CHARGES, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Exercise_Shield.png" }, + name = "Exercise Shield", + price = 700, + itemtype = 44065, + charges = 1500, + description = "Use it to train your shielding skill on an exercise dummy!\n\n{character}\n{storeinbox}\n{info} use it on an exercise dummy to train your shielding skill\n{info} usable 1500 times a piece", + type = GameStore.OfferTypes.OFFER_TYPE_CHARGES, + coinType = GameStore.CoinType.Tournament, }, }, }, - -- Tournament ~ Exclusive Offers + -- Tournament Shop ~ Outfits { - icons = { "Category_ExclusiveOffers.png" }, - name = "Exclusive Offers", - parent = "Tournament", + icons = { "Category_Outfits.png" }, + name = "TS-Outfits", + parent = "Tournament Shop", + rookgaard = true, + offers = { + { + icons = { "Outfit_Dragon_Slayer_Male_Addon_3.png", "Outfit_Dragon_Slayer_Female_Addon_3.png" }, + name = "Full Dragon Slayer Outfit", + price = 5000, + sexId = { female = 1289, male = 1288 }, + addon = 3, + description = "{info} usable by all characters of the account\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nThe souls of countless slain dragons have been fused over the years with this armour, wrought from the impervious scales of the ancestors of those very same beings, wicked and wise, winged and wild. The Dragon Slayer Outfit has seen an unfathomable amount of bloodshed, but it pales in comparison to the untold lives lost in the strife over the armour itself. Only the mightiest warriors can even begin to dream of ever owning this exceedingly rare token of power.", + type = GameStore.OfferTypes.OFFER_TYPE_OUTFIT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Outfit_Lion_of_War_Male_Addon_3.png", "Outfit_Lion_of_War_Female_Addon_3.png" }, + name = "Full Lion of War Outfit", + price = 2000, + sexId = { female = 1207, male = 1206 }, + addon = 3, + description = "{info} usable by all characters of the account\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nThe Lion of War has fought on countless battlefields and never lost once. Enemies tremble with fear when he batters his sword against his almighty shield. Realising that a Lion of War knows no mercy, his opponents often surrender before the battle even begins.", + type = GameStore.OfferTypes.OFFER_TYPE_OUTFIT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Outfit_Veteran_Paladin_Male_Addon_3.png", "Outfit_Veteran_Paladin_Female_Addon_3.png" }, + name = "Full Veteran Paladin Outfit", + price = 2000, + sexId = { female = 1205, male = 1204 }, + addon = 3, + description = "{info} usable by all characters of the account\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nA Veteran Paladin has mastered the art of distance fighting. No matter how far away his prey may be, a marksman like the Veteran Paladin will always hit with extraordinary precision. No one can escape his keen hawk-eyed vision and even small stones become deadly weapons in his hands.", + type = GameStore.OfferTypes.OFFER_TYPE_OUTFIT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Outfit_Void_Master_Male_Addon_3.png", "Outfit_Void_Master_Female_Addon_3.png" }, + name = "Full Void Master Outfit", + price = 2000, + sexId = { female = 1203, male = 1202 }, + addon = 3, + description = "{info} usable by all characters of the account\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nAccording to ancient rumours, the pulsating orb that the Void Master balances skilfully on the tip of his staff consists of powerful cosmic spheres. If you gaze too long into the infinite emptiness inside the orb, its powers will absorb your mind.", + type = GameStore.OfferTypes.OFFER_TYPE_OUTFIT, + coinType = GameStore.CoinType.Tournament, + }, + }, + }, + -- Tournament Shop ~ Mounts + { + icons = { "Category_Mounts.png" }, + name = "TS-Mounts", + parent = "Tournament Shop", + rookgaard = true, + offers = { + { + icons = { "Cerberus_Champion.png" }, + name = "Cerberus Champion", + price = 4000, + id = 146, + description = "{info} usable by all characters of the account\n{speedboost}\n\nA fierce and grim guardian of the underworld has risen to fight side by side with the bravest warriors in order to send evil creatures into the realm of the dead. The three headed Cerberus Champion is constantly baying for blood and using its sharp fangs it easily rips apart even the strongest armour and shield.", + type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Jousting_Eagle.png" }, + name = "Jousting Eagle", + price = 1500, + id = 145, + description = "{info} usable by all characters of the account\n{speedboost}\n\nHigh above the clouds far away from dry land, the training of giant eagles takes place. Only the cream of the crop is able to survive in such harsh environment long enough to call themselves Jousting Eagles while the weaklings find themselves at the bottom of the sea. The tough ones become noble and graceful mounts that are well known for their agility and endurance.", + type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Doom_Skull.png" }, + name = "Doom Skull", + price = 4000, + id = 219, + description = "{character}\n{speedboost}\n\nSkulls are the infernal heralds of untamed power. Bodies are obsolete when sinister forces animate your being. Embrace their presence and command the devastating might that awaits on the back of a grim Doom Skull.", + type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Foxmouse.png" }, + name = "Foxmouse", + price = 2500, + id = 218, + description = "{character}\n{speedboost}\n\nA wild, ancient creature, which had been hiding in the depths of the shadows for a very long time, has been spotted in Tibia again! The almighty Shadow Draptor has returned and only the bravest Tibians can control such a beast!", + type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Corpsefire_Skull.png" }, + name = "Corpsefire Skull", + price = 4000, + id = 221, + description = "{character}\n{speedboost}\n\nSkulls are the infernal heralds of untamed power. Bodies are obsolete when sinister forces animate your being. Embrace their presence and command the devastating might that awaits on the back of an eerie Corpsefire Skull!", + type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, + coinType = GameStore.CoinType.Tournament, + }, + { + icons = { "Spirit_of_Purity.png" }, + name = "Spirit of Purity", + price = 4000, + id = 217, + description = "{character}\n{speedboost}\n\nA wild, ancient creature, which had been hiding in the depths of the shadows for a very long time, has been spotted in Tibia again! The almighty Shadow Draptor has returned and only the bravest Tibians can control such a beast!", + type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, + coinType = GameStore.CoinType.Tournament, + }, + }, + }, + -- Tournament Shop ~ Dolls + { + icons = { "Category_HouseDecorations.png" }, + name = "TS-Dolls", + parent = "Tournament Shop", rookgaard = true, - state = GameStore.States.STATE_NONE, offers = { { icons = { "Baby_Brain_Squid.png" }, @@ -6489,6 +6678,7 @@ GameStore.Categories = { count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { icons = { "Baby_Vulcongra.png" }, @@ -6498,105 +6688,107 @@ GameStore.Categories = { count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Carved_Table.png" }, - name = "Carved Table", - price = 100, - itemtype = 32972, - count = 1, - description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", - type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, - }, - { - icons = { "Carved_Table_Centre.png" }, - name = "Carved Table Centre", - price = 100, - itemtype = 32974, + icons = { "Cerberus_Champion_Puppy.png" }, + name = "Cerberus Champion Puppy", + price = 800, + itemtype = 31464, count = 1, - description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", + description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Carved_Table_Corner.png" }, - name = "Carved Table Corner", - price = 100, - itemtype = 32969, + icons = { "Guzzlemaw_Grub.png" }, + name = "Guzzlemaw Grub", + price = 800, + itemtype = 32907, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Cerberus_Champion.png" }, - name = "Cerberus Champion", - price = 1250, - id = 146, - description = "{info} usable by all characters of the account\n{speedboost}\n\nA fierce and grim guardian of the underworld has risen to fight side by side with the bravest warriors in order to send evil creatures into the realm of the dead. The three headed Cerberus Champion is constantly baying for blood and using its sharp fangs it easily rips apart even the strongest armour and shield.", - type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, - }, - { - icons = { "Cerberus_Champion_Puppy.png" }, - name = "Cerberus Champion Puppy", + icons = { "Jousting_Eagle_Baby.png" }, + name = "Jousting Eagle Baby", price = 800, - itemtype = 31464, + itemtype = 31462, count = 1, description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Cozy_Couch.png" }, - name = "Cozy Couch", - price = 100, - itemtype = 32948, + icons = { "Demon_Doll.png" }, + name = "Demon Doll", + price = 400, + itemtype = 32918, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Cozy_Couch_Left_End.png" }, - name = "Cozy Couch Left End", - price = 100, - itemtype = 32952, + icons = { "Ogre_Rowdy_Doll.png" }, + name = "Ogre Rowdy Doll", + price = 400, + itemtype = 32944, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Cozy_Couch_Right_End.png" }, - name = "Cozy Couch Right End", - price = 100, - itemtype = 32956, + icons = { "Retching_Horror_Doll.png" }, + name = "Retching Horror Doll", + price = 400, + itemtype = 32945, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Cozy_Couch_Corner.png" }, - name = "Cozy Couch Corner", - price = 100, - itemtype = 32964, + icons = { "Vexclaw_Doll.png" }, + name = "Vexclaw Doll", + price = 400, + itemtype = 32943, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Demon_Doll.png" }, - name = "Demon Doll", - price = 400, - itemtype = 32918, + icons = { "Draken_Doll.png" }, + name = "Draken Doll", + price = 150, + itemtype = 12044, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Outfit_Dragon_Slayer_Male_Addon_3.png", "Outfit_Dragon_Slayer_Female_Addon_3.png" }, - name = "Full Dragon Slayer Outfit", - price = 5000, - sexId = { female = 1289, male = 1288 }, - addon = 3, - description = "{info} usable by all characters of the account\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nThe souls of countless slain dragons have been fused over the years with this armour, wrought from the impervious scales of the ancestors of those very same beings, wicked and wise, winged and wild. The Dragon Slayer Outfit has seen an unfathomable amount of bloodshed, but it pales in comparison to the untold lives lost in the strife over the armour itself. Only the mightiest warriors can even begin to dream of ever owning this exceedingly rare token of power.", - type = GameStore.OfferTypes.OFFER_TYPE_OUTFIT, + icons = { "Bear_Doll.png" }, + name = "Bear Doll", + price = 150, + itemtype = 3001, + count = 1, + description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", + type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, + }, + }, + -- Tournament Shop ~ House Furniture + { + icons = { "Category_HouseDecorations.png" }, + name = "TS-House Furniture", + parent = "Tournament Shop", + rookgaard = true, + offers = { { icons = { "Gilded_Blessed_Shield.png" }, name = "Gilded Blessed Shield", @@ -6605,7 +6797,7 @@ GameStore.Categories = { count = 1, description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, - home = true, + coinType = GameStore.CoinType.Tournament, }, { icons = { "Gilded_Crown.png" }, @@ -6615,7 +6807,7 @@ GameStore.Categories = { count = 1, description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, - home = true, + coinType = GameStore.CoinType.Tournament, }, { icons = { "Gilded_Horned_Helmet.png" }, @@ -6625,7 +6817,7 @@ GameStore.Categories = { count = 1, description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, - home = true, + coinType = GameStore.CoinType.Tournament, }, { icons = { "Gilded_Magic_Longsword.png" }, @@ -6635,7 +6827,7 @@ GameStore.Categories = { count = 1, description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, - home = true, + coinType = GameStore.CoinType.Tournament, }, { icons = { "Gilded_Warlord_Sword.png" }, @@ -6645,105 +6837,117 @@ GameStore.Categories = { count = 1, description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, - home = true, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Guzzlemaw_Grub.png" }, - name = "Guzzlemaw Grub", - price = 800, - itemtype = 32907, + icons = { "Sublime_Tournament_Accolade.png" }, + name = "Sublime Tournament Accolade", + price = 500, + itemtype = 31472, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Jousting_Eagle.png" }, - name = "Jousting Eagle", - price = 1250, - id = 145, - description = "{info} usable by all characters of the account\n{speedboost}\n\nHigh above the clouds far away from dry land, the training of giant eagles takes place. Only the cream of the crop is able to survive in such harsh environment long enough to call themselves Jousting Eagles while the weaklings find themselves at the bottom of the sea. The tough ones become noble and graceful mounts that are well known for their agility and endurance.", - type = GameStore.OfferTypes.OFFER_TYPE_MOUNT, + icons = { "Tournament_Accolade.png" }, + name = "Tournament Accolade", + price = 500, + itemtype = 31470, + count = 1, + description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", + type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Jousting_Eagle_Baby.png" }, - name = "Jousting Eagle Baby", - price = 800, - itemtype = 31462, + icons = { "Sublime_Tournament_Carpet.png" }, + name = "Sublime Tournament Carpet", + price = 100, + itemtype = 31467, count = 1, - description = "{house}\n{box}\n{storeinbox}\n{use}\n{backtoinbox}", + description = "{house}\n{box}\n{storeinbox}\n{useicon} use an unwrapped carpet to roll it out or up\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Outfit_Lion_of_War_Male_Addon_3.png", "Outfit_Lion_of_War_Female_Addon_3.png" }, - name = "Full Lion of War Outfit", - price = 1750, - sexId = { female = 1207, male = 1206 }, - addon = 3, - description = "{info} usable by all characters of the account\n{info} colours can be changed using the Outfit dialog\n{info} includes basic outfit and 2 addons which can be selected individually\n\nThe Lion of War has fought on countless battlefields and never lost once. Enemies tremble with fear when he batters his sword against his almighty shield. Realising that a Lion of War knows no mercy, his opponents often surrender before the battle even begins.", - type = GameStore.OfferTypes.OFFER_TYPE_OUTFIT, + icons = { "Tournament_Carpet.png" }, + name = "Tournament Carpet", + price = 100, + itemtype = 31466, + count = 1, + description = "{house}\n{box}\n{storeinbox}\n{useicon} use an unwrapped carpet to roll it out or up\n{backtoinbox}", + type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Ogre_Rowdy_Doll.png" }, - name = "Ogre Rowdy Doll", - price = 400, - itemtype = 32944, + icons = { "Carved_Table.png" }, + name = "Carved Table", + price = 100, + itemtype = 32972, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Retching_Horror_Doll.png" }, - name = "Retching Horror Doll", - price = 400, - itemtype = 32945, + icons = { "Carved_Table_Centre.png" }, + name = "Carved Table Centre", + price = 100, + itemtype = 32974, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Sublime_Tournament_Accolade.png" }, - name = "Sublime Tournament Accolade", - price = 500, - itemtype = 31472, + icons = { "Carved_Table_Corner.png" }, + name = "Carved Table Corner", + price = 100, + itemtype = 32969, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Sublime_Tournament_Carpet.png" }, - name = "Sublime Tournament Carpet", - price = 70, - itemtype = 31467, + icons = { "Cozy_Couch.png" }, + name = "Cozy Couch", + price = 100, + itemtype = 32948, count = 1, - description = "{house}\n{box}\n{storeinbox}\n{useicon} use an unwrapped carpet to roll it out or up\n{backtoinbox}", + description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Tournament_Accolade.png" }, - name = "Tournament Accolade", - price = 500, - itemtype = 31470, + icons = { "Cozy_Couch_Left_End.png" }, + name = "Cozy Couch Left End", + price = 100, + itemtype = 32952, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Tournament_Carpet.png" }, - name = "Tournament Carpet", - price = 70, - itemtype = 31466, + icons = { "Cozy_Couch_Right_End.png" }, + name = "Cozy Couch Right End", + price = 100, + itemtype = 32956, count = 1, - description = "{house}\n{box}\n{storeinbox}\n{useicon} use an unwrapped carpet to roll it out or up\n{backtoinbox}", + description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, { - icons = { "Vexclaw_Doll.png" }, - name = "Vexclaw Doll", - price = 400, - itemtype = 32943, + icons = { "Cozy_Couch_Corner.png" }, + name = "Cozy Couch Corner", + price = 100, + itemtype = 32964, count = 1, description = "{house}\n{box}\n{storeinbox}\n{backtoinbox}", type = GameStore.OfferTypes.OFFER_TYPE_HOUSE, + coinType = GameStore.CoinType.Tournament, }, }, }, diff --git a/data/modules/scripts/gamestore/init.lua b/data/modules/scripts/gamestore/init.lua index 214aec77d43..d17fa6a4b83 100644 --- a/data/modules/scripts/gamestore/init.lua +++ b/data/modules/scripts/gamestore/init.lua @@ -68,6 +68,7 @@ GameStore.ActionType = { GameStore.CoinType = { Coin = 0, Transferable = 1, + Tournament = 2, } GameStore.Storages = { diff --git a/src/account/account.cpp b/src/account/account.cpp index 2e5f58dd864..77f56189b92 100644 --- a/src/account/account.cpp +++ b/src/account/account.cpp @@ -110,7 +110,9 @@ uint8_t Account::addCoins(const uint8_t &type, const uint32_t &amount, const std return enumToValue(AccountErrors_t::Storage); } - registerCoinTransaction(enumToValue(CoinTransactionType::Add), type, amount, detail); + if (!detail.empty()) { + registerCoinTransaction(enumToValue(CoinTransactionType::Add), type, amount, detail); + } return enumToValue(AccountErrors_t::Ok); } diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index 0e53c97546e..f93ed9c8238 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -304,6 +304,7 @@ enum ConfigKey_t : uint16_t { TOGGLE_SERVER_IS_RETRO, TOGGLE_TRAVELS_FREE, TOGGLE_WHEELSYSTEM, + TOURNAMENT_COINS_NAME, TRANSCENDANCE_AVATAR_DURATION, TRANSCENDANCE_CHANCE_FORMULA_A, TRANSCENDANCE_CHANCE_FORMULA_B, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index 35d2cf3b1be..3166226e15a 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -367,6 +367,7 @@ bool ConfigManager::load() { loadStringConfig(L, SERVER_NAME, "serverName", ""); loadStringConfig(L, STORE_IMAGES_URL, "coinImagesURL", ""); loadStringConfig(L, TIBIADROME_CONCOCTION_TICK_TYPE, "tibiadromeConcoctionTickType", "online"); + loadStringConfig(L, TOURNAMENT_COINS_NAME, "tournamentCoinsName", "Tournament Coins"); loadStringConfig(L, URL, "url", ""); loadStringConfig(L, WORLD_TYPE, "worldType", "pvp"); diff --git a/src/lua/functions/creatures/player/player_functions.cpp b/src/lua/functions/creatures/player/player_functions.cpp index 9cc5434abd5..ccba3ffb803 100644 --- a/src/lua/functions/creatures/player/player_functions.cpp +++ b/src/lua/functions/creatures/player/player_functions.cpp @@ -2561,7 +2561,7 @@ int PlayerFunctions::luaPlayerGetTibiaCoins(lua_State* L) { } int PlayerFunctions::luaPlayerAddTibiaCoins(lua_State* L) { - // player:addTibiaCoins(coins) + // player:addTibiaCoins(coins[, detail = ""]) std::shared_ptr player = getUserdataShared(L, 1); if (!player || !player->getAccount()) { reportErrorFunc(getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); @@ -2569,7 +2569,7 @@ int PlayerFunctions::luaPlayerAddTibiaCoins(lua_State* L) { return 1; } - if (player->account->addCoins(enumToValue(CoinType::Normal), getNumber(L, 2)) != enumToValue(AccountErrors_t::Ok)) { + if (player->account->addCoins(enumToValue(CoinType::Normal), getNumber(L, 2), getString(L, 3, "")) != enumToValue(AccountErrors_t::Ok)) { reportErrorFunc("Failed to add coins"); lua_pushnil(L); return 1; @@ -2630,7 +2630,7 @@ int PlayerFunctions::luaPlayerGetTransferableCoins(lua_State* L) { } int PlayerFunctions::luaPlayerAddTransferableCoins(lua_State* L) { - // player:addTransferableCoins(coins) + // player:addTransferableCoins(coins[, detail = ""]) std::shared_ptr player = getUserdataShared(L, 1); if (!player || !player->getAccount()) { reportErrorFunc(getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); @@ -2638,7 +2638,7 @@ int PlayerFunctions::luaPlayerAddTransferableCoins(lua_State* L) { return 1; } - if (player->account->addCoins(enumToValue(CoinType::Transferable), getNumber(L, 2)) != enumToValue(AccountErrors_t::Ok)) { + if (player->account->addCoins(enumToValue(CoinType::Transferable), getNumber(L, 2), getString(L, 3, "")) != enumToValue(AccountErrors_t::Ok)) { reportErrorFunc("failed to add transferable coins"); lua_pushnil(L); return 1; @@ -2681,6 +2681,57 @@ int PlayerFunctions::luaPlayerRemoveTransferableCoins(lua_State* L) { return 1; } +int PlayerFunctions::luaPlayerGetTournamentCoins(lua_State* L) { + // player:getTournamentCoins() + std::shared_ptr player = getUserdataShared(L, 1); + if (!player || !player->getAccount()) { + reportErrorFunc(getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + + auto [coins, result] = player->getAccount()->getCoins(account::CoinType::TOURNAMENT); + + if (result == account::ERROR_NO) { + lua_pushnumber(L, coins); + } + + return 1; +} + +int PlayerFunctions::luaPlayerUpdateTournamentCoins(lua_State* L) { + // player:updateTournamentCoins(coins, action: 'add' | 'remove') + std::shared_ptr player = getUserdataShared(L, 1); + if (!player || !player->getAccount()) { + reportErrorFunc(getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + + std::string tournamentCoinName = asLowerCaseString(g_configManager().getString(TOURNAMENT_COINS_NAME, __FUNCTION__)); + const std::string &action = getString(L, 3); + uint32_t amount = getNumber(L, 2); + if (action == "add" && player->account->addCoins(account::CoinType::TOURNAMENT, amount, "", false) != account::ERROR_NO) { + reportErrorFunc(fmt::format("Failed to update (add) {}", tournamentCoinName)); + lua_pushnil(L); + return 1; + } else if (action == "remove" && player->account->removeCoins(account::CoinType::TOURNAMENT, amount) != account::ERROR_NO) { + reportErrorFunc(fmt::format("Failed to update (remove) {}", tournamentCoinName)); + lua_pushnil(L); + return 1; + } + + if (player->getAccount()->save() != account::ERROR_NO) { + reportErrorFunc("Failed to save account"); + lua_pushnil(L); + return 1; + } + + pushBoolean(L, true); + + return 1; +} + int PlayerFunctions::luaPlayerHasBlessing(lua_State* L) { // player:hasBlessing(blessing) uint8_t blessing = getNumber(L, 2); diff --git a/src/lua/functions/creatures/player/player_functions.hpp b/src/lua/functions/creatures/player/player_functions.hpp index 4d89a86d27f..9a9c77927b9 100644 --- a/src/lua/functions/creatures/player/player_functions.hpp +++ b/src/lua/functions/creatures/player/player_functions.hpp @@ -227,6 +227,9 @@ class PlayerFunctions final : LuaScriptInterface { registerMethod(L, "Player", "addTransferableCoins", PlayerFunctions::luaPlayerAddTransferableCoins); registerMethod(L, "Player", "removeTransferableCoins", PlayerFunctions::luaPlayerRemoveTransferableCoins); + registerMethod(L, "Player", "getTournamentCoins", PlayerFunctions::luaPlayerGetTournamentCoins); + registerMethod(L, "Player", "updateTournamentCoins", PlayerFunctions::luaPlayerUpdateTournamentCoins); + registerMethod(L, "Player", "hasBlessing", PlayerFunctions::luaPlayerHasBlessing); registerMethod(L, "Player", "addBlessing", PlayerFunctions::luaPlayerAddBlessing); registerMethod(L, "Player", "removeBlessing", PlayerFunctions::luaPlayerRemoveBlessing); @@ -587,6 +590,9 @@ class PlayerFunctions final : LuaScriptInterface { static int luaPlayerAddTransferableCoins(lua_State* L); static int luaPlayerRemoveTransferableCoins(lua_State* L); + static int luaPlayerGetTournamentCoins(lua_State* L); + static int luaPlayerUpdateTournamentCoins(lua_State* L); + static int luaPlayerHasBlessing(lua_State* L); static int luaPlayerAddBlessing(lua_State* L); static int luaPlayerRemoveBlessing(lua_State* L);