Skip to content

Commit

Permalink
feat: vip system (#1063)
Browse files Browse the repository at this point in the history
Created vip system functionality with some validations and improvements:
• Adjusted store checking to sell VIP or premium;
• Created configs and scripts;
• Fixed and created validation to auto-loot flag enabled by each player.

Features (Vip Accounts):
• Gain more XP
• Gain more loot
• Gain more skill
• Gain coins to be online
• Gain tokens (customized) to be online
• Toggle auto-loot exclusive
• Reduce familiar cooldown time
  • Loading branch information
elsongabriel committed Jul 29, 2023
1 parent 873f3ee commit 88b08ad
Show file tree
Hide file tree
Showing 37 changed files with 741 additions and 193 deletions.
20 changes: 20 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -415,3 +415,23 @@ location = "South America"
-- Leave empty if you wish to disable.
discordWebhookURL = ""

-- Vip System (Get more info in: https://github.com/opentibiabr/canary/pull/1063)
-- NOTE: set vipSystemEnabled to true to enable the vip system functionalities (this overrides premium checks)
-- NOTE: vipBonusExp = 0 is deactivated, active changing value between 1 and 100 (percent xp bonus to gain. ex: 3 = 3%, 30 = 30%)
-- NOTE: vipBonusLoot = 0 is deactivated, active changing value between 1 and 100 (percent loot bonus to gain. ex: 3 = 3%, 30 = 30%)
-- NOTE: vipBonusSkill = 0 is deactivated, active changing value between 1 and 100 (percent skill bonus to gain. ex: 3 = 3%, 30 = 30%)
-- NOTE: vipAutoLootVipOnly = activates only vip to get automatic loot, config 'autoLoot' need to be enabled, for this config works
-- NOTE: vipStayOnline = when this config is activated, players vip will be kicked after 'kickIdlePlayerAfterMinutes' config minutes too
-- NOTE: vipFamiliarTimeCooldownReduction = the minutes that will be debited from the familiar time cooldown for vip accounts, use 0 to deactivate the bonus (the default maximum value is 15, but it is calculated automatically)
-- examples: The default config 'familiarTime' is 30, this value is divided by 2 (15 minutes familiar and 15 minutes to cooldown)
-- If you use 'vipFamiliarTimeCooldownReduction = 10' the vip players will have only, in this case, 5 minutes of cooldown.
-- If you use 'vipFamiliarTimeCooldownReduction' greater than half of 'familiarTime', it will get the highest possible value, in this case 15
-- NOTE: GainCoin function, please configure script: data-otservbr-global/scripts/globalevents/vip/online_coins.lua
-- NOTE: GainToken function, please configure script: data-otservbr-global/scripts/globalevents/vip/online_tokens.lua
vipSystemEnabled = false
vipBonusExp = 0
vipBonusLoot = 0
vipBonusSkill = 0
vipAutoLootVipOnly = false
vipStayOnline = false
vipFamiliarTimeCooldownReduction = 0
27 changes: 27 additions & 0 deletions data-canary/scripts/talkactions/player/auto_loot.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
local autoLoot = TalkAction("!autoloot")

function autoLoot.onSay(player, words, param)
if not configManager.getBoolean(configKeys.AUTOLOOT) then
return false
end
if (configManager.getBoolean(configKeys.VIP_SYSTEM_ENABLED) and
configManager.getBoolean(configKeys.VIP_AUTOLOOT_VIP_ONLY) and not player:isVip()) then
player:sendCancelMessage("You need to be VIP to use this command!")
return false
end
if param == "" then
player:sendCancelMessage("You need to specify on/off param.")
return false
end
if param == "on" then
player:setStorageValue(STORAGEVALUE_AUTO_LOOT, 1)
player:sendTextMessage(MESSAGE_INFO_DESCR, "You have successfully enabled your automatic looting!")
elseif param == "off" then
player:setStorageValue(STORAGEVALUE_AUTO_LOOT, 0)
player:sendTextMessage(MESSAGE_INFO_DESCR, "You have successfully disabled your automatic looting!")
end
return true
end

autoLoot:separator(" ")
autoLoot:register()
6 changes: 6 additions & 0 deletions data-otservbr-global/lib/core/storages.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2989,6 +2989,12 @@ Storage = {
LastActivatedAt = 64039,
},
},

VipSystem = {
IsVip = 150001,
OnlineCoinsGain = 150002,
OnlineTokensGain = 150003,
},
}

GlobalStorage = {
Expand Down
3 changes: 3 additions & 0 deletions data-otservbr-global/lib/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ dofile(DATA_DIRECTORY .. '/lib/others/load.lua')

-- Quests library
dofile(DATA_DIRECTORY .. '/lib/quests/quest.lua')

-- Vip System library
dofile(DATA_DIRECTORY .. '/lib/vip/vip_system.lua')
50 changes: 50 additions & 0 deletions data-otservbr-global/lib/vip/vip_system.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
local config = {
activationMessage = 'You have received %s VIP days.',
activationMessageType = MESSAGE_EVENT_ADVANCE,

expirationMessage = 'Your VIP days ran out.',
expirationMessageType = MESSAGE_STATUS_WARNING,

outfits = {},
mounts = {},
}

function Player.onRemoveVip(self)
self:sendTextMessage(config.expirationMessageType, config.expirationMessage)

for _, outfit in ipairs(config.outfits) do
self:removeOutfit(outfit)
end

for _, mount in ipairs(config.mounts) do
self:removeMount(mount)
end

local playerOutfit = self:getOutfit()
if table.contains(config.outfits, self:getOutfit().lookType) then
if self:getSex() == PLAYERSEX_FEMALE then
playerOutfit.lookType = 136
else
playerOutfit.lookType = 128
end
playerOutfit.lookAddons = 0
self:setOutfit(playerOutfit)
end

self:setStorageValue(Storage.VipSystem.IsVip, 0)
end

function Player.onAddVip(self, days)
self:sendTextMessage(config.activationMessageType, string.format(config.activationMessage, days))

for _, outfit in ipairs(config.outfits) do
self:addOutfitAddon(outfit, 3)
end

for _, mount in ipairs(config.mounts) do
self:removeMount(mount)
end

self:setStorageValue(Storage.VipSystem.IsVip, 1)
end

16 changes: 16 additions & 0 deletions data-otservbr-global/scripts/creaturescripts/customs/vip.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
local playerLogin = CreatureEvent("VipLogin")

function playerLogin.onLogin(player)
if configManager.getBoolean(configKeys.VIP_SYSTEM_ENABLED) then
local wasVip = player:getStorageValue(Storage.VipSystem.IsVip) == 1
if wasVip and not player:isVip() then player:onRemoveVip() end
if not wasVip and player:isVip() then player:onAddVip(player:getVipDays()) end
if player:isVip() then
local days = player:getVipDays()
player:sendTextMessage(MESSAGE_LOGIN, string.format('You have %s VIP day%s left.', (days == 0xFFFF and 'infinite amount of' or days), (days == 1 and '' or 's')))
end
end
return true
end

playerLogin:register()
64 changes: 35 additions & 29 deletions data-otservbr-global/scripts/creaturescripts/others/login.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ local function onMovementRemoveProtection(cid, oldPos, time)
end

local function protectionZoneCheck(playerName)
doRemoveCreature(playerName)
return true
doRemoveCreature(playerName)
return true
end

local playerLogin = CreatureEvent("PlayerLogin")

function playerLogin.onLogin(player)
local items = {
{3003, 1},
{3031, 3}
{ 3003, 1 },
{ 3031, 3 }
}
if player:getLastLoginSaved() == 0 then
player:sendOutfitWindow()
Expand All @@ -34,17 +34,22 @@ function playerLogin.onLogin(player)
end
end
player:addItem(2920, 1, true, 1, CONST_SLOT_AMMO)
db.query('UPDATE `players` SET `istutorial` = 0 where `id`='..player:getGuid())
db.query('UPDATE `players` SET `istutorial` = 0 where `id`=' .. player:getGuid())
-- Open channels
if table.contains({TOWNS_LIST.DAWNPORT, TOWNS_LIST.DAWNPORT_TUTORIAL}, player:getTown():getId())then
if table.contains({ TOWNS_LIST.DAWNPORT, TOWNS_LIST.DAWNPORT_TUTORIAL }, player:getTown():getId()) then
player:openChannel(3) -- World chat
else
player:openChannel(3) -- World chat
player:openChannel(5) -- Advertsing main
end
else
player:sendTextMessage(MESSAGE_STATUS, SERVER_MOTD)
player:sendTextMessage(MESSAGE_LOGIN, string.format("Your last visit in ".. SERVER_NAME ..": %s.", os.date("%d. %b %Y %X", player:getLastLoginSaved())))
player:sendTextMessage(MESSAGE_LOGIN, string.format("Your last visit in " .. SERVER_NAME .. ": %s.", os.date("%d. %b %Y %X", player:getLastLoginSaved())))
-- Vip system
if (configManager.getBoolean(configKeys.VIP_SYSTEM_ENABLED) and player:isVip()) then
local days = player:getVipDays()
player:sendTextMessage(MESSAGE_LOGIN, string.format('You have %s vip day%s left.', (days == 0xFFFF and 'infinite amount of' or days), (days == 1 and '' or 's')))
end
end

-- Reset bosstiary time
Expand All @@ -58,7 +63,7 @@ function playerLogin.onLogin(player)
end
-- Premium Ends Teleport to Temple, change addon (citizen) houseless
local defaultTown = "Thais" -- default town where player is teleported if his home town is in premium area
local freeTowns = {"Ab'Dendriel", "Carlin", "Kazordoon", "Thais", "Venore", "Rookgaard", "Dawnport", "Dawnport Tutorial", "Island of Destiny"} -- towns in free account area
local freeTowns = { "Ab'Dendriel", "Carlin", "Kazordoon", "Thais", "Venore", "Rookgaard", "Dawnport", "Dawnport Tutorial", "Island of Destiny" } -- towns in free account area

if isPremium(player) == false and isInArray(freeTowns, player:getTown():getName()) == false then
local town = player:getTown()
Expand All @@ -70,20 +75,20 @@ function playerLogin.onLogin(player)
player:sendTextMessage(MESSAGE_FAILURE, "Your premium time has expired.")
player:setStorageValue(Storage.PremiumAccount, 0)
if sex == 1 then
player:setOutfit({lookType = 128, lookFeet = 114, lookLegs = 134, lookHead = 114,lookAddons = 0})
elseif sex == 0 then
player:setOutfit({lookType = 136, lookFeet = 114, lookLegs = 134, lookHead = 114, lookAddons = 0})
end
if home ~= nil and not isPremium(player) then
setHouseOwner(home, 0)
player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, 'You\'ve lost your house because you are not premium anymore.')
player:setOutfit({ lookType = 128, lookFeet = 114, lookLegs = 134, lookHead = 114, lookAddons = 0 })
elseif sex == 0 then
player:setOutfit({ lookType = 136, lookFeet = 114, lookLegs = 134, lookHead = 114, lookAddons = 0 })
end
if home ~= nil and not isPremium(player) then
setHouseOwner(home, 0)
player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, 'You\'ve lost your house because you are not premium anymore.')
player:sendTextMessage(MESSAGE_GAME_HIGHLIGHT, 'Your items from house are send to your inbox.')
end
end
end
-- End 'Premium Ends Teleport to Temple'

-- Recruiter system
local resultId = db.storeQuery('SELECT `recruiter` from `accounts` where `id`='..getAccountNumberByPlayerName(getPlayerName(player)))
local resultId = db.storeQuery('SELECT `recruiter` from `accounts` where `id`=' .. getAccountNumberByPlayerName(getPlayerName(player)))
local recruiterStatus = Result.getNumber(resultId, 'recruiter')
local sex = player:getSex()
if recruiterStatus >= 1 then
Expand All @@ -101,27 +106,27 @@ function playerLogin.onLogin(player)
end
if recruiterStatus >= 3 then
if sex == 1 then
local outfit = player:hasOutfit(746,1)
local outfit = player:hasOutfit(746, 1)
if outfit == false then
player:addOutfitAddon(746,1)
player:addOutfitAddon(746, 1)
end
else
local outfit = player:hasOutfit(745,1)
local outfit = player:hasOutfit(745, 1)
if outfit == false then
player:addOutfit(745,1)
player:addOutfit(745, 1)
end
end
end
if recruiterStatus >= 10 then
if sex == 1 then
local outfit = player:hasOutfit(746,2)
local outfit = player:hasOutfit(746, 2)
if outfit == false then
player:addOutfitAddon(746,2)
player:addOutfitAddon(746, 2)
end
else
local outfit = player:hasOutfit(745,2)
local outfit = player:hasOutfit(745, 2)
if outfit == false then
player:addOutfit(745,2)
player:addOutfit(745, 2)
end
end
end
Expand Down Expand Up @@ -195,7 +200,7 @@ function playerLogin.onLogin(player)
nextUseConcoctionTime[playerId] = 1

if (player:getAccountType() == ACCOUNT_TYPE_TUTOR) then
local msg = [[:: Tutor Rules
local msg = [[:: Tutor Rules
1 *> 3 Warnings you lose the job.
2 *> Without parallel conversations with players in Help, if the player starts offending, you simply mute it.
3 *> Be educated with the players in Help and especially in the Private, try to help as much as possible.
Expand All @@ -218,9 +223,9 @@ function playerLogin.onLogin(player)

-- Rewards
local rewards = #player:getRewardList()
if(rewards > 0) then
if (rewards > 0) then
player:sendTextMessage(MESSAGE_LOGIN, string.format("You have %d %s in your reward chest.",
rewards, rewards > 1 and "rewards" or "reward"))
rewards, rewards > 1 and "rewards" or "reward"))
end

-- Update player id
Expand All @@ -245,7 +250,8 @@ function playerLogin.onLogin(player)

player:getFinalLowLevelBonus()

if onExerciseTraining[player:getId()] then -- onLogin & onLogout
if onExerciseTraining[player:getId()] then
-- onLogin & onLogout
stopEvent(onExerciseTraining[player:getId()].event)
onExerciseTraining[player:getId()] = nil
player:setTraining(false)
Expand Down
60 changes: 60 additions & 0 deletions data-otservbr-global/scripts/globalevents/vip/online_coins.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
local config = {
enabled = false,
storage = Storage.VipSystem.OnlineCoinsGain,
checkDuplicateIps = false,

interval = 60 * 1000,

-- 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,
vip = 5,
},

-- system will distribute when the player accumulate x coins
awardOn = 5,
}

local onlineCoinsEvent = GlobalEvent("GainCoinInterval")
local runsPerHour = 3600 / (config.interval / 1000)

local function coinsPerRun(coinsPerHour)
return coinsPerHour / runsPerHour
end

function onlineCoinsEvent.onThink(interval)
local players = Game.getPlayers()
if #players == 0 then
return true
end

local checkIp = {}
for _, player in pairs(players) do
if player:getAccountType() >= ACCOUNT_TYPE_GAMEMASTER then
goto continue
end

local ip = player:getIp()
if ip ~= 0 and (not config.checkDuplicateIps or not checkIp[ip]) then
checkIp[ip] = true
local remainder = math.max(0, player:getStorageValue(config.storage)) / 10000000
local coins = coinsPerRun(player:isVip() and config.coinsPerHour.vip or config.coinsPerHour.free) + remainder
player:setStorageValue(config.storage, coins * 10000000)
if coins >= config.awardOn then
local coinsMath = math.floor(coins)
player:addTibiaCoins(coinsMath, true)
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

:: continue ::
end
return true
end

if config.enabled then
onlineCoinsEvent:interval(config.interval)
onlineCoinsEvent:register()
end

0 comments on commit 88b08ad

Please sign in to comment.