• 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!

TFS 1.X+ Achievements

Eryn

Active Member
Joined
Nov 29, 2015
Messages
91
Reaction score
25
Hello, is it possible to port this system from 0.4 to 1.5 (Nekiro)?

LUA:
<mod name="Achievements" version="1.0.0.0" author="VirrageS" contact="otland.net" enabled="yes">
    <config name="achievements_config">
        <![CDATA[
            quests = {4631, 4660, 4622, 4605, 4608, 4640, 4682, 4661, 4662, 4663, 4659, 4639, 4620, 4619, 4985, 4986, 300, 301, 302, 303, 305, 306, 9103}  -- wszystkie storage questow
            addons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23} -- wszystkie id addonow

            achievements = {
                ['begginer'] = {doneStorage = 1310000},
                ['no_lifer'] = {doneStorage = 1310100, hours = 20},
                ['quest_maker'] = {doneStorage = 1310200, percent = 30},
                ['death_friend'] = {doneStorage = 1310300, storage = 1310400, deaths = 50},
                ['log_in'] = {doneStorage = 1310500, storage = 1310600, logins = 100},
                ['gladiator'] = {doneStorage = 1310700, storage = 1310800, kills = 200},
                ['vip'] = {doneStorage = 1310900, vipStorage = 55888}, -- zmienic vip storage
                ['vocation_quest'] = {doneStorage = 1311100, questStorage = 303}, -- zmienic storage voc questa
                ['lucker'] = {doneStorage = 1311300, wins = 2},
                ['always_hungry'] = {doneStorage = 1311400, storage = 1311500, eats = 200},
                ['donator'] = {doneStorage = 1311600},
                ['bug_finder'] = {doneStorage = 1311700},
                ['addon_maker'] = {doneStorage = 1311800},
            }
        ]]>
    </config>

    <talkaction words="!achivbug" access="5" event="script">
        <![CDATA[
            domodlib('achievements_config')

            function onSay(cid, words, param)
                local x = getPlayerByNameWildcard(param)
                if isPlayer(x) then
                    if getCreatureStorage(x, achievements['bug_finder'].doneStorage) < 1 then
                        doCreatureSetStorage(x, achievements['bug_finder'].doneStorage, 1)
                        doPlayerSendTextMessage(x, MESSAGE_STATUS_CONSOLE_ORANGE, 'You obtain [bug finder] achievement.')
                    end
                end
                return true
            end
        ]]>
    </talkaction>

    <event type="kill" name="achiv_kill" event="script">
        <![CDATA[
            domodlib('achievements_config')

            function onKill(cid, target, damage, flags)
                if isPlayer(target) then
                    if getCreatureStorage(cid, achievements['gladiator'].doneStorage) < 1 then
                        if getCreatureStorage(cid, achievements['gladiator'].storage)+1 < achievements['gladiator'].kills then
                            doCreatureSetStorage(cid, achievements['gladiator'].storage, math.max(getCreatureStorage(cid, achievements['gladiator'].storage),0)+1)
                        else
                            doCreatureSetStorage(cid, achievements['gladiator'].doneStorage, 1)
                            doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You killed '..achievements['gladiator'].kills..' players and you obtain [gladiator] achievement.')
                        end
                    end
                end
                return true
            end
        ]]>
    </event>

    <event type="death" name="achiv_death" event="script">
        <![CDATA[
            domodlib('achievements_config')

            function onDeath(cid, corpse, deathList)
                if getCreatureStorage(cid, achievements['death_friend'].doneStorage) < 1 then
                    if getCreatureStorage(cid, achievements['death_friend'].storage)+1 < achievements['death_friend'].deaths then
                        doCreatureSetStorage(cid, achievements['death_friend'].storage, math.max(getCreatureStorage(cid, achievements['death_friend'].storage),0)+1)
                    else
                        doCreatureSetStorage(cid, achievements['death_friend'].doneStorage, 1)
                        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You died '..achievements['death_friend'].deaths..' times and you obtain [death friend] achievement.')
                    end
                end
                return true
            end
        ]]>
    </event>

    <globalevent name="achiv_check_badges" interval="1000" event="script">
        <![CDATA[
            domodlib('achievements_config')

            function onThink(interval)
                for _, cid in ipairs(getPlayersOnline()) do
                    if not isPlayer(cid) then
                        return true
                    end
                
                    if getCreatureStorage(cid, achievements['no_lifer'].doneStorage) < 1 and getPlayerStamina(cid) < achievements['no_lifer'].hours*60 then
                        doCreatureSetStorage(cid, achievements['no_lifer'].doneStorage, 1)
                        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Your stamina is lower than '..achievements['no_lifer'].hours..' hours. You obtain [no lifer] achievement.')
                    end

                    if getCreatureStorage(cid, achievements['quest_maker'].doneStorage) < 1 then
                        local n = 0
                        for _, s in ipairs(quests) do
                            if getCreatureStorage(cid, s) > 0 then
                                n = n+1
                            end

                            if #quests*achievements['quest_maker'].percent/100 < n then
                                doCreatureSetStorage(cid, achievements['quest_maker'].doneStorage, 1)
                                doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You done more than '..achievements['quest_maker'].percent..'% quests and you get [quest maker] achievement.')
                            end
                        end
                    end

                    if getCreatureStorage(cid, achievements['addon_maker'].doneStorage) < 1 then
                        n = 0
                        for _, s in ipairs(addons) do
                            if not canPlayerWearOutfitId(cid, s, 2) then
                                break
                            end
                            n = n + 1
                        end

                        if #addons == n then
                            doCreatureSetStorage(cid, achievements['addon_maker'].doneStorage, 1)
                            doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You can wear all addons and you get [addon maker] achievement.')
                        end
                    end

                    if getCreatureStorage(cid, achievements['vip'].doneStorage) < 1 and getCreatureStorage(cid, achievements['vip'].vipStorage) > 0 then
                        doCreatureSetStorage(cid, achievements['vip'].doneStorage, 1)
                        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You are vip and you get [vip] achievement.')
                    end

                    if getCreatureStorage(cid, achievements['vocation_quest'].doneStorage) < 1 and getCreatureStorage(cid, achievements['vip'].questStorage) > 0 then
                        doCreatureSetStorage(cid, achievements['vocation_quest'].doneStorage, 1)
                        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You\'ve done a vocation quest and you obtain new [vocation_quest] achievement.')
                    end

                    if getCreatureStorage(cid, achievements['lucker'].doneStorage) < 1 then
                        local q = db.getResult("SELECT COUNT(*) as c FROM events WHERE winner_name='"..getPlayerName(cid).."'")
                        if q:getID() ~= -1 then
                            if q:getDataInt("c") >= achievements['lucker'].wins then
                                doCreatureSetStorage(cid, achievements['lucker'].doneStorage, 1)
                                doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You\'ve won 2 times in events and you obtain new [lucker] achievement.')
                            end
                            q:free()
                        end
                    end
                end
                return true
            end
        ]]>
    </globalevent>

    <event type="login" name="achiv_login" event="script">
        <![CDATA[
            domodlib('achievements_config')

            function onLogin(cid)
                if getCreatureStorage(cid, achievements['begginer'].doneStorage) < 1 then
                    doCreatureSetStorage(cid, achievements['begginer'].doneStorage, 1)
                    doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You logged first time on our server and you obtain [begginer] achievement. Welcome!')
                end

                
                if getCreatureStorage(cid, achievements['donator'].doneStorage) < 1 then
                    local q = db.getResult("SELECT premium_points as p FROM accounts WHERE id="..getPlayerAccountId(cid).."")
                    if q:getID() ~= -1 then
                        if q:getDataInt("p") > 0 then
                            doCreatureSetStorage(cid, achievements['donator'].doneStorage, 1)
                            doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You bought points on our server you obtain [donator] achievement.')
                        end
                        q:free()
                    end
                end

                if getCreatureStorage(cid, achievements['log_in'].doneStorage) < 1 then
                    if getCreatureStorage(cid, achievements['log_in'].storage)+1 < achievements['log_in'].logins then
                        doCreatureSetStorage(cid, achievements['log_in'].storage, math.max(getCreatureStorage(cid, achievements['log_in'].storage),0)+1)
                    else
                        doCreatureSetStorage(cid, achievements['log_in'].doneStorage, 1)
                        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You loged in '..achievements['log_in'].logins..' times and you obtain [log in] achievement.')
                    end
                end

                registerCreatureEvent(cid, 'achiv_kill')
                registerCreatureEvent(cid, 'achiv_death')
                return true
            end
        ]]>
    </event>
</mod>
 
TFS 0.4 mod to 1.x events translation:
LUA:
local quests = {4631, 4660, 4622, 4605, 4608, 4640, 4682, 4661, 4662, 4663, 4659, 4639, 4620, 4619, 4985, 4986, 300, 301, 302, 303, 305, 306, 9103}  -- wszystkie storage questow
local addons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23} -- wszystkie id addonow

local achievements = {
	['begginer'] = {doneStorage = 1310000},
	['no_lifer'] = {doneStorage = 1310100, hours = 20},
	['quest_maker'] = {doneStorage = 1310200, percent = 30},
	['death_friend'] = {doneStorage = 1310300, storage = 1310400, deaths = 50},
	['log_in'] = {doneStorage = 1310500, storage = 1310600, logins = 100},
	['gladiator'] = {doneStorage = 1310700, storage = 1310800, kills = 200},
	['vip'] = {doneStorage = 1310900, vipStorage = 55888}, -- zmienic vip storage
	['vocation_quest'] = {doneStorage = 1311100, questStorage = 303}, -- zmienic storage voc questa
	['lucker'] = {doneStorage = 1311300, wins = 2},
	['always_hungry'] = {doneStorage = 1311400, storage = 1311500, eats = 200},
	['donator'] = {doneStorage = 1311600},
	['bug_finder'] = {doneStorage = 1311700},
	['addon_maker'] = {doneStorage = 1311800},
}

local talk = TalkAction("!achivbug")
function onSay(cid, words, param)
	local x = getPlayerByNameWildcard(param)
	if isPlayer(x) then
		if getCreatureStorage(x, achievements['bug_finder'].doneStorage) < 1 then
			doCreatureSetStorage(x, achievements['bug_finder'].doneStorage, 1)
			doPlayerSendTextMessage(x, MESSAGE_STATUS_CONSOLE_ORANGE, 'You obtain [bug finder] achievement.')
		end
	end
	return true
end
talk:register()

local creatureEventKill = CreatureEvent("achiv_kill")
function creatureEventKill(cid, target)
	if isPlayer(target) then
		if getCreatureStorage(cid, achievements['gladiator'].doneStorage) < 1 then
			if getCreatureStorage(cid, achievements['gladiator'].storage)+1 < achievements['gladiator'].kills then
				doCreatureSetStorage(cid, achievements['gladiator'].storage, math.max(getCreatureStorage(cid, achievements['gladiator'].storage),0)+1)
			else
				doCreatureSetStorage(cid, achievements['gladiator'].doneStorage, 1)
				doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You killed '..achievements['gladiator'].kills..' players and you obtain [gladiator] achievement.')
			end
		end
	end
	return true
end
creatureEventKill:register()

local creatureEventDeath = CreatureEvent("achiv_death")
function creatureEventDeath.onDeath(cid, corpse, deathList)
	if getCreatureStorage(cid, achievements['death_friend'].doneStorage) < 1 then
		if getCreatureStorage(cid, achievements['death_friend'].storage)+1 < achievements['death_friend'].deaths then
			doCreatureSetStorage(cid, achievements['death_friend'].storage, math.max(getCreatureStorage(cid, achievements['death_friend'].storage),0)+1)
		else
			doCreatureSetStorage(cid, achievements['death_friend'].doneStorage, 1)
			doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You died '..achievements['death_friend'].deaths..' times and you obtain [death friend] achievement.')
		end
	end
	return true
end
creatureEventDeath:register()

local globalEventThink = GlobalEvent("achiv_think")
function globalEventThink.onThink(interval)
	for _, cid in ipairs(getPlayersOnline()) do
		if not isPlayer(cid) then
			return true
		end

		if getCreatureStorage(cid, achievements['no_lifer'].doneStorage) < 1 and getPlayerStamina(cid) < achievements['no_lifer'].hours*60 then
			doCreatureSetStorage(cid, achievements['no_lifer'].doneStorage, 1)
			doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Your stamina is lower than '..achievements['no_lifer'].hours..' hours. You obtain [no lifer] achievement.')
		end

		if getCreatureStorage(cid, achievements['quest_maker'].doneStorage) < 1 then
			local n = 0
			for _, s in ipairs(quests) do
				if getCreatureStorage(cid, s) > 0 then
					n = n+1
				end

				if #quests*achievements['quest_maker'].percent/100 < n then
					doCreatureSetStorage(cid, achievements['quest_maker'].doneStorage, 1)
					doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You done more than '..achievements['quest_maker'].percent..'% quests and you get [quest maker] achievement.')
				end
			end
		end

		if getCreatureStorage(cid, achievements['addon_maker'].doneStorage) < 1 then
			n = 0
			for _, s in ipairs(addons) do
				if not canPlayerWearOutfitId(cid, s, 2) then
					break
				end
				n = n + 1
			end

			if #addons == n then
				doCreatureSetStorage(cid, achievements['addon_maker'].doneStorage, 1)
				doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You can wear all addons and you get [addon maker] achievement.')
			end
		end

		if getCreatureStorage(cid, achievements['vip'].doneStorage) < 1 and getCreatureStorage(cid, achievements['vip'].vipStorage) > 0 then
			doCreatureSetStorage(cid, achievements['vip'].doneStorage, 1)
			doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You are vip and you get [vip] achievement.')
		end

		if getCreatureStorage(cid, achievements['vocation_quest'].doneStorage) < 1 and getCreatureStorage(cid, achievements['vip'].questStorage) > 0 then
			doCreatureSetStorage(cid, achievements['vocation_quest'].doneStorage, 1)
			doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You\'ve done a vocation quest and you obtain new [vocation_quest] achievement.')
		end

		if getCreatureStorage(cid, achievements['lucker'].doneStorage) < 1 then
			local q = db.getResult("SELECT COUNT(*) as c FROM events WHERE winner_name='"..getPlayerName(cid).."'")
			if q:getID() ~= -1 then
				if q:getDataInt("c") >= achievements['lucker'].wins then
					doCreatureSetStorage(cid, achievements['lucker'].doneStorage, 1)
					doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You\'ve won 2 times in events and you obtain new [lucker] achievement.')
				end
				q:free()
			end
		end
	end
	return true
end
globalEventThink:interval(1000)
globalEventThink:register()

local creatureEventLogin = CreatureEvent("achiv_login")
function creatureEventLogin.onLogin(player)
	if getCreatureStorage(cid, achievements['begginer'].doneStorage) < 1 then
		doCreatureSetStorage(cid, achievements['begginer'].doneStorage, 1)
		doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You logged first time on our server and you obtain [begginer] achievement. Welcome!')
	end


	if getCreatureStorage(cid, achievements['donator'].doneStorage) < 1 then
		local q = db.getResult("SELECT premium_points as p FROM accounts WHERE id="..getPlayerAccountId(cid).."")
		if q:getID() ~= -1 then
			if q:getDataInt("p") > 0 then
				doCreatureSetStorage(cid, achievements['donator'].doneStorage, 1)
				doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You bought points on our server you obtain [donator] achievement.')
			end
			q:free()
		end
	end

	if getCreatureStorage(cid, achievements['log_in'].doneStorage) < 1 then
		if getCreatureStorage(cid, achievements['log_in'].storage)+1 < achievements['log_in'].logins then
			doCreatureSetStorage(cid, achievements['log_in'].storage, math.max(getCreatureStorage(cid, achievements['log_in'].storage),0)+1)
		else
			doCreatureSetStorage(cid, achievements['log_in'].doneStorage, 1)
			doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'You loged in '..achievements['log_in'].logins..' times and you obtain [log in] achievement.')
		end
	end

	registerCreatureEvent(cid, 'achiv_kill')
	registerCreatureEvent(cid, 'achiv_death')
	return true
end
creatureEventLogin:register()
"Compat" lib should take care about all Player/Monster/Tile/Item functions:

Only thing that may fail is database query db. ex.:
Code:
		local q = db.getResult("SELECT premium_points as p FROM accounts WHERE id="..getPlayerAccountId(cid).."")
		if q:getID() ~= -1 then
Of course "compat" library may fail too on multiple functions, so this code has to be tested heavily in game.
 
I took this script and worked on adapting everything to the latest TFS 1.x, ensuring full compatibility. After finishing it, I returned to the forum and noticed that you had already posted it before me—impressively fast, haha! That said, I believe this version is cleaner and more polished.

LUA:
-- Achievement System Configuration
local config = {
    quests = {4631, 4660, 4622, 4605, 4608, 4640, 4682, 4661, 4662, 4663, 4659, 4639, 4620, 4619, 4985, 4986, 300, 301, 302, 303, 305, 306, 9103},
    addons = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
    achievements = {
        beginner = {doneStorage = 1310000},
        no_lifer = {doneStorage = 1310100, hours = 20},
        quest_maker = {doneStorage = 1310200, percent = 30},
        death_friend = {doneStorage = 1310300, storage = 1310400, deaths = 50},
        log_in = {doneStorage = 1310500, storage = 1310600, logins = 100},
        gladiator = {doneStorage = 1310700, storage = 1310800, kills = 200},
        vip = {doneStorage = 1310900, vipStorage = 55888},
        vocation_quest = {doneStorage = 1311100, questStorage = 303},
        lucker = {doneStorage = 1311300, wins = 2},
        always_hungry = {doneStorage = 1311400, storage = 1311500, eats = 200},
        donator = {doneStorage = 1311600},
        bug_finder = {doneStorage = 1311700},
        addon_maker = {doneStorage = 1311800}
    },
    debug = false -- Set to true to enable debug messages
}

local function debugLog(message)
    if config.debug then
        print("[Achievement Debug] " .. message)
    end
end

local function executeQuery(query)
    if not query or query == "" then
        debugLog("Empty query string.")
        return false
    end
    debugLog("Executing query: " .. query)
    return db.query(query)
end

local function fetchSingleValue(query)
    if not query or query == "" then
        debugLog("Empty query string.")
        return 0
    end
    debugLog("Fetching single value with query: " .. query)
    local resultId = db.storeQuery(query)
    if not resultId then
        debugLog("Query failed: " .. query)
        return 0
    end
    local value = result.getNumber(resultId, "count")
    result.free(resultId)
    return value or 0
end

local function checkAndUpdateAchievement(player, achievementConfig, currentValue, targetValue, achievementName)
    if player:getStorageValue(achievementConfig.doneStorage) < 1 and currentValue >= targetValue then
        player:setStorageValue(achievementConfig.doneStorage, 1)
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, string.format("Achievement unlocked: %s!", achievementName))
        executeQuery(string.format("INSERT INTO player_achievements (player_id, achievement_name, date_earned) VALUES (%d, %s, %d)",
            player:getId(),
            db.escapeString(achievementName),
            os.time()
        ))
        debugLog(string.format("Achievement '%s' awarded to player: %s", achievementName, player:getName()))
        return true
    end
    return false
end

local talkAction = TalkAction("!achivbug")
function talkAction.onSay(player, words, param)
    if not player:getGroup():getAccess() or player:getAccountType() < ACCOUNT_TYPE_GOD then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Access denied. Only GODs or authorized groups can use this command.")
        return false
    end

    param = string.trim(param)
    if param == '' then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
            "Command usage: !achivbug <player name>")
        return false
    end

    local target = Player(param)
    if not target then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
            "Error: The specified player could not be found.")
        return false
    end

    local bugFinderConfig = config.achievements.bug_finder
    if target:getStorageValue(bugFinderConfig.doneStorage) > 0 then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
            string.format("Notice: %s already has the [Bug Finder] achievement.", target:getName()))
        return false
    end

    if checkAndUpdateAchievement(target, bugFinderConfig, 1, 1, "Bug Finder") then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
            string.format("Achievement successfully awarded to %s.", target:getName()))
    end

    return false
end
talkAction:separator(" ")
talkAction:register()

-- CreatureEvent for Kills
local killEvent = CreatureEvent("AchievementKill")
function killEvent.onKill(creature, target)
    if not creature:isPlayer() or not target:isPlayer() then
        return true
    end

    local gladiatorConfig = config.achievements.gladiator
    local kills = creature:getStorageValue(gladiatorConfig.storage)
    kills = kills > 0 and kills + 1 or 1
    creature:setStorageValue(gladiatorConfig.storage, kills)

    if kills >= gladiatorConfig.kills then
        creature:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
            string.format("You killed %d players and you obtain [gladiator] achievement.",
            gladiatorConfig.kills))
        checkAndUpdateAchievement(creature, gladiatorConfig, kills, gladiatorConfig.kills, "Gladiator")
    end

    return true
end
killEvent:register()

local deathEvent = CreatureEvent("AchievementDeath")
function deathEvent.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    if not creature:isPlayer() then
        return true
    end

    local deathConfig = config.achievements.death_friend
 
    if creature:getStorageValue(deathConfig.doneStorage) < 1 then
        local deaths = creature:getStorageValue(deathConfig.storage)
        deaths = deaths > 0 and deaths + 1 or 1
     
        creature:setStorageValue(deathConfig.storage, deaths)

        if deaths >= deathConfig.deaths then
            creature:setStorageValue(deathConfig.doneStorage, 1)
            creature:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
                string.format("You died %d times and you obtain [death friend] achievement.",
                deathConfig.deaths))
        end
    end

    return true
end

local globalEvent = GlobalEvent("CheckAchievements")
function globalEvent.onThink(interval)
    for _, player in ipairs(Game.getPlayers()) do
        if player:isPlayer() then
            -- No Lifer Achievement
            local noLiferConfig = config.achievements.no_lifer
            if player:getStorageValue(noLiferConfig.doneStorage) < 1 and player:getStamina() < noLiferConfig.hours * 60 then
                player:setStorageValue(noLiferConfig.doneStorage, 1)
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
                    string.format("Your stamina is lower than %d hours. You obtained the [No Lifer] achievement!", 
                    noLiferConfig.hours))
                debugLog(string.format("Player %s obtained No Lifer achievement", player:getName()))
            end

            -- Quest Maker Achievement
            local questMakerConfig = config.achievements.quest_maker
            if player:getStorageValue(questMakerConfig.doneStorage) < 1 then
                local completedQuests = 0
                for _, questStorage in ipairs(config.quests) do
                    if player:getStorageValue(questStorage) > 0 then
                        completedQuests = completedQuests + 1
                    end
                end

                local requiredQuests = math.ceil(#config.quests * (questMakerConfig.percent / 100))
                if completedQuests >= requiredQuests then
                    player:setStorageValue(questMakerConfig.doneStorage, 1)
                    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
                        string.format("You've completed more than %d%% of quests and obtained the [Quest Maker] achievement!", 
                        questMakerConfig.percent))
                    debugLog(string.format("Player %s obtained Quest Maker achievement", player:getName()))
                end
            end

            -- Addon Maker Achievement
            local addonMakerConfig = config.achievements.addon_maker
            if player:getStorageValue(addonMakerConfig.doneStorage) < 1 then
                local addonCount = 0
                local totalAddons = #config.addons
                
                for _, outfitId in ipairs(config.addons) do
                    if player:hasOutfit(outfitId) then
                        if player:hasOutfit(outfitId, 1) and player:hasOutfit(outfitId, 2) then
                            addonCount = addonCount + 1
                            debugLog(string.format("Player %s has outfit %d with both addons", 
                                player:getName(), outfitId))
                        end
                    end
                end

                if addonCount >= totalAddons then
                    player:setStorageValue(addonMakerConfig.doneStorage, 1)
                    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 
                        "You have all addons and obtained the [Addon Maker] achievement!")
                    debugLog(string.format("Player %s obtained Addon Maker achievement", player:getName()))
                end
            end

            -- VIP Achievement
            local vipConfig = config.achievements.vip
            if player:getStorageValue(vipConfig.doneStorage) < 1 and player:getStorageValue(vipConfig.vipStorage) > 0 then
                player:setStorageValue(vipConfig.doneStorage, 1)
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
                    "You are VIP and obtained the [VIP] achievement!")
                debugLog(string.format("Player %s obtained VIP achievement", player:getName()))
            end

            -- Vocation Quest Achievement
            local vocationQuestConfig = config.achievements.vocation_quest
            if player:getStorageValue(vocationQuestConfig.doneStorage) < 1 and player:getStorageValue(vocationQuestConfig.questStorage) > 0 then
                player:setStorageValue(vocationQuestConfig.doneStorage, 1)
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
                    "You completed the vocation quest and obtained the [Vocation Quest] achievement!")
                debugLog(string.format("Player %s obtained Vocation Quest achievement", player:getName()))
            end

            -- Lucker Achievement
            local luckerConfig = config.achievements.lucker
            if player:getStorageValue(luckerConfig.doneStorage) < 1 then
                local query = db.storeQuery("SELECT COUNT(*) as c FROM events WHERE winner_name = " .. db.escapeString(player:getName()))
                if query then
                    local winCount = result.getDataInt(query, "c")
                    result.free(query)

                    if winCount >= luckerConfig.wins then
                        player:setStorageValue(luckerConfig.doneStorage, 1)
                        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE,
                            string.format("You've won %d events and obtained the [Lucker] achievement!", 
                            luckerConfig.wins))
                        debugLog(string.format("Player %s obtained Lucker achievement", player:getName()))
                    end
                end
            end
        end
    end
    return true
end

globalEvent:interval(60000) -- Check every minute
globalEvent:register()

local loginEvent = CreatureEvent("AchievementLogin")
function loginEvent.onLogin(player)
    if not player:isPlayer() then
        return true
    end

    player:registerEvent("AchievementKill")
    player:registerEvent("AchievementDeath")

    checkAndUpdateAchievement(player, config.achievements.beginner, 1, 1, "Beginner")

    local loginConfig = config.achievements.log_in
    local logins = player:getStorageValue(loginConfig.storage)
    logins = logins > 0 and logins + 1 or 1
    player:setStorageValue(loginConfig.storage, logins)
    checkAndUpdateAchievement(player, loginConfig, logins, loginConfig.logins, "Login")

    if player:getStorageValue(config.achievements.donator.doneStorage) < 1 then
        local query = string.format("SELECT premium_points as count FROM accounts WHERE id = %d", player:getAccountId())
        local points = fetchSingleValue(query)
        if points > 0 then
            checkAndUpdateAchievement(player, config.achievements.donator, 1, 1, "Donator")
        end
    end

    debugLog(string.format("Player %s has logged in. Logins: %d", player:getName(), logins))

    return true
end
loginEvent:register()
 
Last edited:
The post has been updated. I addressed a bug in database queries and added missing achievements: Quest Maker, Vocation Quest, Lucker Achievement, and VIP Achievement. I also implemented debugging to track errors more easily and make corrections if necessary.

debug = false -- Set to true to enable debug messages
 
it doesn't show errors, gladiator achievement still doesn't work

I can pay for help

LUA:
gladiator = {doneStorage = 1310700, storage = 1310800, kills = 4},

I tested it with my base on TFS 1.7 (8.6) and TFS 1.4.2 (1098), and it’s working perfectly. You need to kill up to 200 for the message to display only once and not show again, understand? Try setting it to 5 and test with another account to see if the message displays. The script you provided is designed to show the message only once and then stop, storing the information in the player's storage. However, regarding the onLogin event from revscript, it seems like it’s not registering correctly. I recommend removing this line: player:registerEvent("AchievementKill") and adding it to data/creaturescripts/login.lua. Restart the server and test—it should work.


 
Back
Top