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

TalkAction Achievements LIB/Talkaction

Joined
Apr 17, 2008
Messages
1,922
Solutions
1
Reaction score
188
Location
Venezuela
Achievements (All TibiaRl Achievements, including the secret ones)

This lib includes all existing achievements.
List and functions were made by me.

To add this achievements system to your server, just follow these steps:

Create a file named:
data/lib/108-achievements.lua
Lua:
ACHIEVEMENTSPOINTS_BASE = "achievement_points"

achievements = {
	[1] = {name = "Afraid of no Ghost!", grade = 1, points = 2, secret = false},
	[2] = {name = "Allow Cookies?", grade = 1, points = 2, secret = false},
	[3] = {name = "Allowance Collector", grade = 1, points = 2, secret = true},
	[4] = {name = "Amateur Actor", grade = 1, points = 2, secret = false},
	[5] = {name = "Animal Activist", grade = 1, points = 2, secret = false},
	[6] = {name = "Arachnoise", grade = 1, points = 1, secret = false},
	[7] = {name = "Archpostman", grade = 1, points = 3, secret = false},
	[8] = {name = "Askarak Nemesis", grade = 1, points = 1, secret = true},
	[9] = {name = "Baby Sitter", grade = 1, points = 1, secret = true},
	[10] = {name = "Back from the Dead", grade = 1, points = 2, secret = false},
	[11] = {name = "Back into the Abyss", grade = 1, points = 1, secret = false},
	[12] = {name = "Backpack Tourist", grade = 1, points = 1, secret = true},
	[13] = {name = "Bad Timing", grade = 1, points = 2, secret = true},
	[14] = {name = "Bane of the Hive", grade = 1, points = 2, secret = false},
	[15] = {name = "Banebringers' Bane", grade = 1, points = 2, secret = true},
	[16] = {name = "Beach Tamer", grade = 1, points = 2, secret = false},
	[17] = {name = "Bearhugger", grade = 1, points = 1, secret = false},
	[18] = {name = "Beautiful Agony", grade = 1, points = 2, secret = false},
	[19] = {name = "Berserker", grade = 1, points = 3, secret = false},
	[20] = {name = "King of the Ring", grade = 1, points = 2, secret = false},
	[21] = {name = "Blessed!", grade = 1, points = 2, secret = false},
	[22] = {name = "Blood-Red Snapper", grade = 1, points = 1, secret = false},
	[23] = {name = "Bluebarian", grade = 1, points = 2, secret = true},
	[24] = {name = "Bone Brother", grade = 1, points = 1, secret = false},
	[25] = {name = "Breaking the Ice", grade = 1, points = 1, secret = false},
	[26] = {name = "Bunny Slipped", grade = 1, points = 2, secret = true},
	[27] = {name = "Cake Conqueror", grade = 1, points = 1, secret = true},
	[28] = {name = "Chest Robber", grade = 1, points = 1, secret = false},
	[29] = {name = "Choking on Her Venom", grade = 1, points = 1, secret = false},
	[30] = {name = "Chorister", grade = 1, points = 1, secret = false},
	[31] = {name = "Clay Fighter", grade = 1, points = 3, secret = true},
	[32] = {name = "Coccon of Doom", grade = 1, points = 3, secret = true},
	[33] = {name = "Commitment Phobic", grade = 1, points = 2, secret = true},
	[34] = {name = "Confusion", grade = 1, points = 0, secret = false},
	[35] = {name = "Cookie Monster", grade = 1, points = 1, secret = true},
	[36] = {name = "Crawling Death", grade = 1, points = 1, secret = false},
	[37] = {name = "Cursed!", grade = 1, points = 3, secret = true},
	[38] = {name = "Daring Trespasser", grade = 1, points = 3, secret = true},
	[39] = {name = "Dark Voodoo Priest", grade = 1, points = 2, secret = true},
	[40] = {name = "Dazzler", grade = 1, points = 3, secret = false},
	[41] = {name = "Death Song", grade = 1, points = 3, secret = false},
	[42] = {name = "Deer Hunt", grade = 1, points = 1, secret = true},
	[43] = {name = "Demonic Barkeeper", grade = 1, points = 3, secret = false},
	[44] = {name = "Depth Dwellers", grade = 1, points = 3, secret = false},
	[45] = {name = "Desert Fisher", grade = 1, points = 1, secret = false},
	[46] = {name = "Do not Disturb", grade = 1, points = 1, secret = true},
	[47] = {name = "Doctor! Doctor!", grade = 1, points = 2, secret = true},
	[48] = {name = "Dog Slitter", grade = 1, points = 1, secret = false},
	[49] = {name = "Down the Drain", grade = 1, points = 2, secret = false},
	[50] = {name = "Dream's Over", grade = 1, points = 1, secret = false},
	[51] = {name = "Efreet Ally", grade = 1, points = 3, secret = false},
	[52] = {name = "Enter zze Draken!", grade = 1, points = 2, secret = false},
	[53] = {name = "Exquisite Taste", grade = 1, points = 2, secret = false},
	[54] = {name = "Extreme Degustation", grade = 1, points = 2, secret = true},
	[55] = {name = "Eye of the Deep", grade = 1, points = 1, secret = true},
	[56] = {name = "Fire Devil", grade = 1, points = 3, secret = true},
	[57] = {name = "Fire from the Earth", grade = 1, points = 2, secret = false},
	[58] = {name = "Fire Lighter", grade = 1, points = 1, secret = true},
	[59] = {name = "Firefighter", grade = 1, points = 2, secret = true},
	[60] = {name = "Fireworks in the Sky", grade = 1, points = 2, secret = true},
	[61] = {name = "Fool at Heart", grade = 1, points = 3, secret = false},
	[62] = {name = "Fountain of Life", grade = 1, points = 1, secret = true},
	[63] = {name = "Free Items!", grade = 1, points = 3, secret = true},
	[64] = {name = "Gatherer", grade = 1, points = 2, secret = false},
	[65] = {name = "Gem Cutter", grade = 1, points = 1, secret = true},
	[66] = {name = "Ghost Sailor", grade = 1, points = 1, secret = true},
	[67] = {name = "Ghostwhisperer", grade = 1, points = 3, secret = false},
	[68] = {name = "Greenhorn", grade = 1, points = 2, secret = false},
	[69] = {name = "Guard Killer", grade = 1, points = 2, secret = false},
	[70] = {name = "Guinea Pig", grade = 1, points = 2, secret = false},
	[71] = {name = "Happy Farmer", grade = 1, points = 1, secret = true},
	[72] = {name = "Headache", grade = 1, points = 2, secret = false},
	[73] = {name = "Heartburn", grade = 1, points = 3, secret = false},
	[74] = {name = "Here, Fishy Fishy!", grade = 1, points = 1, secret = true},
	[75] = {name = "Hickup", grade = 1, points = 2, secret = false},
	[76] = {name = "Hidden Powers", grade = 1, points = 2, secret = false},
	[77] = {name = "His True Face", grade = 1, points = 3, secret = true},
	[78] = {name = "Hissing Downfall", grade = 1, points = 2, secret = false},
	[79] = {name = "Hive Fighter", grade = 1, points = 1, secret = false},
	[80] = {name = "Hive Infiltrator", grade = 1, points = 3, secret = false},
	[81] = {name = "Hive War Veteran", grade = 1, points = 1, secret = false},
	[82] = {name = "Homebrewed", grade = 1, points = 1, secret = true},
	[83] = {name = "Honest Finder", grade = 1, points = 1, secret = false},
	[84] = {name = "Honorary Barbarian", grade = 1, points = 1, secret = false},
	[85] = {name = "Howly Silence", grade = 1, points = 1, secret = false},
	[86] = {name = "Huntsman", grade = 1, points = 2, secret = false},
	[87] = {name = "I Did My Part", grade = 1, points = 2, secret = true},
	[88] = {name = "I Like it Fancy", grade = 1, points = 1, secret = true},
	[89] = {name = "I Need a Hug", grade = 1, points = 2, secret = false},
	[90] = {name = "Ice Harvester", grade = 1, points = 1, secret = false},
	[91] = {name = "Ice Sculptor", grade = 1, points = 3, secret = true},
	[92] = {name = "Invader of the Deep", grade = 1, points = 2, secret = true},
	[93] = {name = "Jinx", grade = 1, points = 2, secret = true},
	[94] = {name = "Joke's on You", grade = 1, points = 1, secret = true},
	[95] = {name = "Just Cracked Me Up!", grade = 1, points = 2, secret = false},
	[96] = {name = "Just in Time", grade = 1, points = 1, secret = false},
	[97] = {name = "Kapow!", grade = 1, points = 1, secret = false},
	[98] = {name = "Keeper of the Flame", grade = 1, points = 2, secret = true},
	[99] = {name = "King Tibianus Fan", grade = 1, points = 3, secret = false},
	[100] = {name = "Let the Sunshine In", grade = 1, points = 1, secret = true},
	[101] = {name = "Loyal Subject", grade = 1, points = 1, secret = true},
	[102] = {name = "Lucid Dreamer", grade = 1, points = 2, secret = false},
	[103] = {name = "Mageslayer", grade = 1, points = 1, secret = true},
	[104] = {name = "Make a Wish", grade = 1, points = 1, secret = true},
	[105] = {name = "Marbeleous", grade = 1, points = 3, secret = true},
	[106] = {name = "Marid Ally", grade = 1, points = 3, secret = false},
	[107] = {name = "Masquerader", grade = 1, points = 3, secret = true},
	[108] = {name = "Master Shapeshifter", grade = 1, points = 2, secret = true},
	[109] = {name = "Mastermind", grade = 1, points = 3, secret = false},
	[110] = {name = "Matchmaker", grade = 1, points = 1, secret = false},
	[111] = {name = "Mathemagician", grade = 1, points = 1, secret = false},
	[112] = {name = "Meat Skewer", grade = 1, points = 1, secret = false},
	[113] = {name = "Merry Adventures", grade = 1, points = 2, secret = false},
	[114] = {name = "Ministrel", grade = 1, points = 2, secret = true},
	[115] = {name = "Minor Disturbance", grade = 1, points = 2, secret = false},
	[116] = {name = "Mister Sandman", grade = 1, points = 2, secret = true},
	[117] = {name = "Modest Guest", grade = 1, points = 1, secret = true},
	[118] = {name = "Mutated Presents", grade = 1, points = 1, secret = true},
	[119] = {name = "Natural Born Cowboy", grade = 1, points = 1, secret = true},
	[120] = {name = "Natural Sweetener", grade = 1, points = 1, secret = true},
	[121] = {name = "Nether Pirate", grade = 1, points = 3, secret = true},
	[122] = {name = "Nightmare Knight", grade = 1, points = 1, secret = false},
	[123] = {name = "No More Hiding", grade = 1, points = 1, secret = false},
	[124] = {name = "Nomad Soul", grade = 1, points = 2, secret = true},
	[125] = {name = "Nothing Can Stop Me", grade = 1, points = 1, secret = true},
	[126] = {name = "Number of the Beast", grade = 1, points = 2, secret = false},
	[127] = {name = "One Less", grade = 1, points = 2, secret = false},
	[128] = {name = "Oops", grade = 1, points = 2, secret = true},
	[129] = {name = "Party Animal", grade = 1, points = 1, secret = true},
	[130] = {name = "Passionate Kisser", grade = 1, points = 3, secret = false},
	[131] = {name = "Perfect Fool", grade = 1, points = 3, secret = false},
	[132] = {name = "Petrologist", grade = 1, points = 2, secret = true},
	[133] = {name = "Piece of Cake", grade = 1, points = 1, secret = false},
	[134] = {name = "Pimple", grade = 1, points = 3, secret = false},
	[135] = {name = "Planter", grade = 1, points = 2, secret = false},
	[136] = {name = "Poet Laureate", grade = 1, points = 2, secret = true},
	[137] = {name = "Preservationist", grade = 1, points = 1, secret = true},
	[138] = {name = "Quick as a Turtle", grade = 1, points = 2, secret = true},
	[139] = {name = "Recognised Trader", grade = 1, points = 3, secret = false},
	[140] = {name = "Rock Me to Sleep", grade = 1, points = 1, secret = true},
	[141] = {name = "Rocket in Pocket", grade = 1, points = 1, secret = true},
	[142] = {name = "Rockstar", grade = 1, points = 3, secret = true},
	[143] = {name = "Rollercoaster", grade = 1, points = 1, secret = false},
	[144] = {name = "Rootless Behaviour", grade = 1, points = 1, secret = false},
	[145] = {name = "Safely Stored Away", grade = 1, points = 2, secret = true},
	[146] = {name = "Santa's Li'l Helper", grade = 1, points = 2, secret = true},
	[147] = {name = "Scorched Flames", grade = 1, points = 1, secret = false},
	[148] = {name = "Scrapper", grade = 1, points = 3, secret = false},
	[149] = {name = "Sea Scout", grade = 1, points = 2, secret = false},
	[150] = {name = "Secret Agent", grade = 1, points = 1, secret = false},
	[151] = {name = "Shaburak Nemesis", grade = 1, points = 1, secret = true},
	[152] = {name = "Sharpshooter", grade = 1, points = 3, secret = false},
	[153] = {name = "Si, Ariki!", grade = 1, points = 1, secret = false},
	[154] = {name = "Shell Seeker", grade = 1, points = 3, secret = true},
	[155] = {name = "Silent Pet", grade = 1, points = 1, secret = true},
	[156] = {name = "Slayer of Anmothra", grade = 1, points = 2, secret = true},
	[157] = {name = "Slayer of Chikhaton", grade = 1, points = 2, secret = true},
	[158] = {name = "Slayer of Irahsae", grade = 1, points = 2, secret = true},
	[159] = {name = "Slayer of Phrodomo", grade = 1, points = 2, secret = true},
	[160] = {name = "Slayer of Teneshpar", grade = 1, points = 2, secret = true},
	[161] = {name = "Slim Chance", grade = 1, points = 1, secret = false},
	[162] = {name = "Slimer", grade = 1, points = 1, secret = true},
	[163] = {name = "Snowbunny", grade = 1, points = 2, secret = true},
	[164] = {name = "Someone's Bored", grade = 1, points = 1, secret = true},
	[165] = {name = "Something Smells", grade = 1, points = 1, secret = false},
	[166] = {name = "Something's in There", grade = 1, points = 1, secret = true},
	[167] = {name = "Spareribs for Dinner", grade = 1, points = 1, secret = false},
	[168] = {name = "Spectral Traveler", grade = 1, points = 2, secret = true},
	[169] = {name = "Steampunked", grade = 1, points = 2, secret = true},
	[170] = {name = "Stepped on a Big Toe", grade = 1, points = 1, secret = false},
	[171] = {name = "Supersitious", grade = 1, points = 2, secret = true},
	[172] = {name = "Supplier", grade = 1, points = 3, secret = false},
	[173] = {name = "Sweet Tooth", grade = 1, points = 2, secret = true},
	[174] = {name = "Talented Dancer", grade = 1, points = 1, secret = false},
	[175] = {name = "Teamplayer", grade = 1, points = 2, secret = true},
	[176] = {name = "Territorial", grade = 1, points = 1, secret = true},
	[177] = {name = "The Cake's the Truth", grade = 1, points = 1, secret = true},
	[178] = {name = "The Day After", grade = 1, points = 2, secret = true},
	[179] = {name = "The Drowned Sea God", grade = 1, points = 2, secret = false},
	[180] = {name = "The Milkman", grade = 1, points = 2, secret = false},
	[181] = {name = "The Serpent's Bride", grade = 1, points = 2, secret = false},
	[182] = {name = "The Undertaker", grade = 1, points = 2, secret = true},
	[183] = {name = "Torn Treasures", grade = 1, points = 1, secret = true},
	[184] = {name = "Trail of the Ape God", grade = 1, points = 1, secret = true},
	[185] = {name = "True Colors", grade = 1, points = 3, secret = true},
	[186] = {name = "Truth Be Told", grade = 1, points = 2, secret = true},
	[187] = {name = "Twisted Mutation", grade = 1, points = 1, secret = false},
	[188] = {name = "Vanity", grade = 1, points = 3, secret = true},
	[189] = {name = "Vive la Resistance", grade = 1, points = 2, secret = false},
	[190] = {name = "Wayfarer", grade = 1, points = 3, secret = true},
	[191] = {name = "Whistle-Blower", grade = 1, points = 1, secret = true},
	[192] = {name = "Witches Lil' Helper", grade = 1, points = 1, secret = true},
	[193] = {name = "With a Cherry on Top", grade = 1, points = 1, secret = true},
	[194] = {name = "Worm Whacker", grade = 1, points = 1, secret = true},
	[195] = {name = "Yalahari of Power", grade = 1, points = 3, secret = false},
	[196] = {name = "Yalahari of Wisdom", grade = 1, points = 3, secret = false},
	[197] = {name = "You Don't  Know Jack", grade = 1, points = 2, secret = true},
	[198] = {name = "Zzztill Zzztanding!", grade = 1, points = 1, secret = false},
	[199] = {name = "Alumni", grade = 2, points = 6, secret = false},
	[200] = {name = "Annihilator", grade = 2,  points = 5, secret = false},
	[201] = {name = "Aristocrat", grade = 2,  points = 4, secret = false},
	[202] = {name = "Ashes to Dust", grade = 2, points = 4, secret = true},
	[203] = {name = "Beak Doctor", grade = 2, points = 4, secret = false},
	[204] = {name = "Brutal Politeness", grade = 2, points = 6, secret = false},
	[205] = {name = "Castlemania", grade = 2, points = 5, secret = true},
	[206] = {name = "Champion of Chazorai", grade = 2, points = 4, secret = false},
	[207] = {name = "Chistin Bane", grade = 2, points = 5, secret = false},
	[208] = {name = "Clay to Fame", grade = 2, points = 4, secret = true},
	[209] = {name = "Culinary Master", grade = 2, points = 4, secret = false},
	[210] = {name = "Deep Sea Diver", grade = 2, points = 4, secret = true},
	[211] = {name = "Demonbane", grade = 2, points = 6, secret = false},
	[212] = {name = "Devovorga's Nemesis", grade = 2, points = 5, secret = true},
	[213] = {name = "Elite Hunter", points = 5, secret = false},
	[214] = {name = "Exemplary Citizen", grade = 2, points = 4, secret = false},
	[215] = {name = "Explorer", grade = 2, points = 4, secret = false},
	[216] = {name = "Exterminator", grade = 2, points = 0, secret = false},
	[217] = {name = "Follower of Azerus", grade = 2, points = 4, secret = false},
	[218] = {name = "Follower of Palimuth", grade = 2, points = 4, secret = false},
	[219] = {name = "Friend of the Apes", grade = 2, points = 4, secret = false},
	[220] = {name = "Godslayer", grade = 2, points = 4, secret = false},
	[221] = {name = "Gold Digger", points = 4, secret = true},
	[222] = {name = "Golem in the Gears", grade = 2, points = 4, secret = false},
	[223] = {name = "Green Thumb", grade = 2, points = 4, secret = true},
	[224] = {name = "Guardian Downfall", grade = 2, points = 4, secret = false},
	[225] = {name = "High Inquisitor", grade = 2, points = 5, secret = false},
	[226] = {name = "High-Flyer", grade = 2, points = 4, secret = true},
	[227] = {name = "Hive Blinder", grade = 2, points = 4, secret = false},
	[228] = {name = "Honorary Witch", grade = 2, points = 4, secret = true},
	[229] = {name = "Hunting with Style", grade = 2, points = 6, secret = false},
	[230] = {name = "In Shining Armor", grade = 2, points = 6, secret = false},
	[231] = {name = "Interior Decorator", grade = 2, points = 4, secret = true},
	[232] = {name = "Jamjam", grade = 2, points = 5, secret = true},
	[233] = {name = "Life on the Streets", grade = 2, points = 4, secret = false},
	[234] = {name = "Lord of the Elements", grade = 2, points = 5, secret = false},
	[235] = {name = "Lucky Devil", grade = 2, points = 4, secret = true},
	[236] = {name = "Manic", grade = 2, points = 0, secret = false},
	[237] = {name = "Marble Madness", grade = 2, points = 6, secret = true},
	[238] = {name = "Master of the Nexus", grade = 2, points = 6, secret = false},
	[239] = {name = "Master of War", grade = 2, points = 6, secret = false},
	[240] = {name = "Master Thief", grade = 2, points = 4, secret = false},
	[241] = {name = "Mystic Fabric Magic", grade = 2, points = 0, secret = false},
	[242] = {name = "Navigational Error", grade = 2, points = 5, secret = true},
	[243] = {name = "Nightmare Walker", grade = 2, points = 6, secret = false},
	[244] = {name = "Of Wolves and Bears", grade = 2, points = 6, secret = false},
	[245] = {name = "One Thousand and One", grade = 2, points = 6, secret = false},
	[246] = {name = "Out in the Snowstorm", grade = 2, points = 4, secret = false},
	[247] = {name = "Peazzekeeper", grade = 2, points = 6, secret = false},
	[248] = {name = "Polisher", grade = 2, points = 4, secret = true},
	[249] = {name = "Potion Addict", grade = 2, points = 4, secret = true},
	[250] = {name = "Ritualist", grade = 2, points = 6, secret = false},
	[251] = {name = "Ruthless", grade = 2, points = 5, secret = false},
	[252] = {name = "Scourge of Death", grade = 2, points = 5, secret = true},
	[253] = {name = "Ship's Kobold", grade = 2, points = 4, secret = true},
	[254] = {name = "Skin-Deep", grade = 2, points = 4, secret = true},
	[255] = {name = "Skull and Bones", grade = 2, points = 6, secret = false},
	[256] = {name = "Spolium Profundis", grade = 2, points = 4, secret = false},
	[257] = {name = "Stomach Ulcer", grade = 2, points = 4, secret = false},
	[258] = {name = "Suppressor", grade = 2, points = 4, secret = false},
	[259] = {name = "Swashbuckler", grade = 2, points = 6, secret = false},
	[260] = {name = "Swift Death", grade = 2, points = 6, secret = false},
	[261] = {name = "Top AVIN Agent", grade = 2, points = 4, secret = false},
	[262] = {name = "Top CGB Agent", grade = 2, points = 4, secret = false},
	[263] = {name = "Top TBI Agent", grade = 2, points = 4, secret = false},
	[264] = {name = "True Lightbearer", grade = 2, points = 5, secret = true},
	[265] = {name = "Turncoat", grade = 2, points = 4, secret = true},
	[266] = {name = "Warlock", grade = 2, points = 6, secret = false},
	[267] = {name = "Warlord of Svargrond", grade = 2, points = 5, secret = false},
	[268] = {name = "Way of the Shaman", grade = 2, points = 6, secret = false},
	[269] = {name = "Wild Warrior", grade = 2, points = 6, secret = false},
	[270] = {name = "Dead Lord", grade = 3, points = 8, secret = true},
	[271] = {name = "Herbicide", grade = 3, points = 8, secret = true},
	[272] = {name = "Lord Protector", grade = 3, points = 8, secret = true},
	[273] = {name = "Pwned a Lot of Fur", grade = 3, points = 8, secret = true},
	[274] = {name = "Pwned All Fur", grade = 3, points = 8, secret = true},
	[275] = {name = "Razing!", grade = 3, points = 7, secret = true}
}

ACHIEVEMENT_FIRST = 1
ACHIEVEMENT_LAST = #achievements

function getAchievementInfoById(id)
	for k, v in pairs(achievements) do
		if k == id then
			local t = {}
			t.id = k
			for inf, it in pairs(v) do
				t[inf] = it
			end
			return t
		end
	end
	return false
end

function getAchievementInfoByName(name)
	for k, v in pairs(achievements) do
		if v.name:lower() == name:lower() then
			local t = {}
			t.id = k
			for inf, it in pairs(v) do
				t[inf] = it
			end
			return t
		end
	end
	return false
end

function getSecretAchievements()
	local t = {}
	for k, v in pairs(achievements) do
		if v.secret then
			table.insert(t, k)
		end
	end
	return t
end

function getPublicAchievements()
	local t = {}
	for k, v in ipairs(achivements) do
		if not v.secret then
			table.insert(t, k)
		end
	end
	return t
end

function doPlayerAddAchievement(cid, ach, showMsg)

	local achievement
	if isNumber(ach) then
		achievement = getAchievementInfoById(ach)
	else
		achievement = getAchievementInfoByName(ach)
	end
	if not achievement then return print("[!] -> Invalid achievement \"" .. ach .. "\".") and false end
	
	if not hasAchievement(cid, achievement.id) then
		doCreatureSetStorage(cid, achievement.name:lower(), 1)
		if getCreatureStorage(cid, ACHIEVEMENTSPOINTS_BASE) < 0 then
			doCreatureSetStorage(cid, ACHIEVEMENTSPOINTS_BASE, 0)
		end
		doCreatureSetStorage(cid, ACHIEVEMENTSPOINTS_BASE, getCreatureStorage(cid, ACHIEVEMENTSPOINTS_BASE) + achievement.points)
		if showMsg then
			doPlayerSendTextMessage(cid, MESSAGE_EVENT_ADVANCE, "Congratulations! You earned the achievement \"" .. achievement.name .. "\".")
		end
	end
	return true
end

function doPlayerRemoveAchievement(cid, ach)

	local achievement
	if isNumber(ach) then
		achievement = getAchievementInfoById(ach)
	else
		achievement = getAchievementInfoByName(ach)
	end
	if not achievement then return print("[!] -> Invalid achievement \"" .. ach .. "\".") and false end
	
	if hasAchievement(cid, achievement.id) then
		doCreatureSetStorage(cid, achievement.name:lower(), 0)
		doCreatureSetStorage(cid, ACHIEVEMENTSPOINTS_BASE, getCreatureStorage(cid, ACHIEVEMENTSPOINTS_BASE) - achievement.points)
	end
	return true
end

function hasAchievement(cid, ach)
	local achievement
	if isNumber(ach) then
		achievement = getAchievementInfoById(ach)
	else
		achievement = getAchievementInfoByName(ach)
	end
	if not achievement then return print("[!] -> Invalid achievement \"" .. ach .. "\".") and false end
	
	if getCreatureStorage(cid, achievement.name:lower()) > 0 then
		return true
	end
	return false
end

function doPlayerAddAllAchievements(cid, showMsg)

	for k, v in pairs(achievements) do
		if not hasAchievement(cid, k) then
			doPlayerAddAchievement(cid, k, showMsg)
		end
	end
	return true
end

function doPlayerRemoveAllAchievements(cid)

	for k, v in pairs(achievements) do
		if hasAchievement(cid, k) then
			doPlayerRemoveAchievement(cid, k)
		end
	end
	return true
end

function getPlayerSecretAchievements(cid)
	local t = {}
	for k, v in pairs(achievements) do
		if hasAchievement(cid, k) and v.secret then
			table.insert(t, k)
		end
	end
	return t
end

function getPlayerPublicAchievements(cid)
	local t = {}
	for k, v in pairs(achievements) do
		if hasAchievement(cid, k) and not v.secret then
			table.insert(t, k)
		end
	end
	return t
end

function getPlayerAchievements(cid)
	local t = {}
	for k, v in pairs(achievements) do
		if hasAchievement(cid, k) then
			table.insert(t, k)
		end
	end
	return t
end

function isAchievementSecret(ach)
	local achievement
	if isNumber(ach) then
		achievement = getAchievementInfoById(ach)
	else
		achievement = getAchievementInfoByName(ach)
	end
	if not achievement then return print("[!] -> Invalid achievement \"" .. ach .. "\".") and false end
	
	return achievement.secret
end

How to use? here is an example of all functions.
data/talkactions/scripts/achievements.lua
Lua:
function onSay(cid, words, param, channel)

	if(param == "") then
		return true
	end

	local player, ach
	local DESCR = MESSAGE_INFO_DESCR
	if words == "/addach" then
		param = string.explode(param, ",")
		if not param[2] then
			return doPlayerSendCancel(cid, "Invalid achievement id/name.")
		end
		if not getPlayerByNameWildcard(param[1]) or getPlayerByNameWildcard(param[1]) == "" then
			return doPlayerSendCancel(cid, "Invalid player name.")
		end
		
		player, ach = getPlayerByNameWildcard(param[1]), param[2]
		ach = type(ach) == "string" and getAchievementInfoByName(ach) or getAchievementInfo(tonumber(ach))
		if ach then
			if playerHasAchievement(cid, ach.id) then
				doPlayerSendCancel(cid, "Player already has the achievement \"" .. ach.name .. "\".")
			else
				doPlayerAddAchievement(player, ach.id, (param[3] and true or false))
				doPlayerSendTextMessage(cid, DESCR, "You added achievement " .. ach.id .. " (" .. ach.name .. ") to " .. param[1] .. ".")
				doPlayerSendTextMessage(player, DESCR, "You received the achievement: " .. ach.name)
				doSendMagicEffect(getCreaturePosition(player), CONST_ME_MAGIC_RED)
				return true
			end
		else
			return doPlayerSendCancel(cid, "Invaled achievement.")
		end

	elseif words == "/addallach" then

		param = string.explode(param, ",")
		player = getPlayerByNameWildcard(param[1])
		if not player or player == "" then
			return doPlayerSendCancel(cid, "Invalid player name.")
		end

		doPlayerAddAllAchievements(player, (param[2] and true or false))
		doPlayerSendTextMessage(cid, DESCR, "You added all achievements to " .. param .. ".")
		doPlayerSendTextMessage(player, DESCR, "You received all achievements.")
		doSendMagicEffect(getCreaturePosition(player), CONST_ME_MAGIC_RED)
		return true

	elseif words == "/removeach" then

		param = string.explode(param, ",")
		if not param[2] then
			return doPlayerSendCancel(cid, "Invalid achievement id/name.")
		end
		if not getPlayerByNameWildcard(param[1]) or getPlayerByNameWildcard(param[1]) == "" then
			return doPlayerSendCancel(cid, "Invalid player name.")
		end
		
		player, ach = getPlayerByNameWildcard(param[1]), tonumber(param[2])
		ach = type(ach) == "string" and getAchievementInfoByName(ach) or getAchievementInfo(tonumber(ach))
		if ach then
			if playerHasAchievement(cid, ach.id) then
				doPlayerRemoveAchievement(player, ach.id)
				doPlayerSendTextMessage(cid, DESCR, "You removed achievement " .. ach.id .. " (" .. ach.name .. ") to " .. param[1] .. ".")
				doPlayerSendTextMessage(player, DESCR, "You lost the achievement: " .. ach.name)
				return true
			else
				return doPlayerSendCancel(cid, "That player doest not has that achievement.")
			end
		else
			return doPlayerSendCancel(cid, "Invaled achievement.")
		end

	elseif words == "/removeallach" then

		player = getPlayerByNameWildcard(param)
		if not player or player == "" then
			return doPlayerSendCancel(cid, "Invalid player name.")
		end

		doPlayerRemoveAllAchievements(player)
		doPlayerSendTextMessage(cid, DESCR, "You removed all achievements to " .. getCreatureName(player) .. ".")
		doPlayerSendTextMessage(player, DESCR, "You lost all achievements.")
		return true

	elseif words == "/getach" then
		
		player = getPlayerByNameWildcard(param)
		if not player or player == "" then
			return doPlayerSendCancel(cid, "Invalid player name.")
		end

		local ach = getPlayerAchievements(player)
		if #ach > 0 then
			local text = ""
			for i = 1, #ach do
				text = text .. getAchievementInfo(tonumber(ach[i])).id .. " - " .. getAchievementInfo(tonumber(ach[i])).name .. "\n"
			end
			return doShowTextDialog(cid, 2195, "Player " .. param .. " has the following achievements...\n\n" .. text)
		else
			return doPlayerSendTextMessage(cid, DESCR, "Player " .. param .. " does not have any achievements.")
		end

	elseif words == "/getsecretach" then

		player = getPlayerByNameWildcard(param)
		if not player or player == "" then
			return doPlayerSendCancel(cid, "Invalid player name.")
		end

		local ach = getPlayerSecretAchievements(player)
		if #ach > 0 then
			local text = ""
			for i = 1, #ach do
				text = text .. getAchievementInfo(tonumber(ach[i])).id .. " - " .. getAchievementInfo(tonumber(ach[i])).name .. "\n"
			end
			return doShowTextDialog(cid, 2195, "Player " .. param .. " has the following secret achievements...\n\n" .. text)
		else
			return doPlayerSendTextMessage(cid, DESCR, "Player " .. param .. " does not have any secret achievements.")
		end
	end
	return true
end

data/talkactions/talkactions.xml
XML:
	<talkaction words="/addach;/addallach;/removeach;/removeallach;/getach;/getsecretach" event="script" value="achievements.lua"/>

Commands:
* /addach -- add achievement to a player (/addach Darkhaos, 5 - /addach Darkhaos, Chorister)
* /addallach --add all achievements to a player (/addallach Darkhaos)
* /removeach --remove achievement to a player (/removeach Darkhaos, 5 - /removeach Darkhaos, Chorister)
* /removeallach --remove all achievements to a player (/removeallach Darkhaos)
* /getach --get achievements from a player (/getach Darkhaos)
* /getsecretach --get secret achievements from a player (/getsecretach Darkhaos)

Please report all bugs here... Enjoy.
 
Last edited:
Achievement 13 - Party Animal

Party Hat
Lua:
function onUse(cid, item, fromPosition, itemEx, toPosition)
	if(item.uid ~= getPlayerSlotItem(cid, CONST_SLOT_HEAD).uid) then
		return false
	end
 
        if getPlayerStorageValue(cid,20013) == 200 then
        doPlayerSendTextMessage(cid,22,"Congratulations! You earned the achievement \"Party Animal\".")
   	setPlayerStorageValue(cid,21013,1)
        end

	doSendMagicEffect(getCreaturePosition(cid), CONST_ME_GIFT_WRAPS)
   	setPlayerStorageValue(cid, 20013, getCreatureStorage(cid, 20013) + 1)
	return true
end

Party Trumpet
Lua:
function onUse(cid, item, fromPosition, itemEx, toPosition)
        if getPlayerStorageValue(cid,20013) == 200 then
        doPlayerSendTextMessage(cid,22,"Congratulations! You earned the achievement \"Party Animal\".")
   	setPlayerStorageValue(cid,21013,1)
        end

	doCreatureSay(cid, "TOOOOOOT!", TALKTYPE_ORANGE_1)
	doSendMagicEffect(fromPosition, CONST_ME_SOUND_BLUE)
	doDecayItem(item.uid)
   	setPlayerStorageValue(cid, 20013, getCreatureStorage(cid, 20013) + 1)
	return true
end

I made it, but it's not checking Achievements. It's checking storage, how to make it check achievements?
 
Last edited:
An example is:
Lua:
local achievement = 50 --achievement No. 50

function onUse(cid, item, fromPosition, itemEx, toPosition)
	if(item.uid ~= getPlayerSlotItem(cid, CONST_SLOT_HEAD).uid) then
		return false
	end
 
        if not playerHasAchievement(achievement) then
		doPlayerAddAchievement(cid, achievement)
		doPlayerSendTextMessage(cid, "Congratulations, you earned the achievement " .. getAchievementInfo(tonumber(achievement)).name .. ".")
	end
 
	doSendMagicEffect(getCreaturePosition(cid), CONST_ME_GIFT_WRAPS)
	return true
end
 
Darkhaos, to get the Achievement 'Party Animal' you have to use Party Hat or Party Trumpet 200 times.
I think your script do not work fine.

Here is Potion Addict, you have to use 100,000 times.
Lua:
local config = {
	removeOnUse = "no",
	usableOnTarget = "yes", -- can be used on target? (fe. healing friend)
	splashable = "no",
	realAnimation = "no", -- make text effect visible only for players in range 1x1
	healthMultiplier = 1.0,
	manaMultiplier = 1.0
}

config.removeOnUse = getBooleanFromString(config.removeOnUse)
config.usableOnTarget = getBooleanFromString(config.usableOnTarget)
config.splashable = getBooleanFromString(config.splashable)
config.realAnimation = getBooleanFromString(config.realAnimation)

local POTIONS = {
	[8704] = {empty = 7636, splash = 2, health = {50, 100}}, -- small health potion
	[7618] = {empty = 7636, splash = 2, health = {100, 200}}, -- health potion
	[7588] = {empty = 7634, splash = 2, health = {200, 400}, level = 50, vocations = {3, 4, 7, 8, 11, 12}, vocStr = "knights and paladins"}, -- strong health potion
	[7591] = {empty = 7635, splash = 2, health = {500, 700}, level = 80, vocations = {4, 8, 12}, vocStr = "knights"}, -- great health potion
	[8473] = {empty = 7635, splash = 2, health = {800, 1000}, level = 130, vocations = {4, 8, 12}, vocStr = "knights"}, -- ultimate health potion

	[7620] = {empty = 7636, splash = 7, mana = {70, 130}}, -- mana potion
	[7589] = {empty = 7634, splash = 7, mana = {110, 190}, level = 50, vocations = {1, 2, 3, 5, 6, 7, 9, 10 ,11}, vocStr = "sorcerers, druids and paladins"}, -- strong mana potion
	[7590] = {empty = 7635, splash = 7, mana = {200, 300}, level = 80, vocations = {1, 2, 5, 6, 9, 10}, vocStr = "sorcerers and druids"}, -- great mana potion

	[8472] = {empty = 7635, splash = 3, health = {200, 400}, mana = {110, 190}, level = 80, vocations = {3, 7, 11}, vocStr = "paladins"} -- great spirit potion
}

local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, (getConfigInfo('timeBetweenExActions') - 100))

function onUse(cid, item, fromPosition, itemEx, toPosition)
	local potion = POTIONS[item.itemid]
	if(not potion) then
		return false
	end

        if getPlayerStorageValue(cid,21066) == 100000 then
        doPlayerSendTextMessage(cid,22,"Congratulations! You earned the achievement \"Potion Addict\".")
   	doPlayerAddAchievement(cid, 66)
        end

	if(not isPlayer(itemEx.uid) or (not config.usableOnTarget and cid ~= itemEx.uid)) then
		if(not config.splashable) then
			return false
		end

		if(toPosition.x == CONTAINER_POSITION) then
			toPosition = getThingPos(item.uid)
		end

		doDecayItem(doCreateItem(2016, potion.splash, toPosition))
		doTransformItem(item.uid, potion.empty)
		return true
	end

	if(hasCondition(cid, CONDITION_EXHAUST_HEAL)) then
		doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUAREEXHAUSTED)
		return true
	end

	if(((potion.level and getPlayerLevel(cid) < potion.level) or (potion.vocations and not isInArray(potion.vocations, getPlayerVocation(cid)))) and
		not getPlayerCustomFlagValue(cid, PLAYERCUSTOMFLAG_GAMEMASTERPRIVILEGES))
	then
		doCreatureSay(itemEx.uid, "Only " .. potion.vocStr .. (potion.level and (" of level " .. potion.level) or "") .. " or above may drink this fluid.", TALKTYPE_ORANGE_1)
		return true
	end

	local health = potion.health
	if(health and not doCreatureAddHealth(itemEx.uid, math.ceil(math.random(health[1], health[2]) * config.healthMultiplier))) then
		return false
	end

	local mana = potion.mana
	if(mana and not doPlayerAddMana(itemEx.uid, math.ceil(math.random(mana[1], mana[2]) * config.manaMultiplier))) then
		return false
	end

	doSendMagicEffect(getThingPos(itemEx.uid), CONST_ME_MAGIC_BLUE)
	if(not realAnimation) then
		doCreatureSay(itemEx.uid, "Aaaah...", TALKTYPE_ORANGE_1)
   	        setPlayerStorageValue(cid, 21066, getCreatureStorage(cid, 21066) + 1)
	else
		for i, tid in ipairs(getSpectators(getCreaturePosition(cid), 1, 1)) do
			if(isPlayer(tid)) then
				doCreatureSay(itemEx.uid, "Aaaah...", TALKTYPE_ORANGE_1, false, tid)
			end
		end
	end

	doAddCondition(cid, exhaust)
	if(not potion.empty or config.removeOnUse) then
		doRemoveItem(item.uid, 1)
		return true
	end
	doRemoveItem(item.uid, 1)
	doPlayerAddItem(cid, potion.empty, 1)
    pot_count = getPlayerItemCount(cid, potion.empty)
    doPlayerRemoveItem(cid, potion.empty, pot_count)
    doPlayerAddItem(cid, potion.empty, pot_count)
	return true
end
 
Last edited:
Oh ok, then..
Lua:
local config = {
	removeOnUse = "no",
	usableOnTarget = "yes", -- can be used on target? (fe. healing friend)
	splashable = "no",
	realAnimation = "no", -- make text effect visible only for players in range 1x1
	healthMultiplier = 1.0,
	manaMultiplier = 1.0
}
 
config.removeOnUse = getBooleanFromString(config.removeOnUse)
config.usableOnTarget = getBooleanFromString(config.usableOnTarget)
config.splashable = getBooleanFromString(config.splashable)
config.realAnimation = getBooleanFromString(config.realAnimation)
 
local POTIONS = {
	[8704] = {empty = 7636, splash = 2, health = {50, 100}}, -- small health potion
	[7618] = {empty = 7636, splash = 2, health = {100, 200}}, -- health potion
	[7588] = {empty = 7634, splash = 2, health = {200, 400}, level = 50, vocations = {3, 4, 7, 8, 11, 12}, vocStr = "knights and paladins"}, -- strong health potion
	[7591] = {empty = 7635, splash = 2, health = {500, 700}, level = 80, vocations = {4, 8, 12}, vocStr = "knights"}, -- great health potion
	[8473] = {empty = 7635, splash = 2, health = {800, 1000}, level = 130, vocations = {4, 8, 12}, vocStr = "knights"}, -- ultimate health potion
 
	[7620] = {empty = 7636, splash = 7, mana = {70, 130}}, -- mana potion
	[7589] = {empty = 7634, splash = 7, mana = {110, 190}, level = 50, vocations = {1, 2, 3, 5, 6, 7, 9, 10 ,11}, vocStr = "sorcerers, druids and paladins"}, -- strong mana potion
	[7590] = {empty = 7635, splash = 7, mana = {200, 300}, level = 80, vocations = {1, 2, 5, 6, 9, 10}, vocStr = "sorcerers and druids"}, -- great mana potion
 
	[8472] = {empty = 7635, splash = 3, health = {200, 400}, mana = {110, 190}, level = 80, vocations = {3, 7, 11}, vocStr = "paladins"} -- great spirit potion
}
 
local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, (getConfigInfo('timeBetweenExActions') - 100))

local achievement = "Potion Addict"
 
function onUse(cid, item, fromPosition, itemEx, toPosition)
	local potion = POTIONS[item.itemid]
	if(not potion) then
		return false
	end
 
        if getPlayerStorageValue(cid,20066) == 100000 then --storage to get uses of potion
		if not playerHasAchievement(cid, getAchievementInfoByName(achievement).id) then
        		doPlayerSendTextMessage(cid,22,"Congratulations! You earned the achievement " .. achievement .. ".")
   			doPlayerAddAchievement(cid, getAchievementInfoByName(achievement).id)
		end
        end
 
	if(not isPlayer(itemEx.uid) or (not config.usableOnTarget and cid ~= itemEx.uid)) then
		if(not config.splashable) then
			return false
		end
 
		if(toPosition.x == CONTAINER_POSITION) then
			toPosition = getThingPos(item.uid)
		end
 
		doDecayItem(doCreateItem(2016, potion.splash, toPosition))
		doTransformItem(item.uid, potion.empty)
		return true
	end
 
	if(hasCondition(cid, CONDITION_EXHAUST_HEAL)) then
		doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUAREEXHAUSTED)
		return true
	end
 
	if(((potion.level and getPlayerLevel(cid) < potion.level) or (potion.vocations and not isInArray(potion.vocations, getPlayerVocation(cid)))) and
		not getPlayerCustomFlagValue(cid, PLAYERCUSTOMFLAG_GAMEMASTERPRIVILEGES))
	then
		doCreatureSay(itemEx.uid, "Only " .. potion.vocStr .. (potion.level and (" of level " .. potion.level) or "") .. " or above may drink this fluid.", TALKTYPE_ORANGE_1)
		return true
	end
 
	local health = potion.health
	if(health and not doCreatureAddHealth(itemEx.uid, math.ceil(math.random(health[1], health[2]) * config.healthMultiplier))) then
		return false
	end
 
	local mana = potion.mana
	if(mana and not doPlayerAddMana(itemEx.uid, math.ceil(math.random(mana[1], mana[2]) * config.manaMultiplier))) then
		return false
	end
 
	doSendMagicEffect(getThingPos(itemEx.uid), CONST_ME_MAGIC_BLUE)
	if(not realAnimation) then
		doCreatureSay(itemEx.uid, "Aaaah...", TALKTYPE_ORANGE_1)
   	        setPlayerStorageValue(cid, 20066, getCreatureStorage(cid, 20066) + 1)
	else
		for i, tid in ipairs(getSpectators(getCreaturePosition(cid), 1, 1)) do
			if(isPlayer(tid)) then
				doCreatureSay(itemEx.uid, "Aaaah...", TALKTYPE_ORANGE_1, false, tid)
			end
		end
	end
 
	doAddCondition(cid, exhaust)
	if(not potion.empty or config.removeOnUse) then
		doRemoveItem(item.uid, 1)
		return true
	end
	doRemoveItem(item.uid, 1)
	doPlayerAddItem(cid, potion.empty, 1)
   	pot_count = getPlayerItemCount(cid, potion.empty)
    	doPlayerRemoveItem(cid, potion.empty, pot_count)
    	doPlayerAddItem(cid, potion.empty, pot_count)
	return true
end
 
I think this libs are unnecessary, you can add storages and 'Congratulations..' in scripts.
 
135 views and 13 responses and no rep? x)

I do not ask for reputation, but some reputation will be appreciated D:
 
135 views and 13 responses and no rep? x)

I do not ask for reputation, but some reputation will be appreciated D:

can't, You must spread some Reputation around before giving it to darkhaos again.
 
A bunch of fixes and optimizations in functions:
Code:
-- achievements functions by Renusek, Darkhaos and Hermes.
 
ACHIEVEMENTS = {
	-- `secret` tag is used in Cipsoft' Tibia website to show image `SECRET` next to the achievement name - there are 45 secret achievements
	-- Table example: [0] = {name = "Achievement Name", storage = 20000, value = 3, message = "You are lucky! You won the lottery 3 times!", grade = 2, points = 5, secret = true}
	-- Grades: GR. 1: 1-3 points, GR. 2: 4-6 points, GR. 3: 7-9 points, GR. 4: 10 points
	-- At the moment, Real Tibia doesn't have achievements with Grade 4, they will be added in next updates.
	-- YOU WILL HAVE TO EDIT MANY `value` TAGS. Also, I'm not sure about `secret` tag correctness.
 
	[1] = {name = "Allow Cookies?", value = 1, message = "With a perfectly harmless smile you fooled all of those wisecrackers into eating your Exploding Cookies. Consider a boy or girl scout outfit next time to make the trick even better.", grade = 1, points = 1},
	[2] = {name = "Backpack Tourist", value = 1, message = "If someone lost a random thing in a random place, you're probably a good person to ask and go find it, even if you don't know what and where.", grade = 1, points = 1, secret = true},
	[3] = {name = "Bearhugger", value = 1, message = "Warm, furry and cuddly - though that same bear you just hugged would probably rip you into pieces if he had been conscious, he reminded you of that old teddy bear which always slept in your bed when you were still small.", grade = 1, points = 1},
	[4] = {name = "Bone Brother", value = 1, message = "You've joined the undead bone brothers - making death your enemy and your weapon as well. Devouring what's weak and leaving space for what's strong is your primary goal.", grade = 1, points = 1},
	[5] = {name = "Chorister", value = 4, message = "Lalalala... you now know the cult's hymn sung in Liberty Bay by heart. Not that hard, considering that it mainly consists of two notes and repetitive lyrics.", grade = 1, points = 1},
	[6] = {name = "Fountain of Life", value = 1, message = "You found and took a sip from the Fountain of Life. Thought it didn't grant you eternal life, you feel changed and somehow at peace.", grade = 1, points = 1, secret = true},
	[7] = {name = "Here, Fishy Fishy!", value = 1000, message = "Ah, the smell of the sea! Standing at the shore and casting a line is one of your favourite activities. For you, fishing is relaxing - and at the same time, providing easy food. Perfect!", grade = 1, points = 1, secret = true},
	[8] = {name = "Honorary Barbarian", value = 1, message = "You've hugged bears, pushed mammoths and proved your drinking skills. And even though you have a slight hangover, a partially fractured rib and some greasy hair on your tongue, you're quite proud to call yourself a honorary barbarian from now on.", grade = 1, points = 1},
	[9] = {name = "Huntsman", value = 1, message = "You're familiar with hunting tasks and have carried out quite a few already. A bright career as hunter for the Paw & Fur society lies ahead!", grade = 1, points = 1},
	[10] = {name = "Just in Time", value = 1, message = "You're a fast runner and are good at delivering wares which are bound to decay just in the nick of time, even if you can't use any means of transportation or if your hands get cold or smelly in the process.", grade = 1, points = 1},
	[11] = {name = "Matchmaker", value = 1, message = "You don't believe in romance to be a coincidence or in love at first sight. In fact - love potions, bouquets of flowers and cheesy poems do the trick much better than ever could. Keep those hormones flowing!", grade = 1, points = 1},
	[12] = {name = "Nightmare Knight", value = 1, message = "You follow the path of dreams and that of responsibility without self-centered power. Free from greed and selfishness, you help others without expecting a reward.", grade = 1, points = 1},
	[13] = {name = "Party Animal", value = 200, message = "Oh my god, it's a paaaaaaaaaaaarty! You're always in for fun, friends and booze and love being the center of attention. There's endless reasons to celebrate! Woohoo!", grade = 1, points = 1, secret = true},
	[14] = {name = "Secret Agent", value = 1, message = "Pack your spy gear and get ready for some dangerous missions in service of a secret agency. You've shown you want to - but can you really do it? Time will tell.", grade = 1, points = 1},
	[15] = {name = "Talented Dancer", value = 1, message = "You're a lord or lady of the dance - and not afraid to use your skills to impress tribal gods. One step to the left, one jump to the right, twist and shout!", grade = 1, points = 1},
	[16] = {name = "Territorial", value = 1, message = "Your map is your friend - always in your back pocket and covered with countless marks of interesting and useful locations. One could say that you might be lost without it - but luckily there's no way to take it from you.", grade = 1, points = 1, secret = true},
	[17] = {name = "Worm Whacker", value = 1, message = "Weehee! Whack those worms! You sure know how to handle a big hammer.", grade = 1, points = 1, secret = true},
	[18] = {name = "Allowance Collector", value = 50, message = "You certainly have your ways when it comes to acquiring money. Many of them are pink and paved with broken fragments of porcelain.", grade = 1, points = 2, secret = true},
	[19] = {name = "Amateur Actor", value = 1, message = "You helped bringing Princess Buttercup, Doctor Dumbness and Lucky the Wonder Dog to life - and will probably dream of them tonight, since you memorised your lines perfectly. What a .. special piece of.. screenplay.", grade = 1, points = 2},
	[20] = {name = "Animal Activist", value = 1, message = "You have a soft spot for little, weak animals, and you do everything in your power to protect them - even if you probably eat dragons for breakfast.", grade = 1, points = 2},
	[21] = {name = "Beach Tamer", value = 1, message = "You re-enacted the Taming of the Shrew on a beach setting and proved that you can handle capricious girls quite well. With or without fish tails.", grade = 1, points = 2},
	[22] = {name = "Blessed!", value = 1, message = "You travelled the world for an almost meaningless prayer - but at least you don't have to do that again and can get a new blessed stake in the blink of an eye.", grade = 1, points = 2},
	[23] = {name = "Exquisite Taste", value = 250, message = "You love fish - but preferably those caught in the cold north. Even though they're hard to come by you never get tired of picking holes in ice sheets and hanging your fishing rod in.", grade = 1, points = 2, secret = true},
	[24] = {name = "Fireworks in the Sky", value = 250, message = "You love the moment right before your rocket takes off and explodes into beautiful colours - not only on new year's eve!", grade = 1, points = 2, secret = true},
	[25] = {name = "Greenhorn", value = 1, message = "You wiped out Orcus the Cruel in the Arena of Svargrond. You're still a bit green behind the ears, but there's some great potential.", grade = 1, points = 2},
	[26] = {name = "Jinx", value = 500, message = "Sometimes you feel there's a gremlin in there. So many lottery tickets, so many blanks? That's just not fair! Share your misery with the world.", grade = 1, points = 2, secret = true},
	[27] = {name = "Lucid Dreamer", value = 1, message = "Dreams - are your reality? Strange visions, ticking clocks, going to bed and waking up somewhere completely else - that was some trip, but you're almost sure you actually did enjoy it.", grade = 1, points = 2},
	[28] = {name = "Mathemagician", value = 1, message = "Sometimes the biggest secrets of life can have a simple solution.", grade = 1, points = 2},
	[29] = {name = "Masquerader", value = 100, message = "You probably don't know anymore how you really look like - usually when you look into a mirror, some kind of monster stares back at you. On the other hand - maybe that's an improvement?", grade = 1, points = 2, secret = true},
	[30] = {name = "Ministrel", value = 1, message = "You can handle any music instrument you're given - and actually manage to produce a pleasant sound with it. You're a welcome guest and entertainer in most taverns.", grade = 1, points = 2, secret = true},
	[31] = {name = "Poet Laureate", value = 1, message = "Poems, verses, songs and rhymes you've recited many times. You have passed the cryptic door, raconteur of ancient lore. Even elves you've left impressed, so it seems you're truly blessed.", grade = 1, points = 2, secret = true},
	[32] = {name = "Quick as a Turtle", value = 2000, message = "There... is... simply... no... better... way - than to travel on the back of a turtle. At least you get to enjoy the beautiful surroundings of Laguna.", grade = 1, points = 2, secret = true},
	[33] = {name = "Sea Scout", value = 1, message = "Not even the hostile underwater environment stops you from doing your duty for the Explorer Society. Scouting the Quara realm is a piece of cake for you.", grade = 1, points = 2},
	[34] = {name = "Steampunked", value = 100, message = "Travelling with the dwarven steamboats through the underground rivers is your preferred way of crossing the lands. No pesky seagulls, and good beer on board!", grade = 1, points = 2, secret = true},
	[35] = {name = "Superstitios", value = 100, message = "Fortune tellers and horoscopes guide you through your life. And you probably wouldn't dare going on a big game hunt without your trusty voodoo skull giving you his approval for the day.", grade = 1, points = 2, secret = true},
	[36] = {name = "The Milkman", value = 1, message = "Who's the milkman? You are!", grade = 1, points = 2},
	[37] = {name = "Turncoat", value = 1, message = "You served Yalahar - but you didn't seem so sure whom to believe on the way. Both Azerus and Palimuth had good reasons for their actions, and thus you followed your gut instinct in the end, even if you helped either of them. May Yalahar prosper!", grade = 1, points = 2, secret = true},
	[38] = {name = "Vive la Resistance", value = 1, message = "You've always been a rebel - admit it! Supplying prisoners, caring for outcasts, stealing from the rich and giving to the poor - no wait, that was another story.", grade = 1, points = 2},
	[39] = {name = "Archpostman", value = 1, message = "Delivering letters and parcels has always been a secret passion of yours, and now you can officially put on your blue hat, blow your Post Horn and do what you like to do most. Beware of dogs!", grade = 1, points = 3},
	[40] = {name = "Clay Fighter", value = 1, message = "Sculpting Brog, the raging Titan, is your secret passion. Numerous perfect little clay statues with your name on them can be found everywhere around Tibia.", grade = 1, points = 3, secret = true},
	[41] = {name = "Efreet Ally", value = 1, message = "Even though the Efreet welcomed you only reluctantly and viewed you as \"only a human\" for quite some time, you managed to impress Malor and gained his respect and trade options with the green djinns.", grade = 1, points = 3},
	[42] = {name = "Ghostwisperer", value = 1, message = "You don't hunt them, you talk to them. You know that ghosts might keep secrets that have been long lost among the living, and you're skilled at talking them into revealing them to you.", grade = 1, points = 3},
	[43] = {name = "His True Face", value = 1, message = "You're one of the few Tibians who Armenius chose to actually show his true face to - and he made you fight him. Either that means you're very lucky or very unlucky, but one thing's for sure - it's extremely rare.", grade = 1, points = 3, secret = true},
	[44] = {name = "Ice Sculptor", value = 1, message = "You love to hang out in cold surroundings and consider ice the best material to be shaped. What a waste to use ice cubes for drinks when you can create a beautiful mammoth statue from it!", grade = 1, points = 3, secret = true},
	[45] = {name = "King Tibanus Fan", value = 1, message = "You're not sure what it is, but you feel drawn to royalty. Your knees are always a bit grazed from crawling around in front of thrones and you love hanging out in castles. Maybe you should consider applying as a guard?", grade = 1, points = 3},
	[46] = {name = "Marblelous", value = 1, message = "Your little statues of Tibiasula have become quite famous around Tibia and there's few people with similar skills when it comes to shaping marble.", grade = 1, points = 3, secret = true},
	[47] = {name = "Marid Ally", value = 1, message = "You've proven to be a valuable ally to the Marid, and Gabel welcomed you to trade with Haroun and Nah'Bob whenever you want to. Though the Djinn war has still not ended, the Marid can't fail with you on their side.", grade = 1, points = 3},
	[48] = {name = "Passionate Kisser", value = 1, message = "For you, a kiss is more than a simple touch of lips. You kiss maidens and deadbeats alike with unmatched affection and faced death and rebirth through the kiss of the banshee queen. Lucky are those who get to share such an intimate moment with you!", grade = 1, points = 3},
	[49] = {name = "Perfect Fool", value = 1, message = "You love playing jokes on others and tricking them into looking a little silly. Wagging tongues say that the moment of realisation in your victims' eyes is the reward you feed on, but you're probably just kidding and having fun with them... right??", grade = 1, points = 3},
	[50] = {name = "Recognised Trader", value = 1, message = "You're a talented merchant who's able to handle wares with care, finds good offers and digs up rares every now and then. Never late to complete an order, you're a reliable trader - at least in Rashid's eyes.", grade = 1, points = 3},
	[51] = {name = "Rockstar", value = 10000, message = "Music just comes to you naturally. You feel comfortable on any stage, at any time, and secretly hope that someday you will be able to defeat your foes by playing music only. Rock on!", grade = 1, points = 3, secret = true},
	[52] = {name = "Scrapper", value = 1, message = "You put out the Spirit of Fire's flames in the arena of Svargrond. Arena fights are for you - fair, square, with simple rules and one-on-one battles.", grade = 1, points = 3},
	[53] = {name = "Vanity", value = 300, message = "Aren't you just perfectly, wonderfully, beautifully gorgeous? You can't pass a mirror without admiring your looks. Or maybe doing a quick check whether something's stuck in your teeth, perhaps?", grade = 1, points = 3, secret = true},
	[54] = {name = "Wayfarer", value = 1, message = "Dragon dreams are golden.", grade = 1, points = 3, secret = true},
	[55] = {name = "Champion of Chazorai", value = 1, message = "You won the merciless 2 vs. 2 team tournament on the Isle of Strife and wiped out wave after wave of fearsome opponents. Death or victory - you certainly chose the latter.", grade = 2, points = 4},
	[56] = {name = "Culinary Master", value = 1, message = "Simple hams and bread merely make you laugh. You're the master of the extra-ordinaire, melter of cheese, fryer of bat wings and shaker of shakes. Delicious!", grade = 2, points = 4},
	[57] = {name = "Explorer", value = 1, message = "You've been to places most people don't even know the names of. Collecting botanic, zoologic and ectoplasmic samples is your daily business and you're always prepared to discover new horizons.", grade = 2, points = 4},
	[58] = {name = "Follower of Azerus", value = 1, message = "When you do something, you do it right. You have an opinion and you stand by it - and no one will be able to convince you otherwise. On a sidenote, you're a bit on the brutal and war-oriented side, but that's not a bad thing, is it?", grade = 2, points = 4},
	[59] = {name = "Follower of Palimuth", value = 1, message = "You're a peacekeeper and listen to what the small people have to say. You've made up your mind and know who to help and for which reasons - and you do it consistently. Your war is fought with reason rather than weapons.", grade = 2, points = 4},
	[60] = {name = "Friend of the Apes", value = 1, message = "You know Banuta like the back of your hand and are good at destroying caskets and urns. The sight of giant footprints doesn't keep you from exploring unknown areas either.", grade = 2, points = 4},
	[61] = {name = "Golem in the Gears", value = 1, message = "You're an aspiring mago-mechanic. Science and magic work well together in your eyes - and even though you probably delivered countless wrong charges while working for Telas, you might just have enough knowledge to build your own golem now.", grade = 2, points = 4},
	[62] = {name = "High-Flyer", value = 1000, message = "The breeze in your hair, your fingers clutching the rim of your Carpet - that's how you like to travel. Faster! Higher! And a looping every now and then.", grade = 2, points = 4, secret = true},
	[63] = {name = "Interior Decorator", value = 1000, message = "Your home is your castle - and the furniture in it is just as important. Your friends ask for your advice when decorating their Houses and your probably own every statue, rack and bed there is.", grade = 2, points = 4, secret = true},
	[64] = {name = "Master Thief", value = 1, message = "Robbing, inviting yourself to VIP parties, faking contracts and pretending to be someone else - you're a jack of all trades when it comes to illegal activities. You take no prisoners, except for the occasional goldfish now and then.", grade = 2, points = 4},
	[65] = {name = "Polisher", value = 1, message = "If you see a rusty item, you can't resist polishing it. There's always a little flask of rust remover in your inventory - who knows, there might be a golden armor beneath all that dirt!", grade = 2, points = 4, secret = true},
	[66] = {name = "Potion Addict", value = 1, message = "Your local magic trader considers you one of his best customers - you usually buy large stocks of potions so you won't wake up in the middle of the night craving for more. Yet, you always seem to run out of them too fast. Cheers!", grade = 2, points = 4, secret = true},
	[67] = {name = "Ruthless", value = 1, message = "You've touched all thrones of the Ruthless Seven and absorbed some of their evil spirit. It may have changed you forever.", grade = 2, points = 5},
	[68] = {name = "Ship's Kobold", value = 1000, message = "You've probably never gotten seasick in your life - you love spending your free time on the ocean and covered quite a lot of miles with ships. Aren't you glad you didn't have to swim all that?", grade = 2, points = 4, secret = true}, 
	[69] = {name = "Top AVIN Agent", value = 1, message = "You've proven yourself as a worthy member of the 'family' and successfully carried out numerous spy missions for your 'uncle' to support the Venorean traders and their goals.", grade = 2, points = 4},
	[70] = {name = "Top CGB Agent", value = 1, message = "Girl power! Whether you're female or not, you've proven absolute loyalty and the willingness to put your life at stake for the girls brigade of Carlin.", grade = 2, points = 4},
	[71] = {name = "Top TBI Agent", value = 1, message = "Conspiracies and open secrets are your daily bread. You've shown loyalty to the Thaian crown through your courage when facing enemies and completing spy missions. You're an excellent field agent of the TBI.", grade = 2, points = 4},
	[72] = {name = "Annihilator", value = 1, message = "You've daringly jumped into the infamous Annihilator and survived - taking home fame, glory and your reward.", grade = 2, points = 5},
	[73] = {name = "Castlemania", value = 1, message = "You have an eye for suspicious places and love to read other people's diaries, especially those with vampire stories in it. You're also a dedicated token collector and explorer. Respect!", grade = 2, points = 5, secret = true},
	[74] = {name = "Elite Hunter", value = 1, message = "You jump at every opportunity for a hunting challenge that's offered to you and carry out those tasks with deadly precision. You're a hunter at heart and a valuable member of the Paw & Fur Society.", grade = 2, points = 5},
	[75] = {name = "High Inquisitor", value = 1, message = "You're the one who poses the questions around here, and you know how to get the answers you want to hear. Besides, you're a famous exorcist and slay a few vampires and demons here and there. You and your stake are a perfect team.", grade = 2, points = 5},
	[76] = {name = "Jamjam", value = 1, message = "When it comes to interracial understanding, you're an expert. You've mastered the language of the Chakoya and made someone really happy with your generosity. Achuq!", grade = 2, points = 5},
	[77] = {name = "Lord of the Elements", value = 1, message = "You travelled the surreal realm of the elemental spheres, summoned and slayed the Lord of the Elements, all in order to retrieve neutral matter. And as brave as you were, you couldn't have done it without your team!", grade = 2, points = 5},
	[78] = {name = "Warlord of Svargrond", value = 1, message = "You sent the Obliverator into oblivion in the arena of Svargrond and defeated nine other dangerous enemies on the way. All hail the Warlord of Svargrond!", grade = 2, points = 5},
	[79] = {name = "Master of the Nexus", value = 1, message = "You were able to fight your way through the countless hordes in the Demon Forge. Once more you proved that nothing is impossible.", grade = 2, points = 6},
	[80] = {name = "Razing!", value = 1, message = "People with sharp canine teeth better beware of you, especially at nighttime, or they might find a stake between their ribs. You're a merciless vampire hunter and have gathered numerous tokens as proof.", grade = 3, points = 7, secret = true},
	[81] = {name = "Dread Lord", value = 1, message = "You don't care for rules that others set up and shape the world to your liking. Having left behind meaningless conventions and morals, you prize only the power you wield. You're a master of your fate and battle to cleanse the world.", grade = 3, points = 8, secret = true},
	[82] = {name = "Lord Protector", value = 1, message = "You proved yourself - not only in your dreams - and possess a strong and spiritual mind. Your valorous fight against demons and the undead plague has granted you the highest and most respected rank among the Nightmare Knights.", grade = 3, points = 8, secret = true},
	[83] = {name = "Herbicide", value = 1, message = "You're one of the brave heroes to face and defeat the mysterious demon oak and all the critters it threw in your face. Wielding your blessed axe no tree dares stand in your way - demonic or not.", grade = 3, points = 7, secret = true}
}
 
-- default storage values
ACHIEVEMENT_BASE = 20000
ACHIEVEMENT_FIRST = 1
ACHIEVEMENT_LAST = #ACHIEVEMENTS
ACHIEVEMENT_POINTS = 15200

-- function by Hermes
function getAchievement(achievement) -- achievement may be the name or id
	return type(achievement) == "string" and getAchievementInfoByName(achievement) or getAchievementInfo(tonumber(achievement))
end

-- functions by Darkhaos
function getAchievementInfo(id)
	local tmp = ACHIEVEMENTS[id]
	if(not tmp) then return false end
	return tmp and {
		id = id,
		name = tmp.name,
		storage = ACHIEVEMENT_BASE + id,
		value = tmp.value,
		message = tmp.message,
		grade = tmp.grade,
		points = tmp.points,
		secret = tmp.secret or false
	}
end
 
function getAchievementInfoByName(name)
	name = name:lower()
	local found = false
	for k, tmp in pairs(ACHIEVEMENTS) do
		if(tmp.name:lower() == name) then
			local found = k
			break
		end
	end
	return found and getAchievementInfo(found) or false
end
 
function isAchievementSecret(achievement) -- achievement may be the name or id
	return getAchievement(achievement).secret or false
end
 
function getPlayerAchievements(cid, name) -- name will make function return acievement names instead of ids
	local tmp = {}
	for i = ACHIEVEMENT_FIRST, ACHIEVEMENT_LAST do
		if(getCreatureStorage(cid, ACHIEVEMENT_BASE + i) >= getAchievementInfo(i).value) then
			table.insert(tmp, name and getAchievementInfo(i).name or i)
		end
	end
	return tmp
end
 
function playerHasAchievement(cid, achievement) -- achievement may be the name or id
	local achievement = getAchievement(achievement)
	return getCreatureStorage(cid, achievement.storage) < achievement.value and false or true
end
 
function getPlayerSecretAchievements(cid, name) -- name will make function return acievement names instead of ids
	local tmp = {}
	for i = ACHIEVEMENT_FIRST, ACHIEVEMENT_LAST do
		if(not getCreatureStorage(cid, ACHIEVEMENT_BASE + i) < getAchievementInfo(i).value and isAchievementSecret(i)) then
			table.insert(tmp, name and getAchievementInfo(i).name or i)
		end
	end
	return tmp
end
 
function doPlayerAddAchievement(cid, achievement) -- achievement may be the name or id
	local tmp = getAchievement(achievement)
	if(not tmp) then return false end
	if(getCreatureStorage(cid, ACHIEVEMENT_POINTS) < 0) then doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, 0) end
	if(getCreatureStorage(cid, tmp.storage) < tmp.value) then
		return doCreatureSetStorage(cid, tmp.storage, tmp.value) and doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, getCreatureStorage(cid, ACHIEVEMENT_POINTS) + tmp.points)
	end
	return false
end
 
function doPlayerAddAllAchievements(cid)
	if(getCreatureStorage(cid, ACHIEVEMENT_POINTS) < 0) then doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, 0) end
	for i = ACHIEVEMENT_FIRST, ACHIEVEMENT_LAST do
		local tmp = getAchievementInfo(i)
		if(tmp) then
			if(getCreatureStorage(cid, tmp.storage) < tmp.value) then
				doCreatureSetStorage(cid, tmp.storage, tmp.value)
				doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, getCreatureStorage(cid, ACHIEVEMENT_POINTS) + tmp.points)
			end
		end
	end
	return true
end
 
function doPlayerRemoveAchievement(cid, achievement) -- achievement may be the name or id
	local tmp = getAchievement(achievement)
	if(not tmp) then return false end
	if(getCreatureStorage(cid, ACHIEVEMENT_POINTS) < 0) then doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, 0) end
	if getCreatureStorage(cid, tmp.storage) >= tmp.value then
		return doCreatureSetStorage(cid, tmp.storage, 0) and doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, getCreatureStorage(cid, ACHIEVEMENT_POINTS) - tmp.points)
	end
	return false
end	
 
function doPlayerRemoveAllAchievements(cid)
	if(getCreatureStorage(cid, ACHIEVEMENT_POINTS) < 0) then doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, 0) end
	for i = ACHIEVEMENT_FIRST, ACHIEVEMENT_LAST do
		local tmp = getAchievementInfo(i)
		if(tmp) then
			if(getCreatureStorage(cid, tmp.storage) >= tmp.value) then
				doCreatureSetStorage(cid, tmp.storage, 0)
				doCreatureSetStorage(cid, ACHIEVEMENT_POINTS, getCreatureStorage(cid, ACHIEVEMENT_POINTS) - tmp.points)
			end
		end
	end
	return true
end

If the `secret` tag is optional, we mustn't use it in table. Also, I've added getAchievement(achievement) function just to optimize and cleanup code. Whole file was correctly tabbed. Not tested though.
 
Backpack Tourist Achievement (NPC Sam):

Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

function onCreatureAppear(cid)            npcHandler:onCreatureAppear(cid)            end
function onCreatureDisappear(cid)        npcHandler:onCreatureDisappear(cid)            end
function onCreatureSay(cid, type, msg)    npcHandler:onCreatureSay(cid, type, msg)    end
function onThink()                        npcHandler:onThink()    end


local achievement = 2 --achievement No. 2 - Backpack Tourist

function OldBackpack(cid, message, keywords, parameters, node)

    if(not npcHandler:isFocused(cid)) then
        return false
    end

    if isPremium(cid) then
    if getPlayerStorageValue(cid,35600) == -1 then
        if getPlayerItemCount(cid,3960) >= 1 then
        if doPlayerRemoveItem(cid,3960,1) then
            npcHandler:say("Thank you very much! This brings back good old memories! Please, as a reward, travel to Kazordoon and ask my old friend {Kroox} to provide you a special dwarven armor.")
            doSendMagicEffect(getCreaturePosition(cid), 13)
			setPlayerStorageValue(cid,35600,1) 
			doPlayerAddAchievement(cid, achievement)
			doPlayerSendTextMessage(cid,22, "Congratulations, you earned the achievement " .. getAchievementInfo(tonumber(achievement)).name .. ".")
			doSendMagicEffect(getCreaturePosition(cid), CONST_ME_GIFT_WRAPS)
			setPlayerStorageValue(cid,76202,1) 
        end
        else
            selfSay("Thank you for your concern, but I don't think this is my backpack")
        end
    else
        selfSay("Thank you for your concern, but I don't think this is my backpack, since you gave it to me already")
    end
    end

end


node1 = keywordHandler:addKeyword({'old backpack'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, text = "What? Did you find my old backpack, I've lost it in Uldrak's Rock..."})
node1:addChildKeyword({'yes'}, OldBackpack, {})
node1:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, text = 'Ahh, for one moment I tought you have find my old backpack...', reset = true})


npcHandler:addModule(FocusModule:new())
 
doPlayerSendTextMessage(cid,22, "Congratulations, you earned the achievement " .. getAchievementInfo(tonumber(achievement)).name .. ".")
don't do this, make doPlayerAddAchievement send the message instead

fixed up the npc a bit too:
Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

local Topic = {}

function onCreatureAppear(cid) npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid) npcHandler:onCreatureDisappear(cid) end
function onCreatureSay(cid, type, msg) npcHandler:onCreatureSay(cid, type, msg) end
function onThink() npcHandler:onThink() end

function thinkCallback(cid)
	if math.random(400) == 1 then
		selfSay('Hello there, adventurer! Need a deal in weapons or armor? I\'m your man!')
	end
	return true
end

function creatureSayCallback(cid, type, msg)
	if not npcHandler:isFocused(cid) then
		if msgcontains(msg, 'hello') or msgcontains(msg, 'hi') then
			npcHandler:say(msgcontains(msg, 'sam') and 'Hi '.. getCreatureName(cid) ..'. Can I do something for you? I trade with weapons and armor.' or 'Welcome to my shop, adventurer '.. getCreatureName(cid) ..'! I trade with weapons and armor.', cid)
			Topic[cid] = nil
			npcHandler:addFocus(cid)
		else
			return false
		end
	elseif msgcontains(msg, 'bye') or msgcontains(msg, 'farewell') then
		npcHandler:say('Good bye and come again, '.. getCreatureName(cid) ..'.', cid)
		Topic[cid] = nil
		npcHandler:releaseFocus(cid)
	elseif msgcontains(msg, 'backpack') then
		if getCreatureStorage(cid, 289) == -1 then
			npcHandler:say('What? Are you telling me you found my old adventurer\'s backpack that I lost years ago??', cid)
			Topic[cid] = 1
		else
			npcHandler:say('Yes, you brought back my old backpack. Thank you again.', cid)
			Topic[cid] = nil
		end
	elseif Topic[cid] == 1 and msgcontains(msg, 'yes') then
		if doPlayerRemoveItem(cid, 3960, 1) then
			doCreatureSetStorage(cid, 289, 1)
			npcHandler:say('Thank you very much! This brings back good old memories! Please, as a reward, travel to Kazordoon and ask my old friend Kroox to provide you a special dwarven armor. ...', cid)
			npcHandler:say('I will mail him about you immediately. Just tell him, his old buddy Sam is sending you.', cid)
			doPlayerAddAchievement(cid, 2)
			doPlayerSendTextMessage(cid, MESSAGE_EVENT_ADVANCE, 'Congratulations, you earned the achievement ' .. getAchievementInfo(2).name .. '.')
		else
			npcHandler:say('No, you don\'t have my old backpack. What a pity.', cid)
		end
		Topic[cid] = nil
	elseif Topic[cid] == 1 and msgcontains(msg, 'no') then
		npcHandler:say('What a pity.', cid)
		Topic[cid] = nil
	end
	return true
end

npcHandler:setMessage(MESSAGE_WALKAWAY, 'Good bye and come again.')
npcHandler:setCallback(CALLBACK_ONTHINK, thinkCallback)
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
 
Last edited:
Back
Top