diff --git a/achvlist.py b/achvlist.py
index 50547fe..7d532b4 100644
--- a/achvlist.py
+++ b/achvlist.py
@@ -1,93 +1,189 @@
-ACHV = [{"name": "Welcome to Hell", "desc": "Play a game"},
- {"name": "Welcome to the Asylum", "desc": "Play a chaos game"},
- {"name": "Alzheimer's Patient", "desc": "Play a game with an amnesia language pack"},
- {"name": "O HAI DER!", "desc": "Play a game with Para's secret account (not @para949)"},
- {"name": "Spy vs Spy", "desc": "Play a game in secret mode (no role reveal)"},
- {"name": "Explorer", "desc": "Play at least 2 games each in 10 different groups", "inactive":True},
- {"name": "Linguist", "desc": "Play at least 2 games each in 10 different language packs", "inactive":True},
- {"name": "I Have No Idea What I'm Doing", "desc": "Play a game in secret amnesia mode"},
- {"name": "Enochlophobia", "desc": "Play a 35 player game"},
- {"name": "Introvert", "desc": "Play a 5 player game"},
- {"name": "Naughty!", "desc": "Play a game using any NSFW language pack"},
- {"name": "Dedicated", "desc": "Play 100 games"},
- {"name": "Obsessed", "desc": "Play 1000 games"},
- {"name": "Here's Johnny!", "desc": "Get 50 kills as the serial killer", "not_via_playing":True},
- {"name": "I've Got Your Back", "desc": "Save 50 people as the Guardian Angel", "not_via_playing":True},
- {"name": "Masochist", "desc": "Win a game as the Tanner"},
- {"name": "Wobble Wobble", "desc": "Survive a game as the drunk (at least 10 players)"},
- {"name": "Inconspicuous", "desc": "In a game of 20 or more people, do not get a single lynch vote against you (and survive)"},
- {"name": "Survivalist", "desc": "Survive 100 games"},
- {"name": "Black Sheep", "desc": "Get lynched first 3 games in a row", "inactive":True},
- {"name": "Promiscuous", "desc": "As the harlot, survive a 5+ night game without staying home or visiting the same person more than once"},
- {"name": "Mason Brother", "desc": "Be one of at least two surviving masons in a game"},
- {"name": "Double Shifter", "desc": "Change roles twice in one game (cult conversion does not count)"},
- {"name": "Hey Man, Nice Shot", "desc": "As the hunter, use your dying shot to kill a wolf or serial killer"},
- {"name": "That's Why You Don't Stay Home", "desc": "As a wolf or cultist, kill or convert a harlot that stayed home"},
- {"name": "Double Vision", "desc": "Be one of two seers at the same time"},
- {"name": "Double Kill", "desc": "Be part of the Serial Killer / Hunter ending"},
- {"name": "Should Have Known", "desc": "As the Seer, reveal the Beholder"},
- {"name": "I See a Lack of Trust", "desc": "As the Seer, get lynched on the first day"},
- {"name": "Sunday Bloody Sunday", "desc": "Be one of at least 4 victims to die in a single night"},
- {"name": "Change Sides Works", "desc": "Change roles in a game, and win"},
- {"name": "Forbidden Love", "desc": "Win as a wolf / villager couple (villager, not village team)"},
- {"name": "Developer", "desc": "Have a pull request merged into the repo", "not_via_playing":True},
- {"name": "The First Stone", "desc": "Be the first to cast a lynch vote 5 times in a single game"},
- {"name": "Smart Gunner", "desc": "As the Gunner, both of your bullets hit a wolf, serial killer, or cultist"},
- {"name": "Streetwise", "desc": "Find a different wolf, serial killer, or cultist 4 nights in a row as the detective"},
- {"name": "Speed Dating", "desc": "Have the bot select you as a lover (cupid failed to choose)"},
- {"name": "Even a Stopped Clock is Right Twice a Day", "desc": "As the Fool, have at least two of your visions be correct by the end of the game"},
- {"name": "So Close!", "desc": "As the Tanner, be tied for the most lynch votes"},
- {"name": "Cultist Convention", "desc": "Be one of 10 or more cultists alive at the end of a game"},
- {"name": "Self Loving", "desc": "As cupid, pick yourself as one of the lovers"},
- {"name": "Should've Said Something", "desc": "As a wolf, your pack eats your lover (first night does not count)"},
- {"name": "Tanner Overkill", "desc": "As the Tanner, have everyone (but yourself) vote to lynch you"},
- {"name": "Serial Samaritan", "desc": "As the Serial Killer, kill at least 3 wolves in single game"},
- {"name": "Cultist Fodder", "desc": "Be the cultist that is sent to attempt to convert the Cult Hunter"},
- {"name": "Lone Wolf", "desc": "In a chaos game of 10 or more people, be the only wolf - and win"},
- {"name": "Pack Hunter", "desc": "Be one of 7 living wolves at one time"},
- {"name": "Saved by the Bull(et)", "desc": "As a villager, the wolves match the number of villagers, but the game does not end because the gunner has a bullet"},
- {"name": "In for the Long Haul", "desc": "Survive for at least an hour in a single game"},
- {"name": "OH SHI-", "desc": "Kill your lover on the first night"},
- {"name": "Veteran", "desc": "Play 500 games. You can now join @werewolfvets"},
- {"name": "No Sorcery!", "desc": "As a wolf, kill your sorcerer"},
- {"name": "Cultist Tracker", "desc": "As the cultist hunter, kill at least 3 cultists in one game"},
- {"name": "I'M NOT DRUN-- *BURPPP*", "desc": "As the clumsy guy, have at least 3 correct lynches by the end of the game"},
- {"name": "Wuffie-Cult", "desc": "As the alpha wolf, successfully convert at least 3 victims into wolves"},
- {"name": "Did you guard yourself?", "desc": "As the guardian angel, survive after 3 tries guarding an unattacked wolf"},
- {"name": "Spoiled Rich Brat", "desc": "As the prince, still gets lynched even after revealing your identity"},
- {"name": "Three Little Wolves and a Big Bad Pig", "desc": "As the sorcerer, survive a game with three or more alive wolves"},
- {"name": "President", "desc": "As the mayor, successfully cast 3 lynch votes after revealing"},
- {"name": "I Helped!", "desc": "As a wolf cub, the alive pack has 2 successful eat attempts after you die"},
- {"name": "It Was a Busy Night!", "desc": "During the same night, got visited by 3 or more different visiting roles"},
- {"name": "Strongest Alpha", "desc": "As the alpha wolf, successfully infect the serial killer!"},
- {"name": "Am I Your Seer?", "desc": "As the fool, correctly spot the beholder"},
- {"name": "Demoted by the Death", "desc": "As the hunter, shoot the wise elder with your final shot and die as lowly villager"},
- {"name": "Wasted Silver", "desc": "As the blacksmith, spread your silver dust the same day that the sandman sings"},
- {"name": "Trustworthy!", "desc": "As the wolf man, survive and win the game after being checked by seer"},
- {"name": "Deep Love", "desc": "As the doppelgänger, choose your lover as role model. What a deep love <3"},
- {"name": "Time to retire...", "desc": "As the sorcerer, be the last person alive in the village and lose the game"},
- {"name": "Seeing between Teams", "desc": "Be in a seer/sorcerer couple"},
- {"name": "Just a Beardy Guy..?", "desc": "As the wolf man, be infected by the alpha wolf and become a real werewolf. AWOOOOOOO!"},
- {"name": "That Came Unexpected!", "desc": "As tanner, be lynched and win the game when there are only 3 persons left"},
- {"name": "Now I'm Blind", "desc": "As the oracle, fail to get a vision because everyone else has the same role."},
- {"name": "Every Man for Himself!", "desc": "As the pacifist, save yourself from being lynched (at least 50% of votes have been cast for you already)"},
- {"name": "My Sweetie so Strong!", "desc": "Be in love with the pacifist, and get saved from being lynched by them (at least 50% of votes have been cast for you already)"},
- {"name": "Cult Leader", "desc": "Be a cultist from the beginning of the game, survive and win."},
- {"name": "Thanks, Junior!", "desc": "After the wolf pack ate the Drunk, you turn into a wolf and can try to eat someone while the rest of the wolf pack is drunk!"},
- {"name": "Death Village", "desc": "Participate in a game that has no winner."},
- {"name": "I Lost my Wisdom", "desc": "As the wise elder, change your role! Suddenly you're not that wise anymore..."},
- {"name": "Affectionate", "desc": "As the harlot, visit your lover!"},
- {"name": "Lucky Day", "desc": "As the Alpha Wolf, infect the drunk and stay sober! Phew..."},
- {"name": "Condition Red!", "desc": "As the last wolf alive, eat the traitor. Oh no!"},
- {"name": "Indestructible", "desc": "Become Doppelgänger or Wild Child with your role model being yourself!"},
- {"name": "Psychopath Killer", "desc": "As the serial killer, win a game with 35 players!"},
- {"name": "Today's Special!", "desc": "Be the role only available on special events!"},
- {"name": "Romeo and Juliet", "desc": "Be in love with the tanner, and win by lynching your lover!"},
- {"name": "Really bad luck", "desc": "As a serial killer, stumble in a grave, then kill someone randomly and get fought off by the guardian angel."},
- {"name": "Domino", "desc": "As a hunter, shoot another hunter causing them to shoot as well."},
- {"name": "Double Shot", "desc": "As the hunter or the gunner, shoot a bad role who is in love with another bad role!"},
- {"name": "Playing with the Fire", "desc": "As the arsonist, burn 5 or more houses in one night."},
- {"name": "Firework", "desc": "As the arsonist, burn 10 or more houses in one night! What a nice firework :)"},
- {"name": "Cold as Ice", "desc": "As the Snow Wolf, freeze the harlot. Their love is cold as ice."},
- {"name": "Good Choice... For You", "desc": "As the chemist, visit a player and survive 3 times in a single game."},
- {"name": "Increase the Pack!", "desc": "After the wolf cub died, infect 2 players as the alpha wolf!"}]
+ACHV = {
+ 'en': [{"name": "Welcome to Hell", "desc": "Play a game"},
+ {"name": "Welcome to the Asylum", "desc": "Play a chaos game"},
+ {"name": "Alzheimer's Patient", "desc": "Play a game with an amnesia language pack"},
+ {"name": "O HAI DER!", "desc": "Play a game with Para's secret account (not @para949)"},
+ {"name": "Spy vs Spy", "desc": "Play a game in secret mode (no role reveal)"},
+ {"name": "Explorer", "desc": "Play at least 2 games each in 10 different groups", "inactive": True},
+ {"name": "Linguist", "desc": "Play at least 2 games each in 10 different language packs", "inactive": True},
+ {"name": "I Have No Idea What I'm Doing", "desc": "Play a game in secret amnesia mode"},
+ {"name": "Enochlophobia", "desc": "Play a 35 player game"},
+ {"name": "Introvert", "desc": "Play a 5 player game"},
+ {"name": "Naughty!", "desc": "Play a game using any NSFW language pack"},
+ {"name": "Dedicated", "desc": "Play 100 games"},
+ {"name": "Obsessed", "desc": "Play 1000 games"},
+ {"name": "Here's Johnny!", "desc": "Get 50 kills as the serial killer", "not_via_playing": True},
+ {"name": "I've Got Your Back", "desc": "Save 50 people as the Guardian Angel", "not_via_playing": True},
+ {"name": "Masochist", "desc": "Win a game as the Tanner"},
+ {"name": "Wobble Wobble", "desc": "Survive a game as the drunk (at least 10 players)"},
+ {"name": "Inconspicuous", "desc": "In a game of 20 or more people, do not get a single lynch vote against you (and survive)"},
+ {"name": "Survivalist", "desc": "Survive 100 games"},
+ {"name": "Black Sheep", "desc": "Get lynched first 3 games in a row", "inactive": True},
+ {"name": "Promiscuous", "desc": "As the harlot, survive a 5+ night game without staying home or visiting the same person more than once"},
+ {"name": "Mason Brother", "desc": "Be one of at least two surviving masons in a game"},
+ {"name": "Double Shifter", "desc": "Change roles twice in one game (cult conversion does not count)"},
+ {"name": "Hey Man, Nice Shot", "desc": "As the hunter, use your dying shot to kill a wolf or serial killer"},
+ {"name": "That's Why You Don't Stay Home", "desc": "As a wolf or cultist, kill or convert a harlot that stayed home"},
+ {"name": "Double Vision", "desc": "Be one of two seers at the same time"},
+ {"name": "Double Kill", "desc": "Be part of the Serial Killer / Hunter ending"},
+ {"name": "Should Have Known", "desc": "As the Seer, reveal the Beholder"},
+ {"name": "I See a Lack of Trust", "desc": "As the Seer, get lynched on the first day"},
+ {"name": "Sunday Bloody Sunday", "desc": "Be one of at least 4 victims to die in a single night"},
+ {"name": "Change Sides Works", "desc": "Change roles in a game, and win"},
+ {"name": "Forbidden Love", "desc": "Win as a wolf / villager couple (villager, not village team)"},
+ {"name": "Developer", "desc": "Have a pull request merged into the repo", "not_via_playing": True},
+ {"name": "The First Stone", "desc": "Be the first to cast a lynch vote 5 times in a single game"},
+ {"name": "Smart Gunner", "desc": "As the Gunner, both of your bullets hit a wolf, serial killer, or cultist"},
+ {"name": "Streetwise", "desc": "Find a different wolf, serial killer, or cultist 4 nights in a row as the detective"},
+ {"name": "Speed Dating", "desc": "Have the bot select you as a lover (cupid failed to choose)"},
+ {"name": "Even a Stopped Clock is Right Twice a Day", "desc": "As the Fool, have at least two of your visions be correct by the end of the game"},
+ {"name": "So Close!", "desc": "As the Tanner, be tied for the most lynch votes"},
+ {"name": "Cultist Convention", "desc": "Be one of 10 or more cultists alive at the end of a game"},
+ {"name": "Self Loving", "desc": "As cupid, pick yourself as one of the lovers"},
+ {"name": "Should've Said Something", "desc": "As a wolf, your pack eats your lover (first night does not count)"},
+ {"name": "Tanner Overkill", "desc": "As the Tanner, have everyone (but yourself) vote to lynch you"},
+ {"name": "Serial Samaritan", "desc": "As the Serial Killer, kill at least 3 wolves in single game"},
+ {"name": "Cultist Fodder", "desc": "Be the cultist that is sent to attempt to convert the Cult Hunter"},
+ {"name": "Lone Wolf", "desc": "In a chaos game of 10 or more people, be the only wolf - and win"},
+ {"name": "Pack Hunter", "desc": "Be one of 7 living wolves at one time"},
+ {"name": "Saved by the Bull(et)", "desc": "As a villager, the wolves match the number of villagers, but the game does not end because the gunner has a bullet"},
+ {"name": "In for the Long Haul", "desc": "Survive for at least an hour in a single game"},
+ {"name": "OH SHI-", "desc": "Kill your lover on the first night"},
+ {"name": "Veteran", "desc": "Play 500 games. You can now join @werewolfvets"},
+ {"name": "No Sorcery!", "desc": "As a wolf, kill your sorcerer"},
+ {"name": "Cultist Tracker", "desc": "As the cultist hunter, kill at least 3 cultists in one game"},
+ {"name": "I'M NOT DRUN-- *BURPPP*", "desc": "As the clumsy guy, have at least 3 correct lynches by the end of the game"},
+ {"name": "Wuffie-Cult", "desc": "As the alpha wolf, successfully convert at least 3 victims into wolves"},
+ {"name": "Did you guard yourself?", "desc": "As the guardian angel, survive after 3 tries guarding an unattacked wolf"},
+ {"name": "Spoiled Rich Brat", "desc": "As the prince, still gets lynched even after revealing your identity"},
+ {"name": "Three Little Wolves and a Big Bad Pig", "desc": "As the sorcerer, survive a game with three or more alive wolves"},
+ {"name": "President", "desc": "As the mayor, successfully cast 3 lynch votes after revealing"},
+ {"name": "I Helped!", "desc": "As a wolf cub, the alive pack has 2 successful eat attempts after you die"},
+ {"name": "It Was a Busy Night!", "desc": "During the same night, got visited by 3 or more different visiting roles"},
+ {"name": "Strongest Alpha", "desc": "As the alpha wolf, successfully infect the serial killer!"},
+ {"name": "Am I Your Seer?", "desc": "As the fool, correctly spot the beholder"},
+ {"name": "Demoted by the Death", "desc": "As the hunter, shoot the wise elder with your final shot and die as lowly villager"},
+ {"name": "Wasted Silver", "desc": "As the blacksmith, spread your silver dust the same day that the sandman sings"},
+ {"name": "Trustworthy!", "desc": "As the wolf man, survive and win the game after being checked by seer"},
+ {"name": "Deep Love", "desc": "As the doppelgänger, choose your lover as role model. What a deep love <3"},
+ {"name": "Time to retire...", "desc": "As the sorcerer, be the last person alive in the village and lose the game"},
+ {"name": "Seeing between Teams", "desc": "Be in a seer/sorcerer couple"},
+ {"name": "Just a Beardy Guy..?", "desc": "As the wolf man, be infected by the alpha wolf and become a real werewolf. AWOOOOOOO!"},
+ {"name": "That Came Unexpected!", "desc": "As tanner, be lynched and win the game when there are only 3 persons left"},
+ {"name": "Now I'm Blind", "desc": "As the oracle, fail to get a vision because everyone else has the same role."},
+ {"name": "Every Man for Himself!", "desc": "As the pacifist, save yourself from being lynched (at least 50% of votes have been cast for you already)"},
+ {"name": "My Sweetie so Strong!", "desc": "Be in love with the pacifist, and get saved from being lynched by them (at least 50% of votes have been cast for you already)"},
+ {"name": "Cult Leader", "desc": "Be a cultist from the beginning of the game, survive and win."},
+ {"name": "Thanks, Junior!", "desc": "After the wolf pack ate the Drunk, you turn into a wolf and can try to eat someone while the rest of the wolf pack is drunk!"},
+ {"name": "Death Village", "desc": "Participate in a game that has no winner."},
+ {"name": "I Lost my Wisdom", "desc": "As the wise elder, change your role! Suddenly you're not that wise anymore..."},
+ {"name": "Affectionate", "desc": "As the harlot, visit your lover!"},
+ {"name": "Lucky Day", "desc": "As the Alpha Wolf, infect the drunk and stay sober! Phew..."},
+ {"name": "Condition Red!", "desc": "As the last wolf alive, eat the traitor. Oh no!"},
+ {"name": "Indestructible", "desc": "Become Doppelgänger or Wild Child with your role model being yourself!"},
+ {"name": "Psychopath Killer", "desc": "As the serial killer, win a game with 35 players!"},
+ {"name": "Today's Special!", "desc": "Be the role only available on special events!"},
+ {"name": "Romeo and Juliet", "desc": "Be in love with the tanner, and win by lynching your lover!"},
+ {"name": "Really bad luck", "desc": "As a serial killer, stumble in a grave, then kill someone randomly and get fought off by the guardian angel."},
+ {"name": "Domino", "desc": "As a hunter, shoot another hunter causing them to shoot as well."},
+ {"name": "Double Shot", "desc": "As the hunter or the gunner, shoot a bad role who is in love with another bad role!"},
+ {"name": "Playing with the Fire", "desc": "As the arsonist, burn 5 or more houses in one night."},
+ {"name": "Firework", "desc": "As the arsonist, burn 10 or more houses in one night! What a nice firework :)"},
+ {"name": "Cold as Ice", "desc": "As the Snow Wolf, freeze the harlot. Their love is cold as ice."},
+ {"name": "Good Choice... For You", "desc": "As the chemist, visit a player and survive 3 times in a single game."},
+ {"name": "Increase the Pack!", "desc": "After the wolf cub died, infect 2 players as the alpha wolf!"}],
+
+ 'fa': [{'name': 'Welcome to Hell', 'desc': 'یه بازی انجام بده!'},
+ {'name': 'Welcome to the Asylum', 'desc': 'یه بازی به حالت آشوب انجام بده!'},
+ {'name': "Alzheimer's Patient", 'desc': 'یه بازی به حالت فراموشی انجام بده'},
+ {'name': 'O HAI DER!', 'desc': 'یه بازی با اکانت مخفی para انجام بده!)'},
+ {'name': 'Spy vs Spy', 'desc': 'یه بازی به حالت مخفی انجام بده! (نقش مخفی)'},
+ {'name': "I Have No Idea What I'm Doing", 'desc': 'یه بازی با حالت مخفی به زبان فراموشی انجام بده!'},
+ {'name': 'Enochlophobia', 'desc': 'تو یه بازی ۳۵ نفره شرکت کن'},
+ {'name': 'Introvert', 'desc': 'تو یه بازی ۵ نفره شرکت کن!'},
+ {'name': 'Naughty!', 'desc': 'یه بازی به زبان بی ادبی انجام بده!'},
+ {'name': 'Dedicated', 'desc': '۱۰۰ تا بازی انجام بده!'},
+ {'name': 'Obsessed', 'desc': '۱۰۰۰ تا بازی انجام بده!'},
+ {'name': 'Masochist', 'desc': 'منافق باشی و اعدامت کنن!'},
+ {'name': 'Wobble Wobble', 'desc': 'مست باشی و تو یه بازی حداقل ۱۰ نفره تا اخر بازی زنده بمونی!'},
+ {'name': 'Inconspicuous', 'desc': 'تو یه بازی حداقل ۲۰ نفره هیچ رایی برای اعدام بهت ندن و تا آخر بازی زنده بمونی'},
+ {'name': 'Survivalist', 'desc': '۱۰۰ تا بازی زنده بمونی'},
+ {'name': 'Promiscuous', 'desc': 'فاحشه باشی و ۵ شب بدون وقفه خونه نمونی بدون اینکه خونه کسی دو بار بری و زنده بمونی!'},
+ {'name': 'Mason Brother', 'desc': 'یکی از ۲ فراماسون زنده مونده تو بازی باشی!'},
+ {'name': 'Double Shifter', 'desc': 'دو بار تو یه بازی نقش عوض کنی (فرقه شدن حساب نیست)'},
+ {'name': 'Hey Man, Nice Shot', 'desc': 'کلانتر باشی و تیر قبل مرگت رو به گرگ یا قاتل بزنی!'},
+ {'name': "That's Why You Don't Stay Home", 'desc': 'به عنوان گرگ یا فرقه فاحشه رو بخوری یا تبدیل کنی وقتی که خونه مونده و جایی نرفته!'},
+ {'name': 'Double Vision', 'desc': 'شیکی از دو پیشگوی همزمان تو بازی باشی'},
+ {'name': 'Double Kill', 'desc': 'قاتل و کلانتر آخر بازی تنها بمونن و کسی برنده نشه تو بازی'},
+ {'name': 'Should Have Known', 'desc': 'به عنوان پیشگو ناظر رو استعلام کنی شب اول!'},
+ {'name': 'I See a Lack of Trust', 'desc': 'پیشگو باشی و شب اول اعدامت کنن!'},
+ {'name': 'Sunday Bloody Sunday', 'desc': 'یکی از چهار نفری باشی که تو یه شب میمیرند!'},
+ {'name': 'Change Sides Works', 'desc': 'تو بازی نقش عوض کنی و بازیو ببری!'},
+ {'name': 'Forbidden Love', 'desc': 'گرگ باشی یا روستای ساده و بازی رو عاشقانه ببرید!'},
+ {'name': 'The First Stone', 'desc': 'تو یه بازی ۵ شب اولین نفر رای بدی!'},
+ {'name': 'Smart Gunner', 'desc': 'به عنوان تفنگدار هر دوتا تیرت رو به گرگ، قاتل یا فرقه بزنی!'},
+ {'name': 'Streetwise', 'desc': 'کارآگاه باشی و ۴ شب گرگ، قاتل یا فرقه بدون تکرار و پشت هم استعلام کنی!'},
+ {'name': 'Speed Dating', 'desc': 'ربات تو رو به عنوان عاشق انتخاب کنه'},
+ {'name': 'Even a Stopped Clock is Right Twice a Day','desc': 'احمق باشی و حداقل دوتا استعلام درست تا آخر بازی داشته باشی!'},
+ {'name': 'So Close!', 'desc': 'منافق باشی و رای اعدامت مساوی شه'},
+ {'name': 'Cultist Convention', 'desc': 'یکی از ده تا فرقه زنده در بازی باشی !'},
+ {'name': 'Self Loving', 'desc': 'الهه باشی و خودت رو عاشق کنی!'},
+ {'name': "Should've Said Something", 'desc': 'گرگ باشی و لاورت رو بخوری (شب اول حساب نیست)'},
+ {'name': 'Tanner Overkill', 'desc': 'منافق باشی و همه بهت رای بدن'},
+ {'name': 'Serial Samaritan', 'desc': 'قاتل باشی و سه تا گرگ تو یه بازی بکشی!'},
+ {'name': 'Cultist Fodder', 'desc': 'فرقه باشی و شکار دعوت بدی!'},
+ {'name': 'Lone Wolf', 'desc': 'تو یه بازی آشوب که ده نفره یا بیشتر هست تک گرگ باشی و بازی رو ببری'},
+ {'name': 'Pack Hunter', 'desc': 'یکی از ۷ تا گرگ زنده تو بازی باشی!'},
+ {'name': 'Saved by the Bull(et)', 'desc': 'تعداد گرگ و روستا برابر باشه و به خاطر گلوله داشتن تفنگدار زنده بازی تموم نشه!'},
+ {'name': 'In for the Long Haul', 'desc': 'تو یه بازی یک ساعته زنده بمونی'},
+ {'name': 'OH SHI-', 'desc': 'لاورت رو شب اول بکشی!'},
+ {'name': 'Veteran', 'desc': '۵۰۰ تا بازی داشته باشی!'},
+ {'name': 'No Sorcery!', 'desc': 'گرگ باشی و جادو رو بکشی'},
+ {'name': 'Cultist Tracker', 'desc': 'شکار باشی و تو یه بازی سه تا فرقه شکار کنی!'},
+ {'name': "I'M NOT DRUN-- *BURPPP*", 'desc': 'به عنوان پسر گیج سه تا رای درست تو یه بازی بدی!'},
+ {'name': 'Wuffie-Cult', 'desc': 'گرگ آلفا باشی و سه تا تبدیل تو یه بازی داشته باشی!'},
+ {'name': 'Did you guard yourself?', 'desc': 'به عنوان فرشته سه شب از گرگ ها محافظت کنی و زنده بمونی!'},
+ {'name': 'Spoiled Rich Brat', 'desc': 'شاهزاده باشی و دو شب اعدامت کنن!'},
+ {'name': 'Three Little Wolves and a Big Bad Pig', 'desc': 'به عنوان جادو تو یه بازی با سه تا گرگ یا بیشتر زنده بمونی!'},
+ {'name': 'President', 'desc': 'به عنوان کدخدا بتونی سه تا رای بعد از نشون دادن مهرت بدی!'},
+ {'name': 'I Helped!', 'desc': 'توله گرگ باشی و گرگ ها بعد مردنت دو نفر رو بکشن!'},
+ {'name': 'It Was a Busy Night!', 'desc': 'تو یه شب سه نفر یا بیشتر بیان خونت!'},
+ {'name': 'Strongest Alpha', 'desc': 'آلفا باشی و قاتل رو تبدیل کنی!'},
+ {'name': 'Am I Your Seer?', 'desc': 'احمق باشی و ناظر رو درست استعلام کنی!'},
+ {'name': 'Demoted by the Death', 'desc': 'کلانتر باشی و تیر قبل مرگت رو به ریش سفید بزنی و روستایی ساده بمیری!'},
+ {'name': 'Wasted Silver', 'desc': 'آهنگر باشی و وقتی تو هوا نقره پخش کردی همزمان خواب هم ورد بخونه و نقره هات به چیز بره!'},
+ {'name': 'Trustworthy!', 'desc': 'گرگ نما باشی و پیشگو استعلامت کنه و تو بازی زنده بمونی!'},
+ {'name': 'Deep Love', 'desc': 'همزاد لاورت باشی!'},
+ {'name': 'Time to retire...', 'desc': 'جادوگر باشی و تنها بازمانده روستا!'},
+ {'name': 'Seeing between Teams', 'desc': 'جادوگر باشی و لاورت پیشگو باشه یا برعکس!'},
+ {'name': 'Just a Beardy Guy..?', 'desc': 'گرگنما باشی و گرگ آلفا تبدیل به یه گرگ واقعیت کنه!!'},
+ {'name': 'That Came Unexpected!', 'desc': 'منافق باشی و بهت رای بدن و ببری وقتی فقط سه نفر تو بازی موندن!'},
+ {'name': "Now I'm Blind", 'desc': 'نگاتیو باشی و در جواب استعلامت نقش دیگه ای نمونده باشه بهت بگه!'},
+ {'name': 'Every Man for Himself!', 'desc': 'صلح گرا باشی و جون خودت رو نجات بدی وقتی حداقل نصف افراد بهت رای داده باشن!'},
+ {'name': 'My Sweetie so Strong!', 'desc': 'عاشق صلح باشی و وقتی بهت رای دادن جونت رو نجات بده!'},
+ {'name': 'Cult Leader', 'desc': 'پدر فرقه باشی و تا آخر بازی زنده بمونی و بازی رو ببری!'},
+ {'name': 'Thanks, Junior!', 'desc': 'وقتی گرگ ها مست رو خوردن تو به یه گرگ تبدیل بشی و بتونی کسیو بخوری درحالیکه بقیه گرگ ها مست هستن!'},
+ {'name': 'Death Village', 'desc': 'تو بازی ای باشی که هیچکس برنده نشه!'},
+ {'name': 'I Lost my Wisdom', 'desc': 'ریش سفید باشی و نقشت عوض بشه!'},
+ {'name': 'Affectionate', 'desc': 'فاحشه باشی و بری خونه ی عشقت!'},
+ {'name': 'Lucky Day', 'desc': 'آلفا باشی و مست رو تبدیل کنی!'},
+ {'name': 'Condition Red!', 'desc': 'آخرین گرگ زنده باشی و خائن رو بخوری!'},
+ {'name': 'Indestructible', 'desc': 'به عنوان همزاد یا بچه وحشی خودت الگوی خودت باشی!'},
+ {'name': 'Psychopath Killer', 'desc': 'قاتل باشی و در یک بازی 35 نفره برنده بشی!'},
+ {'name': "Today's Special!", 'desc': 'نقشی داشته باشید که فقط در رویدادهای ویژه وجود داره!'},
+ {'name': 'Romeo and Juliet', 'desc': 'عاشق منافق باشی و با اعدام شدن عشقت دوتایی برنده بشید!'},
+ {'name': 'Really bad luck', 'desc': 'قاتل باشی و توی قبر بیفتی و بعد به طور تصادفی سعی کنی فردی رو بکشی که فرشته ازش محافظت میکنه!'},
+ {'name': 'Domino', 'desc': 'به عنوان کلانتر به يک کلانتر ديگه شليک کنی!'},
+ {'name': 'Double Shot', 'desc': 'به عنوان کلانتر یا تفنگدار به یک نقش منفی شلیک کنی که لاور یک نقش منفی دیگه باشه!'},
+ {'name': 'Playing with the Fire', 'desc': 'به عنوان آتش زن توی یک شب 5 خونه رو بسوزونی!'},
+ {'name': 'Firework', 'desc': 'به عنوان آتش زن توی یک شب 10 خونه رو بسوزونی!'},
+ {'name': 'Cold as Ice', 'desc': 'به عنوان گرگ برفی فاحشه رو فریز کنی!'},
+ {'name': 'Good Choice... For You', 'desc': 'به عنوان شیمیدان تو یک بازی 3 بار سم بدی و زنده بمونی!'},
+ {'name': 'Increase the Pack!', 'desc': 'آلفا باشی و بعد مرگ توله گرگ دو نفر رو تبدیل کنی!'},
+ {'name': "Here's Johnny!", 'desc': 'قاتل باشی و ۵۰ نفر رو بکشی!', "not_via_playing": True},
+ {'name': "I've Got Your Back", 'desc': 'فرشته نگهبان باشی و جون ۵۰ نفر رو نجات بدی!', "not_via_playing": True},
+ {'name': 'Developer', 'desc': 'Have a pull request merged into the repo', "not_via_playing": True},
+ {'name': 'Explorer', 'desc': 'حداقل دوتا بازی تو ده تا گروه مختلف انجام بده!', "inactive": True},
+ {'name': 'Linguist', 'desc': 'حداقل دوتا بازی تو ده تا زبان مختلف انجام بده!', "inactive": True},
+ {'name': 'Black Sheep', 'desc': 'سه بازی پیاپی نفر اول اعدام بشی', "inactive": True}]
+}
diff --git a/main.py b/main.py
index a73e66d..e75c47f 100644
--- a/main.py
+++ b/main.py
@@ -39,39 +39,53 @@ def get_achievement_count(user_id):
r = requests.get(wuff_url.format(user_id)).json()
return len(r)
+
def get_kills(user_id):
wuff_url = "http://www.tgwerewolf.com/Stats/PlayerKills/?pid={}&json=true"
kills = requests.get(wuff_url.format(user_id)).json()
return kills
+
def get_killed_by(user_id):
wuff_url = "http://www.tgwerewolf.com/Stats/PlayerKilledBy/?pid={}&json=true"
killedby = requests.get(wuff_url.format(user_id)).json()
return killedby
+
def get_deaths(user_id):
wuff_url = "http://www.tgwerewolf.com/Stats/PlayerDeaths/?pid={}&json=true"
deaths = requests.get(wuff_url.format(user_id)).json()
return deaths
+
def get_achievements(user_id):
wuff_url = "http://www.tgwerewolf.com/Stats/PlayerAchievements/?pid={}&json=true"
r = requests.get(wuff_url.format(user_id)).json()
return r
+
@run_async
-def display_kills(bot, update):
+def display_kills(bot, update, args):
chat_id = update.message.chat_id
if update.message.reply_to_message is not None:
user_id = update.message.reply_to_message.from_user.id
name = update.message.reply_to_message.from_user.first_name
- name = html.escape(name)
else:
- user_id = update.message.from_user.id
- name = update.message.from_user.first_name
- name = html.escape(name)
+ if args:
+ try:
+ user_id = int(args[0])
+ name = args[0]
+ except:
+ user_id = update.message.from_user.id
+ name = update.message.from_user.first_name
+ else:
+ user_id = update.message.from_user.id
+ name = update.message.from_user.first_name
+ name = html.escape(name)
+
- print("%s - %s (%d) - kills" % (str(datetime.datetime.now()+datetime.timedelta(hours=8)), unidecode(name), user_id))
+ print(
+ "%s - %s (%d) - kills" % (str(datetime.datetime.now() + datetime.timedelta(hours=8)), unidecode(name), user_id))
kills = get_kills(user_id)
@@ -82,19 +96,28 @@ def display_kills(bot, update):
bot.sendMessage(chat_id, msg, parse_mode="HTML", disable_web_page_preview=True)
+
@run_async
-def display_killed_by(bot, update):
+def display_killed_by(bot, update, args):
chat_id = update.message.chat_id
if update.message.reply_to_message is not None:
user_id = update.message.reply_to_message.from_user.id
name = update.message.reply_to_message.from_user.first_name
- name = html.escape(name)
else:
- user_id = update.message.from_user.id
- name = update.message.from_user.first_name
- name = html.escape(name)
+ if args:
+ try:
+ user_id = int(args[0])
+ name = args[0]
+ except:
+ user_id = update.message.from_user.id
+ name = update.message.from_user.first_name
+ else:
+ user_id = update.message.from_user.id
+ name = update.message.from_user.first_name
+ name = html.escape(name)
- print("%s - %s (%d) - killed by" % (str(datetime.datetime.now()+datetime.timedelta(hours=8)), unidecode(name), user_id))
+ print("%s - %s (%d) - killed by" % (
+ str(datetime.datetime.now() + datetime.timedelta(hours=8)), unidecode(name), user_id))
killedby = get_killed_by(user_id)
@@ -105,19 +128,29 @@ def display_killed_by(bot, update):
bot.sendMessage(chat_id, msg, parse_mode="HTML", disable_web_page_preview=True)
+
@run_async
-def display_deaths(bot, update):
+def display_deaths(bot, update, args):
chat_id = update.message.chat_id
if update.message.reply_to_message is not None:
user_id = update.message.reply_to_message.from_user.id
name = update.message.reply_to_message.from_user.first_name
- name = html.escape(name)
else:
- user_id = update.message.from_user.id
- name = update.message.from_user.first_name
- name = html.escape(name)
+ if args:
+ try:
+ user_id = int(args[0])
+ name = args[0]
+ except:
+ user_id = update.message.from_user.id
+ name = update.message.from_user.first_name
+ else:
+ user_id = update.message.from_user.id
+ name = update.message.from_user.first_name
+ name = html.escape(name)
+
- print("%s - %s (%d) - deaths" % (str(datetime.datetime.now()+datetime.timedelta(hours=8)), unidecode(name), user_id))
+ print("%s - %s (%d) - deaths" % (
+ str(datetime.datetime.now() + datetime.timedelta(hours=8)), unidecode(name), user_id))
deaths = get_deaths(user_id)
stats = get_stats(user_id)
@@ -125,16 +158,18 @@ def display_deaths(bot, update):
msg = "Types of deaths that {} most had:\n".format(user_id, name)
for n in range(len(deaths)):
-
""" The total of deaths for each kill method is calculated based on the percentage
gave by the JSON data. Because of that, the calculated value is not totally accurate."""
- totalMethod = ((stats['gamesPlayed']-stats['survived']['total'])*float(deaths[n]['percent'])/100)
- msg += "{}% {} (approx. {})\n".format(deaths[n]['percent'],deaths[n]['method'],round(totalMethod))
+ totalMethod = ((stats['gamesPlayed'] - stats['survived']['total']) * float(deaths[n]['percent']) / 100)
+ msg += "{}% {} (approx. {})\n".format(deaths[n]['percent'],
+ deaths[n]['method'],
+ round(totalMethod))
"""msg += "({}%) {}\n".format(deaths[n]['percent'],deaths[n]['method'])"""
bot.sendMessage(chat_id, msg, parse_mode="HTML", disable_web_page_preview=True)
+
@run_async
def display_search(bot, update, args):
chat_id = update.message.chat_id
@@ -147,7 +182,8 @@ def display_search(bot, update, args):
name = update.message.from_user.first_name
name = html.escape(name)
- print("%s - %s (%d) - search %s" % (str(datetime.datetime.now()+datetime.timedelta(hours=8)), unidecode(name), user_id, args))
+ print("%s - %s (%d) - search %s" % (
+ str(datetime.datetime.now() + datetime.timedelta(hours=8)), unidecode(name), user_id, args))
if len(args) == 0:
msg = "Invalid parameter! Syntax:\n/search [achievement_to_search]\n"
@@ -161,9 +197,9 @@ def display_search(bot, update, args):
for n in range(len(achv_name.split())):
for word in range(len(args)):
- if achv_name.split()[n].lower().startswith(args[word].lower()):
+ if achv_name.split()[n].lower().startswith(args[word].lower()):
msg += "{}\n".format(achv_name)
- found_counter+=1
+ found_counter += 1
break
if found_counter == 0:
@@ -171,6 +207,7 @@ def display_search(bot, update, args):
bot.sendMessage(chat_id, msg, parse_mode="HTML", disable_web_page_preview=True)
+
@run_async
def display_stats(bot, update, args):
by_id = False
@@ -194,16 +231,20 @@ def display_stats(bot, update, args):
name = update.message.from_user.first_name
name = html.escape(name)
- print("%s - %s (%d) - stats" % (str(datetime.datetime.now()+datetime.timedelta(hours=8)), unidecode(name), user_id))
+ print(
+ "%s - %s (%d) - stats" % (str(datetime.datetime.now() + datetime.timedelta(hours=8)), unidecode(name), user_id))
stats = get_stats(user_id)
achievements = get_achievement_count(user_id)
if stats:
- msg = "{} the {}\n".format(user_id, name, stats['mostCommonRole']) if not by_id else "{} the {}\n".format(name, stats['mostCommonRole'])
+ msg = "{} the {}\n".format(user_id, name, stats[
+ 'mostCommonRole']) if not by_id else "{} the {}\n".format(name, stats['mostCommonRole'])
msg += "{:<5} Achievements Unlocked!\n".format(achievements)
- msg += "{:<5} Games Won ({}%)\n".format(stats['won']['total'], stats['won']['percent'])
- msg += "{:<5} Games Lost ({}%)\n".format(stats['lost']['total'], stats['lost']['percent'])
+ msg += "{:<5} Games Won ({}%)\n".format(stats['won']['total'],
+ stats['won']['percent'])
+ msg += "{:<5} Games Lost ({}%)\n".format(stats['lost']['total'],
+ stats['lost']['percent'])
msg += "{:<5} Games Survived ({}%)\n".format(
stats['survived']['total'], stats['survived']['percent'])
msg += "{:<5} Total Games\n".format(stats['gamesPlayed'])
@@ -214,10 +255,13 @@ def display_stats(bot, update, args):
msg += "{:<5} times I've been slaughted by {}\n\n".format(
stats['mostKilledBy']['times'], html.escape(stats['mostKilledBy']['name']))
else:
- msg = "{} has not played any games.".format(user_id, name) if not by_id else "{} has not played any games.".format(name)
+ msg = "{} has not played any games.".format(user_id,
+ name) if not by_id else "{} has not played any games.".format(
+ name)
bot.sendMessage(chat_id, msg, parse_mode="HTML", disable_web_page_preview=True)
+
def display_about(bot, update):
chat_id = update.message.chat_id
msg = "Use /stats for stats. Use /achievements or /achv for achivement list."
@@ -234,19 +278,22 @@ def startme(bot, update):
else:
return
+
@run_async
def display_achv(bot, update):
user_id = update.message.from_user.id
name = update.message.from_user.first_name
+ lang = update.message.from_user.language_code
name = html.escape(name)
- print("%s - %s (%d) - achv" % (str(datetime.datetime.now()+datetime.timedelta(hours=8)), unidecode(name), user_id))
+ print(
+ "%s - %s (%d) - achv" % (str(datetime.datetime.now() + datetime.timedelta(hours=8)), unidecode(name), user_id))
- msgs = wwstats.check(user_id)
+ msgs = wwstats.check(user_id, lang)
try:
for msg in msgs:
- bot.sendMessage(chat_id = user_id, text=msg, parse_mode='Markdown')
+ bot.sendMessage(chat_id=user_id, text=msg, parse_mode='Markdown')
if update.message.chat.type != 'private':
update.message.reply_text("I have sent you your achievement list in PM.")
except:
@@ -272,9 +319,9 @@ def main():
d.add_handler(CommandHandler('start', startme))
d.add_handler(CommandHandler('stats', display_stats, pass_args=True))
- d.add_handler(CommandHandler('kills', display_kills))
- d.add_handler(CommandHandler('killedby', display_killed_by))
- d.add_handler(CommandHandler('deaths', display_deaths))
+ d.add_handler(CommandHandler('kills', display_kills, pass_args=True))
+ d.add_handler(CommandHandler('killedby', display_killed_by, pass_args=True))
+ d.add_handler(CommandHandler('deaths', display_deaths, pass_args=True))
d.add_handler(CommandHandler(['search', 'sch'], display_search, pass_args=True))
d.add_handler(CommandHandler('about', display_about))
d.add_handler(CommandHandler(['achievements', 'achv'], display_achv))
diff --git a/wwstats.py b/wwstats.py
index 92ea58c..89c0520 100644
--- a/wwstats.py
+++ b/wwstats.py
@@ -1,8 +1,9 @@
import requests
from achvlist import ACHV
-achv_names = [y['name'] for y in ACHV]
-total = len(ACHV)
+langs = ACHV.keys()
+total = len(ACHV['en'])
+achv_names = {lang : [y['name'] for y in ACHV[lang]] for lang in langs}
def chunks(l, n):
@@ -11,26 +12,27 @@ def chunks(l, n):
yield l[i:i + n]
-def check(userid):
+def check(userid, lang):
+ lang = 'en' if lang not in langs else lang
url = "http://tgwerewolf.com/stats/PlayerAchievements/?pid={}&json=true".format(userid)
stats = requests.get(url).json()
attained_count = len(stats)
attained_names = [each['name'] for each in stats]
- not_via_playing = [z for z in ACHV if z['name'] not in attained_names and "not_via_playing" in z]
- inactive = [z for z in ACHV if z['name'] not in attained_names and "inactive" in z]
- missing = [z for z in ACHV if z['name'] not in attained_names and not ("inactive" in z or "not_via_playing" in z)]
-
+ not_via_playing = [z for z in ACHV[lang] if z['name'] not in attained_names and "not_via_playing" in z]
+ inactive = [z for z in ACHV[lang] if z not in attained_names and "inactive" in z]
+ missing = [z for z in ACHV[lang] if z not in attained_names and not ("inactive" in z or "not_via_playing" in z)]
+
msgs = []
header = "*ATTAINED ({0}/{1}):*\n".format(attained_count, total)
msg = ""
-
+
for each in stats:
- if each['name'] in achv_names:
+ if each['name'] in achv_names['en']:
msg += "- {}\n".format(each['name'])
-
+
msg = header + "```" + msg + "```"
msgs.append(msg)
-
+
main = "*MISSING ({0}/{1}):*\n".format(total - attained_count , total)
missing_header = "*MISSING AND ATTAINABLE VIA PLAYING ({0}/{1}):*\n\n".format(len(missing) , total)
missing_msgs = []
@@ -42,7 +44,7 @@ def check(userid):
msg = main + missing_header
msg += "".join(each)
msgs.append(msg)
-
+
not_via_playing_header = "*NOT DIRECTLY ATTAINABLE VIA PLAYING ({0}/{1}):*\n\n".format(len(not_via_playing) , total)
not_via_playing_msgs = []
for z in not_via_playing:
@@ -53,7 +55,7 @@ def check(userid):
msg = main + not_via_playing_header
msg += "".join(each)
msgs.append(msg)
-
+
inactive_header = "*INACTIVE ({0}/{1}):*\n\n".format(len(inactive) , total)
inactive_msgs = []
for z in inactive:
@@ -64,5 +66,5 @@ def check(userid):
msg = main + inactive_header
msg += "".join(each)
msgs.append(msg)
-
+
return msgs