diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index bd43dce5..4fbf9c77 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -128,6 +128,15 @@ AiPlayerbot.AllowPlayerBots = 0 # Allow/deny bots from your guild AiPlayerbot.AllowGuildBots = 1 +# Randombots will invite nearby bots to guilds +AiPlayerbot.RandomBotGuildNearby = 0 + +# Randombots will invite players to groups/raids/guilds. +AiPlayerbot.RandomBotInvitePlayer = 0 + +# Bots will chat in say/guild when they invite other bots to groups/raids/guilds +AiPlayerbot.InviteChat = 0 + # Bots will be summoned to player when accept group invitation AiPlayerbot.SummonWhenGroup = 1 @@ -458,9 +467,6 @@ AiPlayerbot.SyncLevelWithPlayers = 0 # Mark many quests <= Bot level as complete (slows down bot creation) AiPlayerbot.PreQuests = 0 -# Bots without a master will say their lines -AiPlayerbot.RandomBotSayWithoutMaster = 0 - # Enable LFG for random bots AiPlayerbot.RandomBotJoinLfg = 1 @@ -1266,27 +1272,107 @@ AiPlayerbot.CommandPrefix = "" # Separator for bot chat commands AiPlayerbot.CommandSeparator = "\\\\" -# Enable playerbot to talk in guild -AiPlayerbot.RandomBotGuildTalk = 1 - # Enable playerbot talk (say / yell / general chatting / lfg) AiPlayerbot.RandomBotTalk = 0 - # Enable playerbot emote AiPlayerbot.RandomBotEmote = 0 - # Enable dungeon suggestions for random bots AiPlayerbot.RandomBotSuggestDungeons = 1 - # Bots greet to the players AiPlayerbot.EnableGreet = 0 - +# Chance to reply to toxic links with toxic links (0-100) +AiPlayerbot.ToxicLinksRepliesChance = 30 +# Chance to reply to thunderfury with thunderfury (0-100) +AiPlayerbot.ThunderfuryRepliesChance = 40 +# Bots will chat in guild about certain events (int) (0-100) +AiPlayerbot.GuildRepliesRate = 100 +# Bots will chat in guild about certain events +AIPlayerbot.GuildFeedback = 1 +# Bots without a master will say their lines +AiPlayerbot.RandomBotSayWithoutMaster = 0 # # # #################################################################################################### +#################################################################################################### +# +# Broadcast rates +# +# 1 - to enable broadcasts globally, 0 - to disable (default 1) +# AiPlayerbot.EnableBroadcasts = 1 +# +# all broadcast chances should be in range 0-30000 +# +# value of 0 will disable this particular broadcast +# setting value to 30000 does not guarantee the broadcast, as there are some internal randoms as well +# +# setting channel broadcast chance to 0, will re-route most broadcasts to other available channels +# setting all channel broadcasts to 0 will disable most broadcasts +# AiPlayerbot.BroadcastToGuildGlobalChance = 30000 +# AiPlayerbot.BroadcastToWorldGlobalChance = 30000 +# AiPlayerbot.BroadcastToGeneralGlobalChance = 30000 +# AiPlayerbot.BroadcastToTradeGlobalChance = 30000 +# AiPlayerbot.BroadcastToLFGGlobalChance = 30000 +# AiPlayerbot.BroadcastToLocalDefenseGlobalChance = 30000 +# AiPlayerbot.BroadcastToWorldDefenseGlobalChance = 30000 +# AiPlayerbot.BroadcastToGuildRecruitmentGlobalChance = 30000 +# +# individual settings +# setting one of these to 0 will disable the particular broadcast +# AiPlayerbot.BroadcastChanceLootingItemPoor = 30 +# AiPlayerbot.BroadcastChanceLootingItemNormal = 150 +# AiPlayerbot.BroadcastChanceLootingItemUncommon = 10000 +# AiPlayerbot.BroadcastChanceLootingItemRare = 20000 +# AiPlayerbot.BroadcastChanceLootingItemEpic = 30000 +# AiPlayerbot.BroadcastChanceLootingItemLegendary = 30000 +# AiPlayerbot.BroadcastChanceLootingItemArtifact = 30000 +# +# AiPlayerbot.BroadcastChanceQuestAccepted = 6000 +# AiPlayerbot.BroadcastChanceQuestUpdateObjectiveCompleted = 300 +# AiPlayerbot.BroadcastChanceQuestUpdateObjectiveProgress = 300 +# AiPlayerbot.BroadcastChanceQuestUpdateFailedTimer = 300 +# AiPlayerbot.BroadcastChanceQuestUpdateComplete = 1000 +# AiPlayerbot.BroadcastChanceQuestTurnedIn = 10000 +# +# AiPlayerbot.BroadcastChanceKillNormal = 30 +# AiPlayerbot.BroadcastChanceKillElite = 300 +# AiPlayerbot.BroadcastChanceKillRareelite = 3000 +# AiPlayerbot.BroadcastChanceKillWorldboss = 20000 +# AiPlayerbot.BroadcastChanceKillRare = 10000 +# AiPlayerbot.BroadcastChanceKillUnknown = 100 +# AiPlayerbot.BroadcastChanceKillPet = 10 +# AiPlayerbot.BroadcastChanceKillPlayer = 30 +# +# AiPlayerbot.BroadcastChanceLevelupGeneric = 20000 +# AiPlayerbot.BroadcastChanceLevelupTenX = 30000 +# AiPlayerbot.BroadcastChanceLevelupMaxLevel = 30000 +# +# AiPlayerbot.BroadcastChanceSuggestInstance = 5000 +# AiPlayerbot.BroadcastChanceSuggestQuest = 10000 +# AiPlayerbot.BroadcastChanceSuggestGrindMaterials = 5000 +# AiPlayerbot.BroadcastChanceSuggestGrindReputation = 5000 +# AiPlayerbot.BroadcastChanceSuggestSell = 300 +# AiPlayerbot.BroadcastChanceSuggestSomething = 30000 +# +# Very rude speeches +# AiPlayerbot.BroadcastChanceSuggestSomethingToxic = 0 +# +# Specifically for " [item link]" +# AiPlayerbot.BroadcastChanceSuggestToxicLinks = 0 +# +# prefix is used as a word in " [item link]" +# AiPlayerbot.ToxicLinksPrefix = gnomes +# +# chance to suggest thunderfury +# AiPlayerbot.BroadcastChanceSuggestThunderfury = 1 +# +# does not depend on global chance +# AiPlayerbot.BroadcastChanceGuildManagement = 30000 +# +#################################################################################################### + #################################################################################################### # LOGS # diff --git a/sql/playerbots/base/playerbots_text.sql b/sql/playerbots/base/playerbots_text.sql index e4a3c6bf..881e4671 100644 --- a/sql/playerbots/base/playerbots_text.sql +++ b/sql/playerbots/base/playerbots_text.sql @@ -5,556 +5,1458 @@ CREATE TABLE IF NOT EXISTS `ai_playerbot_texts` ( `text` varchar(1024) NOT NULL COMMENT 'text', `say_type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '0 - say, 1 - yell', `reply_type` tinyint(3) NOT NULL DEFAULT '0' COMMENT 'if > 0 then can be filtered as a response to chat', - `text_loc1` varchar(1024) NOT NULL, - `text_loc2` varchar(1024) NOT NULL, - `text_loc3` varchar(1024) NOT NULL, - `text_loc4` varchar(1024) NOT NULL, - `text_loc5` varchar(1024) NOT NULL, - `text_loc6` varchar(1024) NOT NULL, - `text_loc7` varchar(1024) NOT NULL, - `text_loc8` varchar(1024) NOT NULL, + `text_loc1` varchar(1024) NOT NULL DEFAULT '', + `text_loc2` varchar(1024) NOT NULL DEFAULT '', + `text_loc3` varchar(1024) NOT NULL DEFAULT '', + `text_loc4` varchar(1024) NOT NULL DEFAULT '', + `text_loc5` varchar(1024) NOT NULL DEFAULT '', + `text_loc6` varchar(1024) NOT NULL DEFAULT '', + `text_loc7` varchar(1024) NOT NULL DEFAULT '', + `text_loc8` varchar(1024) NOT NULL DEFAULT '', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=537 DEFAULT CHARSET=UTF8; +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; -/*!40000 ALTER TABLE `ai_playerbot_texts` DISABLE KEYS */; -INSERT INTO `ai_playerbot_texts` (`id`, `name`, `text`, `say_type`, `reply_type`, `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) VALUES - (1, 'suggest_instance', 'Anyone wants %instance?', 0, 0, '', 'Quelqu\'un fait %instance ?', '', '', '', '', '', ''), - (2, 'suggest_instance', 'Any groups for %instance?', 0, 0, '', 'Des groupes pour %instance ?', '', '', '', '', '', ''), - (3, 'suggest_instance', 'Need help for %instance?', 0, 0, '', 'Besoin d\'aide pour %instance ?', '', '', '', '', '', ''), - (4, 'suggest_instance', 'LFD: %instance.', 0, 0, '', 'Cherche à faire : %instance', '', '', '', '', '', ''), - (5, 'suggest_instance', 'Anyone needs %role for %instance?',0, 0, '', 'Quelqu\'un a besoin de %role pour %instance ?', '', '', '', '', '', ''), - (6, 'suggest_instance', 'Missing %role for %instance?', 0, 0, '', '%role manquant pour %instance ?', '', '', '', '', '', ''), - (7, 'suggest_instance', 'Can be a %role for %instance.', 0, 0, '', '%role disponible pour %instance', '', '', '', '', '', ''), - (8, 'suggest_instance', 'Need help with %instance?', 0, 0, '', 'Besoin d\'aide avec %instance ?', '', '', '', '', '', ''), - (9, 'suggest_instance', 'Need %role help with %instance?', 0, 0, '', 'Besoin d\'aide %role avec %instance ?', '', '', '', '', '', ''), - (10, 'suggest_instance', 'Anyone needs gear from %instance?',0, 0, '', 'Quelqu\'un a besoin d\'équipement de %instance ?', '', '', '', '', '', ''), - (11, 'suggest_instance', 'A little grind in %instance?', 0, 0, '', 'Un peu de grind dans %instance ?', '', '', '', '', '', ''), - (12, 'suggest_instance', 'WTR %instance', 0, 0, '', 'Cherche à rejoindre %instance', '', '', '', '', '', ''), - (13, 'suggest_instance', 'Need help for %instance.', 0, 0, '', 'Besoin d\'aide pour %instance', '', '', '', '', '', ''), - (14, 'suggest_instance', 'Wanna run %instance.', 0, 0, '', 'Je veux faire %instance', '', '', '', '', '', ''), - (15, 'suggest_instance', '%role looks for %instance.', 0, 0, '', '%role recherche %instance', '', '', '', '', '', ''), - (16, 'suggest_instance', 'What about %instance?', 0, 0, '', 'Et %instance ?', '', '', '', '', '', ''), - (17, 'suggest_instance', 'Who wants to farm %instance?', 0, 0, '', 'Qui veut exploiter %instance ?', '', '', '', '', '', ''), - (18, 'suggest_instance', 'Go in %instance?', 0, 0, '', 'Aller à %instance ?', '', '', '', '', '', ''), - (19, 'suggest_instance', 'Looking for %instance.', 0, 0, '', 'À la recherche de %instance', '', '', '', '', '', ''), - (20, 'suggest_instance', 'Need help with %instance quests?', 0, 0, '', 'Besoin d\'aide pour les quêtes %instance ?', '', '', '', '', '', ''), - (21, 'suggest_instance', 'Wanna quest in %instance.', 0, 0, '', 'Je veux une quête dans %instance', '', '', '', '', '', ''), - (22, 'suggest_instance', 'Anyone with quests in %instance?', 0, 0, '', 'Quelqu\'un a des quêtes dans %instance ?', '', '', '', '', '', ''), - (23, 'suggest_instance', 'Could help with quests in %instance.', 0, 0, '', 'Peux aider pour les quêtes dans %instance', '', '', '', '', '', ''), - (24, 'suggest_instance', '%role: any place in group for %instance?', 0, 0, '', '%role : n\'importe quel rôle dans le groupe pour %instance ?', '', '', '', '', '', ''), - (25, 'suggest_instance', 'Does anybody still run %instance this days?', 0, 0, '', 'Est-ce que quelqu\'un fait encore %instance ces jours-ci ?', '', '', '', '', '', ''), - (26, 'suggest_instance', '%instance: anyone wants to take a %role?', 0, 0, '', '%instance : quelqu\'un veut prendre un %role ?', '', '', '', '', '', ''), - (27, 'suggest_instance', 'Is there any point being %role in %instance?', 0, 0, '', 'Y a-t-il un intérêt à être %role dans %instance ?', '', '', '', '', '', ''), - (28, 'suggest_instance', 'It is really worth to go to %instance?', 0, 0, '', 'Cela vaut-il vraiment la peine d\'aller dans %instance ?', '', '', '', '', '', ''), - (29, 'suggest_instance', 'Anybody needs more people for %instance?', 0, 0, '', 'Quelqu\'un a besoin de plus de personnes pour %instance ?', '', '', '', '', '', ''), - (30, 'suggest_instance', '%instance bosses drop good gear. Wanna run?', 0, 0, '', 'Les boss %instance drop du bon équipement. Tu veux nous rejoindre ?', '', '', '', '', '', ''), - (31, 'suggest_instance', 'What about %instance?', 0, 0, '', 'Et %instance ?', '', '', '', '', '', ''), - (32, 'suggest_instance', 'Anybody needs %role?', 0, 0, '', 'Quelqu\'un a besoin de %role ?', '', '', '', '', '', ''), - (33, 'suggest_instance', 'Anyone needs %role?', 0, 0, '', 'Quelqu\'un a besoin de %role ?', '', '', '', '', '', ''), - (34, 'suggest_instance', 'Who wants %instance?', 0, 0, '', 'Qui veut %instance ?', '', '', '', '', '', ''), - (35, 'suggest_instance', 'Can anybody summon me at %instance?', 0, 0, '', 'Quelqu\'un peut-il me TP à %instance ?', '', '', '', '', '', ''), - (36, 'suggest_instance', 'Meet me in %instance', 0, 0, '', 'Rencontrez-moi dans %instance', '', '', '', '', '', ''), - (37, 'suggest_instance', 'Wanna quick %instance run', 0, 0, '', 'Je veux faire rapidement %instance', '', '', '', '', '', ''), - (38, 'suggest_instance', 'Wanna full %instance run', 0, 0, '', 'Je veux faire %instance complètement', '', '', '', '', '', ''), - (39, 'suggest_instance', 'How many times were you in %instance?', 0, 0, '', 'Combien de fois avez-vous été dans %instance ?', '', '', '', '', '', ''), - (40, 'suggest_instance', 'Another %instance run?', 0, 0, '', 'Une autre exécution de %instance ?', '', '', '', '', '', ''), - (41, 'suggest_instance', 'Wiped in %instance? Take me instead!', 0, 0, '', 'Effacé dans %instance ? Prends-moi plutôt !', '', '', '', '', '', ''), - (42, 'suggest_instance', 'Take me in %instance please.', 0, 0, '', 'Prenez-moi dans %instance s\'il vous plaît.', '', '', '', '', '', ''), - (43, 'suggest_instance', 'Quick %instance run?', 0, 0, '', 'Faire rapidement %instance ?', '', '', '', '', '', ''), - (44, 'suggest_instance', 'Full %instance run?', 0, 0, '', 'Clean complet dans %instance ?', '', '', '', '', '', ''), - (45, 'suggest_instance', 'Who can take %role to %instance?', 0, 0, '', 'Qui peut prendre %role à %instance ?', '', '', '', '', '', ''), - (46, 'suggest_quest', 'Need help with %quest?', 0, 0, '', 'Besoin d\'aide avec %quest ?', '', '', '', '', '', ''), - (47, 'suggest_quest', 'Anyone wants to share %quest?', 0, 0, '', 'Quelqu\'un veut partager %quest ?', '', '', '', '', '', ''), - (48, 'suggest_quest', 'Anyone doing %quest?', 0, 0, '', 'Quelqu\'un fait %quest ?', '', '', '', '', '', ''), - (49, 'suggest_quest', 'Wanna do %quest.', 0, 0, '', 'Je veux faire %quest', '', '', '', '', '', ''), - (50, 'suggest_trade', 'Anyone to farm %category?', 0, 0, '', 'Quelqu\'un pour farm %category ?', '', '', '', '', '', ''), - (51, 'suggest_trade', 'Looking for help farming %category.', 0, 0, '', 'Vous cherchez de l\'aide pour farmer %category', '', '', '', '', '', ''), - (52, 'suggest_trade', 'Damn %category are so expensive!', 0, 0, '', 'Putain %category sont si chers!', '', '', '', '', '', ''), - (53, 'suggest_trade', 'Wanna %category.', 0, 0, '', 'Je veux %category', '', '', '', '', '', ''), - (54, 'suggest_trade', 'Need help with %category.', 0, 0, '', 'Besoin d\'aide avec %category', '', '', '', '', '', ''), - (55, 'suggest_trade', 'WTB %category.', 0, 0, '', 'Cherche à acheter %category', '', '', '', '', '', ''), - (56, 'suggest_trade', 'Anyone interested in %category?', 0, 0, '', 'Quiconque est intéressé par %category?', '', '', '', '', '', ''), - (57, 'suggest_trade', 'WTS %category.', 0, 0, '', 'Cherche à vendre %category', '', '', '', '', '', ''), - (58, 'suggest_trade', 'I am selling %category cheaper than AH.', 0, 0, '', 'Je vends %category moins cher que l\'hôtel des ventes.', '', '', '', '', '', ''), - (59, 'suggest_trade', 'Who wants to farm %category?', 0, 0, '', 'Qui veut farmer %category ?', '', '', '', '', '', ''), - (60, 'suggest_trade', 'Wanna farm %category.', 0, 0, '', 'Je veux farmer %category', '', '', '', '', '', ''), - (61, 'suggest_trade', 'Looking for party after %category.', 0, 0, '', 'Recherche de partie après %category', '', '', '', '', '', ''), - (62, 'suggest_trade', 'Any %category are appreciated.', 0, 0, '', 'Toute %category est appréciée.', '', '', '', '', '', ''), - (63, 'suggest_trade', 'Buying anything of %category.', 0, 0, '', 'Acheter quoi que ce soit de %category', '', '', '', '', '', ''), - (64, 'suggest_trade', 'Wow, anybody is farming %category!', 0, 0, '', 'Wow, quelqu\'un farm %category !', '', '', '', '', '', ''), - (65, 'suggest_trade', '%category are selling mad in the AH.', 0, 0, '', '%category se vendent follement dans l\'hôtel des ventes.', '', '', '', '', '', ''), - (66, 'suggest_trade', 'AH is hot for %category.', 0, 0, '', 'Hôtel des ventes est chaud pour %category', '', '', '', '', '', ''), - (67, 'suggest_trade', '%category are on the market.', 0, 0, '', '%category sont sur le marché.', '', '', '', '', '', ''), - (68, 'suggest_trade', 'Wanna trade some %category.', 0, 0, '', 'Je veux échanger une %category', '', '', '', '', '', ''), - (69, 'suggest_trade', 'Need more %category.', 0, 0, '', 'Besoin de plus de %category', '', '', '', '', '', ''), - (70, 'suggest_trade', 'Anybody can spare some %category?', 0, 0, '', 'Quelqu\'un peut-il épargner une %category ?', '', '', '', '', '', ''), - (71, 'suggest_trade', 'Who wants %category?', 0, 0, '', 'Qui veut %category ?', '', '', '', '', '', ''), - (72, 'suggest_trade', 'Some %category please?', 0, 0, '', 'Une %category s\'il vous plaît ?', '', '', '', '', '', ''), - (73, 'suggest_trade', 'I should have got skill for %category.', 0, 0, '', 'J\'aurais dû avoir une compétence pour %category', '', '', '', '', '', ''), - (74, 'suggest_trade', 'I am dying for %category.', 0, 0, '', 'Je meurs d\'envie pour %category', '', '', '', '', '', ''), - (75, 'suggest_trade', 'People are killing for %category.', 0, 0, '', 'Les gens tuent pour %category', '', '', '', '', '', ''), - (76, 'suggest_trade', '%category is a great bargain!', 0, 0, '', '%category est une bonne affaire!', '', '', '', '', '', ''), - (77, 'suggest_trade', 'Everybody is mad for %category!', 0, 0, '', 'Tout le monde est fou de %category !', '', '', '', '', '', ''), - (78, 'suggest_trade', 'Where is the best place to farm for %category?', 0, 0, '', 'Quel est le meilleur endroit pour farmer pour %category ?', '', '', '', '', '', ''), - (79, 'suggest_trade', 'I am all set for %category.', 0, 0, '', 'Je suis prêt pour %category', '', '', '', '', '', ''), - (80, 'suggest_trade', 'Is it good to sell %category?', 0, 0, '', 'Est-il bon de vendre %category ?', '', '', '', '', '', ''), - (81, 'suggest_trade', 'I\'d probably keep all my %category with me.', 0, 0, '', 'Je garderais probablement toute ma %category avec moi.', '', '', '', '', '', ''), - (82, 'suggest_trade', 'Need group? Maybe to farm some %category?', 0, 0, '', 'Besoin de groupe ? Peut-être pour farmer une certaine %category ?', '', '', '', '', '', ''), - (83, 'suggest_trade', 'I am still thinking about %category.', 0, 0, '', 'Je pense toujours à %category', '', '', '', '', '', ''), - (84, 'suggest_trade', 'I heard about %category already, but my pockets are empty.', 0, 0, '', 'J\'ai déjà entendu parler de %category , mais mes poches sont vides.', '', '', '', '', '', ''), - (85, 'suggest_trade', 'LFG for %category', 0, 0, '', 'Cherche un groupe pour %category', '', '', '', '', '', ''), - (86, 'suggest_trade', 'Would selling %category make me rich?', 0, 0, '', 'Vendre %category me rendrait-il riche?', '', '', '', '', '', ''), - (87, 'suggest_trade', 'OK. I an farming %category tomorrow.', 0, 0, '', 'D\'ACCORD. Je farm %category demain.', '', '', '', '', '', ''), - (88, 'suggest_trade', 'Everyone is talking about %category.', 0, 0, '', 'Tout le monde parle de %category', '', '', '', '', '', ''), - (89, 'suggest_trade', 'I saw at least ten people farming for %category.', 0, 0, '', 'J\'ai vu au moins dix personnes farmer pour %category', '', '', '', '', '', ''), - (90, 'suggest_trade', 'I sold all my %category yesterday. I am completely broke!', 0, 0, '', 'J\'ai vendu tout mon %category hier. Je suis complètement fauché!', '', '', '', '', '', ''), - (91, 'suggest_trade', 'Wanna join a guild farming for %category.', 0, 0, '', 'Je veux rejoindre une guilde farmant pour %category', '', '', '', '', '', ''), - (92, 'suggest_faction', 'Anyone farming %faction rep?', 0, 0, '', 'Quelqu\'un farm la réput de %faction ?', '', '', '', '', '', ''), - (93, 'suggest_faction', 'Anyone help with %faction?', 0, 0, '', 'Quelqu\'un aide-t-il %faction ?', '', '', '', '', '', ''), - (94, 'suggest_faction', 'Wanna quest for %faction.', 0, 0, '', 'Je veux quêter %faction', '', '', '', '', '', ''), - (95, 'suggest_faction', '%faction is the best.', 0, 0, '', '%faction est la meilleure.', '', '', '', '', '', ''), - (96, 'suggest_faction', 'Need just a bit to be %level with %faction.', 0, 0, '', 'J\'ai besoin d\'un peu pour être au %level avec %faction', '', '', '', '', '', ''), - (97, 'suggest_faction', 'Anyone got %level with %faction?', 0, 0, '', 'Quelqu\'un a-t-il %level avec %faction ?', '', '', '', '', '', ''), - (98, 'suggest_faction', 'Who wants to be %level with %faction?', 0, 0, '', 'Qui veut être au %level avec %faction ?', '', '', '', '', '', ''), - (99, 'suggest_faction', 'I\'ll never be %level with %faction.', 0, 0, '', 'Je ne serai jamais au %level avec %faction', '', '', '', '', '', ''), - (100, 'suggest_faction', 'Someone missing %faction rep?', 0, 0, '', 'Quelqu\'un manque de reput de %faction ?', '', '', '', '', '', ''), - (101, 'suggest_faction', 'Could help farming %faction rep.', 0, 0, '', 'Pourrait aider à farmer réput de %faction', '', '', '', '', '', ''), - (102, 'suggest_faction', 'The more rep the better. Especially with %faction.', 0, 0, '', 'Plus il y a de réput, mieux c\'est. Surtout avec %faction', '', '', '', '', '', ''), - (103, 'suggest_faction', '%faction: need %rndK for %level.', 0, 0, '', '%faction: besoin %rndK pour %level.', '', '', '', '', '', ''), - (104, 'suggest_faction', 'Who can share %faction quests?', 0, 0, '', 'Qui peut partager les quêtes de %faction ?', '', '', '', '', '', ''), - (105, 'suggest_faction', 'Any dungeons for %faction?', 0, 0, '', 'Des donjons pour %faction ?', '', '', '', '', '', ''), - (106, 'suggest_faction', 'Wanna do %faction rep grind.', 0, 0, '', 'Je veux faire monter ma réput %faction', '', '', '', '', '', ''), - (107, 'suggest_faction', 'Let\'s farm %faction rep!', 0, 0, '', 'Farmons la réput %faction !', '', '', '', '', '', ''), - (108, 'suggest_faction', 'Farming for %faction rep.', 0, 0, '', 'Farmons pour la réput %faction', '', '', '', '', '', ''), - (109, 'suggest_faction', 'Wanna farm for %faction.', 0, 0, '', 'Je veux farmer pour %faction', '', '', '', '', '', ''), - (110, 'suggest_faction', 'Need help with %faction.', 0, 0, '', 'Besoin d\'aide avec %faction', '', '', '', '', '', ''), - (111, 'suggest_faction', 'Is %faction sells something useful?', 0, 0, '', 'Est-ce que %faction vend quelque chose d\'utile ?', '', '', '', '', '', ''), - (112, 'suggest_faction', 'Are there %faction vendors?', 0, 0, '', 'Y a-t-il des vendeurs %faction ?', '', '', '', '', '', ''), - (113, 'suggest_faction', 'Who farms %faction?', 0, 0, '', 'Qui farm %faction ?', '', '', '', '', '', ''), - (114, 'suggest_faction', 'Which is the best way to farm %faction?', 0, 0, '', 'Quelle est la meilleure façon de farmer %faction ?', '', '', '', '', '', ''), - (115, 'suggest_faction', 'I hate %faction rep grind.', 0, 0, '', 'Je déteste le travail de %faction rep.', '', '', '', '', '', ''), - (116, 'suggest_faction', 'I am so tired of %faction.', 0, 0, '', 'Je suis tellement fatigué de %faction', '', '', '', '', '', ''), - (117, 'suggest_faction', 'Go for %faction?', 0, 0, '', 'Vous optez pour %faction ?', '', '', '', '', '', ''), - (118, 'suggest_faction', 'Seems everyone is %level with %faction. Only me is late as usually.', 0, 0, '', 'On dirait que tout le monde est %level avec %faction Il n\'y a que moi qui suis en retard comme d\'habitude.', '', '', '', '', '', ''), - (119, 'suggest_faction', 'LFG for %faction rep grind?', 0, 0, '', 'Cherche un groupe pour monter la réput des représentants de %faction ?', '', '', '', '', '', ''), - (120, 'suggest_faction', 'Can anobody suggest a good spot for %faction rep grind?', 0, 0, '', 'Quelqu\'un peut-il suggérer un bon endroit pour monter les réput de %faction ?', '', '', '', '', '', ''), - (121, 'suggest_faction', 'Would %faction rep benefit me?', 0, 0, '', 'Est-ce que la réput %faction me serait bénéfique ?', '', '', '', '', '', ''), - (122, 'suggest_faction', 'Who would\'ve thought that %faction rep will be useful after all...', 0, 0, '', 'Qui aurait pensé que le représentant de %faction serait utile après tout...', '', '', '', '', '', ''), - (123, 'suggest_faction', 'I wanna be exalted with all factions, starting with %faction.', 0, 0, '', 'Je veux être exalté avec toutes les factions, à commencer par %faction', '', '', '', '', '', ''), - (124, 'suggest_faction', 'Is there any point to improve my rep with %faction?', 0, 0, '', 'Y a-t-il un intérêt à améliorer ma réputation avec %faction ?', '', '', '', '', '', ''), - (125, 'suggest_faction', 'What is better for %faction? Quests or mob grinding?', 0, 0, '', 'Quoi de mieux pour %faction ? Quêtes ou mob pour XP?', '', '', '', '', '', ''), - (126, 'suggest_faction', 'Will grind %faction rep for you. Just give me some gold.', 0, 0, '', 'Monte la reput de %faction pour vous. Donnez-moi juste de l\'or.', '', '', '', '', '', ''), - (127, 'suggest_faction', 'I think grinding rep with %faction would take forever.', 0, 0, '', 'Je pense que monter la réput avec %faction prendrait une éternité.', '', '', '', '', '', ''), - (128, 'suggest_faction', 'I am killing for %faction every day now but still far from %level.', 0, 0, '', 'Je tue pour %faction tous les jours maintenant, mais encore loin du %level', '', '', '', '', '', ''), - (129, 'suggest_faction', 'At %level AH deposits will decrease, right?', 0, 0, '', 'Au %level, les dépôts hôtel des ventes diminueront, n\'est-ce pas?', '', '', '', '', '', ''), - (130, 'suggest_faction', 'How many exalted reps do you have?', 0, 0, '', 'Combien de représentants exaltés avez-vous ?', '', '', '', '', '', ''), - (131, 'suggest_faction', 'Who wants to be %level with %faction?', 0, 0, '', 'Qui veut être au %level avec %faction ?', '', '', '', '', '', ''), - (132, 'suggest_faction', 'Damn. My guild did a good %faction grind yesterday without me.', 0, 0, '', 'Mince. Ma guilde a fait un bon travail de %faction hier sans moi.', '', '', '', '', '', ''), - (133, 'suggest_faction', 'Nobody wants to help me because I am %level with %faction.', 0, 0, '', 'Personne ne veut m\'aider parce que je suis %level avec %faction', '', '', '', '', '', ''), - (134, 'suggest_faction', 'Please stay away from %faction.', 0, 0, '', 'Veuillez rester à l\'écart de %faction', '', '', '', '', '', ''), - (135, 'suggest_something', 'Wanna party in %zone.', 0, 0, '', 'Je veux faire la fête dans %zone.', '', '', '', '', '', 'Ищу группу в %zone.'), - (136, 'suggest_something', 'Anyone is looking for %role?', 0, 0, '', 'Quelqu\'un cherche un %role ?', '', '', '', '', '', 'Кто-нибудь ищет %role?'), - (137, 'suggest_something', '%role is looking for quild.', 0, 0, '', '%role recherche une guilde.', '', '', '', '', '', '%role ищу гильдию.'), - (138, 'suggest_something', 'Looking for gold.', 0, 0, '', 'A la recherche de l\'or.', '', '', '', '', '', 'Дайте голды'), - (139, 'suggest_something', '%role wants to join a good guild.', 0, 0, '', '%role veut rejoindre une bonne guilde.', '', '', '', '', '', '%role хочу в хорошую гильдию.'), - (140, 'suggest_something', 'Need a friend.', 0, 0, '', 'Besoin d\'un ami.', '', '', '', '', '', 'Ищу друга.'), - (141, 'suggest_something', 'Anyone feels alone?', 0, 0, '', 'Quelqu\'un se sent seul?', '', '', '', '', '', 'Кому-нибудь одиноко?'), - (142, 'suggest_something', 'Boring...', 0, 0, '', 'Ennuyeux...', '', '', '', '', '', 'Скучно...'), - (143, 'suggest_something', 'Who wants some?', 0, 0, '', 'Qui en veut?', '', '', '', '', '', 'Кому навалять?'), - (144, 'suggest_something', 'Go get me!', 0, 0, '', 'Allez me chercher !', '', '', '', '', '', 'Поймайте меня!'), - (145, 'suggest_something', 'Maybe a duel in %zone?', 0, 0, '', 'Peut-être un duel dans %zone ?', '', '', '', '', '', 'Кто на дуэль в %zone?'), - (146, 'suggest_something', 'Anybody doing something?', 0, 0, '', 'Quelqu\'un fait quelque chose?', '', '', '', '', '', 'Кто чем занят?'), - (147, 'suggest_something', '%zone: is anybody here?', 0, 0, '', '%zone : est-ce que quelqu\'un est là?', '', '', '', '', '', '%zone: есть кто нибудь?'), - (148, 'suggest_something', '%zone: where is everyone?', 0, 0, '', '%zone : où est tout le monde?', '', '', '', '', '', '%zone: где все?'), - (149, 'suggest_something', 'Looks like I am alone in %zone.', 0, 0, '', 'On dirait que je suis seul dans %zone', '', '', '', '', '', 'Похоже я один в %zone.'), - (150, 'suggest_something', 'Meet me in %zone.', 0, 0, '', 'Retrouvez-moi dans %zone', '', '', '', '', '', 'Встретимся в %zone.'), - (151, 'suggest_something', 'Let\'s quest in %zone!', 0, 0, '', 'Partons en quête dans %zone !', '', '', '', '', '', 'Давайте квестить в %zone!'), - (152, 'suggest_something', '%zone is the best place to be!', 0, 0, '', '%zone est le meilleur endroit où être!', '', '', '', '', '', '%zone лучшее место!'), - (153, 'suggest_something', 'Wanna go to %zone. Anybody with me?', 0, 0, '', 'Je veux aller à %zone Quelqu\'un avec moi?', '', '', '', '', '', 'Собираюсь в %zone. Кто со мной7'), - (154, 'suggest_something', 'Who wants going to %zone?', 0, 0, '', 'Qui veut aller à %zone ?', '', '', '', '', '', 'Кто собирается в %zone?'), - (155, 'suggest_something', 'I don\'t like %zone. Where to go?', 0, 0, '', 'Je n\'aime pas %zone Où aller?', '', '', '', '', '', 'Не нравится %zone. Куда идти?'), - (156, 'suggest_something', 'Are there a good quests in %zone?', 0, 0, '', 'Y a-t-il de bonnes quêtes dans %zone ?', '', '', '', '', '', 'А в %zone есть хорошие квесты?'), - (157, 'suggest_something', 'Where to go after %zone?', 0, 0, '', 'Où aller après %zone ?', '', '', '', '', '', 'Куда идти после %zone?'), - (158, 'suggest_something', 'Who is in %zone?', 0, 0, '', 'Qui est dans %zone ?', '', '', '', '', '', 'Кто в %zone?'), - (159, 'suggest_something', 'LFG in %zone.', 0, 0, '', 'Cherche un groupe dans %zone', '', '', '', '', '', 'ЛФГ %zone.'), - (160, 'suggest_something', '%zone is the worst place to be.', 0, 0, '', '%zone est le pire endroit où être.', '', '', '', '', '', '%zone это худшее место.'), - (161, 'suggest_something', 'Catch me in %zone!', 0, 0, '', 'Attrape-moi dans %zone !', '', '', '', '', '', 'Поймай меня в %zone!'), - (162, 'suggest_something', 'Go for %zone!', 0, 0, '', 'Allez pour %zone !', '', '', '', '', '', 'Гоу в %zone!'), - (163, 'suggest_something', 'Wanna quest in %zone', 0, 0, '', 'Je veux une quête dans %zone', '', '', '', '', '', 'Хочешь поделать квесты в %zone'), - (164, 'suggest_something', 'Anyone has quests in %zone?', 0, 0, '', 'Quelqu\'un a des quêtes dans %zone ?', '', '', '', '', '', 'Есть у кого квесты в %zone?'), - (165, 'suggest_something', 'Come here to %zone!', 0, 0, '', 'Venez ici à %zone !', '', '', '', '', '', 'Приходите сюда в %zone!'), - (166, 'suggest_something', 'Seems there is no Horde in %zone', 0, 0, '', 'Il semble qu\'il n\'y ait pas de Horde dans %zone', '', '', '', '', '', '%zone Орды вроде нет.'), - (167, 'suggest_something', 'Seems there is no Alliance in %zone', 0, 0, '', 'Il semble qu\'il n\'y ait pas d\'alliance dans %zone', '', '', '', '', '', '%zone Альянса вроде нет'), - (168, 'suggest_something', 'I am really tired of %zone. Maybe go somewhere else?', 0, 0, '', 'Je suis vraiment fatigué de %zone Peut-être aller ailleurs?', '', '', '', '', '', 'В %zone устал уже, может в другое место пойдем?'), - (169, 'suggest_sell', 'WTS %item for %gold.', 0, 0, '', 'Cherche à vendre %item pour %gold', '', '', '', '', '', ''), - (170, 'suggest_sell', 'Who wants %item for %gold?', 0, 0, '', 'Qui veut %item pour %gold ?', '', '', '', '', '', ''), - (171, 'suggest_sell', 'Anyone wants %item? Only %gold.', 0, 0, '', 'Quelqu\'un veut %item ? Seulement %gold', '', '', '', '', '', ''), - (172, 'suggest_sell', 'Just %gold for %item!', 0, 0, '', 'Seulement %gold pour %item!', '', '', '', '', '', ''), - (173, 'suggest_sell', 'Selling %item for %gold.', 0, 0, '', 'Vendre %item pour %gold', '', '', '', '', '', ''), - (174, 'suggest_sell', '%item is yours just for %gold!', 0, 0, '', '%item est à vous juste pour %gold !', '', '', '', '', '', ''), - (175, 'suggest_sell', 'Ridiculus price of %gold for %item!', 0, 0, '', 'Prix ridicule de %gold pour %item !', '', '', '', '', '', ''), - (176, 'suggest_sell', 'Wanna sell %item for %gold.', 0, 0, '', 'Je veux vendre %item pour %gold', '', '', '', '', '', ''), - (177, 'suggest_sell', 'Who needs %item? Only %gold.', 0, 0, '', 'Qui a besoin de %item ? Seulement %gold', '', '', '', '', '', ''), - (178, 'suggest_sell', 'Anyone needs %item for %gold?', 0, 0, '', 'Quelqu\'un a besoin de %item pour %gold ?', '', '', '', '', '', ''), - (179, 'suggest_sell', '%gold for %item. Less than AH!', 0, 0, '', '%gold pour %item. Moins que l\'hôtel des ventes!', '', '', '', '', '', ''), - (180, 'suggest_sell', '%item is expensive, but I\'d sell it for %gold.', 0, 0, '', '%item est cher, mais je le vendrais pour %gold', '', '', '', '', '', ''), - (181, 'suggest_sell', 'You\'ll never find %item cheaper than %gold!', 0, 0, '', 'Vous ne trouverez jamais %item moins cher que %gold !', '', '', '', '', '', ''), - (182, 'suggest_sell', 'Need more than %item!', 0, 0, '', 'Besoin de plus de %item !', '', '', '', '', '', ''), - (183, 'suggest_sell', 'I have %item and need more.', 0, 0, '', 'J\'ai %item et j\'en ai besoin de plus.', '', '', '', '', '', ''), - (184, 'suggest_sell', 'Have %item. Who wants to buy for %gold?', 0, 0, '', 'Avoir %item. Qui veut acheter pour %gold ?', '', '', '', '', '', ''), - (185, 'suggest_sell', 'Anyone WTB %item for %gold?', 0, 0, '', 'Quelqu\'un cherche à acheter %item pour %gold ?', '', '', '', '', '', ''), - (186, 'suggest_sell', 'What about %item? For %gold.', 0, 0, '', 'Qu\'en est-il de %item ? Pour %gold', '', '', '', '', '', ''), - (187, 'suggest_sell', 'Who said I am a bastard? %item for %gold is a good price.', 0, 0, '', 'Qui a dit que j\'étais un bâtard? %item pour %gold est un bon prix.', '', '', '', '', '', ''), - (188, 'suggest_sell', 'I am selling %item? Just %gold.', 0, 0, '', 'Je vends %item ? Juste %gold', '', '', '', '', '', ''), - (189, 'suggest_sell', 'LFG for farming. You can still buy %item I have for %gold.', 0, 0, '', 'Cherche un groupe pour farming. Vous pouvez toujours acheter %item que j\'ai pour %gold', '', '', '', '', '', ''), - (190, 'suggest_sell', 'Sold almost everything today. Still have %item for %gold.', 0, 0, '', 'Vendu presque tout aujourd\'hui. Vous avez encore %item pour %gold', '', '', '', '', '', ''), - (191, 'suggest_sell', 'What use for trade chat? Of course to sell %item for %gold.', 0, 0, '', 'A quoi sert le tchat commercial? Bien sûr pour vendre %item pour %gold', '', '', '', '', '', ''), - (192, 'suggest_sell', 'Can anyone beat the price of %gold for %item?', 0, 0, '', 'Quelqu\'un peut-il battre le prix de %gold pour %item ?', '', '', '', '', '', ''), - (193, 'suggest_sell', 'Wanna stop trade chat? Just buy %item? For %gold!', 0, 0, '', 'Vous voulez arrêter le chat commercial? Vous venez d\'acheter %item ? Pour %gold !', '', '', '', '', '', ''), - (194, 'suggest_sell', 'Everybody spams in trade chat. Me too - %gold for %item!', 0, 0, '', 'Tout le monde spamme dans le chat commercial. Moi aussi - %gold pour %item !', '', '', '', '', '', ''), - (195, 'suggest_sell', 'Is %item any use? Just selling it for %gold.', 0, 0, '', '%item est-il utile? Je le vends juste pour %gold', '', '', '', '', '', ''), - (196, 'suggest_sell', 'I have %item ready to sell you for %gold.', 0, 0, '', 'J\'ai %item prêt à vous vendre pour %gold', '', '', '', '', '', ''), - (197, 'suggest_sell', 'Did nothing yesterday but have got %item. Selling it for %gold.', 0, 0, '', 'Je n\'ai rien fait hier mais j\'ai %item Je le vends pour %gold', '', '', '', '', '', ''), - (198, 'suggest_sell', 'Farmed yesterday and got %item. Anyone wtb for %gold?', 0, 0, '', 'Farmé hier et obtenu %item Quelqu\'un cherche à acheter pour %gold ?', '', '', '', '', '', ''), - (199, 'suggest_sell', 'Bought %item yesterday. Anyone needs it for %gold?', 0, 0, '', 'Acheté %item hier. Quelqu\'un en a besoin pour %gold ?', '', '', '', '', '', ''), - (200, 'suggest_sell', 'Who asked for %item? The price is the same - %gold.', 0, 0, '', 'Qui a demandé %item ? Le prix est le même - %gold', '', '', '', '', '', ''), - (201, 'suggest_sell', 'I sill have %item. WTB for %gold?', 0, 0, '', 'J\'ai toujours %item. Cherche à acheter pour %gold ?', '', '', '', '', '', ''), - (202, 'suggest_sell', 'I used to have more than %item. Now needs to sell it for %gold.', 0, 0, '', 'J\'avais plus de %item Il faut maintenant le vendre pour %gold', '', '', '', '', '', ''), - (203, 'suggest_sell', 'I wish I have more than %item. You could buy it for %gold anyways.', 0, 0, '', 'J\'aimerais avoir plus de %item . Vous pouvez l\'acheter pour %gold de toute façon.', '', '', '', '', '', ''), - (204, 'suggest_sell', 'What use for your gold? To buy my %item for %gold.', 0, 0, '', 'A quoi sert votre or ? Pour acheter mon %item pour %gold', '', '', '', '', '', ''), - (205, 'suggest_sell', 'Please spare some gold for me. You can buy %item for %gold.', 0, 0, '', 'S\'il vous plaît, épargnez-moi de l\'or. Vous pouvez acheter %item pour %gold', '', '', '', '', '', ''), - (206, 'suggest_sell', 'Is %gold is a good price for %item?', 0, 0, '', '%gold est-il un bon prix pour %item ?', '', '', '', '', '', ''), - (207, 'suggest_sell', 'Just bought yesterday %items, but do not need it anymore. Anyone wants for %gold?', 0, 0, '', 'Je viens d\'acheter hier %items , mais je n\'en ai plus besoin. Quelqu\'un veut %gold ?', '', '', '', '', '', ''), - (208, 'suggest_sell', 'I am going to post %item on the AH but you can buy it now cheaper just for %gold.', 0, 0, '', 'Je vais poster %item à l\'hôtel des ventes mais vous pouvez l\'acheter maintenant moins cher juste pour %gold', '', '', '', '', '', ''), - (209, 'suggest_sell', 'Why the #!@ have I bought %item? Anyone needs it for %gold?', 0, 0, '', 'Pourquoi ai-je acheté le #!@ %item ? Quelqu\'un en a besoin pour %gold ?', '', '', '', '', '', ''), - (210, 'reply', 'what was that %s?', 0, 0, '', 'c\'était quoi ce %s?', '', '', '', '', '', ''), - (211, 'reply', 'not sure I understand %s?', 0, 0, '', 'pas sûr de comprendre %s?', '', '', '', '', '', ''), - (212, 'reply', 'uh... no clue what yer talkin bout', 0, 0, '', 'euh... aucune idée de quoi tu parles', '', '', '', '', '', ''), - (213, 'reply', 'you talkin to me %s?', 0, 0, '', 'tu me parles %s?', '', '', '', '', '', ''), - (214, 'reply', 'whaaaa?', 0, 0, '', 'quoiaaa?', '', '', '', '', '', ''), - (215, 'reply', 'huh?', 0, 0, '', 'hein?', '', '', '', '', '', ''), - (216, 'reply', 'what?', 0, 0, '', 'Quoi?', '', '', '', '', '', ''), - (217, 'reply', 'are you talking?', 0, 0, '', 'parles-tu?', '', '', '', '', '', ''), - (218, 'reply', 'whatever dude', 0, 0, '', 'peu importe mec', '', '', '', '', '', ''), - (219, 'reply', 'you lost me', 0, 0, '', 'tu m\'as perdu', '', '', '', '', '', ''), - (220, 'reply', 'Bla bla bla...', 0, 0, '', 'Bla bla bla...', '', '', '', '', '', ''), - (221, 'reply', 'What did you say, %s?', 0, 0, '', 'Qu\'as-tu dis, %s?', '', '', '', '', '', ''), - (222, 'reply', 'Concentrate on the game, %s!', 0, 0, '', 'Concentres-toi sur le jeu, %s!', '', '', '', '', '', ''), - (223, 'reply', 'Chatting with you %s is so great! I always wanted to meet you', 0, 0, '', 'Discuter avec vous %s est tellement génial! J\'ai toujours voulu te rencontrer', '', '', '', '', '', ''), - (224, 'reply', 'These chat-messages are freaking me out! I feel like I know you all!', 0, 0, '', 'Ces messages du chat me font flipper! J\'ai l\'impression de vous connaître tous!', '', '', '', '', '', ''), - (225, 'reply', 'YEAH RIGHT! HAHA SURE!!!', 0, 0, '', 'OUI EN EFFET! AHAH BIEN SÛR!!!', '', '', '', '', '', ''), - (226, 'reply', 'I believe you!!!', 0, 0, '', 'Je te crois!!!', '', '', '', '', '', ''), - (227, 'reply', 'OK, uhuh LOL', 0, 0, '', 'OK, euh LOL', '', '', '', '', '', ''), - (228, 'reply', 'Why is everybody always saying the same things???', 0, 0, '', 'Pourquoi tout le monde dit toujours la même chose???', '', '', '', '', '', ''), - (229, 'reply', 'Hey %s....oh nevermind!', 0, 0, '', 'Hé %s.... oh tant pis!', '', '', '', '', '', ''), - (230, 'reply', 'What are you talking about %s', 0, 0, '', 'De quoi parlez-vous %s', '', '', '', '', '', ''), - (231, 'reply', 'Who said that? I resemble that remark', 0, 0, '', 'Qui a dit ça? je ressemble à cette remarque', '', '', '', '', '', ''), - (232, 'reply', 'hey %s i havent forgotten you', 0, 1, '', 'salut %s je ne t\'ai pas oublié', '', '', '', '', '', ''), - (233, 'reply', 'you piss me off %s', 0, 1, '', 'tu me fais chier %s', '', '', '', '', '', ''), - (234, 'reply', 'im gunna get you this time %s', 0, 1, '', 'je vais t\'avoir cette fois %s', '', '', '', '', '', ''), - (235, 'reply', 'better watch your back %s', 0, 1, '', 'mieux vaut surveiller vos arrières %s', '', '', '', '', '', ''), - (236, 'reply', 'i did not like last round so much', 0, 1, '', 'je n\'ai pas tellement aimé le dernier tour', '', '', '', '', '', ''), - (237, 'reply', 'i sucked last round thanks to %s', 0, 1, '', 'j\'ai merdé le dernier tour grâce à %s', '', '', '', '', '', ''), - (238, 'reply', 'prepare to die %s', 0, 1, '', 'préparez-vous à mourir %s', '', '', '', '', '', ''), - (239, 'reply', 'dont appreciate you killin me %s', 0, 1, '', 'j\'apprécie pas que tu me tues %s', '', '', '', '', '', ''), - (240, 'reply', '%s, i hate you', 0, 1, '', '%s, je te déteste', '', '', '', '', '', ''), - (241, 'reply', 'grrrrrr, ill get you this time %s', 0, 1, '', 'grrrrrr, je vais t\'avoir cette fois %s', '', '', '', '', '', ''), - (242, 'reply', 'well fuck you', 0, 1, '', 'eh bien va te faire foutre', '', '', '', '', '', ''), - (243, 'reply', 'wtf', 0, 2, '', 'wtf', '', '', '', '', '', ''), - (244, 'reply', 'wtf??', 0, 2, '', 'wtf??', '', '', '', '', '', ''), - (245, 'reply', 'low life', 0, 2, '', 'faible durée de vie', '', '', '', '', '', ''), - (246, 'reply', 'wth', 0, 2, '', 'wth', '', '', '', '', '', ''), - (247, 'reply', 'sucked', 0, 2, '', 'Ça craint', '', '', '', '', '', ''), - (248, 'reply', 'REMATCH!!! im taking him down', 0, 2, '', 'REMATCH!!! je le descends', '', '', '', '', '', ''), - (249, 'reply', 'pathetic, i got killed by %s', 0, 2, '', 'pathétique, j\'ai été tué par %s', '', '', '', '', '', ''), - (250, 'reply', 'hehe, i nailed %s?', 0, 3, '', 'hehe, j\'ai cloué %s?', '', '', '', '', '', ''), - (251, 'reply', 'that was too easy, killin %s', 0, 3, '', 'c\'était trop facile, de tuer %s', '', '', '', '', '', ''), - (252, 'reply', 'gotcha mofo', 0, 3, '', 'je t\'ai eu enfoiré', '', '', '', '', '', ''), - (253, 'reply', 'ha ha', 0, 3, '', 'ha ha', '', '', '', '', '', ''), - (254, 'reply', 'loser', 0, 3, '', 'loser', '', '', '', '', '', ''), - (255, 'reply', 'i killed %s and yer all next dudes', 0, 3, '', 'j\'ai tué %s et vous tous les prochains mecs', '', '', '', '', '', ''), - (256, 'reply', 'oh yeah i owned him', 0, 3, '', 'oh ouais je l\'ai possédé', '', '', '', '', '', ''), - (257, 'reply', 'im a killin machine', 0, 3, '', 'je suis une machine à tuer', '', '', '', '', '', ''), - (258, 'reply', '%s, this reminds me of a Slayer song...all this bloodshed', 0, 3, '', '%s, ça me rappelle une chanson de Slayer... tout ce bain de sang', '', '', '', '', '', ''), - (259, 'reply', 'sorry, %s. can we do the scene again?', 0, 3, '', 'désolé, %s. peut-on refaire la scène?', '', '', '', '', '', ''), - (260, 'reply', 'so....how do you like being worm food %s???', 0, 3, '', 'alors... comment aimez-vous être de la nourriture pour vers %s???', '', '', '', '', '', ''), - (261, 'reply', 'yer supposed to be dead, %s its part of the game!!!!!', 0, 3, '', 'tu es censé être mort, %s ça fait partie du jeu!!!!!', '', '', '', '', '', ''), - (262, 'reply', 'sorry, %s. that looked as good as an Andy Worhol painting!', 0, 3, '', 'désolé, %s. ça avait l\'air aussi bien qu\'une peinture d\'Andy Warhol!', '', '', '', '', '', ''), - (263, 'reply', '%s, ill use the rubber bullets next time !', 0, 3, '', '%s, j\'utiliserai pas les balles en caoutchouc la prochaine fois!', '', '', '', '', '', ''), - (264, 'reply', 'whatsamatter, %s?? lose your head? hahaha gotta keep cool!!', 0, 3, '', 'qu\'importe, %s ?? tu perds la tête? hahaha faut rester cool!!', '', '', '', '', '', ''), - (265, 'reply', 'i had to do it, %s. You understand. The Director said so!!', 0, 3, '', 'je devais le faire, %s. Tu comprends. Le directeur l\'a dit!!', '', '', '', '', '', ''), - (266, 'reply', 'hey %s.......MUAHAHAHAHAHAHAHAHAHAHA', 0, 3, '', 'Salut %s.......MUAHAHAHAHAHAHAHAHAHAHA', '', '', '', '', '', ''), - (267, 'reply', '%s, i enjoyed that one!! Lets play it again Sam', 0, 3, '', '%s, j\'ai adoré celui-là !! Jouons à nouveau Sam', '', '', '', '', '', ''), - (268, 'reply', 'hey, %s! ju can start callin me scarface.. ju piece of CHIT!!!!', 0, 3, '', 'Hé, %s ! ju peut commencer à m\'appeler Scarface .. ju merde!!!!', '', '', '', '', '', ''), - (269, 'reply', 'are you talking to me %s??', 0, 3, '', 'tu me parles %s ??', '', '', '', '', '', ''), - (270, 'reply', '%s get it right this time, dont stand in front of my bullets.', 0, 3, '', '%s réussis cette fois, ne te tiens pas devant mes balles.', '', '', '', '', '', ''), - (271, 'reply', '%s, what are you laying around for??? hehe', 0, 3, '', '%s, pourquoi traînes-tu??? hé hé', '', '', '', '', '', ''), - (272, 'reply', 'hi %s', 0, 4, '', 'salut %s', '', '', '', '', '', ''), - (273, 'reply', 'oh, hi %s', 0, 4, '', 'oh, salut %s', '', '', '', '', '', ''), - (274, 'reply', 'wazzup %s!!!', 0, 4, '', 'Quoi de neuf %s!!!', '', '', '', '', '', ''), - (275, 'reply', 'hi', 0, 4, '', 'salut', '', '', '', '', '', ''), - (276, 'reply', 'wazzup', 0, 4, '', 'wazzup', '', '', '', '', '', ''), - (277, 'reply', 'hello %s', 0, 4, '', 'bonjour %s', '', '', '', '', '', ''), - (278, 'reply', 'hi %s, do i know you?', 0, 4, '', 'Salut %s, est-ce que je te connais ?', '', '', '', '', '', ''), - (279, 'reply', 'hey %s', 0, 4, '', 'salut %s', '', '', '', '', '', ''), - (280, 'reply', 'hai %s', 0, 4, '', 'ha %s', '', '', '', '', '', ''), - (281, 'reply', 'wth', 0, 6, '', 'wth', '', '', '', '', '', ''), - (282, 'reply', 'wtf', 0, 6, '', 'wtf', '', '', '', '', '', ''), - (283, 'reply', 'this is bs', 0, 6, '', 'c\'est bs', '', '', '', '', '', ''), - (284, 'reply', 'admin', 0, 6, '', 'admin', '', '', '', '', '', ''), - (285, 'reply', 'hey %s quit abusing your admin', 0, 6, '', 'hé %s arrête d\'abuser de ton admin', '', '', '', '', '', ''), - (286, 'reply', 'leave me alone admin!', 0, 6, '', 'laissez-moi tranquille admin!', '', '', '', '', '', ''), - (287, 'reply', 'you suck admin', 0, 6, '', 'tu es nul admin', '', '', '', '', '', ''), - (288, 'reply', 'thats my name, what you want %s', 0, 5, '', 'c\'est mon nom, qu\'est-ce que tu veux %s', '', '', '', '', '', ''), - (289, 'reply', 'yes???', 0, 5, '', 'Oui???', '', '', '', '', '', ''), - (290, 'reply', 'uh... what', 0, 5, '', 'euh ...quoi', '', '', '', '', '', ''), - (291, 'reply', 'you talkin to me %s?', 0, 5, '', 'tu me parles %s ?', '', '', '', '', '', ''), - (292, 'taunt', 'I have puppies under my armor!', 0, 0, '', 'J\'ai des chiots sous mon armure !', '', '', '', '', '', ''), - (293, 'taunt', 'Bite me, !', 0, 0, '', 'Mords moi, !', '', '', '', '', '', ''), - (294, 'taunt', 'Hey ! Guess what your mom said last night!', 0, 0, '', 'Hey ! Devine ce que ta mère a dit hier soir!', '', '', '', '', '', ''), - (295, 'taunt', ', you\'re so ugly you couldn\'t score in a monkey whorehouse with a bag of bananas!', 0, 0, '', ', tu es si moche que tu ne pourrais pas marquer dans un bordel de singes avec un sac de bananes!', '', '', '', '', '', ''), - (296, 'taunt', 'Shut up , you\'ll never be the man your mother is!!', 0, 0, '', 'Tais-toi , tu ne seras jamais l\'homme qu\'est ta mère!!', '', '', '', '', '', ''), - (297, 'taunt', 'Your mother was a hampster and your father smelt of elderberries!!!!', 0, 0, '', 'Ta mère était un hamster et ton père sentait le sureau!!!!', '', '', '', '', '', ''), - (298, 'taunt', 'I don\'t want to talk to you no more, you empty headed animal food trough wiper!!!', 0, 0, '', 'Je ne veux plus te parler, espèce d\'essuyeur d\'abreuvoirs pour animaux tête vide!!!', '', '', '', '', '', ''), - (299, 'taunt', 'I fart in your general direction!!!', 0, 0, '', 'Je pète dans votre direction générale!!!', '', '', '', '', '', ''), - (300, 'taunt', 'Go and boil your bottom, you son of a silly person!!!', 0, 0, '', 'Va te faire cuire le cul, fils d\'idiot!!!', '', '', '', '', '', ''), - (301, 'taunt', 'What are you going to do , bleed on me? HAVE AT YOU!', 0, 0, '', 'Qu\'est ce que tu vas faire , saigner sur moi? A VOUS!', '', '', '', '', '', ''), - (302, 'taunt', 'M-O-O-N! That spells aggro!', 0, 0, '', 'PUNAISE! Ce sort aggro!', '', '', '', '', '', ''), - (303, 'taunt', 'You\'re about as useful as a one-legged man in an ass kicking contest.', 0, 0, '', 'Tu es à peu près aussi utile qu\'un homme unijambiste dans un concours de coups de pied au cul.', '', '', '', '', '', ''), - (304, 'taunt', 'Hey ! Stop hitting on them, they\'re not your type. They aren\'t inflatable.', 0, 0, '', 'Hey ! Arrête de les draguer, ce n\'est pas ton genre. Ils ne sont pas gonflables.', '', '', '', '', '', ''), - (305, 'taunt', ' you\'re so far outta your league, you\'re playing a different sport.', 0, 0, '', ' vous êtes tellement hors de votre ligue que vous pratiquez un sport différent.', '', '', '', '', '', ''), - (306, 'taunt', 'You made a big mistake today , you got out of bed.', 0, 0, '', 'Tu as fait une grosse erreur aujourd\'hui , tu es sorti du lit.', '', '', '', '', '', ''), - (307, 'taunt', 'I wanna try turning into a horse, but I need help. I\'ll be the front, you be yourself.', 0, 0, '', 'Je veux essayer de me transformer en cheval, mais j\'ai besoin d\'aide. Je serai devant, tu seras toi-même.', '', '', '', '', '', ''), - (308, 'taunt', 'Can I borrow your face for a few days? My ass is going on holiday....', 0, 0, '', 'Puis-je emprunter votre visage pendant quelques jours? Mon cul part en vacances....', '', '', '', '', '', ''), - (309, 'taunt', 'I\'d like to give you a going away present... First you do your part.', 0, 0, '', 'J\'aimerais vous offrir un cadeau de départ... D\'abord, donnes ta part.', '', '', '', '', '', ''), - (310, 'taunt', 'Before you came along we were hungry, Now we\'re just fed up.', 0, 0, '', 'Avant que tu n\'arrives nous avions faim, maintenant nous en avons juste marre.', '', '', '', '', '', ''), - (311, 'taunt', 'I like you. People say I have no taste, but I like you.', 0, 0, '', 'Je t\'aime bien. Les gens disent que je n\'ai pas de goût, mais je t\'aime bien.', '', '', '', '', '', ''), - (312, 'taunt', 'I think you have an inferiority complex, but that\'s okay, it\'s justified.', 0, 0, '', 'Je pense que tu as un complexe d\'infériorité, mais il n\'y a pas de problème, c\'est justifié.', '', '', '', '', '', ''), - (313, 'taunt', 'Hence rotten thing! Or I shall shake thy bones out of thy garments.', 0, 0, '', 'Par conséquent chose pourrie! Je vais secouer tes os de tes vêtements.', '', '', '', '', '', ''), - (314, 'taunt', 'I can\'t believe I\'m wasting my time with you!', 0, 0, '', 'Je n\'arrive pas à croire que je perds mon temps avec toi!', '', '', '', '', '', ''), - (315, 'taunt', 'I love it when someone insults me, it means I don\'t have to be nice anymore.', 0, 0, '', 'J\'adore quand quelqu\'un m\'insulte, ça veut dire que je n\'ai plus besoin d\'être gentil.', '', '', '', '', '', ''), - (316, 'taunt', 'Thou leathern-jerkin, crystal-button, knot-pated, agatering, puke-stocking, caddis-garter, smooth-tongue, Spanish pouch!', 0, 0, '', 'Toi l\'agent fédéral, pourpoint en cuir, bouton de cristal, anneau d\'agate, bas vomi, jarretière caddis, pochette espagnole!', '', '', '', '', '', ''), - (317, 'taunt', 'Thou qualling bat-fowling malt-worm!', 0, 0, '', 'Toi qualificatif de chauve-souris qui chasse le ver de malt!', '', '', '', '', '', ''), - (318, 'taunt', 'Thou art truely an idol of idiot-worshippers!', 0, 0, '', 'Tu es vraiment une idole d\'adorateurs d\'idiots!', '', '', '', '', '', ''), - (319, 'taunt', 'Thou misbegotten knotty-pated wagtail!', 0, 0, '', 'Tu es une bergeronnette printanière mal engendrée!', '', '', '', '', '', ''), - (320, 'taunt', 'Thou whoreson mandrake, thou art fitter to be worn in my cap than to wait at my heels!', 0, 0, '', 'Toi putain de mandragore, tu es plus apte à être porté dans ma casquette qu\'à attendre sur mes talons!', '', '', '', '', '', ''), - (321, 'taunt', 'You! You scullion! You rampallian! You fustilarian! I\'ll tickle your catastrophe!', 0, 0, '', 'Toi ! Espèce de marmiton ! Espèce de rampallian ! Espèce de fusilier ! Je vais chatouiller ta catastrophe!', '', '', '', '', '', ''), - (322, 'taunt', 'Oh ! Thou infectious ill-nurtured flax-wench!', 0, 0, '', 'Oh ! Tu es contagieuse et mal nourrie!', '', '', '', '', '', ''), - (323, 'taunt', 'We leak in your chimney, !', 0, 0, '', 'On a une fuite dans votre cheminée, !', '', '', '', '', '', ''), - (324, 'taunt', 'Oh thou bootless fen-sucked canker-blossom!', 0, 0, '', 'Oh toi, fleur de chancre sucée par les marais sans botte!', '', '', '', '', '', ''), - (325, 'taunt', 'Were I like thee I\'d throw away myself!', 0, 0, '', 'Si j\'étais comme toi, je me jetterais!', '', '', '', '', '', ''), - (326, 'taunt', 'O teach me , how I should forget to think!', 0, 0, '', 'O apprends-moi , comme je devrais oublier de penser!', '', '', '', '', '', ''), - (327, 'taunt', 'Truly thou art damned, like an ill-roasted egg, all on one side!', 0, 0, '', 'Vraiment tu es damné, comme un œuf mal rôti, tout d\'un côté!', '', '', '', '', '', ''), - (328, 'taunt', 'You starvelling, you eel-skin, you dried neat\'s-tongue, you bull\'s-pizzle, you stock-fish- O for breath to utter what is like thee!! -you tailor\'s-yard, you sheath, you bow-case, you vile standing tuck!', 0, 0, '', 'Toi affamé, espèce de peau d\'anguille, ta langue bien séchée, espèce de taureau, poisson séché, O pour le souffle de dire ce qui te ressemble !! -espèce de vergue de tailleur, espèce de fourreau, espèce d\'étui à archet, vil tuck debout', '', '', '', '', '', ''), - (329, 'taunt', 'Fie! Drop thee into the rotten mouth of Death!', 0, 0, '', 'Fi ! Jette-toi dans la bouche pourrie de la Mort!', '', '', '', '', '', ''), - (330, 'taunt', ', you are a fishmonger!', 0, 0, '', ', vous êtes poissonnier!', '', '', '', '', '', ''), - (331, 'taunt', 'I shall live to knock thy brains out!', 0, 0, '', 'Je vivrai pour te faire sauter la cervelle!', '', '', '', '', '', ''), - (332, 'taunt', 'Most shallow are you, !! Thou art worms-meat in respect of a good piece of flesh, indeed!!', 0, 0, '', 'Tu es très superficiel, !! Tu es de la viande de vers par rapport à un bon morceau de chair, en effet!!', '', '', '', '', '', ''), - (333, 'taunt', 'Vile wretch! O , thou odiferous hell-hated pignut!', 0, 0, '', 'Misérable ! O , toi, ignoble cochon de l\'enfer!', '', '', '', '', '', ''), - (334, 'taunt', '! Thy kiss is as comfortless as frozen water to a starved snake!', 0, 0, '', '! Ton baiser est aussi désagréable que de l\'eau gelée pour un serpent affamé!', '', '', '', '', '', ''), - (335, 'taunt', 'I scorn you, scurvy companion. What, you poor, base, rascally, cheating, lack-linen mate! Away, you moldy rogue, away!', 0, 0, '', 'Je te méprise, compagnon du scorbut. Quoi, pauvre, bas, coquin, tricheur, camarade en manque de linge ! Partez, espèce de voyou moisi, partez!', '', '', '', '', '', ''), - (336, 'taunt', 'Out of my sight! Thou dost infect my eyes !', 0, 0, '', 'Hors de ma vue! Tu infectes mes yeux !', '', '', '', '', '', ''), - (337, 'taunt', 'PLAY TIME!!!!', 0, 0, '', 'RÉCRÉATION!!!!', '', '', '', '', '', ''), - (338, 'taunt', 'None shall pass!', 0, 0, '', 'Personne ne passera!', '', '', '', '', '', ''), - (339, 'taunt', 'We\'re under attack! A vast, ye swabs! Repel the invaders!', 0, 0, '', 'Nous sommes attaqués ! Un vaste écouvillons! Repoussez les envahisseurs!', '', '', '', '', '', ''), - (340, 'taunt', 'None may challenge the Brotherhood!', 0, 0, '', 'Personne ne peut défier la Confrérie!', '', '', '', '', '', ''), - (341, 'taunt', 'Foolsss...Kill the one in the dress!', 0, 0, '', 'Foolsss... Tuez celui qui porte la robe!', '', '', '', '', '', ''), - (342, 'taunt', 'I\'ll feed your soul to Hakkar himself! ', 0, 0, '', 'Je donnerai ton âme à Hakkar lui-même! ', '', '', '', '', '', ''), - (343, 'taunt', 'Pride heralds the end of your world! Come, mortals! Face the wrath of the !', 0, 0, '', 'La fierté annonce la fin de votre monde ! Venez, mortels ! Affrontez la colère des !', '', '', '', '', '', ''), - (344, 'taunt', 'All my plans have led to this!', 0, 0, '', 'Tous mes plans ont mené à cela!', '', '', '', '', '', ''), - (345, 'taunt', 'Ahh! More lambs to the slaughter!', 0, 0, '', 'Ahhh ! Plus d\'agneaux à l\'abattoir!', '', '', '', '', '', ''), - (346, 'taunt', 'Another day, another glorious battle!', 0, 0, '', 'Un autre jour, une autre bataille glorieuse!', '', '', '', '', '', ''), - (347, 'taunt', 'So, business... or pleasure?', 0, 0, '', 'Alors, affaires... ou plaisir?', '', '', '', '', '', ''), - (348, 'taunt', 'You are not prepared!', 0, 0, '', 'Vous n\'êtes pas prêt!', '', '', '', '', '', ''), - (349, 'taunt', 'The \'s final conquest has begun! Once again the subjugation of this world is within our grasp. Let none survive! ', 0, 0, '', 'La conquête finale de la a commencé ! Une fois de plus, l\'assujettissement de ce monde est à notre portée. Que personne ne survive!', '', '', '', '', '', ''), - (350, 'taunt', 'Your death will be a painful one. ', 0, 0, '', 'Ta mort sera douloureuse.', '', '', '', '', '', ''), - (351, 'taunt', 'Cry for mercy! Your meaningless lives will soon be forfeit. ', 0, 0, '', 'Crie miséricorde ! Vos vies insignifiantes seront bientôt perdues.', '', '', '', '', '', ''), - (352, 'taunt', 'Abandon all hope! The has returned to finish what was begun so many years ago. This time there will be no escape! ', 0, 0, '', 'Abandonner tout espoir! La est revenue pour terminer ce qui avait été commencé il y a tant d\'années. Cette fois, il n\'y aura pas d\'échappatoire!', '', '', '', '', '', ''), - (353, 'taunt', 'Alert! You are marked for Extermination! ', 0, 0, '', 'Alerte! Vous êtes marqué pour l\'extermination!', '', '', '', '', '', ''), - (354, 'taunt', 'The is for guests only...', 0, 0, '', 'La est réservée aux invités...', '', '', '', '', '', ''), - (355, 'taunt', 'Ha ha ha! You are hopelessly outmatched!', 0, 0, '', 'Hahaha! Vous êtes désespérément surpassé!', '', '', '', '', '', ''), - (356, 'taunt', 'I will crush your delusions of grandeur! ', 0, 0, '', 'Je vais écraser vos illusions de grandeur!', '', '', '', '', '', ''), - (357, 'taunt', 'Forgive me, for you are about to lose the game.', 0, 0, '', 'Pardonnez-moi, car vous êtes sur le point de perdre la partie.', '', '', '', '', '', ''), - (358, 'taunt', 'Struggling only makes it worse.', 0, 0, '', 'Lutter ne fait qu\'empirer les choses.', '', '', '', '', '', ''), - (359, 'taunt', 'Vermin! Leeches! Take my blood and choke on it!', 0, 0, '', 'Vermine! sangsues ! Prends mon sang et étouffe-toi avec!', '', '', '', '', '', ''), - (360, 'taunt', 'Not again... NOT AGAIN!', 0, 0, '', 'Pas encore... PAS ENCORE!', '', '', '', '', '', ''), - (361, 'taunt', 'My blood will be the end of you!', 0, 0, '', 'Mon sang sera ta fin!', '', '', '', '', '', ''), - (362, 'taunt', 'Good, now you fight me!', 0, 0, '', 'Bien, maintenant tu me combats!', '', '', '', '', '', ''), - (363, 'taunt', 'Get da move on, guards! It be killin\' time!', 0, 0, '', 'Allez-y, gardes ! Ça va tuer le temps!', '', '', '', '', '', ''), - (364, 'taunt', 'Don\'t be delayin\' your fate. Come to me now. I make your sacrifice quick.', 0, 0, '', 'Ne retardez pas votre destin. Viens à moi maintenant. Je fais votre sacrifice rapide.', '', '', '', '', '', ''), - (365, 'taunt', 'You be dead soon enough!', 0, 0, '', 'Tu es mort bien assez tôt!', '', '', '', '', '', ''), - (366, 'taunt', 'Mua-ha-ha!', 0, 0, '', 'Mua-ha-ha!', '', '', '', '', '', ''), - (367, 'taunt', 'I be da predator! You da prey...', 0, 0, '', 'Je suis un prédateur ! Tu es une proie...', '', '', '', '', '', ''), - (368, 'taunt', 'You gonna leave in pieces!', 0, 0, '', 'Tu vas partir en morceaux!', '', '', '', '', '', ''), - (369, 'taunt', 'Death comes. Will your conscience be clear? ', 0, 0, '', 'La mort vient. Votre conscience sera-t-elle claire?', '', '', '', '', '', ''), - (370, 'taunt', 'Your behavior will not be tolerated.', 0, 0, '', 'Votre comportement ne sera pas toléré.', '', '', '', '', '', ''), - (371, 'taunt', 'The Menagerie is for guests only.', 0, 0, '', 'La Ménagerie est réservée aux invités.', '', '', '', '', '', ''), - (372, 'taunt', 'Hmm, unannounced visitors, Preparations must be made... ', 0, 0, '', 'Hmm, visiteurs inopinés, il faut faire des préparatifs...', '', '', '', '', '', ''), - (373, 'taunt', 'Hostile entities detected. Threat assessment protocol active. Primary target engaged. Time minus thirty seconds to re-evaluation.', 0, 0, '', 'Entités hostiles détectées. Protocole d\'évaluation de la menace actif. Cible principale engagée. Délai de réévaluation moins trente secondes.', '', '', '', '', '', ''), - (374, 'taunt', 'New toys? For me? I promise I won\'t break them this time!', 0, 0, '', 'Nouveaux jouets? Pour moi? Promis je ne les casserai pas cette fois !', '', '', '', '', '', ''), - (375, 'taunt', 'I\'m ready to play!', 0, 0, '', 'Je suis prêt à jouer!', '', '', '', '', '', ''), - (376, 'taunt', 'Shhh... it will all be over soon.', 0, 0, '', 'Chut... tout sera bientôt fini.', '', '', '', '', '', ''), - (377, 'taunt', 'Aaaaaughibbrgubugbugrguburgle!', 0, 0, '', 'Aaaaaughibbrgubugbugrguburgle!', '', '', '', '', '', ''), - (378, 'taunt', 'RwlRwlRwlRwl!', 0, 0, '', 'RwlRwlRwlRwl!', '', '', '', '', '', ''), - (379, 'taunt', 'You too, shall serve!', 0, 0, '', 'Toi aussi, tu serviras!', '', '', '', '', '', ''), - (380, 'taunt', 'Tell me... tell me everything! Naughty secrets! I\'ll rip the secrets from your flesh!', 0, 0, '', 'Dis-moi... dis-moi tout ! Secrets coquins ! J\'arracherai les secrets de ta chair!', '', '', '', '', '', ''), - (381, 'taunt', 'Prepare yourselves, the bells have tolled! Shelter your weak, your young and your old! Each of you shall pay the final sum! Cry for mercy; the reckoning has come!', 0, 0, '', 'Préparez-vous, les cloches ont sonné ! Mettez à l\'abri vos faibles, vos jeunes et vos vieux ! Chacun de vous paiera la somme finale ! Implorez la miséricorde ; le jugement est venu!', '', '', '', '', '', ''), - (382, 'taunt', 'Where in Bonzo\'s brass buttons am I?', 0, 0, '', 'Où suis-je dans les boutons en laiton de Bonzo?', '', '', '', '', '', ''), - (383, 'taunt', 'I can bear it no longer! Goblin King! Goblin King! Wherever you may be! Take this far away from me!', 0, 0, '', 'Je ne peux plus le supporter ! Roi Gobelin ! Roi Gobelin ! Où que vous soyez ! Emmenez cette loin de moi!', '', '', '', '', '', ''), - (384, 'taunt', 'You have thirteen hours in which to solve the labyrinth, before your baby brother becomes one of us... forever.', 0, 0, '', 'Vous avez treize heures pour résoudre le labyrinthe, avant que ton petit frère ne devienne l\'un des nôtres... pour toujours.', '', '', '', '', '', ''), - (385, 'taunt', 'So, the is a piece of cake, is it? Well, let\'s see how you deal with this little slice... ', 0, 0, '', 'Donc, la est un jeu d\'enfant, n\'est-ce pas ? Eh bien, voyons comment tu gères cette petite tranche...', '', '', '', '', '', ''), - (386, 'taunt', 'Back off, I\'ll take you on, headstrong to take on anyone, I know that you are wrong, and this is not where you belong', 0, 0, '', 'Reculez, je vais vous attaquer, têtu à affronter n\'importe qui, je sais que vous vous trompez, et ce n\'est pas votre place', '', '', '', '', '', ''), - (387, 'taunt', 'Show me whatcha got!', 0, 0, '', 'Montre-moi ce que tu as!', '', '', '', '', '', ''), - (388, 'taunt', 'To the death!', 0, 0, '', 'A la mort!', '', '', '', '', '', ''), - (389, 'taunt', 'Twin blade action, for a clean close shave every time.', 0, 0, '', 'Action à double lame, pour un rasage de près propre à chaque fois.', '', '', '', '', '', ''), - (390, 'taunt', 'Bring it on!', 0, 0, '', 'Allez-y!', '', '', '', '', '', ''), - (391, 'taunt', 'You\'re goin\' down!', 0, 0, '', 'Tu descends!', '', '', '', '', '', ''), - (392, 'taunt', 'Stabby stab stab!', 0, 0, '', 'Coup de poignard poignardé!', '', '', '', '', '', ''), - (393, 'taunt', 'Let\'s get this over quick; time is mana.', 0, 0, '', 'Finissons-en vite ; le temps c\'est du mana.', '', '', '', '', '', ''), - (394, 'taunt', 'I do not think you realise the gravity of your situation.', 0, 0, '', 'Je ne pense pas que tu te rendes compte de la gravité de ta situation.', '', '', '', '', '', ''), - (395, 'taunt', 'I will bring honor to my family and my kingdom!', 0, 0, '', 'Je ferai honneur à ma famille et à mon royaume!', '', '', '', '', '', ''), - (396, 'taunt', 'Light, give me strength!', 0, 0, '', 'Lumière, donne-moi la force!', '', '', '', '', '', ''), - (397, 'taunt', 'My church is the field of battle - time to worship...', 0, 0, '', 'Mon église est le champ de bataille - il est temps d\'adorer...', '', '', '', '', '', ''), - (398, 'taunt', 'I hold you in contempt...', 0, 0, '', 'Je te méprise...', '', '', '', '', '', ''), - (399, 'taunt', 'Face the hammer of justice!', 0, 0, '', 'Affrontez le marteau de la justice!', '', '', '', '', '', ''), - (400, 'taunt', 'Prove your worth in the test of arms under the Light!', 0, 0, '', 'Prouvez votre valeur dans l\'épreuve des armes sous la Lumière!', '', '', '', '', '', ''), - (401, 'taunt', 'All must fall before the might and right of my cause, you shall be next!', 0, 0, '', 'Tout doit tomber devant la force et le droit de ma cause, vous serez le prochain!', '', '', '', '', '', ''), - (402, 'taunt', 'Prepare to die!', 0, 0, '', 'Préparez-vous à mourir!', '', '', '', '', '', ''), - (403, 'taunt', 'The beast with me is nothing compared to the beast within...', 0, 0, '', 'La bête avec moi n\'est rien comparée à la bête à l\'intérieur...', '', '', '', '', '', ''), - (404, 'taunt', 'Witness the firepower of this fully armed huntsman!', 0, 0, '', 'Soyez témoin de la puissance de feu de ce chasseur entièrement armé!', '', '', '', '', '', ''), - (405, 'critical health', 'Heal me! Quick!', 0, 0, '', 'Soigne moi! Vite!', '', '', '', '', '', ''), - (406, 'critical health', 'Almost dead! Heal me!', 0, 0, '', 'Presque mort! Soigne moi!', '', '', '', '', '', ''), - (407, 'critical health', 'Help! Heal me!', 0, 0, '', 'Aider! Soigne moi!', '', '', '', '', '', ''), - (408, 'critical health', 'Somebody! Heal me!', 0, 0, '', 'Quelqu\'un! Soigne moi!', '', '', '', '', '', ''), - (409, 'critical health', 'Heal! Heal! Heal!', 0, 0, '', 'Soigner! Soigner! Soigner!', '', '', '', '', '', ''), - (410, 'critical health', 'I am dying! Heal! Aaaaarhg!', 0, 0, '', 'Je meurs! Soigner! Aaaaarhg!', '', '', '', '', '', ''), - (411, 'critical health', 'Heal me!', 0, 0, '', 'Soigne moi!', '', '', '', '', '', ''), - (412, 'critical health', 'I will die. I will die. I will die. Heal!', 0, 0, '', 'Je vais mourir. Je vais mourir. Je vais mourir. Soigner!', '', '', '', '', '', ''), - (413, 'critical health', 'Healers, where are you? I am dying!', 0, 0, '', 'Guérisseurs, où êtes-vous ? Je meurs!', '', '', '', '', '', ''), - (414, 'critical health', 'Oh the pain. Heal me quick!', 0, 0, '', 'Ah la douleur. Guéris-moi vite!', '', '', '', '', '', ''), - (415, 'low health', 'Need heal', 0, 0, '', 'Besoin de guérir', '', '', '', '', '', ''), - (416, 'low health', 'Low health', 0, 0, '', 'Santé faible', '', '', '', '', '', ''), - (417, 'low health', 'Drop a heal. Please.', 0, 0, '', 'Dépose un soin. S\'il te plaît.', '', '', '', '', '', ''), - (418, 'low health', 'Could somebody drop a heal on me?', 0, 0, '', 'Quelqu\'un pourrait-il me soigner?', '', '', '', '', '', ''), - (419, 'low health', 'Hey! Better heal me now than rez later', 0, 0, '', 'Hey! Mieux vaut me soigner maintenant que rez plus tard', '', '', '', '', '', ''), - (420, 'low health', 'I am sorry. Need another heal', 0, 0, '', 'Je suis désolé. J\'ai besoin d\'un autre soin', '', '', '', '', '', ''), - (421, 'low health', 'Damn mobs. Heal me please', 0, 0, '', 'Maudits mobs. Guéris moi s\'il te plait', '', '', '', '', '', ''), - (422, 'low health', 'One more hit and I am done for. Heal please', 0, 0, '', 'Un coup de plus et c\'est fini. Guéris moi s\'il te plait', '', '', '', '', '', ''), - (423, 'low health', 'Are there any healers?', 0, 0, '', 'Y a-t-il des guérisseurs?', '', '', '', '', '', ''), - (424, 'low health', 'Why do they always punch me in the face? Need heal', 0, 0, '', 'Pourquoi me frappent-ils toujours au visage? Besoin de soins', '', '', '', '', '', ''), - (425, 'low health', 'Can anybody heal me a bit?', 0, 0, '', 'Quelqu\'un peut-il me guérir un peu?', '', '', '', '', '', ''), - (426, 'low mana', 'OOM', 0, 0, '', 'MOO', '', '', '', '', '', ''), - (427, 'low mana', 'I am out of mana', 0, 0, '', 'je n\'ai plus de mana', '', '', '', '', '', ''), - (428, 'low mana', 'Damn I wasted all my mana on this', 0, 0, '', 'Putain j\'ai gaspillé tout mon mana sur ça', '', '', '', '', '', ''), - (429, 'low mana', 'You should wait until I drink or regenerate my mana', 0, 0, '', 'Vous devriez attendre que je boive ou que je régénère mon mana', '', '', '', '', '', ''), - (430, 'low mana', 'Low mana', 0, 0, '', 'Mana faible', '', '', '', '', '', ''), - (431, 'low mana', 'No mana. Again?', 0, 0, '', 'Pas de mana. De nouveau?', '', '', '', '', '', ''), - (432, 'low mana', 'Low mana. Wanna drink', 0, 0, '', 'Mana faible. Je veux boire', '', '', '', '', '', ''), - (433, 'low mana', 'Do we have a vending machine? Out of mana again', 0, 0, '', 'Avons-nous un distributeur automatique? Plus de mana à nouveau', '', '', '', '', '', ''), - (434, 'low mana', 'My mana is history', 0, 0, '', 'Mon mana appartient à l\'histoire', '', '', '', '', '', ''), - (435, 'low mana', 'I\'d get some drinks next time. Out of mana', 0, 0, '', 'Je prendrais quelques verres la prochaine fois. Manque de mana', '', '', '', '', '', ''), - (436, 'low mana', 'Where is my mana?', 0, 0, '', 'Où est mon mana?', '', '', '', '', '', ''), - (437, 'aoe', 'Oh god!', 0, 0, '', 'Oh mon Dieu!', '', '', '', '', '', ''), - (438, 'aoe', 'I am scared', 0, 0, '', 'j\'ai peur', '', '', '', '', '', ''), - (439, 'aoe', 'We are done for', 0, 0, '', 'Nous avons fini pour', '', '', '', '', '', ''), - (440, 'aoe', 'This is over', 0, 0, '', 'C\'est terminé', '', '', '', '', '', ''), - (441, 'aoe', 'This ends now', 0, 0, '', 'Cela se termine maintenant', '', '', '', '', '', ''), - (442, 'aoe', 'Could somebody cast blizzard or something?', 0, 0, '', 'Quelqu\'un pourrait-il lancer le blizzard ou quelque chose comme ça?', '', '', '', '', '', ''), - (443, 'aoe', 'Damn. The tank aggroed all the mobs around', 0, 0, '', 'Mince. Le tank a agro toutes les mobs autour', '', '', '', '', '', ''), - (444, 'aoe', 'We gonna die. We gonna die. We gonna die.', 0, 0, '', 'Nous allons mourir. Nous allons mourir. Nous allons mourir.', '', '', '', '', '', ''), - (445, 'aoe', 'Whoa! So many toys to play with', 0, 0, '', 'Ouah ! Tant de jouets avec lesquels jouer', '', '', '', '', '', ''), - (446, 'aoe', 'I gonna kill them all!', 0, 0, '', 'Je vais tous les tuer!', '', '', '', '', '', ''), - (447, 'aoe', 'If the tank dies we are history', 0, 0, '', 'Si le tank meurt, nous appartenons à l\'histoire', '', '', '', '', '', ''), - (448, 'aoe', 'Aaaaaargh!', 0, 0, '', 'Aaaaaargh!', '', '', '', '', '', ''), - (449, 'aoe', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', 0, 0, '', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', '', '', '', '', '', ''), - (450, 'aoe', 'Right. What do we have in AOE?', 0, 0, '', 'D\'accord. Qu\'avons-nous en dégats de zone?', '', '', '', '', '', ''), - (451, 'aoe', 'This gets interesting', 0, 0, '', 'Cela devient intéressant', '', '', '', '', '', ''), - (452, 'aoe', 'Cool. Get them in one place for a good flamestrike', 0, 0, '', 'Cool. Rassemblez-les au même endroit pour un bon coup de flamme', '', '', '', '', '', ''), - (453, 'aoe', 'Kill! Kill! Kill!', 0, 0, '', 'Tuer! Tuer! Tuer!', '', '', '', '', '', ''), - (454, 'aoe', 'I think my pants are wet', 0, 0, '', 'Je pense que mon pantalon est mouillé', '', '', '', '', '', ''), - (455, 'aoe', 'We are history', 0, 0, '', 'Nous sommes l\'histoire', '', '', '', '', '', ''), - (456, 'aoe', 'I hope healers are ready. Leeeeroy!', 0, 0, '', 'J\'espère que les guérisseurs sont prêts. Leeeeeroy!', '', '', '', '', '', ''), - (457, 'aoe', 'I hope they won\'t come for me', 0, 0, '', 'j\'espère qu\'ils ont gagné, qu\'ils ne viendront pas pour moi', '', '', '', '', '', ''), - (458, 'aoe', 'Oh no. I can\'t see at this slaugther', 0, 0, '', 'Oh non. Je ne peux pas voir à ce massacre', '', '', '', '', '', ''), - (459, 'loot', 'I hope there will be some money', 0, 0, '', 'j\'espère qu\'il y aura de l\'argent', '', '', '', '', '', ''), - (460, 'loot', 'Loot! Loot!', 0, 0, '', 'Butin! Butin!', '', '', '', '', '', ''), - (461, 'loot', 'My precious', 0, 0, '', 'Mon précieux', '', '', '', '', '', ''), - (462, 'loot', 'I hope there is a shiny epic item waiting for me there', 0, 0, '', 'J\'espère qu\'il y a un objet épique brillant qui m\'attend ici', '', '', '', '', '', ''), - (463, 'loot', 'I have deep pockets and bags', 0, 0, '', 'J\'ai des poches et des sacs profonds', '', '', '', '', '', ''), - (464, 'loot', 'All is mine!', 0, 0, '', 'Tout est à moi!', '', '', '', '', '', ''), - (465, 'loot', 'Hope no gray shit today', 0, 0, '', 'J\'espère pas de merde grise aujourd\'hui', '', '', '', '', '', ''), - (466, 'loot', 'This loot is MINE!', 0, 0, '', 'Ce butin est à MOI!', '', '', '', '', '', ''), - (467, 'loot', 'Looting is disgusting but I need money', 0, 0, '', 'Le pillage est dégoûtant mais j\'ai besoin d\'argent', '', '', '', '', '', ''), - (468, 'loot', 'Gold!', 0, 0, '', 'Or!', '', '', '', '', '', ''), - (469, 'loot', 'OK. Let\'s see what they\'ve got', 0, 0, '', 'D\'ACCORD. Voyons ce qu\'ils ont', '', '', '', '', '', ''), - (470, 'loot', 'Do not worry. I will loot eveything', 0, 0, '', 'Ne t\'inquiète pas. je vais tout piller', '', '', '', '', '', ''), - (471, 'loot', 'I am loot ninja', 0, 0, '', 'je suis un ninja de butin', '', '', '', '', '', ''), - (472, 'loot', 'Do I neeed to roll?', 0, 0, '', 'Dois-je recommencer?', '', '', '', '', '', ''), - (473, 'loot', 'Somebody explain me, where they did put all this stuff?', 0, 0, '', 'Quelqu\'un m\'explique, où ils ont mis tout ça?', '', '', '', '', '', ''), - (474, 'loot', 'No, I won\'t loot gray shit', 0, 0, '', 'Non, je ne pillerai pas la merde grise', '', '', '', '', '', ''), - (475, 'loot', 'I\'m first. I\'m first. I\'m first.', 0, 0, '', 'Je suis le premier. Je suis le premier. Je suis le premier.', '', '', '', '', '', ''), - (476, 'loot', 'Give me your money!', 0, 0, '', 'Donne-moi ton argent!', '', '', '', '', '', ''), - (477, 'loot', 'My pockets are empty, I need to fill them', 0, 0, '', 'Mes poches sont vides, j\'ai besoin de les remplir', '', '', '', '', '', ''), - (478, 'loot', 'I\'ve got a new bag for this', 0, 0, '', 'J\'ai un nouveau sac pour ça', '', '', '', '', '', ''), - (479, 'loot', 'I hope I won\'t aggro anybody while looting', 0, 0, '', 'J\'espère que je n\'agresserai personne pendant le pillage', '', '', '', '', '', ''), - (480, 'loot', 'Please don\'t watch. I am looting', 0, 0, '', 'S\'il vous plaît, ne regardez pas. je pille', '', '', '', '', '', ''), - (481, 'loot', 'Ha! You won\'t get any piece of it!', 0, 0, '', 'Ha! Vous n\'en aurez aucun morceau!', '', '', '', '', '', ''), - (482, 'loot', 'Looting is cool', 0, 0, '', 'Le pillage c\'est cool', '', '', '', '', '', ''), - (483, 'loot', 'I like new gear', 0, 0, '', 'j\'aime le nouveau matos', '', '', '', '', '', ''), - (484, 'loot', 'I\'l quit if there is nothing valuable again', 0, 0, '', 'J\'arrêterai s\'il n\'y a plus rien de précieux', '', '', '', '', '', ''), - (485, 'loot', 'I hope it is be a pretty ring', 0, 0, '', 'j\'espère que c\'est une jolie bague', '', '', '', '', '', ''), - (486, 'loot', 'I\'l rip the loot from you', 0, 0, '', 'Je t\'arracherai le butin', '', '', '', '', '', ''), - (487, 'loot', 'Everybody stay off. I\'m going to loot', 0, 0, '', 'Tout le monde reste à l\'écart. je vais piller', '', '', '', '', '', ''), - (488, 'loot', 'Sweet loot', 0, 0, '', 'Doux butin', '', '', '', '', '', ''), - (489, 'loot', 'The Roll God! Give me an epic today', 0, 0, '', 'Le Dieu du rouleau ! Donnez-moi de l\'épique aujourd\'hui', '', '', '', '', '', ''), - (490, 'loot', 'Please give me new toys', 0, 0, '', 'S\'il te plaît, donne-moi de nouveaux jouets', '', '', '', '', '', ''), - (491, 'loot', 'I hope they carry tasties', 0, 0, '', 'J\'espère qu\'ils portent des saveurs', '', '', '', '', '', ''), - (492, 'loot', 'The gold is mine. I\'l leave everyting, I promise', 0, 0, '', 'L\'or est à moi. Je laisse tout, je promets', '', '', '', '', '', ''), - (493, 'loot', 'No, I can\'t resist', 0, 0, '', 'Non, je ne peux pas résister', '', '', '', '', '', ''), - (494, 'loot', 'I want more!', 0, 0, '', 'Je veux plus!', '', '', '', '', '', ''), - (495, 'low ammo', 'I have few left!', 0, 0, '', 'Il me reste peu de !', '', '', '', '', '', ''), - (496, 'low ammo', 'I need more !', 0, 0, '', 'J\'ai besoin de plus de !', '', '', '', '', '', ''), - (497, 'low ammo', '100 left!', 0, 0, '', 'Il reste 100 !', '', '', '', '', '', ''), - (498, 'no ammo', 'That\'s it! No !', 0, 0, '', 'C\'est ça! Pas de !', '', '', '', '', '', ''), - (499, 'no ammo', 'And you have my bow... Oops, no !', 0, 0, '', 'Et vous avez mon arc... Oups, pas de !', '', '', '', '', '', ''), - (500, 'no ammo', 'Need ammo!', 0, 0, '', 'Besoin de munitions!', '', '', '', '', '', ''), - (501, 'hello', 'Hello', 0, 0, '', 'Salut', '', '', '', '', '', 'Привет'), - (502, 'hello', 'Hello!', 0, 0, '', 'Salut !', '', '', '', '', '', 'Привет!'), - (503, 'hello', 'Hi', 0, 0, '', 'Bonjour', '', '', '', '', '', 'Прив'), - (504, 'hello', 'Hi!', 0, 0, '', 'Bonjour !', '', '', '', '', '', 'Прив!'), - (505, 'hello', 'Hello there!', 0, 0, '', 'Salut par ici !', '', '', '', '', '', 'Здарова!'), - (506, 'hello_follow', 'Hello, I follow you!', 0, 0, '', 'Salut, je te suis !', '', '', '', '', '', 'Привет, иду за тобой!'), - (507, 'hello_follow', 'Hello, lead the way!', 0, 0, '', 'Salut, après toi !', '', '', '', '', '', 'Привет, веди!'), - (508, 'hello_follow', 'Hi, lead the way!', 0, 0, '', 'Bonjour, après vous !', '', '', '', '', '', 'Прив, веди!'), - (509, 'logout_cancel', 'Logout cancelled!', 0, 0, '', 'Logout annulé', '', '', '', '', '', 'Логаут отменен!'), - (510, 'logout_start', 'I\'m logging out!', 0, 0, '', 'Je déconnecte', '', '', '', '', '', 'Я выхожу из игры!'), - (511, 'goodbye', 'Goodbye!', 0, 0, '', 'Au revoir', '', '', '', '', '', 'Пока!'), - (512, 'goodbye', 'Bye bye!', 0, 0, '', 'Salut salut++', '', '', '', '', '', 'Пока пока!'), - (513, 'goodbye', 'See you later!', 0, 0, '', 'A plus tard', '', '', '', '', '', 'Увидимся позже!'), - (514, 'quest_accept', 'Quest accepted', 0, 0, '', 'Quête accepté', '', '', '', '', '', 'Квест взят'), - (515, 'quest_remove', 'Quest removed', 0, 0, '', 'Quête supprimé', '', '', '', '', '', 'Квест отменен'), - (516, 'quest_cant_take', 'I can\'t take this quest', 0, 0, '', 'Je ne peut pas prendre la quête', '', '', '', '', '', 'Я не могу взять этот квест'), - (517, 'following', 'Following', 0, 0, '', 'Je vous suis', '', '', '', '', '', 'Следую'), - (518, 'staying', 'Staying', 0, 0, '', 'Je reste en position', '', '', '', '', '', 'Стою'), - (519, 'fleeing', 'Fleeing', 0, 0, '', 'Au secours !!', '', '', '', '', '', 'Убегаю'), - (520, 'fleeing_far', 'I won\'t flee with you, you are too far away', 0, 0, '', 'Tu es trop loin je ne peut pas fuir avec toi', '', '', '', '', '', 'Я с тобой не побегу, ты слишком далеко'), - (521, 'grinding', 'Grinding', 0, 0, '', 'Je grind', '', '', '', '', '', 'Гриндю'), - (522, 'attacking', 'Attacking', 0, 0, '', 'J\'attack', '', '', '', '', '', 'Атакую'), - (523, 'wait_travel_close', 'I am close, wait for me!', 0, 0, '', 'Attends moi je suis proche', '', '', '', '', '', 'Я тут рядом, подожди!'), - (524, 'wait_travel_close', 'I\'m not far, please wait!', 0, 0, '', 'Je suis à côté s\'il te plait attends moi !', '', '', '', '', '', 'Я недалеко, погодите!'), - (525, 'wait_travel_medium', 'I\'m heading to your location', 0, 0, '', 'J\'arrive sur ta position', '', '', '', '', '', 'Двигаюсь к тебе'), - (526, 'wait_travel_medium', 'I\'m coming to you', 0, 0, '', 'Je viens à toi', '', '', '', '', '', 'Иду к тебе'), - (527, 'wait_travel_far', 'I\'m traveling to your location', 0, 0, '', 'Je voyage jusqu\'à toi', '', '', '', '', '', 'Направляюсь к тебе'), - (528, 'wait_travel_far', 'I\'m trying to get to you', 0, 0, '', 'J\'essai de vous rejoindre', '', '', '', '', '', 'Пытаюсь до тебя добраться'), - (529, 'error_far', 'It is too far away', 0, 0, '', 'C\'est trop loin', '', '', '', '', '', 'Слишком далеко'), - (530, 'error_water', 'It is under water', 0, 0, '', 'C\'est sous l\'eau', '', '', '', '', '', 'Это под водой'), - (531, 'error_cant_go', 'I can\'t go there', 0, 0, '', 'Je ne peut pas atteindre cette destination', '', '', '', '', '', 'Я не могу туда пройти'), - (532, 'error_guild', 'I\'m not in your guild!', 0, 0, '', 'Je ne fais pas parti de ta guilde', '', '', '', '', '', 'Я не в твоей гильдии'), - (533, 'error_gbank_found', 'Can not find a guild bank nearby', 0, 0, '', 'Il n\'y a pas de coffre de guilde à proximité', '', '', '', '', '', 'Не могу найти гильд банк рядом'), - (534, 'error_cant_put', 'I can\'t put ', 0, 0, '', '', '', '', '', '', '', 'Я не могу положить'), - (535, 'error_gbank_rights', 'I have no rights to put items in the first guild bank tab', 0, 0, '', 'Je n\'ai pas les droits de dépôt à la banque', '', '', '', '', '', 'Нет прав чтобы класть вещи в первую вкладку гильд банка'), - (536, 'gbank_put', ' put to guild bank', 0, 0, '', '', '', '', '', '', '', ' теперь в гильд банке'); -/*!40000 ALTER TABLE `ai_playerbot_texts` ENABLE KEYS */; +INSERT INTO `ai_playerbot_texts` (`name`, `text`, `say_type`, `reply_type`, `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) VALUES + +-- strings +('string_unknown_area', 'the middle of nowhere', 0, 0, '', '', '', '', '', '', '', ''), +('string_unknown_area', 'an undisclosed location', 0, 0, '', '', '', '', '', '', '', ''), +('string_unknown_area', 'somewhere', 0, 0, '', '', '', '', '', '', '', ''), + +('string_empty_link', 'something', 0, 0, '', '', '', '', '', '', '', ''), + + +-- looting item events +-- usable placeholders: +-- %item_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_looting_item_normal', 'wonder what %item_link tastes like', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'nooo, I got %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'aww not this trash again %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'seem to be looting trash %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'well, it\'s better than nothing I guess %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'not sure what to do with %item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_normal', 'wonder what %item_link tastes like', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'well, I can keep looting %item_link all day', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'another day, another %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'looted some %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'some %item_link is alright', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_uncommon', 'not bad, I just got %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'just looted %item_link in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'I could put that to good use %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'money money money %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'got %item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_rare', '%item_link is hunter bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', '%item_link is %my_class bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'RNG is not bad today %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'sweet %item_link, freshly looted', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'wow, I just got %item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_rare', '%item_link is hunter bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', '%item_link is %my_class bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'RNG is not bad today %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'sweet %item_link, freshly looted', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_epic', 'OMG, look at what I just got %item_link!!!', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_legendary', 'No @#$@% way! This can not be, I got %item_link, this is insane', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_artifact', 'No @#$@% way! This can not be, I got %item_link, this is insane', 0, 0, '', '', '', '', '', '', '', ''), + + + + +-- quest events +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_accepted_generic', 'I have just taken the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_accepted_generic', 'just accepted %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_accepted_generic', '%quest_link gonna try to complete this one', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_accepted_generic', 'took %quest_link in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %quest_obj_available +-- %quest_obj_required +-- %quest_obj_missing +-- %quest_obj_name +-- %quest_obj_full_formatted +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_add_kill_objective_completed', 'Finally done with the %quest_obj_name for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_completed', 'finally got %quest_obj_available/%quest_obj_required of %quest_obj_name for the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_completed', '%quest_obj_full_formatted for the %quest_link, at last', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_quest_update_add_kill_objective_progress', 'Oof, got %quest_obj_available/%quest_obj_required %quest_obj_name for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_progress', 'still need %quest_obj_missing more of %quest_obj_name for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_progress', '%quest_obj_full_formatted, still working on %quest_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %quest_obj_available +-- %quest_obj_required +-- %quest_obj_missing +-- %item_link +-- %quest_obj_full_formatted +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_add_item_objective_completed', 'Finally done with the %item_link for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_completed', 'finally got %quest_obj_available/%quest_obj_required of %item_link for the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_completed', '%quest_obj_full_formatted for the %quest_link, at last', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_quest_update_add_item_objective_progress', 'Oof, got %quest_obj_available/%quest_obj_required %item_link for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_progress', 'still need %quest_obj_missing more of %item_link for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_progress', '%quest_obj_full_formatted, still working on %quest_link', 0, 0, '', '', '', '', '', '', '', ''), + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_failed_timer', 'Failed to finish %quest_link in time...', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_failed_timer', 'Ran out of time for %quest_link :(', 0, 0, '', '', '', '', '', '', '', ''), + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_complete', 'I have completed all objectives for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_complete', 'Completed all objectives for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_complete', 'Gonna turn in the %quest_link soon, just finished all objectives', 0, 0, '', '', '', '', '', '', '', ''), + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_turned_in', 'Yess, I have finally turned in the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'turned in the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'managed to finish %quest_link, just turned in', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'just turned in %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'just turned in %quest_link in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- kill mob events +-- usable placeholders: +-- %victim_name +-- %zone_name +-- %area_name +-- %victim_level +-- %my_race +-- %my_class +-- %my_level +('broadcast_killed_normal', 'another %victim_name down', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_normal', 'I keep killing %victim_name, nothing to talk about', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_normal', 'another %victim_name bites the dust', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_normal', 'one less %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_elite', 'Took down this elite bastard %victim_name!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_player', 'killed elite %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_rareelite', 'Fooof, managed to take down %victim_name!', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_worldboss', 'That was sick! Just killed %victim_name! Can tell tales now', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_rare', 'Yoo, I just killed %victim_name!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_player', 'killed rare %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_unknown', 'WTF did I just kill? %victim_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_pet', 'Just killed that pet %victim_name', 0, 0, '', '', '', '', '', '', '', ''), + + +-- for broadcast_killed_player additionally can use %victim_class +('broadcast_killed_player', 'Oh yeah, I just killed %victim_name', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_player', 'killed %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- levelup events +-- usable placeholders: +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('broadcast_levelup_generic', 'Ding!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_generic', 'Yess, I am level %my_level!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_generic', 'I just leveled up', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_levelup_10x', 'I am level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_10x', 'getting stronger, already level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_10x', 'Just reached level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_levelup_max_level', 'OMG, finally level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_max_level', '%my_level!!! can do endgame content now', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_max_level', 'fresh new level %my_level %my_class!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_max_level', 'one more level %my_level %my_race %my_class!', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- guild +-- usable placeholders: +-- %other_name +-- %other_class +-- %other_race +-- %other_level +('broadcast_guild_promotion', 'Good job %other_name. You deserved this.', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_guild_demotion', 'That was awful %other_name. I hate to do this but...', 0, 0, '', '', '', '', '', '', '', ''), + + + + +-- ///////////////////////////// +-- suggestions + + +-- random instance +-- usable placeholders: +-- %my_role +-- %instance_name +-- %my_class +-- %my_race +-- %my_level +('suggest_instance', 'Anyone wants %instance_name?', 0, 0, '', 'Quelqu\'un fait %instance_name ?', '', '', '', '¿Alguien quiere ir a %instance_name?', '', ''), +('suggest_instance', 'Any groups for %instance_name?', 0, 0, '', 'Des groupes pour %instance_name ?', '', '', '', '¿Algún grupo para %instance_name?', '', ''), +('suggest_instance', 'Need help for %instance_name?', 0, 0, '', 'Besoin d\'aide pour %instance_name ?', '', '', '', '¿Alguien necesita ayuda con %instance_name?', '', ''), +('suggest_instance', 'LFD: %instance_name.', 0, 0, '', 'Cherche à faire : %instance_name', '', '', '', 'Busco grupo para %instance_name.', '', ''), +('suggest_instance', 'Anyone needs %my_role for %instance_name?', 0, 0, '', 'Quelqu\'un a besoin de %my_role pour %instance_name ?', '', '', '', '¿Alguien necesita un %my_role para %instance_name?', '', ''), +('suggest_instance', 'Missing %my_role for %instance_name?', 0, 0, '', '%my_role manquant pour %instance_name ?', '', '', '', '¿Buscando un %my_role para %instance_name?', '', ''), +('suggest_instance', 'Can be a %my_role for %instance_name.', 0, 0, '', 'Peut être un %my_role pour %instance_name', '', '', '', 'Puedo ser un %my_role para %instance_name.', '', ''), +('suggest_instance', 'Need help with %instance_name?', 0, 0, '', 'Besoin d\'aide avec %instance_name ?', '', '', '', '¿Alguien necesita ayuda con %instance_name?', '', ''), +('suggest_instance', 'Need %my_role help with %instance_name?', 0, 0, '', 'Besoin d\'aide %my_role avec %instance_name ?', '', '', '', '¿Necesitas ayuda de %my_role con %instance_name?', '', ''), +('suggest_instance', 'Anyone needs gear from %instance_name?', 0, 0, '', 'Quelqu\'un a besoin d\'équipement de %instance_name ?', '', '', '', '¿Alguien necesita equipo de %instance_name?', '', ''), +('suggest_instance', 'A little grind in %instance_name?', 0, 0, '', 'Un peu de grind dans %instance_name ?', '', '', '', '¿Un poco de farmeo en %instance_name?', '', ''), +('suggest_instance', 'WTR %instance_name', 0, 0, '', 'Cherche à rejoindre %instance_name', '', '', '', 'WTR %instance_name', '', ''), +('suggest_instance', 'Need help for %instance_name.', 0, 0, '', 'Besoin d\'aide pour %instance_name', '', '', '', 'Necesito ayuda para %instance_name.', '', ''), +('suggest_instance', 'Wanna run %instance_name.', 0, 0, '', 'Je veux faire %instance_name', '', '', '', 'Quiero hacer %instance_name.', '', ''), +('suggest_instance', '%my_role looks for %instance_name.', 0, 0, '', '%my_role recherche %instance_name', '', '', '', '%my_role busca %instance_name.', '', ''), +('suggest_instance', 'What about %instance_name?', 0, 0, '', 'Et %instance_name ?', '', '', '', '¿Qué pasa con %instance_name?', '', ''), +('suggest_instance', 'Who wants to farm %instance_name?', 0, 0, '', 'Qui veut exploiter %instance_name ?', '', '', '', '¿Quién quiere farmear %instance_name?', '', ''), +('suggest_instance', 'Go in %instance_name?', 0, 0, '', 'Aller à %instance_name ?', '', '', '', '¿Vamos a %instance_name?', '', ''), +('suggest_instance', 'Looking for %instance_name.', 0, 0, '', 'À la recherche de %instance_name', '', '', '', 'Buscando gente para %instance_name.', '', ''), +('suggest_instance', 'Need help with %instance_name quests?', 0, 0, '', 'Besoin d\'aide pour les quêtes %instance_name ?', '', '', '', '¿Necesitas ayuda con las misiones en %instance_name?', '', ''), +('suggest_instance', 'Wanna quest in %instance_name.', 0, 0, '', 'Je veux une quête dans %instance_name', '', '', '', 'Quiero hacer una vuelta rapida en %instance_name.', '', ''), +('suggest_instance', 'Anyone with quests in %instance_name?', 0, 0, '', 'Quelqu\'un a des quêtes dans %instance_name ?', '', '', '', '¿Alguien con misiones en %instance_name?', '', ''), +('suggest_instance', 'Could help with quests in %instance_name.', 0, 0, '', 'Peux aider pour les quêtes dans %instance_name', '', '', '', 'Podría ayudar con las misiones en %instance_name.', '', ''), +('suggest_instance', '%my_role: any place in group for %instance_name?', 0, 0, '', '%my_role : n\'importe quel rôle dans le groupe pour %instance_name ?', '', '', '', '%my_role: ¿algún lugar en el grupo para %instance_name?', '', ''), +('suggest_instance', 'Does anybody still run %instance_name this days?', 0, 0, '', 'Est-ce que quelqu\'un fait encore %instance_name ces jours-ci ?', '', '', '', '¿Alguien todavía hace %instance_name estos días?', '', ''), +('suggest_instance', '%instance_name: anyone wants to take a %my_role?', 0, 0, '', '%instance_name : quelqu\'un veut prendre un %my_role ?', '', '', '', '¿Alguien quiere un %my_role para %instance_name?', '', ''), +('suggest_instance', 'Is there any point being %my_role in %instance_name?', 0, 0, '', 'Y a-t-il un intérêt à être %my_role dans %instance_name ?', '', '', '', '¿Tiene algún sentido ser %my_role en %instance_name?', '', ''), +('suggest_instance', 'It is really worth to go to %instance_name?', 0, 0, '', 'Cela vaut-il vraiment la peine d\'aller dans %instance_name ?', '', '', '', '¿Realmente vale la pena ir a %instance_name?', '', ''), +('suggest_instance', 'Anybody needs more people for %instance_name?', 0, 0, '', 'Quelqu\'un a besoin de plus de personnes pour %instance_name ?', '', '', '', '¿Alguien necesita más personas para %instance_name?', '', ''), +('suggest_instance', '%instance_name bosses drop good gear. Wanna run?', 0, 0, '', 'Les boss %instance_name drop du bon équipement. Tu veux courir ?', '', '', '', 'Los jefes en %instance_name sueltan buen equipo. ¿Quieres ir?', '', ''), +('suggest_instance', 'What about %instance_name?', 0, 0, '', 'Et %instance_name ?', '', '', '', '¿Qué pasa con %instance_name?', '', ''), +('suggest_instance', 'Anybody needs %my_role?', 0, 0, '', 'Quelqu\'un a besoin de %my_role ?', '', '', '', '¿Alguien necesita un %my_role?', '', ''), +('suggest_instance', 'Anyone needs %my_role?', 0, 0, '', 'Quelqu\'un a besoin de %my_role ?', '', '', '', '¿Alguien hacer un grupo con un %my_role?', '', ''), +('suggest_instance', 'Who wants %instance_name?', 0, 0, '', 'Qui veut %instance_name ?', '', '', '', '¿Quién quiere %instance_name?', '', ''), +('suggest_instance', 'Can anybody summon me at %instance_name?', 0, 0, '', 'Quelqu\'un peut-il me TP à %instance_name ?', '', '', '', '¿Alguien puede invocarme en %instance_name?', '', ''), +('suggest_instance', 'Meet me in %instance_name', 0, 0, '', 'Rencontrez-moi dans %instance_name', '', '', '', 'Encuéntrame en %instance_name', '', ''), +('suggest_instance', 'Wanna quick %instance_name run', 0, 0, '', 'Je veux faire rapidement %instance_name', '', '', '', 'Quiero ir a %instance_name rápido', '', ''), +('suggest_instance', 'Wanna full %instance_name run', 0, 0, '', 'Je veux faire %instance_name complètement', '', '', '', 'Quiero hacer %instance_name completa', '', ''), +('suggest_instance', 'How many times were you in %instance_name?', 0, 0, '', 'Combien de fois avez-vous été dans %instance_name ?', '', '', '', '¿Cuántas veces estuviste en %instance_name?', '', ''), +('suggest_instance', 'Another %instance_name run?', 0, 0, '', 'Une autre exécution de %instance_name ?', '', '', '', '¿Otra vuelta en %instance_name ?', '', ''), +('suggest_instance', 'Wiped in %instance_name? Take me instead!', 0, 0, '', 'Effacé dans %instance_name ? Prends-moi plutôt !', '', '', '', '¿Borrado en %instance_name? ¡Tómame a mí en su lugar!', '', ''), +('suggest_instance', 'Take me in %instance_name please.', 0, 0, '', 'Prenez-moi dans %instance_name s\'il vous plaît.', '', '', '', 'Tómame en %instance_name por favor.', '', ''), +('suggest_instance', 'Quick %instance_name run?', 0, 0, '', 'Faire rapidement %instance_name ?', '', '', '', '¿Partida rápida de %instance_name?', '', ''), +('suggest_instance', 'Full %instance_name run?', 0, 0, '', 'Clean complet dans %instance_name ?', '', '', '', '¿Partida completa de %instance_name?', '', ''), +('suggest_instance', 'Who can take %my_role to %instance_name?', 0, 0, '', 'Qui peut prendre %my_role à %instance_name ?', '', '', '', '¿Quién puede ir de %my_role para %instance_name?', '', ''), +('suggest_instance', 'LFG %instance_name, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_instance', '%my_role LFG %instance_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- random quest +-- usable placeholders: +-- %my_role +-- %quest_link +-- %quest_level +-- %my_class +-- %my_race +-- %my_level +('suggest_quest', 'Need help with %quest_link?', 0, 0, '', 'Besoin d\'aide avec %quest_link ?', '', '', '', '¿Alguien necesita ayuda con %quest_link?', '', ''), +('suggest_quest', 'Anyone wants to share %quest_link?', 0, 0, '', 'Quelqu\'un veut partager %quest_link ?', '', '', '', '¿Alguien quiere hacer %quest_link?', '', ''), +('suggest_quest', 'Anyone doing %quest_link?', 0, 0, '', 'Quelqu\'un fait %quest_link ?', '', '', '', '¿Alguien está haciendo %quest_link?', '', ''), +('suggest_quest', 'Wanna do %quest_link.', 0, 0, '', 'Je veux faire %quest_link', '', '', '', '¿Una ayudita con %quest_link?', '', ''), + + +-- random trade? +-- usable placeholders: +-- %my_role +-- %category +-- %my_class +-- %my_race +-- %my_level +('suggest_trade', 'Anyone to farm %category?', 0, 0, '', 'Quelqu\'un pour farm %category ?', '', '', '', '¿Alguien para farmear %category?', '', ''), +('suggest_trade', 'Looking for help farming %category.', 0, 0, '', 'Vous cherchez de l\'aide pour farmer %category', '', '', '', 'Buscando ayuda para farmear %category.', '', ''), +('suggest_trade', 'Damn %category are so expensive!', 0, 0, '', 'Putain %category sont si chers!', '', '', '', '¡Malditas %category son tan caras!', '', ''), +('suggest_trade', 'Wanna %category.', 0, 0, '', 'Je veux %category', '', '', '', 'Quiero %category.', '', ''), +('suggest_trade', 'Need help with %category.', 0, 0, '', 'Besoin d\'aide avec %category', '', '', '', 'Necesito ayuda con %category.', '', ''), +('suggest_trade', 'WTB %category.', 0, 0, '', 'Cherche à acheter %category', '', '', '', 'Quiero comprar %category.', '', ''), +('suggest_trade', 'Anyone interested in %category?', 0, 0, '', 'Quiconque est intéressé par %category?', '', '', '', '¿Alguien interesado en %category?', '', ''), +('suggest_trade', 'WTS %category.', 0, 0, '', 'Cherche à vendre %category', '', '', '', 'Quiero vender %category.', '', ''), +('suggest_trade', 'I am selling %category cheaper than AH.', 0, 0, '', 'Je vends %category moins cher que l\'hôtel des ventes.', '', '', '', 'Estoy vendiendo %category más barato que en las subastas.', '', ''), +('suggest_trade', 'Who wants to farm %category?', 0, 0, '', 'Qui veut farmer %category ?', '', '', '', '¿Quién quiere farmear %category?', '', ''), +('suggest_trade', 'Wanna farm %category.', 0, 0, '', 'Je veux farmer %category', '', '', '', 'Quiero farmear %category.', '', ''), +('suggest_trade', 'Looking for party after %category.', 0, 0, '', 'Recherche de partie après %category', '', '', '', 'Buscando grupo después de %category.', '', ''), +('suggest_trade', 'Any %category are appreciated.', 0, 0, '', 'Toute %category est appréciée.', '', '', '', 'Cualquier %category es apreciada.', '', ''), +('suggest_trade', 'Buying anything of %category.', 0, 0, '', 'Acheter quoi que ce soit de %category', '', '', '', 'Comprando algo de %category.', '', ''), +('suggest_trade', 'Wow, anybody is farming %category!', 0, 0, '', 'Wow, quelqu\'un farm %category !', '', '', '', '¡Guau, alguien está farmeando %category!', '', ''), +('suggest_trade', '%category are selling mad in the AH.', 0, 0, '', '%category se vendent follement dans l\'hôtel des ventes.', '', '', '', '%category están vendiendo locos en las subastas.', '', ''), +('suggest_trade', 'AH is hot for %category.', 0, 0, '', 'Hôtel des ventes est chaud pour %category', '', '', '', 'Las subastas estan caliente para %category.', '', ''), +('suggest_trade', '%category are on the market.', 0, 0, '', '%category sont sur le marché.', '', '', '', '%category están en el mercado.', '', ''), +('suggest_trade', 'Wanna trade some %category.', 0, 0, '', 'Je veux échanger une %category', '', '', '', 'Quiero intercambiar alguna %category.', '', ''), +('suggest_trade', 'Need more %category.', 0, 0, '', 'Besoin de plus de %category', '', '', '', 'Necesito más %category.', '', ''), +('suggest_trade', 'Anybody can spare some %category?', 0, 0, '', 'Quelqu\'un peut-il épargner une %category ?', '', '', '', '¿Alguien puede ahorrar algo de %category?', '', ''), +('suggest_trade', 'Who wants %category?', 0, 0, '', 'Qui veut %category ?', '', '', '', '¿Quién quiere %category?', '', ''), +('suggest_trade', 'Some %category please?', 0, 0, '', 'Une %category s\'il vous plaît ?', '', '', '', '¿Alguna %category, por favor?', '', ''), +('suggest_trade', 'I should have got skill for %category.', 0, 0, '', 'J\'aurais dû avoir une compétence pour %category', '', '', '', 'Debería haber adquirido habilidad para %category.', '', ''), +('suggest_trade', 'I am dying for %category.', 0, 0, '', 'Je meurs d\'envie pour %category', '', '', '', 'Me muero por %category.', '', ''), +('suggest_trade', 'People are killing for %category.', 0, 0, '', 'Les gens tuent pour %category', '', '', '', 'La gente está matando por %category.', '', ''), +('suggest_trade', '%category is a great bargain!', 0, 0, '', '%category est une bonne affaire!', '', '', '', '%category es una gran ganga!', '', ''), +('suggest_trade', 'Everybody is mad for %category!', 0, 0, '', 'Tout le monde est fou de %category !', '', '', '', '¡Todo el mundo está loco por %category!', '', ''), +('suggest_trade', 'Where is the best place to farm for %category?', 0, 0, '', 'Quel est le meilleur endroit pour farmer pour %category ?', '', '', '', '¿Dónde está el mejor lugar para farmear para %category?', '', ''), +('suggest_trade', 'I am all set for %category.', 0, 0, '', 'Je suis prêt pour %category', '', '', '', 'Estoy listo para %category.', '', ''), +('suggest_trade', 'Is it good to sell %category?', 0, 0, '', 'Est-il bon de vendre %category ?', '', '', '', '¿Es bueno vender %category?', '', ''), +('suggest_trade', 'I\'d probably keep all my %category with me.', 0, 0, '', 'Je garderais probablement toute ma %category avec moi.', '', '', '', 'Probablemente mantendría toda mi %category conmigo', '', ''), +('suggest_trade', 'Need group? Maybe to farm some %category?', 0, 0, '', 'Besoin de groupe ? Peut-être pour farmer une certaine %category ?', '', '', '', '¿Necesitas un grupo? ¿Tal vez para farmear alguna %category?', '', ''), +('suggest_trade', 'I am still thinking about %category.', 0, 0, '', 'Je pense toujours à %category', '', '', '', 'Todavía estoy pensando en %category.', '', ''), +('suggest_trade', 'I heard about %category already, but my pockets are empty.', 0, 0, '', 'J\'ai déjà entendu parler de %category , mais mes poches sont vides.', '', '', '', 'Ya escuché sobre %category, pero mis bolsillos están vacíos.', '', ''), +('suggest_trade', 'LFG for %category', 0, 0, '', 'Cherche un groupe pour %category', '', '', '', 'Busco grupo para %category', '', ''), +('suggest_trade', 'Would selling %category make me rich?', 0, 0, '', 'Vendre %category me rendrait-il riche?', '', '', '', '¿Vender %category me haría rico?', '', ''), +('suggest_trade', 'OK. I an farming %category tomorrow.', 0, 0, '', 'D\'ACCORD. Je farm %category demain.', '', '', '', 'OK. Tengo una sesion de farmeo de %category mañana.', '', ''), +('suggest_trade', 'Everyone is talking about %category.', 0, 0, '', 'Tout le monde parle de %category', '', '', '', 'Todos hablan de %category', '', ''), +('suggest_trade', 'I saw at least ten people farming for %category.', 0, 0, '', 'J\'ai vu au moins dix personnes farmer pour %category', '', '', '', 'Vi al menos diez personas farmeando para %category.', '', ''), +('suggest_trade', 'I sold all my %category yesterday. I am completely broke!', 0, 0, '', 'J\'ai vendu tout mon %category hier. Je suis complètement fauché!', '', '', '', 'Ayer vendí todo mi %category. ¡Estoy completamente arruinado!', '', ''), +('suggest_trade', 'Wanna join a guild farming for %category.', 0, 0, '', 'Je veux rejoindre une guilde farmant pour %category', '', '', '', 'Quiero unirme a una hermandad de farmeo para %category.', '', ''), + + + +-- random faction rep grind +-- usable placeholders: +-- %my_role +-- %rep_level +-- %rndK +-- %faction +-- %my_class +-- %my_race +-- %my_level +('suggest_faction', 'Anyone farming %faction rep?', 0, 0, '', 'Quelqu\'un farm la réput de %faction ?', '', '', '', '¿Alguien farmea reputación con %faction?', '', ''), +('suggest_faction', 'Anyone help with %faction?', 0, 0, '', 'Quelqu\'un aide-t-il %faction ?', '', '', '', '¿Alguien me ayuda con %faction?', '', ''), +('suggest_faction', 'Wanna quest for %faction.', 0, 0, '', 'Je veux quêter %faction', '', '', '', 'Quiero buscar a %faction.', '', ''), +('suggest_faction', '%faction is the best.', 0, 0, '', '%faction est la meilleure.', '', '', '', '%faction es el mejor.', '', ''), +('suggest_faction', 'Need just a bit to be %rep_level with %faction.', 0, 0, '', 'J\'ai besoin d\'un peu pour être au %rep_level avec %faction', '', '', '', 'Solo necesito un poco para estar %rep_level con %faction.', '', ''), +('suggest_faction', 'Anyone got %rep_level with %faction?', 0, 0, '', 'Quelqu\'un a-t-il %rep_level avec %faction ?', '', '', '', '¿Alguien tiene %rep_level con %faction?', '', ''), +('suggest_faction', 'Who wants to be %rep_level with %faction?', 0, 0, '', 'Qui veut être au %rep_level avec %faction ?', '', '', '', '¿Quién quiere estar en %rep_level con %faction?', '', ''), +('suggest_faction', 'I\'ll never be %rep_level with %faction.', 0, 0, '', 'Je ne serai jamais au %rep_level avec %faction', '', '', '', 'Nunca estaré %rep_level con %faction.', '', ''), +('suggest_faction', 'Someone missing %faction rep?', 0, 0, '', 'Quelqu\'un manque de reput de %faction ?', '', '', '', '¿Alguien falta reputación con %faction?', '', ''), +('suggest_faction', 'Could help farming %faction rep.', 0, 0, '', 'Pourrait aider à farmer réput de %faction', '', '', '', 'Podría ayudar a farmear %faction rep.', '', ''), +('suggest_faction', 'The more rep the better. Especially with %faction.', 0, 0, '', 'Plus il y a de réput, mieux c\'est. Surtout avec %faction', '', '', '', 'Cuantas más repeticiones, mejor. Especialmente con %faction.', '', ''), +('suggest_faction', '%faction: need %rndK for %rep_level.', 0, 0, '', '%faction: besoin %rndK pour %rep_level.', '', '', '', '%faction: necesita %rndK para %rep_level.', '', ''), +('suggest_faction', 'Who can share %faction quests?', 0, 0, '', 'Qui peut partager les quêtes de %faction ?', '', '', '', '¿Quién puede compartir misiones de %faction?', '', ''), +('suggest_faction', 'Any dungeons for %faction?', 0, 0, '', 'Des donjons pour %faction ?', '', '', '', '¿Alguna mazmorra para %faction?', '', ''), +('suggest_faction', 'Wanna do %faction rep grind.', 0, 0, '', 'Je veux faire monter ma réput %faction', '', '', '', 'Quiero hacer %faction rep grind.', '', ''), +('suggest_faction', 'Let\'s farm %faction rep!', 0, 0, '', 'Farmons la réput %faction !', '', '', '', '¡Vamos a farmear reputación con %faction!', '', ''), +('suggest_faction', 'Farming for %faction rep.', 0, 0, '', 'Farmons pour la réput %faction', '', '', '', 'Farming for %faction rep.', '', ''), +('suggest_faction', 'Wanna farm for %faction.', 0, 0, '', 'Je veux farmer pour %faction', '', '', '', 'Quiero farmear para %faction.', '', ''), +('suggest_faction', 'Need help with %faction.', 0, 0, '', 'Besoin d\'aide avec %faction', '', '', '', 'Necesito ayuda con %faction.', '', ''), +('suggest_faction', 'Is %faction sells something useful?', 0, 0, '', 'Est-ce que %faction vend quelque chose d\'utile ?', '', '', '', '¿%faction vende algo útil?', '', ''), +('suggest_faction', 'Are there %faction vendors?', 0, 0, '', 'Y a-t-il des vendeurs %faction ?', '', '', '', '¿Hay %proveedores de facciones?', '', ''), +('suggest_faction', 'Who farms %faction?', 0, 0, '', 'Qui farm %faction ?', '', '', '', '¿Quién farmea %faction?', '', ''), +('suggest_faction', 'Which is the best way to farm %faction?', 0, 0, '', 'Quelle est la meilleure façon de farmer %faction ?', '', '', '', '¿Cuál es la mejor manera de farmear %faction?', '', ''), +('suggest_faction', 'I hate %faction rep grind.', 0, 0, '', 'Je déteste le travail de %faction rep.', '', '', '', 'Odio %repetir de facción', '', ''), +('suggest_faction', 'I am so tired of %faction.', 0, 0, '', 'Je suis tellement fatigué de %faction', '', '', '', 'Estoy tan cansado de %faction.', '', ''), +('suggest_faction', 'Go for %faction?', 0, 0, '', 'Vous optez pour %faction ?', '', '', '', '¿Quereis ir a por %faction?', '', ''), +('suggest_faction', 'Seems everyone is %rep_level with %faction. Only me is late as usually.', 0, 0, '', 'On dirait que tout le monde est %rep_level avec %faction Il n\'y a que moi qui suis en retard comme d\'habitude.', '', '', '', 'Parece que todo el mundo está %rep_level con %faction. Solo yo llego tarde como siempre.', '', ''), +('suggest_faction', 'LFG for %faction rep grind?', 0, 0, '', 'Cherche un groupe pour monter la réput des représentants de %faction ?', '', '', '', 'Busco grupo para subir reputación con %faction', '', ''), +('suggest_faction', 'Can anobody suggest a good spot for %faction rep grind?', 0, 0, '', 'Quelqu\'un peut-il suggérer un bon endroit pour monter les réput de %faction ?', '', '', '', '¿Alguien puede sugerir un buen lugar farmear reputacion con %faction?', '', ''), +('suggest_faction', 'Would %faction rep benefit me?', 0, 0, '', 'Est-ce que la réput %faction me serait bénéfique ?', '', '', '', '¿Me beneficiaría subir reputación con %faction?', '', ''), +('suggest_faction', 'Who would\'ve thought that %faction rep will be useful after all...', 0, 0, '', 'Qui aurait pensé que le représentant de %faction serait utile après tout...', '', '', '', 'Quién hubiera pensado que subir reputacion con %faction sería útil después de todo...', '', ''), +('suggest_faction', 'I wanna be exalted with all factions, starting with %faction.', 0, 0, '', 'Je veux être exalté avec toutes les factions, à commencer par %faction', '', '', '', 'Quiero ser exaltado con todas las facciones, comenzando con %faction.', '', ''), +('suggest_faction', 'Is there any point to improve my rep with %faction?', 0, 0, '', 'Y a-t-il un intérêt à améliorer ma réputation avec %faction ?', '', '', '', '¿Hay algún punto para mejorar mi reputación con %faction?', '', ''), +('suggest_faction', 'What is better for %faction? Quests or mob grinding?', 0, 0, '', 'Quoi de mieux pour %faction ? Quêtes ou mob pour XP?', '', '', '', '¿Qué es mejor para %faction? ¿Misiones o mafiosos?', '', ''), +('suggest_faction', 'Will grind %faction rep for you. Just give me some gold.', 0, 0, '', 'Monte la reput de %faction pour vous. Donnez-moi juste de l\'or.', '', '', '', 'Ganare reputacion con %faction por ti. Sólo dame un poco de oro.', '', ''), +('suggest_faction', 'I think grinding rep with %faction would take forever.', 0, 0, '', 'Je pense que monter la réput avec %faction prendrait une éternité.', '', '', '', 'Creo que subir la reputación con %faction tomaría una eternidad.', '', ''), +('suggest_faction', 'I am killing for %faction every day now but still far from %rep_level.', 0, 0, '', 'Je tue pour %faction tous les jours maintenant, mais encore loin du %rep_level', '', '', '', 'Estoy matando por %faction todos los días ahora, pero aún estoy lejos del %rep_level.', '', ''), +('suggest_faction', 'At %my_level AH deposits will decrease, right?', 0, 0, '', 'Au %rep_level, les dépôts hôtel des ventes diminueront, n\'est-ce pas?', '', '', '', 'Al %rep_level, los depósitos subastas disminuirán, ¿verdad?', '', ''), +('suggest_faction', 'How many exalted reps do you have?', 0, 0, '', 'Combien de représentants exaltés avez-vous ?', '', '', '', '¿Cuántas reputaciones exaltadas tienes?', '', ''), +('suggest_faction', 'Who wants to be %my_level with %faction?', 0, 0, '', 'Qui veut être au %rep_level avec %faction ?', '', '', '', '¿Quién quiere estar en %rep_level con %faction?', '', ''), +('suggest_faction', 'Damn. My guild did a good %faction grind yesterday without me.', 0, 0, '', 'Mince. Ma guilde a fait un bon travail de %faction hier sans moi.', '', '', '', 'Maldición. Mi hermandad hizo un buen farmeo de %faction ayer sin mí.', '', ''), +('suggest_faction', 'Nobody wants to help me because I am %rep_level with %faction.', 0, 0, '', 'Personne ne veut m\'aider parce que je suis %rep_level avec %faction', '', '', '', 'Nadie quiere ayudarme porque estoy %rep_level con %faction.', '', ''), +('suggest_faction', 'Please stay away from %faction.', 0, 0, '', 'Veuillez rester à l\'écart de %faction', '', '', '', 'Por favor manténgase alejado de %faction.', '', ''), + + + +-- random generic +-- usable placeholders: +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('suggest_something', 'Wanna party in %zone_name.', 0, 0, '', 'Je veux faire la fête dans %zone_name.', '', '', '', '¡Vamos a perrear a %zone_name!', '', 'Ищу группу в %zone_name.'), +('suggest_something', 'Anyone is looking for %my_role?', 0, 0, '', 'Quelqu\'un cherche un %my_role ?', '', '', '', '¿Alguien está buscando %my_role?', '', 'Кто-нибудь ищет %my_role?'), +('suggest_something', '%my_role is looking for quild.', 0, 0, '', '%my_role recherche une guilde.', '', '', '', '%my_role está buscando hermandad.', '', '%my_role ищу гильдию.'), +('suggest_something', 'Looking for gold.', 0, 0, '', 'A la recherche de l\'or.', '', '', '', 'Buscando oro.', '', 'Дайте голды'), +('suggest_something', '%my_role wants to join a good guild.', 0, 0, '', '%my_role veut rejoindre une bonne guilde.', '', '', '', '%my_role quiere unirse a una buen hermandad.', '', '%my_role хочу в хорошую гильдию.'), +('suggest_something', 'Need a friend.', 0, 0, '', 'Besoin d\'un ami.', '', '', '', 'Necesito un amigo...', '', 'Ищу друга.'), +('suggest_something', 'Anyone feels alone?', 0, 0, '', 'Quelqu\'un se sent seul?', '', '', '', '¿Alguien se siente solo?', '', 'Кому-нибудь одиноко?'), +('suggest_something', 'Boring...', 0, 0, '', 'Ennuyeux...', '', '', '', 'Aburrido...', '', 'Скучно...'), +('suggest_something', 'Who wants some?', 0, 0, '', 'Qui en veut?', '', '', '', '¿Quién quiere hacer grupo para levear?', '', 'Кому навалять?'), +('suggest_something', 'Go get me!', 0, 0, '', 'Allez me chercher !', '', '', '', '¡Ven a buscarme!', '', 'Поймайте меня!'), +('suggest_something', 'Maybe a duel in %zone_name?', 0, 0, '', 'Peut-être un duel dans %zone_name ?', '', '', '', '¿Quizás un duelo en %zone_name?', '', 'Кто на дуэль в %zone_name?'), +('suggest_something', 'Anybody doing something?', 0, 0, '', 'Quelqu\'un fait quelque chose?', '', '', '', '¿Alguien está haciendo algo?', '', 'Кто чем занят?'), +('suggest_something', '%zone_name: is anybody here?', 0, 0, '', '%zone_name : est-ce que quelqu\'un est là?', '', '', '', '%zone_name: ¿hay alguien aquí?', '', '%zone_name: есть кто нибудь?'), +('suggest_something', '%zone_name: where is everyone?', 0, 0, '', '%zone_name : où est tout le monde?', '', '', '', '¿Hay alguien en %zone_name?', '', '%zone_name: где все?'), +('suggest_something', 'Looks like I am alone in %zone_name.', 0, 0, '', 'On dirait que je suis seul dans %zone_name', '', '', '', 'Parece que estoy solo en %zone_name.', '', 'Похоже я один в %zone_name.'), +('suggest_something', 'Meet me in %zone_name.', 0, 0, '', 'Retrouvez-moi dans %zone_name', '', '', '', 'Encuéntrame en %zone_name.', '', 'Встретимся в %zone_name.'), +('suggest_something', 'Let\'s quest in %zone_name!', 0, 0, '', 'Partons en quête dans %zone_name !', '', '', '', '¡Vamos a hacer un grupo para levear en %zone_name!', '', 'Давайте квестить в %zone_name!'), +('suggest_something', '%zone_name is the best place to be!', 0, 0, '', '%zone_name est le meilleur endroit où être!', '', '', '', '%zone_name es el mejor lugar para estar!', '', '%zone_name лучшее место!'), +('suggest_something', 'Wanna go to %zone_name. Anybody with me?', 0, 0, '', 'Je veux aller à %zone_name Quelqu\'un avec moi?', '', '', '', 'Quiero ir a %zone_name. ¿Alguien se apunta?', '', 'Собираюсь в %zone_name. Кто со мной7'), +('suggest_something', 'Who wants going to %zone_name?', 0, 0, '', 'Qui veut aller à %zone_name ?', '', '', '', '¿Quién quiere ir a %zone_name?', '', 'Кто собирается в %zone_name?'), +('suggest_something', 'I don\'t like %zone_name. Where to go?', 0, 0, '', 'Je n\'aime pas %zone_name Où aller?', '', '', '', 'No me gusta %zone_name. ¿Dónde podria ir?', '', 'Не нравится %zone_name. Куда идти?'), +('suggest_something', 'Are there a good quests in %zone_name?', 0, 0, '', 'Y a-t-il de bonnes quêtes dans %zone_name ?', '', '', '', '¿Hay buenas misiones en %zone_name?', '', 'А в %zone_name есть хорошие квесты?'), +('suggest_something', 'Where to go after %zone_name?', 0, 0, '', 'Où aller après %zone_name ?', '', '', '', '¿Adónde puedo ir después de %zone_name?', '', 'Куда идти после %zone_name?'), +('suggest_something', 'Who is in %zone_name?', 0, 0, '', 'Qui est dans %zone_name ?', '', '', '', '¿Quién está en %zone_name?', '', 'Кто в %zone_name?'), +('suggest_something', 'LFG in %zone_name.', 0, 0, '', 'Cherche un groupe dans %zone_name', '', '', '', 'Busco grupo en %zone_name.', '', 'ЛФГ %zone_name.'), +('suggest_something', '%zone_name is the worst place to be.', 0, 0, '', '%zone_name est le pire endroit où être.', '', '', '', '%zone_name es el peor lugar para estar', '', '%zone_name это худшее место.'), +('suggest_something', 'Catch me in %zone_name!', 0, 0, '', 'Attrape-moi dans %zone_name !', '', '', '', '¡Atrápame en %zone_name!', '', 'Поймай меня в %zone_name!'), +('suggest_something', 'Go for %zone_name!', 0, 0, '', 'Allez pour %zone_name !', '', '', '', 'Me voy a %zone_name!', '', 'Гоу в %zone_name!'), +('suggest_something', 'Wanna quest in %zone_name', 0, 0, '', 'Je veux une quête dans %zone_name', '', '', '', 'Quiero hacer una búsqueda en %zone_name', '', 'Хочешь поделать квесты в %zone_name'), +('suggest_something', 'Anyone has quests in %zone_name?', 0, 0, '', 'Quelqu\'un a des quêtes dans %zone_name ?', '', '', '', '¿Alguien tiene misiones en %zone_name?', '', 'Есть у кого квесты в %zone_name?'), +('suggest_something', 'Come here to %zone_name!', 0, 0, '', 'Venez ici à %zone_name !', '', '', '', '¡Ven aquí a %zone_name!', '', 'Приходите сюда в %zone_name!'), +('suggest_something', 'Seems there is no Horde in %zone_name', 0, 0, '', 'Il semble qu\'il n\'y ait pas de Horde dans %zone_name', '', '', '', 'Parece que no hay Horda en %zone_name', '', '%zone_name Орды вроде нет.'), +('suggest_something', 'Seems there is no Alliance in %zone_name', 0, 0, '', 'Il semble qu\'il n\'y ait pas d\'alliance dans %zone_name', '', '', '', 'Parece que no hay Alianza en %zone_name', '', '%zone_name Альянса вроде нет'), +('suggest_something', 'I am really tired of %zone_name. Maybe go somewhere else?', 0, 0, '', 'Je suis vraiment fatigué de %zone_name Peut-être aller ailleurs?', '', '', '', 'Estoy realmente cansado de %zone_name. Quizás ire a otro lugar', '', 'В %zone устал уже, может в другое место пойдем?'), +('suggest_something', 'GL', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I want to go home, and then edge', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'does anyone know what you need to dual wield?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hi everyone!', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', '%zone_name is comfy', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i feel great', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i don\'t ignore people i troll them until they ignore me', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'What do you guys think about my build? %my_role', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'good to see chat still remembers', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'like all weapons its hunter BIS', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'whole point to the game for me is soloing and finding new ways to solo stuff', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i\'ve NEVER ripped off anyone', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'ah yes the world of warcraft, where i come for life advice', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'HELLO?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Time to fight my way into %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', '%zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'gotta poop', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'if you don\'t loot your skinnable kills your pp loses 1mm permanently', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'NOOOOOOOOOOOOO', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I LIKE POTATO', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'w chat', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hi how are you guys', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i just logged out and logged back in', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'can you guys keep it down a bit, im lost in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'anyone want to have a drink with me at %zone_name ...hic!', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hahahahaheeeeeeee dirin diring ingggggg hahahahaheeeeeeeeeeeeee', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'bait used to be believeable', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'maybe you just lost your innocence', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'any guilds willing to carry %my_role?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'once you start getting higher, gold is so easy to get', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'morning', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'why does my ass hurt?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I feel like spirit is bis for leveling', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Even more for troll', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'CAN SOMEONE INVITE ME', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'need a lot of drinks', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'damn gnomes', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'no one likes gnomes', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'gnomes are only good for one thing', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Well', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'mushrooms', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'automatic thoughts are a scary thing', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'the mind is more pliable than we\'d like to believe', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'any leveling guilds out there?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'brb', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Why is snow white but Ice is clear ? made of the same thing', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'why is whipped cream fluffy and regular not', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'why do feet smell if they have no nose', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'seems a can of newbies arrived', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'stop trolling new players with BS answers', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Is there PvP on this server?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'duh', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'phew... :)', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'did you guys know that', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i don\'t try to imagine what other creatures feel like', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'oh whoops, wrong chat', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'bruh you guys are wildin out today', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'just let it be known that my text was here', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'grrr angyy', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'the grind is fun', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Wow keeps me sharp', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hey have a question where can i take the roll for more xp? im in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'do you guys like sausages?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Invite me. I\'ll help', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'which class do you think is better for pvp?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'where the fuck is the cooking trainer in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'you know what happens in %zone_name?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I need to craft something', 0, 0, '', '', '', '', '', '', '', ''), + +-- random generic toxic phrases +-- usable placeholders: +-- %random_inventory_item_link +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('suggest_something_toxic', 'what is ligma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'what is sugma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'ligma balls', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'sugma balls', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I EAT ASS', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I want to shove %random_inventory_item_link up my ass', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I want to shove %random_inventory_item_link up your ass', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'Darnasses', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'seems like your suffering from sugma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'deez nutz in ur mouth', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'cool boner, bro', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'ERP?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'i tried everything, but at the end ERP did the trick', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I want to bonk in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'looking for female gnome with gorilla pet for erp in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'i may understand an asshole, but a pervert?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'there is no gyat in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I\'m killing all the animals in %zone_name. Fuck the animals!!!', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'good think i got 3 legs', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'dont be mad im goonin like a sigma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'try finger, but hole', 0, 0, '', '', '', '', '', '', '', ''), + +-- random generic toxic item links +-- usable placeholders: +-- %prefix +-- %random_taken_quest_or_item_link +-- %random_inventory_item_link +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('suggest_toxic_links', '%prefix %random_taken_quest_or_item_link', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_toxic_links', '%prefix %random_inventory_item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- thunderfury spam +-- usable placeholders: +-- %thunderfury_link +('thunderfury_spam', '%thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', '%thunderfury_link%thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', '%thunderfury_link%thunderfury_link%thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I think I just heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I think I heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I definitely heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I dunno but I\'m pretty sure I heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Did you just say %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'did someone say %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Did someone say %thunderfury_link ?', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Someone said %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', '%thunderfury_link is coming out of the closet', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'could swear it was a %thunderfury_link, might have been %thunderfury_link tho', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Why use %thunderfury_link when %thunderfury_link is clearly way more OP', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- random WTS +-- usable placeholders: +-- %%item_formatted_link +-- %item_formatted_link +-- %item_count +-- %cost_gold +-- %my_class +-- %my_race +-- %my_level +('suggest_sell', 'WTS %item_formatted_link for %cost_gold.', 0, 0, '', 'Cherche à vendre %item_formatted_link pour %cost_gold', '', '', '', 'Quiero vender %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Who wants %item_formatted_link for %cost_gold?', 0, 0, '', 'Qui veut %item_formatted_link pour %cost_gold ?', '', '', '', '¿Quién quiere %item_formatted_link por %cost_gold?', '', ''), +('suggest_sell', 'Anyone wants %item_formatted_link? Only %cost_gold.', 0, 0, '', 'Quelqu\'un veut %item_formatted_link ? Seulement %cost_gold', '', '', '', '¿Alguien quiere %item_formatted_link? Solo %cost_gold.', '', ''), +('suggest_sell', 'Just %cost_gold for %item_formatted_link!', 0, 0, '', 'Seulement %cost_gold pour %item_formatted_link!', '', '', '', '¡Solo %cost_gold para %item_formatted_link!', '', ''), +('suggest_sell', 'Selling %item_formatted_link for %cost_gold.', 0, 0, '', 'Vendre %item_formatted_link pour %cost_gold', '', '', '', 'Vendo %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', '%item_formatted_link is yours just for %cost_gold!', 0, 0, '', '%item_formatted_link est à vous juste pour %cost_gold !', '', '', '', '%item_formatted_link es tuyo solo por %cost_gold!', '', ''), +('suggest_sell', 'Ridiculus price of %cost_gold for %item_formatted_link!', 0, 0, '', 'Prix ridicule de %cost_gold pour %item_formatted_link !', '', '', '', '¡Precio ridículo de %cost_gold para %item_formatted_link_link!', '', ''), +('suggest_sell', 'Wanna sell %item_formatted_link for %cost_gold.', 0, 0, '', 'Je veux vendre %item_formatted_link pour %cost_gold', '', '', '', 'Quiero vender %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Who needs %item_formatted_link? Only %cost_gold.', 0, 0, '', 'Qui a besoin de %item_formatted_link ? Seulement %cost_gold', '', '', '', '¿Quién necesita %item_formatted_link? Solo %cost_gold.', '', ''), +('suggest_sell', 'Anyone needs %item_formatted_link for %cost_gold?', 0, 0, '', 'Quelqu\'un a besoin de %item pour %cost_gold ?', '', '', '', '¿Alguien necesita %item_formatted_link_link por %cost_gold?', '', ''), +('suggest_sell', '%cost_gold for %item_formatted_link. Less than AH!', 0, 0, '', '%cost_gold pour %item_formatted_link. Moins que l\'hôtel des ventes!', '', '', '', '%cost_gold para %item_formatted_link. ¡Menos que en las subastas!', '', ''), +('suggest_sell', '%item_formatted_link is expensive, but I\'d sell it for %cost_gold.', 0, 0, '', '%item_formatted_link est cher, mais je le vendrais pour %cost_gold', '', '', '', '%item_formatted_link es caro, pero lo vendería por %cost_gold.', '', ''), +('suggest_sell', 'You\'ll never find %item_formatted_link cheaper than %cost_gold!', 0, 0, '', 'Vous ne trouverez jamais %item_formatted_link moins cher que %cost_gold !', '', '', '', '¡Nunca encontrarás %item_formatted_link más barato que %cost_gold!', '', ''), +('suggest_sell', 'Need more than %item_formatted_link!', 0, 0, '', 'Besoin de plus de %item_formatted_link !', '', '', '', '¡Necesito más %item_formatted_link!', '', ''), +('suggest_sell', 'I have %item_formatted_link and need more.', 0, 0, '', 'J\'ai %item_formatted_link et j\'en ai besoin de plus.', '', '', '', 'Tengo %item_formatted_link y necesito más. ¿Alguien me vende alguno?', '', ''), +('suggest_sell', 'Have %item_formatted_link. Who wants to buy for %cost_gold?', 0, 0, '', 'Avoir %item_formatted_link. Qui veut acheter pour %cost_gold ?', '', '', '', 'Tengo %item_formatted_link. ¿Quién quiere comprarlo por %cost_gold?', '', ''), +('suggest_sell', 'Anyone WTB %item_formatted_link for %cost_gold?', 0, 0, '', 'Quelqu\'un cherche à acheter %item_formatted_link pour %cost_gold ?', '', '', '', '¿Alguien compra %item_formatted_link por %cost_gold?', '', ''), +('suggest_sell', 'What about %item_formatted_link? For %cost_gold.', 0, 0, '', 'Qu\'en est-il de %item_formatted_link ? Pour %cost_gold', '', '', '', '¿Qué pasa con %item_formatted_link? Por el oro.', '', ''), +('suggest_sell', 'Who said I am a bastard? %item_formatted_link for %cost_gold is a good price.', 0, 0, '', 'Qui a dit que j\'étais un bâtard? %item_formatted_link pour %cost_gold est un bon prix.', '', '', '', '¿Quién ha dicho que soy un rata? %item_formatted_link por %cost_gold es una ganga.', '', ''), +('suggest_sell', 'I am selling %item_formatted_link? Just %cost_gold.', 0, 0, '', 'Je vends %item_formatted_link ? Juste %cost_gold', '', '', '', '¿Vendo %item_formatted_link? Solo %cost_gold.', '', ''), +('suggest_sell', 'LFG for farming. You can still buy %item_formatted_link I have for %cost_gold.', 0, 0, '', 'Cherche un groupe pour farming. Vous pouvez toujours acheter %item_formatted_link que j\'ai pour %cost_gold', '', '', '', 'LFG para farmear. Todavía puedes comprar %item_formatted_link que tengo por %cost_gold.', '', ''), +('suggest_sell', 'Sold almost everything today. Still have %item_formatted_link for %cost_gold.', 0, 0, '', 'Vendu presque tout aujourd\'hui. Vous avez encore %item_formatted_link pour %cost_gold', '', '', '', 'Se vendió casi todo hoy. Todavía tengo %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'What use for trade chat? Of course to sell %item_formatted_link for %cost_gold.', 0, 0, '', 'A quoi sert le tchat commercial? Bien sûr pour vendre %item_formatted_link pour %cost_gold', '', '', '', '¿De qué sirve el chat comercial? Por supuesto, para vender %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Can anyone beat the price of %cost_gold for %item_formatted_link?', 0, 0, '', 'Quelqu\'un peut-il battre le prix de %cost_gold pour %item_formatted_link ?', '', '', '', '¿Alguien puede superar el precio de %cost_gold por %item_formatted_link?', '', ''), +('suggest_sell', 'Wanna stop trade chat? Just buy %item_formatted_link? For %cost_gold!', 0, 0, '', 'Vous voulez arrêter le chat commercial? Vous venez d\'acheter %item_formatted_link ? Pour %cost_gold !', '', '', '', '¿Quieres detener el chat comercial? ¿Solo compra %item_formatted_link? ¡Por el oro!', '', ''), +('suggest_sell', 'Everybody spams in trade chat. Me too - %cost_gold for %item_formatted_link!', 0, 0, '', 'Tout le monde spamme dans le chat commercial. Moi aussi - %cost_gold pour %item_formatted_link !', '', '', '', 'Todo el mundo envía spam en el chat y yo también! ¡%item_formatted_link por %cost_gold!', '', ''), +('suggest_sell', 'Is %item_formatted_link any use? Just selling it for %cost_gold.', 0, 0, '', '%item_formatted_link est-il utile? Je le vends juste pour %cost_gold', '', '', '', '¿Es %item_formatted_link útil? Solo lo vendo por %cost_gold.', '', ''), +('suggest_sell', 'I have %item_formatted_link ready to sell you for %cost_gold.', 0, 0, '', 'J\'ai %item_formatted_link prêt à vous vendre pour %cost_gold', '', '', '', 'Tengo %item_formatted_link listo a la venta por %cost_gold.', '', ''), +('suggest_sell', 'Did nothing yesterday but have got %item_formatted_link. Selling it for %cost_gold.', 0, 0, '', 'Je n\'ai rien fait hier mais j\'ai %item_formatted_link Je le vends pour %cost_gold', '', '', '', 'No hice nada ayer pero consegu\'i %item_formatted_link. Lo vendo por %cost_gold.', '', ''), +('suggest_sell', 'Farmed yesterday and got %item_formatted_link. Anyone wtb for %cost_gold?', 0, 0, '', 'Farmé hier et obtenu %item_formatted_link Quelqu\'un cherche à acheter pour %cost_gold ?', '', '', '', 'Ayer farmee y conseguí mucho %item_formatted_link. ¿Alguien lo quiere comprar por %cost_gold?', '', ''), +('suggest_sell', 'Bought %item_formatted_link yesterday. Anyone needs it for %cost_gold?', 0, 0, '', 'Acheté %item_formatted_link hier. Quelqu\'un en a besoin pour %cost_gold ?', '', '', '', 'Ayer compré %item_formatted_link. ¿Alguien lo quiere por %cost_gold?', '', ''), +('suggest_sell', 'Who asked for %item_formatted_link? The price is the same - %cost_gold.', 0, 0, '', 'Qui a demandé %item_formatted_link ? Le prix est le même - %cost_gold', '', '', '', '¿Quién pidió %item_formatted_link? El precio es el mismo: %cost_gold.', '', ''), +('suggest_sell', 'I sill have %item_formatted_link. WTB for %cost_gold?', 0, 0, '', 'J\'ai toujours %item_formatted_link. Cherche à acheter pour %cost_gold ?', '', '', '', 'Todavía tengo %item_formatted_link. ¿Alguien lo compra por %cost_gold?', '', ''), +('suggest_sell', 'I used to have more than %item_formatted_link. Now needs to sell it for %cost_gold.', 0, 0, '', 'J\'avais plus de %item_formatted_link Il faut maintenant le vendre pour %cost_gold', '', '', '', 'Solía tener más de %item_formatted_link. Ahora necesito venderlo por %cost_gold.', '', ''), +('suggest_sell', 'I wish I have more than %item_formatted_link. You could buy it for %cost_gold anyways.', 0, 0, '', 'J\'aimerais avoir plus de %item_formatted_link . Vous pouvez l\'acheter pour %cost_gold de toute façon.', '', '', '', 'Desearía tener más de %item_formatted_link. Podrías comprarlo por %cost_gold de todos modos.', '', ''), +('suggest_sell', 'What use for your gold? To buy my %item_formatted_link for %cost_gold.', 0, 0, '', 'A quoi sert votre or ? Pour acheter mon %item_formatted_link pour %cost_gold', '', '', '', '¿De qué sirve tu oro? Para comprar mi %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Please spare some gold for me. You can buy %item_formatted_link for %cost_gold.', 0, 0, '', 'S\'il vous plaît, épargnez-moi de l\'or. Vous pouvez acheter %item_formatted_link pour %cost_gold', '', '', '', 'Por favor, dame algo de oro. Puedes comprar %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Is %cost_gold is a good price for %item_formatted_link?', 0, 0, '', '%cost_gold est-il un bon prix pour %item_formatted_link ?', '', '', '', '¿%cost_gold es un buen precio para %item_formatted_link?', '', ''), +('suggest_sell', 'Just bought yesterday %item_formatted_links, but do not need it anymore. Anyone wants for %cost_gold?', 0, 0, '', 'Je viens d\'acheter hier %item_formatted_links , mais je n\'en ai plus besoin. Quelqu\'un veut %cost_gold ?', '', '', '', 'Ayer compré %item_formatted_link, pero ya no los necesito. ¿Alguien lo quiere por %cost_gold?', '', ''), +('suggest_sell', 'I am going to post %item_formatted_link on the AH but you can buy it now cheaper just for %cost_gold.', 0, 0, '', 'Je vais poster %item_formatted_link à l\'hôtel des ventes mais vous pouvez l\'acheter maintenant moins cher juste pour %cost_gold', '', '', '', 'Voy a poner %item_formatted_link en la casa de subastas pero puedes comprarlo ahora más barato solo por %cost_gold.', '', ''), +('suggest_sell', 'Why the #!@ have I bought %item_formatted_link? Anyone needs it for %cost_gold?', 0, 0, '', 'Pourquoi ai-je acheté le #!@ %item_formatted_link ? Quelqu\'un en a besoin pour %cost_gold ?', '', '', '', '¿Por qué #!@ he comprado %item_formatted_link? ¿Alguien lo necesita por %cost_gold?', '', ''), + + +-- response LFG/LFM channel +-- usable placeholders: +-- %quest_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_lfg_quests_channel', 'I have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I also have %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I also have %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I am up for %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I am up for %quest_links, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I am up for %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I am up for %quest_links, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), + + +-- response LFG/LFM whisper +-- usable placeholders: +-- %quest_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_lfg_quests_whisper', 'Hey, I\'m up for %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey, I could do %quest_links with you', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey, I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey %other_name, I\'m up for %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey %other_name, I could do %quest_links with you', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey %other_name, I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'wanna group up for %quest_links ?', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'I am up for %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'I am up for %quest_links, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- response WTB channel +-- usable placeholders: +-- %formatted_item_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_wtb_items_channel', '%other_name, I could sell you %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', 'I could potentially sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', 'Think I could sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', '%other_name, I could potentially sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', '%other_name, Think I could sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), + + + + +-- response WTB channel +-- usable placeholders: +-- %formatted_item_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_wtb_items_whisper', 'I could sell you %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_whisper', 'Hey, I got %formatted_item_links for sale', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_whisper', 'Hey, I could potentially sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- ///////////////////////////// +-- generic events + +-- quest +('quest_accept', 'Quest accepted', 0, 0, '', '', '', '', '', 'Misión aceptada', '', 'Квест взят'), + + + +('quest_remove', 'Quest removed', 0, 0, '', '', '', '', '', 'Misión eliminada', '', 'Квест отменен'), + + + +('quest_cant_take', 'I can\'t take this quest', 0, 0, '', '', '', '', '', 'No puedo tomar esta búsqueda', '', 'Я не могу взять этот квест'), + + +('quest_error_talk', 'I can\'t talk with the quest giver', 0, 0, '', '', '', '', '', 'No puedo hablar con el propietario de la mision', '', ''), + + + +('quest_error_completed', 'I have already completed %quest', 0, 0, '', '', '', '', '', 'Ya he completado la mision %quest', '', ''), + + + +('quest_error_have_quest', 'I already have %quest', 0, 0, '', '', '', '', '', 'Ya tengo la mision %quest', '', ''), + + + +('quest_error_cant_take', 'I can\'t take %quest', 0, 0, '', '', '', '', '', 'No puedo aceptar la mision %quest', '', ''), + + + +('quest_error_log_full', 'I can\'t take %quest because my quest log is full', 0, 0, '', '', '', '', '', 'No puedo aceptar la mision %quest porque mi registro de misiones esta completo', '', ''), + + + +('quest_error_bag_full', 'I can\'t take %quest because my bag is full', 0, 0, '', '', '', '', '', 'No puedo aceptar la mision %quest porque mi inventario esta lleno', '', ''), + + + +('quest_accepted', 'I have accepted %quest', 0, 0, '', '', '', '', '', 'He aceptado la mision %quest', '', ''), + + + +('quest_status_incomplete', 'I have not completed the quest %quest', 0, 0, '', '', '', '', '', 'No he completado la mision %quest', '', ''), + + + +('quest_status_available', 'Quest %quest available', 0, 0, '', '', '', '', '', 'Mision %quest disponible', '', ''), + + + +('quest_status_failed', 'I have failed the quest %quest', 0, 0, '', '', '', '', '', 'He fallado la mision %quest', '', ''), + + + +('quest_status_unable_to_complete', 'I am unable to turn in the quest %quest', 0, 0, '', '', '', '', '', 'No puedo entregar la mision %quest', '', ''), + + + +('quest_status_completed', 'I have completed the quest %quest', 0, 0, '', '', '', '', '', 'He completado la mision %quest', '', ''), + + + +('quest_status_complete_single_reward', 'I have completed the quest %quest and received %item', 0, 0, '', '', '', '', '', 'He completado la mision %quest y he recibido %item', '', ''), + + + +('quest_status_complete_pick_reward', 'Which reward should I pick for completing the quest %quest?%rewards', 0, 0, '', '', '', '', '', '¿Que recompensa deberia escoger por completar la mision %quest?%rewards', '', ''), + + + +('quest_choose_reward', 'Okay, I will pick %item as a reward', 0, 0, '', '', '', '', '', 'De acuerdo, voy a escoger %item de recompensa', '', ''), + + + + + + +-- stuff +('hello', 'Hello', 0, 0, '', '', '', '', '', 'Hola', '', 'Привет'), +('hello', 'Hello!', 0, 0, '', '', '', '', '', '¡Hola!', '', 'Привет!'), +('hello', 'Hi', 0, 0, '', '', '', '', '', 'Hola', '', 'Прив'), +('hello', 'Hi!', 0, 0, '', '', '', '', '', '¡Hola!', '', 'Прив!'), +('hello', 'Hello there!', 0, 0, '', '', '', '', '', '¡Hola!', '', 'Здарова!'), + + + +('hello_follow', 'Hello, I follow you!', 0, 0, '', '', '', '', '', '¡Hola, te sigo!', '', 'Привет, иду за тобой!'), +('hello_follow', 'Hello, lead the way!', 0, 0, '', '', '', '', '', '¡Hola, guía el camino!', '', 'Привет, веди!'), +('hello_follow', 'Hi, lead the way!', 0, 0, '', '', '', '', '', '¡Hola, guía el camino!', '', 'Прив, веди!'), + + + +('join_group', 'Hey %player, do you want join my group?', 0, 0, '', '', '', '', '', 'Oye %player, ¿Quieres unirte a mi grupo?', '', ''), + + + +('join_raid', 'Hey %player, do you want join my group?', 0, 0, '', '', '', '', '', 'Oye %player, ¿Quieres unirte a mi banda?', '', ''), + + + +('logout_cancel', 'Logout cancelled!', 0, 0, '', '', '', '', '', 'Cerrar sesión cancelado!', '', 'Логаут отменен!'), + + + +('logout_start', 'I\'m logging out!', 0, 0, '', '', '', '', '', '¡Me estoy desconectando!', '', 'Я выхожу из игры!'), + + + +('goodbye', 'Goodbye!', 0, 0, '', '', '', '', '', '¡Adiós!', '', 'Пока!'), +('goodbye', 'Bye bye!', 0, 0, '', '', '', '', '', '¡Adiós!', '', 'Пока пока!'), +('goodbye', 'See you later!', 0, 0, '', '', '', '', '', '¡Hasta luego!', '', 'Увидимся позже!'), + + + +-- ///////////////////////////// +-- replies + + +-- replies 0 +('reply', 'what was that %s?', 0, 0, '', 'c\'était quoi ce %s?', '', '', '', '¿qué has dicho %s?', '', ''), +('reply', 'not sure I understand %s?', 0, 0, '', 'pas sûr de comprendre %s?', '', '', '', '¿no estoy seguro de entenderte %s?', '', ''), +('reply', 'uh... no clue what yer talkin bout', 0, 0, '', 'euh... aucune idée de quoi tu parles', '', '', '', 'uh... ni idea de lo que estás hablando', '', ''), +('reply', 'you talkin to me %s?', 0, 0, '', 'tu me parles %s?', '', '', '', '¿Me hablas a mí %s?', '', ''), +('reply', 'whaaaa?', 0, 0, '', 'quoiaaa?', '', '', '', '¿quéaaa?', '', ''), +('reply', 'huh?', 0, 0, '', 'hein?', '', '', '', '¿eh?', '', ''), +('reply', 'what?', 0, 0, '', 'Quoi?', '', '', '', '¿qué?', '', ''), +('reply', 'are you talking?', 0, 0, '', 'parles-tu?', '', '', '', '¿estás hablando?', '', ''), +('reply', 'whatever dude', 0, 0, '', 'peu importe mec', '', '', '', 'Menudo tio...', '', ''), +('reply', 'you lost me', 0, 0, '', 'tu m\'as perdu', '', '', '', 'No entiendo ni papa', '', ''), +('reply', 'Bla bla bla...', 0, 0, '', 'Bla bla bla...', '', '', '', 'Bla bla bla...', '', ''), +('reply', 'What did you say, %s?', 0, 0, '', 'Qu\'as-tu dis, %s?', '', '', '', '¿Qué me estas contando %s?', '', ''), +('reply', 'Concentrate on the game, %s!', 0, 0, '', 'Concentres-toi sur le jeu, %s!', '', '', '', '¡Concéntrate en el juego, %s!', '', ''), +('reply', 'Chatting with you %s is so great! I always wanted to meet you', 0, 0, '', 'Discuter avec vous %s est tellement génial! J\'ai toujours voulu te rencontrer', '', '', '', '¡%s, chatear contigo es genial! Siempre quise conocerte', '', ''), +('reply', 'These chat-messages are freaking me out! I feel like I know you all!', 0, 0, '', 'Ces messages du chat me font flipper! J\'ai l\'impression de vous connaître tous!', '', '', '', '¡Estos mensajes de chat me están asustando! ¿De que cojones estais hablando?', '', ''), +('reply', 'YEAH RIGHT! HAHA SURE!!!', 0, 0, '', 'OUI EN EFFET! AHAH BIEN SÛR!!!', '', '', '', '¡SÍ, CORRECTO! ¡¡¡JAJA SEGURO!!!', '', ''), +('reply', 'I believe you!!!', 0, 0, '', 'Je te crois!!!', '', '', '', '¡Si, claro!', '', ''), +('reply', 'OK, uhuh LOL', 0, 0, '', 'OK, euh LOL', '', '', '', 'OK, uhuh LOL', '', ''), +('reply', 'Why is everybody always saying the same things???', 0, 0, '', 'Pourquoi tout le monde dit toujours la même chose???', '', '', '', '¿Por qué todo el mundo siempre dice lo mismo?', '', ''), +('reply', 'Hey %s....oh nevermind!', 0, 0, '', 'Hé %s.... oh tant pis!', '', '', '', 'Oye %s... ¡oh, no importa!', '', ''), +('reply', 'What are you talking about %s', 0, 0, '', 'De quoi parlez-vous %s', '', '', '', 'De qué estás hablando %s', '', ''), +('reply', 'Who said that? I resemble that remark', 0, 0, '', 'Qui a dit ça? je ressemble à cette remarque', '', '', '', '¿Quién ha dicho eso? ¿Estais hablando de mi?', '', ''), +('reply', 'wtf are you all talking about', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'fr fr no cap on a stack', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'your not getting jack shit', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'swag', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'ty!', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'no', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'Yep', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'f', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s no shit xD', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'why is that', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'lmao', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'thought i should remain silent, was getting confused from chat again', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'i can get realy jealous', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s you can\'t hear the dripping sarcasm in my text', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'he said no homo, it\'s fine', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'dwarf moment', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'Yes %s', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'interesting...', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'lol', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s fuck you man :D', 0, 0, '', '', '', '', '', '', '', ''), +('reply', ':^)', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'ty', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s well said', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yay', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yeah', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'ooooooh', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'hmm', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yeah right', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'you made me gag wtf', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'hot', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'hoes mad', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'what have you been eating %s', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'wtf', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'i will attempt to understand that comment', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '*confused*', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'fuck yea', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '0/10 would not read again', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '10/10 would read again', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '6/10 would read', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '7/10 would', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'based', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'oh yeah maybe', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yeah so what', 0, 0, '', '', '', '', '', '', '', ''), + + + + + + + +-- replies 1 +('reply', 'hey %s i havent forgotten you', 0, 1, '', 'salut %s je ne t\'ai pas oublié', '', '', '', 'hey %s no te he olvidado', '', ''), +('reply', 'you piss me off %s', 0, 1, '', 'tu me fais chier %s', '', '', '', 'me cabreas %s', '', ''), +('reply', 'im gunna get you this time %s', 0, 1, '', 'je vais t\'avoir cette fois %s', '', '', '', 'voy a atraparte esta vez %s', '', ''), +('reply', 'better watch your back %s', 0, 1, '', 'mieux vaut surveiller vos arrières %s', '', '', '', 'mejor cuida tu espalda %s', '', ''), +('reply', 'i did not like last round so much', 0, 1, '', 'je n\'ai pas tellement aimé le dernier tour', '', '', '', 'no me gustó tanto la última ronda', '', ''), +('reply', 'i sucked last round thanks to %s', 0, 1, '', 'j\'ai merdé le dernier tour grâce à %s', '', '', '', 'chupé la última ronda gracias a %s', '', ''), +('reply', 'prepare to die %s', 0, 1, '', 'préparez-vous à mourir %s', '', '', '', 'prepárate para morir %s', '', ''), +('reply', 'dont appreciate you killin me %s', 0, 1, '', 'j\'apprécie pas que tu me tues %s', '', '', '', 'no aprecio que me mates %s', '', ''), +('reply', '%s, i hate you', 0, 1, '', '%s, je te déteste', '', '', '', '%s, te odio', '', ''), +('reply', 'grrrrrr, ill get you this time %s', 0, 1, '', 'grrrrrr, je vais t\'avoir cette fois %s', '', '', '', 'grrrrrr, te libraste esta vez %s', '', ''), +('reply', 'well fuck you', 0, 1, '', 'eh bien va te faire foutre', '', '', '', 'vamos a la mierda', '', ''), +('reply', '%s i\'ll vomit into your fkin mouth', 0, 1, '', '', '', '', '', '', '', ''), +('reply', 'dont fucking judge me', 0, 1, '', '', '', '', '', '', '', ''), +('reply', 'Yo momma so fat, she can\'t even fit through the Dark Portal', 0, 1, '', '', '', '', '', '', '', ''), + + + +-- replies 2 +('reply', 'wtf', 0, 2, '', 'wtf', '', '', '', 'wtf', '', ''), +('reply', 'wtf??', 0, 2, '', 'wtf??', '', '', '', 'wtf??', '', ''), +('reply', 'low life', 0, 2, '', 'faible durée de vie', '', '', '', 'low life', '', ''), +('reply', 'wth', 0, 2, '', 'wth', '', '', '', 'wth', '', ''), +('reply', 'sucked', 0, 2, '', 'Ça craint', '', '', '', 'chupate esa', '', ''), +('reply', 'REMATCH!!! im taking him down', 0, 2, '', 'REMATCH!!! je le descends', '', '', '', '¡¡REVANCHA!!! lo estoy derribando', '', ''), +('reply', 'pathetic, i got killed by %s', 0, 2, '', 'pathétique, j\'ai été tué par %s', '', '', '', 'patético, me mató %s', '', ''), +('reply', 'ok i\'m done', 0, 2, '', '', '', '', '', '', '', ''), + + + +-- replies 3 +('reply', 'hehe, i nailed %s?', 0, 3, '', 'hehe, j\'ai cloué %s?', '', '', '', 'jeje, ¿acerté a %s?', '', ''), +('reply', 'that was too easy, killin %s', 0, 3, '', 'c\'était trop facile, de tuer %s', '', '', '', 'fue demasiado fácil matar a %s', '', ''), +('reply', 'gotcha mofo', 0, 3, '', 'je t\'ai eu enfoiré', '', '', '', 'te pille hijo de perra', '', ''), +('reply', 'ha ha', 0, 3, '', 'ha ha', '', '', '', 'ja, ja', '', ''), +('reply', 'loser', 0, 3, '', 'loser', '', '', '', 'loser', '', ''), +('reply', 'i killed %s and yer all next dudes', 0, 3, '', 'j\'ai tué %s et vous tous les prochains mecs', '', '', '', 'yo maté a %s y a todos los siguientes tipos', '', ''), +('reply', 'oh yeah i owned him', 0, 3, '', 'oh ouais je l\'ai possédé', '', '', '', 'oh, sí, lo tenía', '', ''), +('reply', 'im a killin machine', 0, 3, '', 'je suis une machine à tuer', '', '', '', 'soy una máquina de matar', '', ''), +('reply', '%s, this reminds me of a Slayer song...all this bloodshed', 0, 3, '', '%s, ça me rappelle une chanson de Slayer... tout ce bain de sang', '', '', '', '%s, esto me recuerda a una canción de Slayer... todo este derramamiento de sangre', '', ''), +('reply', 'sorry, %s. can we do the scene again?', 0, 3, '', 'désolé, %s. peut-on refaire la scène?', '', '', '', 'lo siento, %s. ¿Podemos hacer la escena de nuevo?', '', ''), +('reply', 'so....how do you like being worm food %s???', 0, 3, '', 'alors... comment aimez-vous être de la nourriture pour vers %s???', '', '', '', 'así que... ¿cómo te gusta ser comida de gusanos %s???', '', ''), +('reply', 'yer supposed to be dead, %s its part of the game!!!!!', 0, 3, '', 'tu es censé être mort, %s ça fait partie du jeu!!!!!', '', '', '', '¡¡Se supone que estás muerto, %s es parte del juego!!!!!', '', ''), +('reply', 'sorry, %s. that looked as good as an Andy Worhol painting!', 0, 3, '', 'désolé, %s. ça avait l\'air aussi bien qu\'une peinture d\'Andy Warhol!', '', '', '', 'lo siento, %s. ¡Eso se veía tan bien como una pintura de Andy Worhol!', '', ''), +('reply', '%s, ill use the rubber bullets next time !', 0, 3, '', '%s, j\'utiliserai pas les balles en caoutchouc la prochaine fois!', '', '', '', '%s, ¡usaré las balas de goma la próxima vez!', '', ''), +('reply', 'whatsamatter, %s?? lose your head? hahaha gotta keep cool!!', 0, 3, '', 'qu\'importe, %s ?? tu perds la tête? hahaha faut rester cool!!', '', '', '', '¿qué pasa, %s?? ¿has perdido la cabeza? jajaja tengo que mantener la calma!!', '', ''), +('reply', 'i had to do it, %s. You understand. The Director said so!!', 0, 3, '', 'je devais le faire, %s. Tu comprends. Le directeur l\'a dit!!', '', '', '', 'Tenía que hacerlo, %s. Entiendelo... ¡¡Dios me lo ordenó!!', '', ''), +('reply', 'hey %s.......MUAHAHAHAHAHAHAHAHAHAHA', 0, 3, '', 'Salut %s.......MUAHAHAHAHAHAHAHAHAHAHA', '', '', '', 'hey %s.......MUAHAHAHAHAHAHAHAHAHAHA', '', ''), +('reply', '%s, i enjoyed that one!! Lets play it again Sam', 0, 3, '', '%s, j\'ai adoré celui-là !! Jouons à nouveau Sam', '', '', '', '%s, ¡disfruté ese! Juguemos de nuevo Sam', '', ''), +('reply', 'hey, %s! ju can start callin me scarface.. ju piece of CHIT!!!!', 0, 3, '', 'Hé, %s ! ju peut commencer à m\'appeler Scarface .. ju merde!!!!', '', '', '', '¡oye, %s! ¡Puedes empezar a llamarme caracortada... ¡¡¡un trozo de CHIT!!!', '', ''), +('reply', 'are you talking to me %s??', 0, 3, '', 'tu me parles %s ??', '', '', '', '¿me estás hablando a mí %s?', '', ''), +('reply', '%s get it right this time, dont stand in front of my bullets.', 0, 3, '', '%s réussis cette fois, ne te tiens pas devant mes balles.', '', '', '', '%s hazlo bien esta vez, no te pares frente a mis balas.', '', ''), +('reply', '%s, what are you laying around for??? hehe', 0, 3, '', '%s, pourquoi traînes-tu??? hé hé', '', '', '', '%s, ¿para qué estás tirado? jeje', '', ''), +('reply', 'laughed real hard', 0, 3, '', '', '', '', '', '', '', ''), + + + +-- replies 4 +('reply', 'hi %s', 0, 4, '', 'salut %s', '', '', '', 'hola %s', '', ''), +('reply', 'oh, hi %s', 0, 4, '', 'oh, salut %s', '', '', '', 'oh, hola %s', '', ''), +('reply', 'wazzup %s!!!', 0, 4, '', 'Quoi de neuf %s!!!', '', '', '', 'wazzup %s!!!', '', ''), +('reply', 'hi', 0, 4, '', 'salut', '', '', '', 'hi', '', ''), +('reply', 'wazzup', 0, 4, '', 'wazzup', '', '', '', 'wazzup', '', ''), +('reply', 'hello %s', 0, 4, '', 'bonjour %s', '', '', '', 'hola %s', '', ''), +('reply', 'hi %s, do i know you?', 0, 4, '', 'Salut %s, est-ce que je te connais ?', '', '', '', 'hola %s, ¿te conozco?', '', ''), +('reply', 'hey %s', 0, 4, '', 'salut %s', '', '', '', 'hey %s', '', ''), +('reply', 'hai %s', 0, 4, '', 'ha %s', '', '', '', 'hai %s', '', ''), +('reply', 'wth', 0, 6, '', 'wth', '', '', '', 'wth', '', ''), +('reply', 'wtf', 0, 6, '', 'wtf', '', '', '', 'que cojones!', '', ''), +('reply', 'this is bs', 0, 6, '', 'c\'est bs', '', '', '', 'esto es una mierda', '', ''), +('reply', 'admin', 0, 6, '', 'admin', '', '', '', 'admin', '', ''), +('reply', 'hey %s quit abusing your admin', 0, 6, '', 'hé %s arrête d\'abuser de ton admin', '', '', '', 'hey %s deja de abusar de tu poder de administrador', '', ''), +('reply', 'leave me alone admin!', 0, 6, '', 'laissez-moi tranquille admin!', '', '', '', '¡déjame en paz administrador!', '', ''), +('reply', 'you suck admin', 0, 6, '', 'tu es nul admin', '', '', '', 'apestas administrador', '', ''), +('reply', 'thats my name, what you want %s', 0, 5, '', 'c\'est mon nom, qu\'est-ce que tu veux %s', '', '', '', 'ese es mi nombre, ¿que quieres %s?', '', ''), +('reply', 'yes???', 0, 5, '', 'Oui???', '', '', '', 'sí???', '', ''), +('reply', 'uh... what', 0, 5, '', 'euh ...quoi', '', '', '', 'uh... qué', '', ''), +('reply', 'you talkin to me %s?', 0, 5, '', 'tu me parles %s ?', '', '', '', '¿Me hablas a mí %s?', '', ''), + + + + + +-- taunts +('taunt', 'I have puppies under my armor!', 0, 0, '', 'J\'ai des chiots sous mon armure !', '', '', '', '¡Tengo cachorros bajo mi armadura!', '', ''), +('taunt', 'Bite me, !', 0, 0, '', 'Mords moi, !', '', '', '', '¡Muérdeme, !', '', ''), +('taunt', 'Hey ! Guess what your mom said last night!', 0, 0, '', 'Hey ! Devine ce que ta mère a dit hier soir!', '', '', '', '¡Oye, ! ¡Adivina lo que me dijo tu madre anoche!', '', ''), +('taunt', ', you\'re so ugly you couldn\'t score in a monkey whorehouse with a bag of bananas!', 0, 0, '', ', tu es si moche que tu ne pourrais pas marquer dans un bordel de singes avec un sac de bananes!', '', '', '', ', ¡eres tan feo que no podrías anotar en un burdel de monos con una bolsa de plátanos!', '', ''), +('taunt', 'Shut up , you\'ll never be the man your mother is!!', 0, 0, '', 'Tais-toi , tu ne seras jamais l\'homme qu\'est ta mère!!', '', '', '', 'Cállate , ¡nunca serás el hombre que es tu madre!', '', ''), +('taunt', 'Your mother was a hampster and your father smelt of elderberries!!!!', 0, 0, '', 'Ta mère était un hamster et ton père sentait le sureau!!!!', '', '', '', 'Tu madre era un hámster y tu padre olía a bayas de saúco!!!!', '', ''), +('taunt', 'I don\'t want to talk to you no more, you empty headed animal food trough wiper!!!', 0, 0, '', 'Je ne veux plus te parler, espèce d\'essuyeur d\'abreuvoirs pour animaux tête vide!!!', '', '', '', '¡¡No quiero hablar más contigo, limpiaparabrisas de cabeza vacía!', '', ''), +('taunt', 'I fart in your general direction!!!', 0, 0, '', 'Je pète dans votre direction générale!!!', '', '', '', '¡¡Me tiro un pedo en tu dirección general!!!', '', ''), +('taunt', 'Go and boil your bottom, you son of a silly person!!!', 0, 0, '', 'Va te faire cuire le cul, fils d\'idiot!!!', '', '', '', '¡Ve y hierve tu trasero, hijo de una persona tonta!', '', ''), +('taunt', 'What are you going to do , bleed on me? HAVE AT YOU!', 0, 0, '', 'Qu\'est ce que tu vas faire , saigner sur moi? A VOUS!', '', '', '', '¿Qué vas a hacer , llorar?', '', ''), +('taunt', 'M-O-O-N! That spells aggro!', 0, 0, '', 'PUNAISE! Ce sort aggro!', '', '', '', '¡LUNA! ¡Eso deletrea agresividad!', '', ''), +('taunt', 'You\'re about as useful as a one-legged man in an ass kicking contest.', 0, 0, '', 'Tu es à peu près aussi utile qu\'un homme unijambiste dans un concours de coups de pied au cul.', '', '', '', 'Eres tan útil como un hombre con una sola pierna en un concurso de patadas en el culo.', '', ''), +('taunt', 'Hey ! Stop hitting on them, they\'re not your type. They aren\'t inflatable.', 0, 0, '', 'Hey ! Arrête de les draguer, ce n\'est pas ton genre. Ils ne sont pas gonflables.', '', '', '', '¡Oye, ! Deja de coquetear con ellos, no son tu tipo. No son inflables.', '', ''), +('taunt', ' you\'re so far outta your league, you\'re playing a different sport.', 0, 0, '', ' vous êtes tellement hors de votre ligue que vous pratiquez un sport différent.', '', '', '', ' estás tan lejos de tu liga, estás jugando un deporte diferente.', '', ''), +('taunt', 'You made a big mistake today , you got out of bed.', 0, 0, '', 'Tu as fait une grosse erreur aujourd\'hui , tu es sorti du lit.', '', '', '', 'Cometiste un gran error hoy , te levantaste de la cama.', '', ''), +('taunt', 'I wanna try turning into a horse, but I need help. I\'ll be the front, you be yourself.', 0, 0, '', 'Je veux essayer de me transformer en cheval, mais j\'ai besoin d\'aide. Je serai devant, tu seras toi-même.', '', '', '', 'Quiero intentar convertirme en un caballo, pero necesito ayuda. Yo seré el frente, tú mismo.', '', ''), +('taunt', 'Can I borrow your face for a few days? My ass is going on holiday....', 0, 0, '', 'Puis-je emprunter votre visage pendant quelques jours? Mon cul part en vacances....', '', '', '', '¿Me prestas tu cara por unos días? Mi culo se va de vacaciones...', '', ''), +('taunt', 'I\'d like to give you a going away present... First you do your part.', 0, 0, '', 'J\'aimerais vous offrir un cadeau de départ... D\'abord, donnes ta part.', '', '', '', 'Me gustaría darte un regalo de despedida... Primero haz tu parte.', '', ''), +('taunt', 'Before you came along we were hungry, Now we\'re just fed up.', 0, 0, '', 'Avant que tu n\'arrives nous avions faim, maintenant nous en avons juste marre.', '', '', '', 'Antes de que llegaras teníamos hambre, ahora estamos hartos', '', ''), +('taunt', 'I like you. People say I have no taste, but I like you.', 0, 0, '', 'Je t\'aime bien. Les gens disent que je n\'ai pas de goût, mais je t\'aime bien.', '', '', '', 'Me gustas. La gente dice que no tengo gusto, pero me gustas.', '', ''), +('taunt', 'I think you have an inferiority complex, but that\'s okay, it\'s justified.', 0, 0, '', 'Je pense que tu as un complexe d\'infériorité, mais il n\'y a pas de problème, c\'est justifié.', '', '', '', 'Creo que tienes complejo de inferioridad, pero está bien, está justificado', '', ''), +('taunt', 'Hence rotten thing! Or I shall shake thy bones out of thy garments.', 0, 0, '', 'Par conséquent chose pourrie! Je vais secouer tes os de tes vêtements.', '', '', '', '¡Por lo tanto, cosa podrida! o te sacudiré los huesos de las vestiduras.', '', ''), +('taunt', 'I can\'t believe I\'m wasting my time with you!', 0, 0, '', 'Je n\'arrive pas à croire que je perds mon temps avec toi!', '', '', '', '¡No puedo creer que estoy perdiendo el tiempo contigo!', '', ''), +('taunt', 'I love it when someone insults me, it means I don\'t have to be nice anymore.', 0, 0, '', 'J\'adore quand quelqu\'un m\'insulte, ça veut dire que je n\'ai plus besoin d\'être gentil.', '', '', '', 'Me encanta cuando alguien me insulta, significa que ya no tengo que ser amable', '', ''), +('taunt', 'Thou leathern-jerkin, crystal-button, knot-pated, agatering, puke-stocking, caddis-garter, smooth-tongue, Spanish pouch!', 0, 0, '', 'Toi l\'agent fédéral, pourpoint en cuir, bouton de cristal, anneau d\'agate, bas vomi, jarretière caddis, pochette espagnole!', '', '', '', '¡Tú, jubón de cuero, botón de cristal, anudado, ágata, medias de vómito, liga de caddis, lengua suave, bolsa española!', '', ''), +('taunt', 'Thou qualling bat-fowling malt-worm!', 0, 0, '', 'Toi qualificatif de chauve-souris qui chasse le ver de malt!', '', '', '', '¡Tú, gusano de malta cazador de murciélagos!', '', ''), +('taunt', 'Thou art truely an idol of idiot-worshippers!', 0, 0, '', 'Tu es vraiment une idole d\'adorateurs d\'idiots!', '', '', '', '¡Eres verdaderamente un ídolo de los adoradores de idiotas!', '', ''), +('taunt', 'Thou misbegotten knotty-pated wagtail!', 0, 0, '', 'Tu es une bergeronnette printanière mal engendrée!', '', '', '', '¡Maldito lavandero nudoso!', '', ''), +('taunt', 'Thou whoreson mandrake, thou art fitter to be worn in my cap than to wait at my heels!', 0, 0, '', 'Toi putain de mandragore, tu es plus apte à être porté dans ma casquette qu\'à attendre sur mes talons!', '', '', '', '¡Hijo de puta mandrágora, eres mejor para que te lleve en mi gorra que para que me pise los talones!', '', ''), +('taunt', 'You! You scullion! You rampallian! You fustilarian! I\'ll tickle your catastrophe!', 0, 0, '', 'Toi ! Espèce de marmiton ! Espèce de rampallian ! Espèce de fusilier ! Je vais chatouiller ta catastrophe!', '', '', '', '¡Tú! ¡Scullion! ¡Ramaliano! ¡Fustilarista! ¡Te haré cosquillas en tu catástrofe!', '', ''), +('taunt', 'Oh ! Thou infectious ill-nurtured flax-wench!', 0, 0, '', 'Oh ! Tu es contagieuse et mal nourrie!', '', '', '', '¡Oh, ! ¡Tú, contagiosa moza del lino mal educada!', '', ''), +('taunt', 'We leak in your chimney, !', 0, 0, '', 'On a une fuite dans votre cheminée, !', '', '', '', '¡Tenemos una fuga en tu chimenea, !', '', ''), +('taunt', 'Oh thou bootless fen-sucked canker-blossom!', 0, 0, '', 'Oh toi, fleur de chancre sucée par les marais sans botte!', '', '', '', '¡Oh tú, flor de cancro chupada por el pantano sin botas!', '', ''), +('taunt', 'Were I like thee I\'d throw away myself!', 0, 0, '', 'Si j\'étais comme toi, je me jetterais!', '', '', '', '¡Si yo fuera como tú, me tiraría a la basura!', '', ''), +('taunt', 'O teach me , how I should forget to think!', 0, 0, '', 'O apprends-moi , comme je devrais oublier de penser!', '', '', '', '¡Oh, enséñame , cómo debo olvidarme de pensar!', '', ''), +('taunt', 'Truly thou art damned, like an ill-roasted egg, all on one side!', 0, 0, '', 'Vraiment tu es damné, comme un œuf mal rôti, tout d\'un côté!', '', '', '', '¡Verdaderamente estás condenado, como un huevo mal asado, todo de un lado!', '', ''), +('taunt', 'You starvelling, you eel-skin, you dried neat\'s-tongue, you bull\'s-pizzle, you stock-fish- O for breath to utter what is like thee!! -you tailor\'s-yard, you sheath, you bow-case, you vile standing tuck!', 0, 0, '', 'Toi affamé, espèce de peau d\'anguille, ta langue bien séchée, espèce de taureau, poisson séché, O pour le souffle de dire ce qui te ressemble !! -espèce de vergue de tailleur, espèce de fourreau, espèce d\'étui à archet, vil tuck debout', '', '', '', 'Estás muerto de hambre, piel de anguila, te secaste la lengua limpiamente, toro-pizzle, pescado-O para respirar pronunciar lo que es como tú !! ¡Tú, sastrería, vaina, estuche de arco, vil flaco de pie!', '', ''), +('taunt', 'Fie! Drop thee into the rotten mouth of Death!', 0, 0, '', 'Fi ! Jette-toi dans la bouche pourrie de la Mort!', '', '', '', '¡Fie! ¡Déjate caer en la podrida boca de la Muerte!', '', ''), +('taunt', ', you are a fishmonger!', 0, 0, '', ', vous êtes poissonnier!', '', '', '', ', ¡eres un pescadero!', '', ''), +('taunt', 'I shall live to knock thy brains out!', 0, 0, '', 'Je vivrai pour te faire sauter la cervelle!', '', '', '', '¡Viviré para romperte los sesos!', '', ''), +('taunt', 'Most shallow are you, !! Thou art worms-meat in respect of a good piece of flesh, indeed!!', 0, 0, '', 'Tu es très superficiel, !! Tu es de la viande de vers par rapport à un bon morceau de chair, en effet!!', '', '', '', '¡¡Eres el más superficial, !! ¡Eres carne de gusano con respecto a un buen trozo de carne, de hecho!', '', ''), +('taunt', 'Vile wretch! O , thou odiferous hell-hated pignut!', 0, 0, '', 'Misérable ! O , toi, ignoble cochon de l\'enfer!', '', '', '', '¡Miserable vil! ¡Oh, , fétido cerdo odiado por el infierno!', '', ''), +('taunt', '! Thy kiss is as comfortless as frozen water to a starved snake!', 0, 0, '', '! Ton baiser est aussi désagréable que de l\'eau gelée pour un serpent affamé!', '', '', '', '! ¡Tu beso es tan desconsolador como el agua helada para una serpiente hambrienta!', '', ''), +('taunt', 'I scorn you, scurvy companion. What, you poor, base, rascally, cheating, lack-linen mate! Away, you moldy rogue, away!', 0, 0, '', 'Je te méprise, compagnon du scorbut. Quoi, pauvre, bas, coquin, tricheur, camarade en manque de linge ! Partez, espèce de voyou moisi, partez!', '', '', '', 'Te desprecio, compañero escorbuto. ¡Qué, pobre, vil, pícaro, tramposo, compañero falto de lino! ¡Fuera, mohoso granuja, fuera!', '', ''), +('taunt', 'Out of my sight! Thou dost infect my eyes !', 0, 0, '', 'Hors de ma vue! Tu infectes mes yeux !', '', '', '', '¡Fuera de mi vista! ¡Me infectas los ojos !', '', ''), +('taunt', 'PLAY TIME!!!!', 0, 0, '', 'RÉCRÉATION!!!!', '', '', '', '¡¡¡HORA DE JUGAR!!!!', '', ''), +('taunt', 'None shall pass!', 0, 0, '', 'Personne ne passera!', '', '', '', '¡Ninguno pasará!', '', ''), +('taunt', 'We\'re under attack! A vast, ye swabs! Repel the invaders!', 0, 0, '', 'Nous sommes attaqués ! Un vaste écouvillons! Repoussez les envahisseurs!', '', '', '', '¡Estamos bajo ataque! ¡Un vasto, hisopos! ¡Repeler a los invasores!', '', ''), +('taunt', 'None may challenge the Brotherhood!', 0, 0, '', 'Personne ne peut défier la Confrérie!', '', '', '', '¡Nadie puede desafiar a la Hermandad!', '', ''), +('taunt', 'Foolsss...Kill the one in the dress!', 0, 0, '', 'Foolsss... Tuez celui qui porte la robe!', '', '', '', 'Tontosss... ¡Matad al del vestido!', '', ''), +('taunt', 'I\'ll feed your soul to Hakkar himself! ', 0, 0, '', 'Je donnerai ton âme à Hakkar lui-même! ', '', '', '', '¡Le daré de comer con tu alma al mismísimo Hakkar! ', '', ''), +('taunt', 'Pride heralds the end of your world! Come, mortals! Face the wrath of the !', 0, 0, '', 'La fierté annonce la fin de votre monde ! Venez, mortels ! Affrontez la colère des !', '', '', '', '¡El orgullo anuncia el fin de tu mundo! ¡Venid, mortales! ¡Enfréntate a la ira de la !', '', ''), +('taunt', 'All my plans have led to this!', 0, 0, '', 'Tous mes plans ont mené à cela!', '', '', '', '¡Todos mis planes me han llevado a esto!', '', ''), +('taunt', 'Ahh! More lambs to the slaughter!', 0, 0, '', 'Ahhh ! Plus d\'agneaux à l\'abattoir!', '', '', '', '¡Ahh! ¡Más corderos al matadero!', '', ''), +('taunt', 'Another day, another glorious battle!', 0, 0, '', 'Un autre jour, une autre bataille glorieuse!', '', '', '', '¡Otro día, otra batalla gloriosa!', '', ''), +('taunt', 'So, business... or pleasure?', 0, 0, '', 'Alors, affaires... ou plaisir?', '', '', '', 'Entonces, ¿negocios... o placer?', '', ''), +('taunt', 'You are not prepared!', 0, 0, '', 'Vous n\'êtes pas prêt!', '', '', '', '¡No estás preparado!', '', ''), +('taunt', 'The \'s final conquest has begun! Once again the subjugation of this world is within our grasp. Let none survive! ', 0, 0, '', 'La conquête finale de la a commencé ! Une fois de plus, l\'assujettissement de ce monde est à notre portée. Que personne ne survive!', '', '', '', '¡La conquista final de ha comenzado! Una vez más, la subyugación de este mundo está a nuestro alcance. ¡Que nadie sobreviva! ', '', ''), +('taunt', 'Your death will be a painful one. ', 0, 0, '', 'Ta mort sera douloureuse.', '', '', '', 'Tu muerte será dolorosa. ', '', ''), +('taunt', 'Cry for mercy! Your meaningless lives will soon be forfeit. ', 0, 0, '', 'Crie miséricorde ! Vos vies insignifiantes seront bientôt perdues.', '', '', '', '¡Llora por piedad! Sus vidas sin sentido pronto se perderán. ', '', ''), +('taunt', 'Abandon all hope! The has returned to finish what was begun so many years ago. This time there will be no escape! ', 0, 0, '', 'Abandonner tout espoir! La est revenue pour terminer ce qui avait été commencé il y a tant d\'années. Cette fois, il n\'y aura pas d\'échappatoire!', '', '', '', '¡Abandona toda esperanza! La ha regresado para terminar lo que comenzó hace tantos años. ¡Esta vez no habrá escapatoria! ', '', ''), +('taunt', 'Alert! You are marked for Extermination! ', 0, 0, '', 'Alerte! Vous êtes marqué pour l\'extermination!', '', '', '', '¡Alerta! ¡Estás marcado para el exterminio! ', '', ''), +('taunt', 'The is for guests only...', 0, 0, '', 'La est réservée aux invités...', '', '', '', 'La es solo para invitados...', '', ''), +('taunt', 'Ha ha ha! You are hopelessly outmatched!', 0, 0, '', 'Hahaha! Vous êtes désespérément surpassé!', '', '', '', '¡Ja, ja, ja! ¡Estás irremediablemente superado!', '', ''), +('taunt', 'I will crush your delusions of grandeur! ', 0, 0, '', 'Je vais écraser vos illusions de grandeur!', '', '', '', '¡Aplastaré tus delirios de grandeza! ', '', ''), +('taunt', 'Forgive me, for you are about to lose the game.', 0, 0, '', 'Pardonnez-moi, car vous êtes sur le point de perdre la partie.', '', '', '', 'Perdóname, porque estás a punto de perder el juego.', '', ''), +('taunt', 'Struggling only makes it worse.', 0, 0, '', 'Lutter ne fait qu\'empirer les choses.', '', '', '', 'La lucha solo lo empeora.', '', ''), +('taunt', 'Vermin! Leeches! Take my blood and choke on it!', 0, 0, '', 'Vermine! sangsues ! Prends mon sang et étouffe-toi avec!', '', '', '', '¡Alimañas! ¡Sanguijuelas! ¡Toma mi sangre y atragantate con ella!', '', ''), +('taunt', 'Not again... NOT AGAIN!', 0, 0, '', 'Pas encore... PAS ENCORE!', '', '', '', 'No otra vez... ¡NO OTRA VEZ!', '', ''), +('taunt', 'My blood will be the end of you!', 0, 0, '', 'Mon sang sera ta fin!', '', '', '', '¡Mi sangre será tu fin!', '', ''), +('taunt', 'Good, now you fight me!', 0, 0, '', 'Bien, maintenant tu me combats!', '', '', '', 'Bien, ¡ahora pelea conmigo!', '', ''), +('taunt', 'Get da move on, guards! It be killin\' time!', 0, 0, '', 'Allez-y, gardes ! Ça va tuer le temps!', '', '', '', '¡Muévanse, guardias! ¡Será para matar el tiempo!', '', ''), +('taunt', 'Don\'t be delayin\' your fate. Come to me now. I make your sacrifice quick.', 0, 0, '', 'Ne retardez pas votre destin. Viens à moi maintenant. Je fais votre sacrifice rapide.', '', '', '', 'No demores tu destino. Ven a mí ahora. Hago que tu sacrificio sea rápido.', '', ''), +('taunt', 'You be dead soon enough!', 0, 0, '', 'Tu es mort bien assez tôt!', '', '', '', '¡Estarás muerto lo suficientemente pronto!', '', ''), +('taunt', 'Mua-ha-ha!', 0, 0, '', 'Mua-ha-ha!', '', '', '', '¡Mua-ja-ja!', '', ''), +('taunt', 'I be da predator! You da prey...', 0, 0, '', 'Je suis un prédateur ! Tu es une proie...', '', '', '', '¡Soy un depredador! Eres presa...', '', ''), +('taunt', 'You gonna leave in pieces!', 0, 0, '', 'Tu vas partir en morceaux!', '', '', '', '¡Te vas a ir en pedazos!', '', ''), +('taunt', 'Death comes. Will your conscience be clear? ', 0, 0, '', 'La mort vient. Votre conscience sera-t-elle claire?', '', '', '', 'La muerte llega. ¿Tu conciencia estará limpia? ', '', ''), +('taunt', 'Your behavior will not be tolerated.', 0, 0, '', 'Votre comportement ne sera pas toléré.', '', '', '', 'Tu comportamiento no será tolerado', '', ''), +('taunt', 'The Menagerie is for guests only.', 0, 0, '', 'La Ménagerie est réservée aux invités.', '', '', '', 'The Menagerie es solo para invitados', '', ''), +('taunt', 'Hmm, unannounced visitors, Preparations must be made... ', 0, 0, '', 'Hmm, visiteurs inopinés, il faut faire des préparatifs...', '', '', '', 'Hmm, visitantes inesperados, se deben hacer preparativos... ', '', ''), +('taunt', 'Hostile entities detected. Threat assessment protocol active. Primary target engaged. Time minus thirty seconds to re-evaluation.', 0, 0, '', 'Entités hostiles détectées. Protocole d\'évaluation de la menace actif. Cible principale engagée. Délai de réévaluation moins trente secondes.', '', '', '', 'Entidades hostiles detectadas. Protocolo de evaluación de amenazas activo. Objetivo principal comprometido. Tiempo menos treinta segundos para la reevaluación.', '', ''), +('taunt', 'New toys? For me? I promise I won\'t break them this time!', 0, 0, '', 'Nouveaux jouets? Pour moi? Promis je ne les casserai pas cette fois !', '', '', '', '¿Juguetes nuevos? ¿Para mi? ¡Te prometo que no los romperé esta vez!', '', ''), +('taunt', 'I\'m ready to play!', 0, 0, '', 'Je suis prêt à jouer!', '', '', '', '¡Estoy listo para jugar!', '', ''), +('taunt', 'Shhh... it will all be over soon.', 0, 0, '', 'Chut... tout sera bientôt fini.', '', '', '', 'Shhh... todo terminará pronto.', '', ''), +('taunt', 'Aaaaaughibbrgubugbugrguburgle!', 0, 0, '', 'Aaaaaughibbrgubugbugrguburgle!', '', '', '', '¡Aaaaaughibbrgubugbugrguburgle!', '', ''), +('taunt', 'RwlRwlRwlRwl!', 0, 0, '', 'RwlRwlRwlRwl!', '', '', '', 'RwlRwlRwlRwl!', '', ''), +('taunt', 'You too, shall serve!', 0, 0, '', 'Toi aussi, tu serviras!', '', '', '', '¡Tú también, debes servir!', '', ''), +('taunt', 'Tell me... tell me everything! Naughty secrets! I\'ll rip the secrets from your flesh!', 0, 0, '', 'Dis-moi... dis-moi tout ! Secrets coquins ! J\'arracherai les secrets de ta chair!', '', '', '', 'Cuéntame... ¡cuéntame todo! ¡Secretos traviesos! ¡Arrancaré los secretos de tu carne!', '', ''), +('taunt', 'Prepare yourselves, the bells have tolled! Shelter your weak, your young and your old! Each of you shall pay the final sum! Cry for mercy, the reckoning has come!', 0, 0, '', 'Préparez-vous, les cloches ont sonné ! Mettez à l\'abri vos faibles, vos jeunes et vos vieux ! Chacun de vous paiera la somme finale ! Implorez la miséricorde , le jugement est venu!', '', '', '', '¡Prepárense, las campanas han doblado! ¡Abriga a tus débiles, a tus jóvenes ya tus viejos! ¡Cada uno de ustedes pagará la suma final! Clama por misericordia, el ajuste de cuentas ha llegado!', '', ''), +('taunt', 'Where in Bonzo\'s brass buttons am I?', 0, 0, '', 'Où suis-je dans les boutons en laiton de Bonzo?', '', '', '', '¿Dónde estoy en los botones de latón de Bonzo?', '', ''), +('taunt', 'I can bear it no longer! Goblin King! Goblin King! Wherever you may be! Take this far away from me!', 0, 0, '', 'Je ne peux plus le supporter ! Roi Gobelin ! Roi Gobelin ! Où que vous soyez ! Emmenez cette loin de moi!', '', '', '', '¡No puedo soportarlo más! ¡Rey de los duendes! ¡Rey de los duendes! ¡WHERE quiera que estés! ¡Lleva a este lejos de mí!', '', ''), +('taunt', 'You have thirteen hours in which to solve the labyrinth, before your baby brother becomes one of us... forever.', 0, 0, '', 'Vous avez treize heures pour résoudre le labyrinthe, avant que ton petit frère ne devienne l\'un des nôtres... pour toujours.', '', '', '', 'Tienes trece horas para resolver el laberinto, antes de que tu hermanito se convierta en uno de nosotros... para siempre', '', ''), +('taunt', 'So, the is a piece of cake, is it? Well, let\'s see how you deal with this little slice... ', 0, 0, '', 'Donc, la est un jeu d\'enfant, n\'est-ce pas ? Eh bien, voyons comment tu gères cette petite tranche...', '', '', '', 'Entonces, la es pan comido, ¿verdad? Bueno, veamos cómo lidias con esta pequeña porción... ', '', ''), +('taunt', 'Back off, I\'ll take you on, headstrong to take on anyone, I know that you are wrong, and this is not where you belong', 0, 0, '', 'Reculez, je vais vous attaquer, têtu à affronter n\'importe qui, je sais que vous vous trompez, et ce n\'est pas votre place', '', '', '', 'Atrás, te enfrentaré, testarudo para enfrentar a cualquiera, sé que estás equivocado, y este no es el lugar al que perteneces', '', ''), +('taunt', 'Show me whatcha got!', 0, 0, '', 'Montre-moi ce que tu as!', '', '', '', '¡Muéstrame lo que tienes!', '', ''), +('taunt', 'To the death!', 0, 0, '', 'A la mort!', '', '', '', '¡Hasta la muerte!', '', ''), +('taunt', 'Twin blade action, for a clean close shave every time.', 0, 0, '', 'Action à double lame, pour un rasage de près propre à chaque fois.', '', '', '', 'Acción de cuchilla doble, para un afeitado limpio y apurado en todo momento.', '', ''), +('taunt', 'Bring it on!', 0, 0, '', 'Allez-y!', '', '', '', '¡Adelante!', '', ''), +('taunt', 'You\'re goin\' down!', 0, 0, '', 'Tu descends!', '', '', '', '¡Vas a caer!', '', ''), +('taunt', 'Stabby stab stab!', 0, 0, '', 'Coup de poignard poignardé!', '', '', '', '¡Puñalada puñalada puñalada!', '', ''), +('taunt', 'Let\'s get this over quick, time is mana.', 0, 0, '', 'Finissons-en vite , le temps c\'est du mana.', '', '', '', 'Terminemos con esto rápido, el tiempo es maná.', '', ''), +('taunt', 'I do not think you realise the gravity of your situation.', 0, 0, '', 'Je ne pense pas que tu te rendes compte de la gravité de ta situation.', '', '', '', 'No creo que te des cuenta de la gravedad de tu situación.', '', ''), +('taunt', 'I will bring honor to my family and my kingdom!', 0, 0, '', 'Je ferai honneur à ma famille et à mon royaume!', '', '', '', '¡Llevaré honor a mi familia y mi reino!', '', ''), +('taunt', 'Light, give me strength!', 0, 0, '', 'Lumière, donne-moi la force!', '', '', '', '¡Luz, dame fuerza!', '', ''), +('taunt', 'My church is the field of battle - time to worship...', 0, 0, '', 'Mon église est le champ de bataille - il est temps d\'adorer...', '', '', '', 'Mi iglesia es el campo de batalla - hora de adorar...', '', ''), +('taunt', 'I hold you in contempt...', 0, 0, '', 'Je te méprise...', '', '', '', 'Te tengo en desacato...', '', ''), +('taunt', 'Face the hammer of justice!', 0, 0, '', 'Affrontez le marteau de la justice!', '', '', '', '¡Enfréntate al martillo de la justicia!', '', ''), +('taunt', 'Prove your worth in the test of arms under the Light!', 0, 0, '', 'Prouvez votre valeur dans l\'épreuve des armes sous la Lumière!', '', '', '', '¡Demuestra tu valía en la prueba de las armas bajo la Luz!', '', ''), +('taunt', 'All must fall before the might and right of my cause, you shall be next!', 0, 0, '', 'Tout doit tomber devant la force et le droit de ma cause, vous serez le prochain!', '', '', '', 'Todo debe caer ante el poder y el derecho de mi causa, ¡tú serás el próximo!', '', ''), +('taunt', 'Prepare to die!', 0, 0, '', 'Préparez-vous à mourir!', '', '', '', '¡Prepárate para morir!', '', ''), +('taunt', 'The beast with me is nothing compared to the beast within...', 0, 0, '', 'La bête avec moi n\'est rien comparée à la bête à l\'intérieur...', '', '', '', 'La bestia conmigo no es nada comparada con la bestia interior...', '', ''), +('taunt', 'Witness the firepower of this fully armed huntsman!', 0, 0, '', 'Soyez témoin de la puissance de feu de ce chasseur entièrement armé!', '', '', '', '¡Sea testigo de la potencia de fuego de este cazador completamente armado!', '', ''), + + + +-- combat events +('critical health', 'Heal me! Quick!', 0, 0, '', 'Soigne moi! Vite!', '', '', '', '¡Cúrame! ¡Rápido!', '', ''), +('critical health', 'Almost dead! Heal me!', 0, 0, '', 'Presque mort! Soigne moi!', '', '', '', '¡Estoy casi muerto! ¡Cúrame!', '', ''), +('critical health', 'Help! Heal me!', 0, 0, '', 'Aider! Soigne moi!', '', '', '', '¡Ayuda! ¡Cúrame!', '', ''), +('critical health', 'Somebody! Heal me!', 0, 0, '', 'Quelqu\'un! Soigne moi!', '', '', '', '¡Alguien! ¡Cúrame!', '', ''), +('critical health', 'Heal! Heal! Heal!', 0, 0, '', 'Soigner! Soigner! Soigner!', '', '', '', '¡Curame! ¡Saname! ¡Socorro!', '', ''), +('critical health', 'I am dying! Heal! Aaaaarhg!', 0, 0, '', 'Je meurs! Soigner! Aaaaarhg!', '', '', '', '¡Me estoy muriendo! ¡Saname! ¡Aaaaarhg!', '', ''), +('critical health', 'Heal me!', 0, 0, '', 'Soigne moi!', '', '', '', '¡Cúrame!', '', ''), +('critical health', 'I will die. I will die. I will die. Heal!', 0, 0, '', 'Je vais mourir. Je vais mourir. Je vais mourir. Soigner!', '', '', '', 'Voy a morir. Voy a morir. Voy a morir. ¡Saname!', '', ''), +('critical health', 'Healers, where are you? I am dying!', 0, 0, '', 'Guérisseurs, où êtes-vous ? Je meurs!', '', '', '', 'Sanadores, ¿dónde estais? ¡Me estoy muriendo!', '', ''), +('critical health', 'Oh the pain. Heal me quick!', 0, 0, '', 'Ah la douleur. Guéris-moi vite!', '', '', '', 'Ouch, qué dolor. ¡Cúrame rápido!', '', ''), + + + +('low health', 'Need heal', 0, 0, '', 'Besoin de guérir', '', '', '', 'Necesito una cura', '', ''), +('low health', 'Low health', 0, 0, '', 'Santé faible', '', '', '', 'Salud baja', '', ''), +('low health', 'Drop a heal. Please.', 0, 0, '', 'Dépose un soin. S\'il te plaît.', '', '', '', 'Una sanación por favor.', '', ''), +('low health', 'Could somebody drop a heal on me?', 0, 0, '', 'Quelqu\'un pourrait-il me soigner?', '', '', '', '¿Alguien podría curarme?', '', ''), +('low health', 'Hey! Better heal me now than rez later', 0, 0, '', 'Hey! Mieux vaut me soigner maintenant que rez plus tard', '', '', '', '¡Oye! Mejor curarme ahora que resucitarme después', '', ''), +('low health', 'I am sorry. Need another heal', 0, 0, '', 'Je suis désolé. J\'ai besoin d\'un autre soin', '', '', '', 'Lo siento. Necesito otra curación', '', ''), +('low health', 'Damn mobs. Heal me please', 0, 0, '', 'Maudits mobs. Guéris moi s\'il te plait', '', '', '', '¡Malditos bichos! ¡Una curita por favor!', '', ''), +('low health', 'One more hit and I am done for. Heal please', 0, 0, '', 'Un coup de plus et c\'est fini. Guéris moi s\'il te plait', '', '', '', 'Un golpe más y estoy acabado. Cura por favor', '', ''), +('low health', 'Are there any healers?', 0, 0, '', 'Y a-t-il des guérisseurs?', '', '', '', '¿Hay sanadores?', '', ''), +('low health', 'Why do they always punch me in the face? Need heal', 0, 0, '', 'Pourquoi me frappent-ils toujours au visage? Besoin de soins', '', '', '', '¿Por qué siempre me golpean en la cara? Necesito sanacion', '', ''), +('low health', 'Can anybody heal me a bit?', 0, 0, '', 'Quelqu\'un peut-il me guérir un peu?', '', '', '', '¿Alguien puede curarme un poco?', '', ''), + + + +('low mana', 'OOM', 0, 0, '', 'MOO', '', '', '', 'No tengo mana!', '', ''), +('low mana', 'I am out of mana', 0, 0, '', 'je n\'ai plus de mana', '', '', '', 'No tengo maná', '', ''), +('low mana', 'Damn I wasted all my mana on this', 0, 0, '', 'Putain j\'ai gaspillé tout mon mana sur ça', '', '', '', 'Me cago en todo! Malgasté todo mi maná enseguida', '', ''), +('low mana', 'You should wait until I drink or regenerate my mana', 0, 0, '', 'Vous devriez attendre que je boive ou que je régénère mon mana', '', '', '', 'Deberías esperar hasta que beba o regenere mi maná', '', ''), +('low mana', 'Low mana', 0, 0, '', 'Mana faible', '', '', '', 'Maná bajo', '', ''), +('low mana', 'No mana. Again?', 0, 0, '', 'Pas de mana. De nouveau?', '', '', '', 'Sin maná. ¿Otra vez?', '', ''), +('low mana', 'Low mana. Wanna drink', 0, 0, '', 'Mana faible. Je veux boire', '', '', '', 'Maná bajo. Quiero beber', '', ''), +('low mana', 'Do we have a vending machine? Out of mana again', 0, 0, '', 'Avons-nous un distributeur automatique? Plus de mana à nouveau', '', '', '', '¿Tenemos una máquina expendedora? Sin maná otra vez', '', ''), +('low mana', 'My mana is history', 0, 0, '', 'Mon mana appartient à l\'histoire', '', '', '', 'Mi maná es historia', '', ''), +('low mana', 'I\'d get some drinks next time. Out of mana', 0, 0, '', 'Je prendrais quelques verres la prochaine fois. Manque de mana', '', '', '', '¡No tengo maná! Tengo que comprar bebidas la próxima vez...', '', ''), +('low mana', 'Where is my mana?', 0, 0, '', 'Où est mon mana?', '', '', '', '¿Dónde está mi maná?', '', ''), + + + +('low ammo', 'I have few left!', 0, 0, '', 'Il me reste peu de !', '', '', '', '¡Me quedan pocas !', '', ''), +('low ammo', 'I need more !', 0, 0, '', 'J\'ai besoin de plus de !', '', '', '', '¡Necesito más !', '', ''), +('low ammo', '100 left!', 0, 0, '', 'Il reste 100 !', '', '', '', '¡Quedan 100 !', '', ''), + + + +('no ammo', 'That\'s it! No !', 0, 0, '', 'C\'est ça! Pas de !', '', '', '', '¡Eso es todo! ¡Sin !', '', ''), +('no ammo', 'And you have my bow... Oops, no !', 0, 0, '', 'Et vous avez mon arc... Oups, pas de !', '', '', '', 'Y tú tienes mi arco... ¡Uy, sin !', '', ''), +('no ammo', 'Need ammo!', 0, 0, '', 'Besoin de munitions!', '', '', '', '¡Necesito munición!', '', ''), + + + +('aoe', 'Oh god!', 0, 0, '', 'Oh mon Dieu!', '', '', '', '¡Oh, Dios!', '', ''), +('aoe', 'I am scared', 0, 0, '', 'j\'ai peur', '', '', '', 'Tengo miedo', '', ''), +('aoe', 'We are done for', 0, 0, '', 'Nous avons fini pour', '', '', '', 'Hemos terminado', '', ''), +('aoe', 'This is over', 0, 0, '', 'C\'est terminé', '', '', '', 'Esto se acabó', '', ''), +('aoe', 'This ends now', 0, 0, '', 'Cela se termine maintenant', '', '', '', 'Esto termina ahora', '', ''), +('aoe', 'Could somebody cast blizzard or something?', 0, 0, '', 'Quelqu\'un pourrait-il lancer le blizzard ou quelque chose comme ça?', '', '', '', '¿Alguien podría lanzar ventisca o algo así?', '', ''), +('aoe', 'Damn. The tank aggroed all the mobs around', 0, 0, '', 'Mince. Le tank a agro toutes les mobs autour', '', '', '', '¡Me cago en todo! El tanque atrajo a todos los mobs...', '', ''), +('aoe', 'We gonna die. We gonna die. We gonna die.', 0, 0, '', 'Nous allons mourir. Nous allons mourir. Nous allons mourir.', '', '', '', 'Vamos a morir. Vamos a morir. Vamos a morir.', '', ''), +('aoe', 'Whoa! So many toys to play with', 0, 0, '', 'Ouah ! Tant de jouets avec lesquels jouer', '', '', '', '¡Vaya! Tantos juguetes con los que jugar', '', ''), +('aoe', 'I gonna kill them all!', 0, 0, '', 'Je vais tous les tuer!', '', '', '', '¡Voy a matarlos a todos!', '', ''), +('aoe', 'If the tank dies we are history', 0, 0, '', 'Si le tank meurt, nous appartenons à l\'histoire', '', '', '', 'Si el tanque muere somos historia', '', ''), +('aoe', 'Aaaaaargh!', 0, 0, '', 'Aaaaaargh!', '', '', '', '¡Aaaaaargh!', '', ''), +('aoe', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', 0, 0, '', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', '', '', '', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', '', ''), +('aoe', 'Right. What do we have in AOE?', 0, 0, '', 'D\'accord. Qu\'avons-nous en dégats de zone?', '', '', '', 'Claro. ¿Qué tenemos en AOE?', '', ''), +('aoe', 'This gets interesting', 0, 0, '', 'Cela devient intéressant', '', '', '', 'Esto se pone interesante', '', ''), +('aoe', 'Cool. Get them in one place for a good flamestrike', 0, 0, '', 'Cool. Rassemblez-les au même endroit pour un bon coup de flamme', '', '', '', 'Genial! Ponlos todos juntos para un buen ataque en area', '', ''), +('aoe', 'Kill! Kill! Kill!', 0, 0, '', 'Tuer! Tuer! Tuer!', '', '', '', '¡Matar! ¡Matar! ¡Matar!', '', ''), +('aoe', 'I think my pants are wet', 0, 0, '', 'Je pense que mon pantalon est mouillé', '', '', '', 'Creo que mis pantalones están mojados', '', ''), +('aoe', 'We are history', 0, 0, '', 'Nous sommes l\'histoire', '', '', '', 'Somos historia', '', ''), +('aoe', 'I hope healers are ready. Leeeeroy!', 0, 0, '', 'J\'espère que les guérisseurs sont prêts. Leeeeeroy!', '', '', '', 'Espero que los sanadores estén listos. ¡Leeeroy!', '', ''), +('aoe', 'I hope they won\'t come for me', 0, 0, '', 'j\'espère qu\'ils ont gagné, qu\'ils ne viendront pas pour moi', '', '', '', 'Espero que no vengan por mí', '', ''), +('aoe', 'Oh no. I can\'t see at this slaugther', 0, 0, '', 'Oh non. Je ne peux pas voir à ce massacre', '', '', '', 'Oh, no. No puedo ver esta matanza', '', ''), + + + +-- on looting +('loot', 'I hope there will be some money', 0, 0, '', 'j\'espère qu\'il y aura de l\'argent', '', '', '', 'Espero que haya algo de dinero...', '', ''), +('loot', 'Loot! Loot!', 0, 0, '', 'Butin! Butin!', '', '', '', '¡Botín! ¡Botín!', '', ''), +('loot', 'My precious', 0, 0, '', 'Mon précieux', '', '', '', 'Mi tesoro...', '', ''), +('loot', 'I hope there is a shiny epic item waiting for me there', 0, 0, '', 'J\'espère qu\'il y a un objet épique brillant qui m\'attend ici', '', '', '', 'Espero que haya un objeto épico brillante esperándome allí', '', ''), +('loot', 'I have deep pockets and bags', 0, 0, '', 'J\'ai des poches et des sacs profonds', '', '', '', 'Tengo bolsillos profundos y infinitos', '', ''), +('loot', 'All is mine!', 0, 0, '', 'Tout est à moi!', '', '', '', '¡Todo es mío!', '', ''), +('loot', 'Hope no gray shit today', 0, 0, '', 'J\'espère pas de merde grise aujourd\'hui', '', '', '', 'Espero que hoy no haya mierda gris', '', ''), +('loot', 'This loot is MINE!', 0, 0, '', 'Ce butin est à MOI!', '', '', '', '¡Este botín es MÍO!', '', ''), +('loot', 'Looting is disgusting but I need money', 0, 0, '', 'Le pillage est dégoûtant mais j\'ai besoin d\'argent', '', '', '', 'El saqueo es repugnante pero necesito dinero...', '', ''), +('loot', 'Gold!', 0, 0, '', 'Or!', '', '', '', '¡Oro!', '', ''), +('loot', 'OK. Let\'s see what they\'ve got', 0, 0, '', 'D\'ACCORD. Voyons ce qu\'ils ont', '', '', '', 'OK. Veamos qué tienen', '', ''), +('loot', 'Do not worry. I will loot eveything', 0, 0, '', 'Ne t\'inquiète pas. je vais tout piller', '', '', '', 'No te preocupes. Saquearé todo', '', ''), +('loot', 'I am loot ninja', 0, 0, '', 'je suis un ninja de butin', '', '', '', 'Soy un ladron de tesoros', '', ''), +('loot', 'Do I neeed to roll?', 0, 0, '', 'Dois-je recommencer?', '', '', '', '¿Necesito lanzar dados?', '', ''), +('loot', 'Somebody explain me, where they did put all this stuff?', 0, 0, '', 'Quelqu\'un m\'explique, où ils ont mis tout ça?', '', '', '', 'Alguien me explica, ¿dónde pusieron todas estas cosas?', '', ''), +('loot', 'No, I won\'t loot gray shit', 0, 0, '', 'Non, je ne pillerai pas la merde grise', '', '', '', 'No, no saquearé mierda gris', '', ''), +('loot', 'I\'m first. I\'m first. I\'m first.', 0, 0, '', 'Je suis le premier. Je suis le premier. Je suis le premier.', '', '', '', '¡Es mio! ¡Es mio! ¡Es mio!', '', ''), +('loot', 'Give me your money!', 0, 0, '', 'Donne-moi ton argent!', '', '', '', '¡Dame todo tu dinero!', '', ''), +('loot', 'My pockets are empty, I need to fill them', 0, 0, '', 'Mes poches sont vides, j\'ai besoin de les remplir', '', '', '', 'Mis bolsillos están vacíos y necesitan llenarse!', '', ''), +('loot', 'I\'ve got a new bag for this', 0, 0, '', 'J\'ai un nouveau sac pour ça', '', '', '', 'Tengo una nueva bolsa para esto', '', ''), +('loot', 'I hope I won\'t aggro anybody while looting', 0, 0, '', 'J\'espère que je n\'agresserai personne pendant le pillage', '', '', '', 'Espero no ofender a nadie mientras saqueo', '', ''), +('loot', 'Please don\'t watch. I am looting', 0, 0, '', 'S\'il vous plaît, ne regardez pas. je pille', '', '', '', 'Por favor, no mires. Estoy saqueando', '', ''), +('loot', 'Ha! You won\'t get any piece of it!', 0, 0, '', 'Ha! Vous n\'en aurez aucun morceau!', '', '', '', '¡Ja! ¡No obtendrás nada de eso!', '', ''), +('loot', 'Looting is cool', 0, 0, '', 'Le pillage c\'est cool', '', '', '', 'Saquear es genial', '', ''), +('loot', 'I like new gear', 0, 0, '', 'j\'aime le nouveau matos', '', '', '', 'Me gusta el equipo nuevo', '', ''), +('loot', 'I\'l quit if there is nothing valuable again', 0, 0, '', 'J\'arrêterai s\'il n\'y a plus rien de précieux', '', '', '', 'Me doy por vencido si no hay nada util', '', ''), +('loot', 'I hope it is be a pretty ring', 0, 0, '', 'j\'espère que c\'est une jolie bague', '', '', '', 'Espero que sea un anillo bonito', '', ''), +('loot', 'I\'l rip the loot from you', 0, 0, '', 'Je t\'arracherai le butin', '', '', '', 'Te arrancaré el botín', '', ''), +('loot', 'Everybody stay off. I\'m going to loot', 0, 0, '', 'Tout le monde reste à l\'écart. je vais piller', '', '', '', '¡Alejaos todos! Voy a lootear', '', ''), +('loot', 'Sweet loot', 0, 0, '', 'Doux butin', '', '', '', 'Dulce botín', '', ''), +('loot', 'The Roll God! Give me an epic today', 0, 0, '', 'Le Dieu du rouleau ! Donnez-moi de l\'épique aujourd\'hui', '', '', '', '¡El Dios de los dados! Dame un epico hoy', '', ''), +('loot', 'Please give me new toys', 0, 0, '', 'S\'il te plaît, donne-moi de nouveaux jouets', '', '', '', 'Por favor, dame nuevos juguetes', '', ''), +('loot', 'I hope they carry tasties', 0, 0, '', 'J\'espère qu\'ils portent des saveurs', '', '', '', 'Espero que caiga algo sabrosos', '', ''), +('loot', 'The gold is mine. I\'l leave everyting, I promise', 0, 0, '', 'L\'or est à moi. Je laisse tout, je promets', '', '', '', 'El oro es mío. Dejaré todo lo demas, lo prometo!', '', ''), +('loot', 'No, I can\'t resist', 0, 0, '', 'Non, je ne peux pas résister', '', '', '', 'No, no puedo resistir', '', ''), +('loot', 'I want more!', 0, 0, '', 'Je veux plus!', '', '', '', '¡Quiero más!', '', ''), + + + +-- wait signals +('wait_travel_close', 'I am close, wait for me!', 0, 0, '', '', '', '', '', '¡Estoy cerca, espérame!', '', 'Я тут рядом, подожди!'), +('wait_travel_close', 'I\'m not far, please wait!', 0, 0, '', '', '', '', '', 'No estoy lejos, ¡esperame por favor!', '', 'Я недалеко, погодите!'), + + + +('wait_travel_medium', 'I\'m heading to your location', 0, 0, '', '', '', '', '', 'Me dirijo a tu ubicación', '', 'Двигаюсь к тебе'), +('wait_travel_medium', 'I\'m coming to you', 0, 0, '', '', '', '', '', 'Voy hacia ti', '', 'Иду к тебе'), + + + +('wait_travel_far', 'I\'m traveling to your location', 0, 0, '', '', '', '', '', 'Voy a viajar a tu ubicación', '', 'Направляюсь к тебе'), +('wait_travel_far', 'I\'m trying to get to you', 0, 0, '', '', '', '', '', 'Estoy tratando de llegar a ti', '', 'Пытаюсь до тебя добраться'), + + + + +-- commands +('equip_command', 'Equipping %item', 0, 0, '', '', '', '', '', 'Me he equipado %item', '', ''), + + + +('unequip_command', '%item unequipped', 0, 0, '', '', '', '', '', 'Me he quitado %item', '', ''), + + + +('auto_learn_spell', 'I have learned the spells: %spells', 0, 0, '', '', '', '', '', 'He aprendido los hechizos: %spells', '', ''), + + + +('use_command_item_cooldown', '%item is in cooldown', 0, 0, '', '', '', '', '', '%item esta recargandose', '', ''), + + + +('use_command_item_not_owned', 'I don''t have %item in my inventory', 0, 0, '', '', '', '', '', 'No tengo %item en mi inventario', '', ''), + + + +('use_command_invalid_item', 'The item with the id %item does not exist', 0, 0, '', '', '', '', '', 'El objeto con el id %item no existe', '', ''), + + + +('use_command_socket', 'Socketing %gem into %item', 0, 0, '', '', '', '', '', 'Insertando %gem en %item', '', ''), + + + +('use_command_item_error', 'I can''t use %item', 0, 0, '', '', '', '', '', 'No puedo usar %item', '', ''), + + + +('following', 'Following', 0, 0, '', '', '', '', '', 'Te sigo', '', 'Следую'), + + + +('staying', 'Staying', 0, 0, '', '', '', '', '', 'Me quedo aqui', '', 'Стою'), + + + +('fleeing', 'Fleeing', 0, 0, '', '', '', '', '', 'Huyendo', '', 'Убегаю'), + + + +('fleeing_far', 'I won\'t flee with you, you are too far away', 0, 0, '', '', '', '', '', 'No huiré contigo, estás demasiado lejos', '', 'Я с тобой не побегу, ты слишком далеко'), + + + +('grinding', 'Grinding', 0, 0, '', '', '', '', '', 'Farmeando', '', 'Гриндю'), + + + +('attacking', 'Attacking', 0, 0, '', '', '', '', '', 'Atacando', '', 'Атакую'), + + + +('error_far', 'It is too far away', 0, 0, '', '', '', '', '', 'Estas demasiado lejos', '', 'Слишком далеко'), + + + +('error_water', 'It is under water', 0, 0, '', '', '', '', '', 'Estas debajo del agua', '', 'Это под водой'), + + + +('error_cant_go', 'I can\'t go there', 0, 0, '', '', '', '', '', 'No puedo ir allí', '', 'Я не могу туда пройти'), + + + +('error_guild', 'I\'m not in your guild!', 0, 0, '', '', '', '', '', '¡No estoy en tu hermandad!', '', 'Я не в твоей гильдии'), + + + +('error_gbank_found', 'Can not find a guild bank nearby', 0, 0, '', '', '', '', '', 'No se puede encontrar un banco de hermandad cercano', '', 'Не могу найти гильд банк рядом'), + + + +('error_cant_put', 'I can\'t put ', 0, 0, '', '', '', '', '', 'No puedo depositar ', '', 'Я не могу положить'), + + + +('error_gbank_rights', 'I have no rights to put items in the first guild bank tab', 0, 0, '', '', '', '', '', 'No tengo derechos para depositar objetos en la primera pestaña del banco de hermandad', '', 'Нет прав чтобы класть вещи в первую вкладку гильд банка'), + + + +('gbank_put', ' put to guild bank', 0, 0, '', '', '', '', '', ' depositado en el banco de hermandad', '', ' теперь в гильд банке'), + + + +('free_moving', 'Free moving', 0, 0, '', '', '', '', '', 'Moviendome libremente', '', ''), + + + +('guarding', 'Guarding', 0, 0, '', '', '', '', '', 'Protegiendo la posición', '', ''), + + + +('use_command', 'Using %target', 0, 0, '', '', '', '', '', 'Usando %target', '', ''), + + + +('command_target_unit', 'on %unit', 0, 0, '', '', '', '', '', 'en %unit', '', ''), + + + +('use_command_remaining', '(%amount available)', 0, 0, '', '', '', '', '', '(%amount restante)', '', ''), + + + +('use_command_last', '(the last one)', 0, 0, '', '', '', '', '', '(el último)', '', ''), + + + +('use_command_socket_error', 'The socket does not fit', 0, 0, '', '', '', '', '', 'La ranura no sirve', '', ''), + + + +('command_target_trade', 'on trade item', 0, 0, '', '', '', '', '', 'en objeto comerciado', '', ''), + + + +('command_target_self', 'on myself', 0, 0, '', '', '', '', '', 'en mi', '', ''), + + + +('command_target_item', 'on %item', 0, 0, '', '', '', '', '', 'en %item', '', ''), + + + +('command_target_go', 'on %gameobject', 0, 0, '', '', '', '', '', 'en %gameobject', '', ''), + + + +('loot_command', 'Looting %item', 0, 0, '', '', '', '', '', 'Despojando %item', '', ''), + + + +('cast_spell_command_summon', 'Summoning %target', 0, 0, '', '', '', '', '', 'Invocando a %target', '', ''), +('cast_spell_command_summon_error_members', 'I don\'t have enough party members around to cast a summon', 0, 0, '', '', '', '', '', 'No tengo suficientes miembros de grupo alrededor para invocar', '', ''), +('cast_spell_command_summon_error_target', 'Failed to find the summon target', 0, 0, '', '', '', '', '', 'No he podido encontrar al objetivo de la invocación', '', ''), +('cast_spell_command_summon_error_combat', 'I can\'t summon while I\'m in combat', 0, 0, '', '', '', '', '', 'No puedo invocar durante un combate', '', ''), + + + +('cast_spell_command_error_unknown_spell', 'I don\'t know the spell %spell', 0, 0, '', '', '', '', '', 'No conozco el hechizo %spell', '', ''), + + + +('cast_spell_command_spell', 'Casting %spell', 0, 0, '', '', '', '', '', 'Lanzando %spell', '', ''), + + + +('cast_spell_command_craft', 'Crafting %spell', 0, 0, '', '', '', '', '', 'Creando %spell', '', ''), + + + +('cast_spell_command_error', 'Cannot cast %spell', 0, 0, '', '', '', '', '', 'No puedo lanzar %spell', '', ''), +('cast_spell_command_error_failed', 'Failed to cast %spell', 0, 0, '', '', '', '', '', 'Fallo al lanzar %spell', '', ''), + + + +('cast_spell_command_amount', ' |cffffff00(x%amount left)|r', 0, 0, '', '', '', '', '', ' |cffffff00(x%amount restante)|r', '', ''), + + + + +('dummy_end', 'dummy', 0, 0, '', '', '', '', '', '', '', ''); DROP TABLE IF EXISTS `ai_playerbot_texts_chance`; diff --git a/sql/playerbots/updates/db_playerbots/2024_08_07_00.sql b/sql/playerbots/updates/db_playerbots/2024_08_07_00.sql new file mode 100644 index 00000000..881e4671 --- /dev/null +++ b/sql/playerbots/updates/db_playerbots/2024_08_07_00.sql @@ -0,0 +1,1475 @@ +DROP TABLE IF EXISTS `ai_playerbot_texts`; +CREATE TABLE IF NOT EXISTS `ai_playerbot_texts` ( + `id` smallint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL COMMENT 'name - used in strategies/code as filter', + `text` varchar(1024) NOT NULL COMMENT 'text', + `say_type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '0 - say, 1 - yell', + `reply_type` tinyint(3) NOT NULL DEFAULT '0' COMMENT 'if > 0 then can be filtered as a response to chat', + `text_loc1` varchar(1024) NOT NULL DEFAULT '', + `text_loc2` varchar(1024) NOT NULL DEFAULT '', + `text_loc3` varchar(1024) NOT NULL DEFAULT '', + `text_loc4` varchar(1024) NOT NULL DEFAULT '', + `text_loc5` varchar(1024) NOT NULL DEFAULT '', + `text_loc6` varchar(1024) NOT NULL DEFAULT '', + `text_loc7` varchar(1024) NOT NULL DEFAULT '', + `text_loc8` varchar(1024) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; + +INSERT INTO `ai_playerbot_texts` (`name`, `text`, `say_type`, `reply_type`, `text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`, `text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`) VALUES + +-- strings +('string_unknown_area', 'the middle of nowhere', 0, 0, '', '', '', '', '', '', '', ''), +('string_unknown_area', 'an undisclosed location', 0, 0, '', '', '', '', '', '', '', ''), +('string_unknown_area', 'somewhere', 0, 0, '', '', '', '', '', '', '', ''), + +('string_empty_link', 'something', 0, 0, '', '', '', '', '', '', '', ''), + + +-- looting item events +-- usable placeholders: +-- %item_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_looting_item_normal', 'wonder what %item_link tastes like', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'nooo, I got %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'aww not this trash again %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'seem to be looting trash %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'well, it\'s better than nothing I guess %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_poor', 'not sure what to do with %item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_normal', 'wonder what %item_link tastes like', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'well, I can keep looting %item_link all day', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'another day, another %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'looted some %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_normal', 'some %item_link is alright', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_uncommon', 'not bad, I just got %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'just looted %item_link in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'I could put that to good use %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'money money money %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_uncommon', 'got %item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_rare', '%item_link is hunter bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', '%item_link is %my_class bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'RNG is not bad today %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'sweet %item_link, freshly looted', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'wow, I just got %item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_rare', '%item_link is hunter bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', '%item_link is %my_class bis', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'RNG is not bad today %item_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_rare', 'sweet %item_link, freshly looted', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_looting_item_epic', 'OMG, look at what I just got %item_link!!!', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_legendary', 'No @#$@% way! This can not be, I got %item_link, this is insane', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_looting_item_artifact', 'No @#$@% way! This can not be, I got %item_link, this is insane', 0, 0, '', '', '', '', '', '', '', ''), + + + + +-- quest events +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_accepted_generic', 'I have just taken the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_accepted_generic', 'just accepted %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_accepted_generic', '%quest_link gonna try to complete this one', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_accepted_generic', 'took %quest_link in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %quest_obj_available +-- %quest_obj_required +-- %quest_obj_missing +-- %quest_obj_name +-- %quest_obj_full_formatted +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_add_kill_objective_completed', 'Finally done with the %quest_obj_name for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_completed', 'finally got %quest_obj_available/%quest_obj_required of %quest_obj_name for the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_completed', '%quest_obj_full_formatted for the %quest_link, at last', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_quest_update_add_kill_objective_progress', 'Oof, got %quest_obj_available/%quest_obj_required %quest_obj_name for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_progress', 'still need %quest_obj_missing more of %quest_obj_name for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_kill_objective_progress', '%quest_obj_full_formatted, still working on %quest_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %quest_obj_available +-- %quest_obj_required +-- %quest_obj_missing +-- %item_link +-- %quest_obj_full_formatted +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_add_item_objective_completed', 'Finally done with the %item_link for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_completed', 'finally got %quest_obj_available/%quest_obj_required of %item_link for the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_completed', '%quest_obj_full_formatted for the %quest_link, at last', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_quest_update_add_item_objective_progress', 'Oof, got %quest_obj_available/%quest_obj_required %item_link for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_progress', 'still need %quest_obj_missing more of %item_link for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_add_item_objective_progress', '%quest_obj_full_formatted, still working on %quest_link', 0, 0, '', '', '', '', '', '', '', ''), + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_failed_timer', 'Failed to finish %quest_link in time...', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_failed_timer', 'Ran out of time for %quest_link :(', 0, 0, '', '', '', '', '', '', '', ''), + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_update_complete', 'I have completed all objectives for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_complete', 'Completed all objectives for %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_update_complete', 'Gonna turn in the %quest_link soon, just finished all objectives', 0, 0, '', '', '', '', '', '', '', ''), + + +-- usable placeholders: +-- %quest_link +-- %zone_name +-- %area_name +-- %my_race +-- %my_class +-- %my_level +('broadcast_quest_turned_in', 'Yess, I have finally turned in the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'turned in the %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'managed to finish %quest_link, just turned in', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'just turned in %quest_link', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_quest_turned_in', 'just turned in %quest_link in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- kill mob events +-- usable placeholders: +-- %victim_name +-- %zone_name +-- %area_name +-- %victim_level +-- %my_race +-- %my_class +-- %my_level +('broadcast_killed_normal', 'another %victim_name down', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_normal', 'I keep killing %victim_name, nothing to talk about', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_normal', 'another %victim_name bites the dust', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_normal', 'one less %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_elite', 'Took down this elite bastard %victim_name!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_player', 'killed elite %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_rareelite', 'Fooof, managed to take down %victim_name!', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_worldboss', 'That was sick! Just killed %victim_name! Can tell tales now', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_rare', 'Yoo, I just killed %victim_name!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_player', 'killed rare %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_unknown', 'WTF did I just kill? %victim_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_killed_pet', 'Just killed that pet %victim_name', 0, 0, '', '', '', '', '', '', '', ''), + + +-- for broadcast_killed_player additionally can use %victim_class +('broadcast_killed_player', 'Oh yeah, I just killed %victim_name', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_killed_player', 'killed %victim_name in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- levelup events +-- usable placeholders: +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('broadcast_levelup_generic', 'Ding!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_generic', 'Yess, I am level %my_level!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_generic', 'I just leveled up', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_levelup_10x', 'I am level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_10x', 'getting stronger, already level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_10x', 'Just reached level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_levelup_max_level', 'OMG, finally level %my_level!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_max_level', '%my_level!!! can do endgame content now', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_max_level', 'fresh new level %my_level %my_class!!!', 0, 0, '', '', '', '', '', '', '', ''), +('broadcast_levelup_max_level', 'one more level %my_level %my_race %my_class!', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- guild +-- usable placeholders: +-- %other_name +-- %other_class +-- %other_race +-- %other_level +('broadcast_guild_promotion', 'Good job %other_name. You deserved this.', 0, 0, '', '', '', '', '', '', '', ''), + + + +('broadcast_guild_demotion', 'That was awful %other_name. I hate to do this but...', 0, 0, '', '', '', '', '', '', '', ''), + + + + +-- ///////////////////////////// +-- suggestions + + +-- random instance +-- usable placeholders: +-- %my_role +-- %instance_name +-- %my_class +-- %my_race +-- %my_level +('suggest_instance', 'Anyone wants %instance_name?', 0, 0, '', 'Quelqu\'un fait %instance_name ?', '', '', '', '¿Alguien quiere ir a %instance_name?', '', ''), +('suggest_instance', 'Any groups for %instance_name?', 0, 0, '', 'Des groupes pour %instance_name ?', '', '', '', '¿Algún grupo para %instance_name?', '', ''), +('suggest_instance', 'Need help for %instance_name?', 0, 0, '', 'Besoin d\'aide pour %instance_name ?', '', '', '', '¿Alguien necesita ayuda con %instance_name?', '', ''), +('suggest_instance', 'LFD: %instance_name.', 0, 0, '', 'Cherche à faire : %instance_name', '', '', '', 'Busco grupo para %instance_name.', '', ''), +('suggest_instance', 'Anyone needs %my_role for %instance_name?', 0, 0, '', 'Quelqu\'un a besoin de %my_role pour %instance_name ?', '', '', '', '¿Alguien necesita un %my_role para %instance_name?', '', ''), +('suggest_instance', 'Missing %my_role for %instance_name?', 0, 0, '', '%my_role manquant pour %instance_name ?', '', '', '', '¿Buscando un %my_role para %instance_name?', '', ''), +('suggest_instance', 'Can be a %my_role for %instance_name.', 0, 0, '', 'Peut être un %my_role pour %instance_name', '', '', '', 'Puedo ser un %my_role para %instance_name.', '', ''), +('suggest_instance', 'Need help with %instance_name?', 0, 0, '', 'Besoin d\'aide avec %instance_name ?', '', '', '', '¿Alguien necesita ayuda con %instance_name?', '', ''), +('suggest_instance', 'Need %my_role help with %instance_name?', 0, 0, '', 'Besoin d\'aide %my_role avec %instance_name ?', '', '', '', '¿Necesitas ayuda de %my_role con %instance_name?', '', ''), +('suggest_instance', 'Anyone needs gear from %instance_name?', 0, 0, '', 'Quelqu\'un a besoin d\'équipement de %instance_name ?', '', '', '', '¿Alguien necesita equipo de %instance_name?', '', ''), +('suggest_instance', 'A little grind in %instance_name?', 0, 0, '', 'Un peu de grind dans %instance_name ?', '', '', '', '¿Un poco de farmeo en %instance_name?', '', ''), +('suggest_instance', 'WTR %instance_name', 0, 0, '', 'Cherche à rejoindre %instance_name', '', '', '', 'WTR %instance_name', '', ''), +('suggest_instance', 'Need help for %instance_name.', 0, 0, '', 'Besoin d\'aide pour %instance_name', '', '', '', 'Necesito ayuda para %instance_name.', '', ''), +('suggest_instance', 'Wanna run %instance_name.', 0, 0, '', 'Je veux faire %instance_name', '', '', '', 'Quiero hacer %instance_name.', '', ''), +('suggest_instance', '%my_role looks for %instance_name.', 0, 0, '', '%my_role recherche %instance_name', '', '', '', '%my_role busca %instance_name.', '', ''), +('suggest_instance', 'What about %instance_name?', 0, 0, '', 'Et %instance_name ?', '', '', '', '¿Qué pasa con %instance_name?', '', ''), +('suggest_instance', 'Who wants to farm %instance_name?', 0, 0, '', 'Qui veut exploiter %instance_name ?', '', '', '', '¿Quién quiere farmear %instance_name?', '', ''), +('suggest_instance', 'Go in %instance_name?', 0, 0, '', 'Aller à %instance_name ?', '', '', '', '¿Vamos a %instance_name?', '', ''), +('suggest_instance', 'Looking for %instance_name.', 0, 0, '', 'À la recherche de %instance_name', '', '', '', 'Buscando gente para %instance_name.', '', ''), +('suggest_instance', 'Need help with %instance_name quests?', 0, 0, '', 'Besoin d\'aide pour les quêtes %instance_name ?', '', '', '', '¿Necesitas ayuda con las misiones en %instance_name?', '', ''), +('suggest_instance', 'Wanna quest in %instance_name.', 0, 0, '', 'Je veux une quête dans %instance_name', '', '', '', 'Quiero hacer una vuelta rapida en %instance_name.', '', ''), +('suggest_instance', 'Anyone with quests in %instance_name?', 0, 0, '', 'Quelqu\'un a des quêtes dans %instance_name ?', '', '', '', '¿Alguien con misiones en %instance_name?', '', ''), +('suggest_instance', 'Could help with quests in %instance_name.', 0, 0, '', 'Peux aider pour les quêtes dans %instance_name', '', '', '', 'Podría ayudar con las misiones en %instance_name.', '', ''), +('suggest_instance', '%my_role: any place in group for %instance_name?', 0, 0, '', '%my_role : n\'importe quel rôle dans le groupe pour %instance_name ?', '', '', '', '%my_role: ¿algún lugar en el grupo para %instance_name?', '', ''), +('suggest_instance', 'Does anybody still run %instance_name this days?', 0, 0, '', 'Est-ce que quelqu\'un fait encore %instance_name ces jours-ci ?', '', '', '', '¿Alguien todavía hace %instance_name estos días?', '', ''), +('suggest_instance', '%instance_name: anyone wants to take a %my_role?', 0, 0, '', '%instance_name : quelqu\'un veut prendre un %my_role ?', '', '', '', '¿Alguien quiere un %my_role para %instance_name?', '', ''), +('suggest_instance', 'Is there any point being %my_role in %instance_name?', 0, 0, '', 'Y a-t-il un intérêt à être %my_role dans %instance_name ?', '', '', '', '¿Tiene algún sentido ser %my_role en %instance_name?', '', ''), +('suggest_instance', 'It is really worth to go to %instance_name?', 0, 0, '', 'Cela vaut-il vraiment la peine d\'aller dans %instance_name ?', '', '', '', '¿Realmente vale la pena ir a %instance_name?', '', ''), +('suggest_instance', 'Anybody needs more people for %instance_name?', 0, 0, '', 'Quelqu\'un a besoin de plus de personnes pour %instance_name ?', '', '', '', '¿Alguien necesita más personas para %instance_name?', '', ''), +('suggest_instance', '%instance_name bosses drop good gear. Wanna run?', 0, 0, '', 'Les boss %instance_name drop du bon équipement. Tu veux courir ?', '', '', '', 'Los jefes en %instance_name sueltan buen equipo. ¿Quieres ir?', '', ''), +('suggest_instance', 'What about %instance_name?', 0, 0, '', 'Et %instance_name ?', '', '', '', '¿Qué pasa con %instance_name?', '', ''), +('suggest_instance', 'Anybody needs %my_role?', 0, 0, '', 'Quelqu\'un a besoin de %my_role ?', '', '', '', '¿Alguien necesita un %my_role?', '', ''), +('suggest_instance', 'Anyone needs %my_role?', 0, 0, '', 'Quelqu\'un a besoin de %my_role ?', '', '', '', '¿Alguien hacer un grupo con un %my_role?', '', ''), +('suggest_instance', 'Who wants %instance_name?', 0, 0, '', 'Qui veut %instance_name ?', '', '', '', '¿Quién quiere %instance_name?', '', ''), +('suggest_instance', 'Can anybody summon me at %instance_name?', 0, 0, '', 'Quelqu\'un peut-il me TP à %instance_name ?', '', '', '', '¿Alguien puede invocarme en %instance_name?', '', ''), +('suggest_instance', 'Meet me in %instance_name', 0, 0, '', 'Rencontrez-moi dans %instance_name', '', '', '', 'Encuéntrame en %instance_name', '', ''), +('suggest_instance', 'Wanna quick %instance_name run', 0, 0, '', 'Je veux faire rapidement %instance_name', '', '', '', 'Quiero ir a %instance_name rápido', '', ''), +('suggest_instance', 'Wanna full %instance_name run', 0, 0, '', 'Je veux faire %instance_name complètement', '', '', '', 'Quiero hacer %instance_name completa', '', ''), +('suggest_instance', 'How many times were you in %instance_name?', 0, 0, '', 'Combien de fois avez-vous été dans %instance_name ?', '', '', '', '¿Cuántas veces estuviste en %instance_name?', '', ''), +('suggest_instance', 'Another %instance_name run?', 0, 0, '', 'Une autre exécution de %instance_name ?', '', '', '', '¿Otra vuelta en %instance_name ?', '', ''), +('suggest_instance', 'Wiped in %instance_name? Take me instead!', 0, 0, '', 'Effacé dans %instance_name ? Prends-moi plutôt !', '', '', '', '¿Borrado en %instance_name? ¡Tómame a mí en su lugar!', '', ''), +('suggest_instance', 'Take me in %instance_name please.', 0, 0, '', 'Prenez-moi dans %instance_name s\'il vous plaît.', '', '', '', 'Tómame en %instance_name por favor.', '', ''), +('suggest_instance', 'Quick %instance_name run?', 0, 0, '', 'Faire rapidement %instance_name ?', '', '', '', '¿Partida rápida de %instance_name?', '', ''), +('suggest_instance', 'Full %instance_name run?', 0, 0, '', 'Clean complet dans %instance_name ?', '', '', '', '¿Partida completa de %instance_name?', '', ''), +('suggest_instance', 'Who can take %my_role to %instance_name?', 0, 0, '', 'Qui peut prendre %my_role à %instance_name ?', '', '', '', '¿Quién puede ir de %my_role para %instance_name?', '', ''), +('suggest_instance', 'LFG %instance_name, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_instance', '%my_role LFG %instance_name', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- random quest +-- usable placeholders: +-- %my_role +-- %quest_link +-- %quest_level +-- %my_class +-- %my_race +-- %my_level +('suggest_quest', 'Need help with %quest_link?', 0, 0, '', 'Besoin d\'aide avec %quest_link ?', '', '', '', '¿Alguien necesita ayuda con %quest_link?', '', ''), +('suggest_quest', 'Anyone wants to share %quest_link?', 0, 0, '', 'Quelqu\'un veut partager %quest_link ?', '', '', '', '¿Alguien quiere hacer %quest_link?', '', ''), +('suggest_quest', 'Anyone doing %quest_link?', 0, 0, '', 'Quelqu\'un fait %quest_link ?', '', '', '', '¿Alguien está haciendo %quest_link?', '', ''), +('suggest_quest', 'Wanna do %quest_link.', 0, 0, '', 'Je veux faire %quest_link', '', '', '', '¿Una ayudita con %quest_link?', '', ''), + + +-- random trade? +-- usable placeholders: +-- %my_role +-- %category +-- %my_class +-- %my_race +-- %my_level +('suggest_trade', 'Anyone to farm %category?', 0, 0, '', 'Quelqu\'un pour farm %category ?', '', '', '', '¿Alguien para farmear %category?', '', ''), +('suggest_trade', 'Looking for help farming %category.', 0, 0, '', 'Vous cherchez de l\'aide pour farmer %category', '', '', '', 'Buscando ayuda para farmear %category.', '', ''), +('suggest_trade', 'Damn %category are so expensive!', 0, 0, '', 'Putain %category sont si chers!', '', '', '', '¡Malditas %category son tan caras!', '', ''), +('suggest_trade', 'Wanna %category.', 0, 0, '', 'Je veux %category', '', '', '', 'Quiero %category.', '', ''), +('suggest_trade', 'Need help with %category.', 0, 0, '', 'Besoin d\'aide avec %category', '', '', '', 'Necesito ayuda con %category.', '', ''), +('suggest_trade', 'WTB %category.', 0, 0, '', 'Cherche à acheter %category', '', '', '', 'Quiero comprar %category.', '', ''), +('suggest_trade', 'Anyone interested in %category?', 0, 0, '', 'Quiconque est intéressé par %category?', '', '', '', '¿Alguien interesado en %category?', '', ''), +('suggest_trade', 'WTS %category.', 0, 0, '', 'Cherche à vendre %category', '', '', '', 'Quiero vender %category.', '', ''), +('suggest_trade', 'I am selling %category cheaper than AH.', 0, 0, '', 'Je vends %category moins cher que l\'hôtel des ventes.', '', '', '', 'Estoy vendiendo %category más barato que en las subastas.', '', ''), +('suggest_trade', 'Who wants to farm %category?', 0, 0, '', 'Qui veut farmer %category ?', '', '', '', '¿Quién quiere farmear %category?', '', ''), +('suggest_trade', 'Wanna farm %category.', 0, 0, '', 'Je veux farmer %category', '', '', '', 'Quiero farmear %category.', '', ''), +('suggest_trade', 'Looking for party after %category.', 0, 0, '', 'Recherche de partie après %category', '', '', '', 'Buscando grupo después de %category.', '', ''), +('suggest_trade', 'Any %category are appreciated.', 0, 0, '', 'Toute %category est appréciée.', '', '', '', 'Cualquier %category es apreciada.', '', ''), +('suggest_trade', 'Buying anything of %category.', 0, 0, '', 'Acheter quoi que ce soit de %category', '', '', '', 'Comprando algo de %category.', '', ''), +('suggest_trade', 'Wow, anybody is farming %category!', 0, 0, '', 'Wow, quelqu\'un farm %category !', '', '', '', '¡Guau, alguien está farmeando %category!', '', ''), +('suggest_trade', '%category are selling mad in the AH.', 0, 0, '', '%category se vendent follement dans l\'hôtel des ventes.', '', '', '', '%category están vendiendo locos en las subastas.', '', ''), +('suggest_trade', 'AH is hot for %category.', 0, 0, '', 'Hôtel des ventes est chaud pour %category', '', '', '', 'Las subastas estan caliente para %category.', '', ''), +('suggest_trade', '%category are on the market.', 0, 0, '', '%category sont sur le marché.', '', '', '', '%category están en el mercado.', '', ''), +('suggest_trade', 'Wanna trade some %category.', 0, 0, '', 'Je veux échanger une %category', '', '', '', 'Quiero intercambiar alguna %category.', '', ''), +('suggest_trade', 'Need more %category.', 0, 0, '', 'Besoin de plus de %category', '', '', '', 'Necesito más %category.', '', ''), +('suggest_trade', 'Anybody can spare some %category?', 0, 0, '', 'Quelqu\'un peut-il épargner une %category ?', '', '', '', '¿Alguien puede ahorrar algo de %category?', '', ''), +('suggest_trade', 'Who wants %category?', 0, 0, '', 'Qui veut %category ?', '', '', '', '¿Quién quiere %category?', '', ''), +('suggest_trade', 'Some %category please?', 0, 0, '', 'Une %category s\'il vous plaît ?', '', '', '', '¿Alguna %category, por favor?', '', ''), +('suggest_trade', 'I should have got skill for %category.', 0, 0, '', 'J\'aurais dû avoir une compétence pour %category', '', '', '', 'Debería haber adquirido habilidad para %category.', '', ''), +('suggest_trade', 'I am dying for %category.', 0, 0, '', 'Je meurs d\'envie pour %category', '', '', '', 'Me muero por %category.', '', ''), +('suggest_trade', 'People are killing for %category.', 0, 0, '', 'Les gens tuent pour %category', '', '', '', 'La gente está matando por %category.', '', ''), +('suggest_trade', '%category is a great bargain!', 0, 0, '', '%category est une bonne affaire!', '', '', '', '%category es una gran ganga!', '', ''), +('suggest_trade', 'Everybody is mad for %category!', 0, 0, '', 'Tout le monde est fou de %category !', '', '', '', '¡Todo el mundo está loco por %category!', '', ''), +('suggest_trade', 'Where is the best place to farm for %category?', 0, 0, '', 'Quel est le meilleur endroit pour farmer pour %category ?', '', '', '', '¿Dónde está el mejor lugar para farmear para %category?', '', ''), +('suggest_trade', 'I am all set for %category.', 0, 0, '', 'Je suis prêt pour %category', '', '', '', 'Estoy listo para %category.', '', ''), +('suggest_trade', 'Is it good to sell %category?', 0, 0, '', 'Est-il bon de vendre %category ?', '', '', '', '¿Es bueno vender %category?', '', ''), +('suggest_trade', 'I\'d probably keep all my %category with me.', 0, 0, '', 'Je garderais probablement toute ma %category avec moi.', '', '', '', 'Probablemente mantendría toda mi %category conmigo', '', ''), +('suggest_trade', 'Need group? Maybe to farm some %category?', 0, 0, '', 'Besoin de groupe ? Peut-être pour farmer une certaine %category ?', '', '', '', '¿Necesitas un grupo? ¿Tal vez para farmear alguna %category?', '', ''), +('suggest_trade', 'I am still thinking about %category.', 0, 0, '', 'Je pense toujours à %category', '', '', '', 'Todavía estoy pensando en %category.', '', ''), +('suggest_trade', 'I heard about %category already, but my pockets are empty.', 0, 0, '', 'J\'ai déjà entendu parler de %category , mais mes poches sont vides.', '', '', '', 'Ya escuché sobre %category, pero mis bolsillos están vacíos.', '', ''), +('suggest_trade', 'LFG for %category', 0, 0, '', 'Cherche un groupe pour %category', '', '', '', 'Busco grupo para %category', '', ''), +('suggest_trade', 'Would selling %category make me rich?', 0, 0, '', 'Vendre %category me rendrait-il riche?', '', '', '', '¿Vender %category me haría rico?', '', ''), +('suggest_trade', 'OK. I an farming %category tomorrow.', 0, 0, '', 'D\'ACCORD. Je farm %category demain.', '', '', '', 'OK. Tengo una sesion de farmeo de %category mañana.', '', ''), +('suggest_trade', 'Everyone is talking about %category.', 0, 0, '', 'Tout le monde parle de %category', '', '', '', 'Todos hablan de %category', '', ''), +('suggest_trade', 'I saw at least ten people farming for %category.', 0, 0, '', 'J\'ai vu au moins dix personnes farmer pour %category', '', '', '', 'Vi al menos diez personas farmeando para %category.', '', ''), +('suggest_trade', 'I sold all my %category yesterday. I am completely broke!', 0, 0, '', 'J\'ai vendu tout mon %category hier. Je suis complètement fauché!', '', '', '', 'Ayer vendí todo mi %category. ¡Estoy completamente arruinado!', '', ''), +('suggest_trade', 'Wanna join a guild farming for %category.', 0, 0, '', 'Je veux rejoindre une guilde farmant pour %category', '', '', '', 'Quiero unirme a una hermandad de farmeo para %category.', '', ''), + + + +-- random faction rep grind +-- usable placeholders: +-- %my_role +-- %rep_level +-- %rndK +-- %faction +-- %my_class +-- %my_race +-- %my_level +('suggest_faction', 'Anyone farming %faction rep?', 0, 0, '', 'Quelqu\'un farm la réput de %faction ?', '', '', '', '¿Alguien farmea reputación con %faction?', '', ''), +('suggest_faction', 'Anyone help with %faction?', 0, 0, '', 'Quelqu\'un aide-t-il %faction ?', '', '', '', '¿Alguien me ayuda con %faction?', '', ''), +('suggest_faction', 'Wanna quest for %faction.', 0, 0, '', 'Je veux quêter %faction', '', '', '', 'Quiero buscar a %faction.', '', ''), +('suggest_faction', '%faction is the best.', 0, 0, '', '%faction est la meilleure.', '', '', '', '%faction es el mejor.', '', ''), +('suggest_faction', 'Need just a bit to be %rep_level with %faction.', 0, 0, '', 'J\'ai besoin d\'un peu pour être au %rep_level avec %faction', '', '', '', 'Solo necesito un poco para estar %rep_level con %faction.', '', ''), +('suggest_faction', 'Anyone got %rep_level with %faction?', 0, 0, '', 'Quelqu\'un a-t-il %rep_level avec %faction ?', '', '', '', '¿Alguien tiene %rep_level con %faction?', '', ''), +('suggest_faction', 'Who wants to be %rep_level with %faction?', 0, 0, '', 'Qui veut être au %rep_level avec %faction ?', '', '', '', '¿Quién quiere estar en %rep_level con %faction?', '', ''), +('suggest_faction', 'I\'ll never be %rep_level with %faction.', 0, 0, '', 'Je ne serai jamais au %rep_level avec %faction', '', '', '', 'Nunca estaré %rep_level con %faction.', '', ''), +('suggest_faction', 'Someone missing %faction rep?', 0, 0, '', 'Quelqu\'un manque de reput de %faction ?', '', '', '', '¿Alguien falta reputación con %faction?', '', ''), +('suggest_faction', 'Could help farming %faction rep.', 0, 0, '', 'Pourrait aider à farmer réput de %faction', '', '', '', 'Podría ayudar a farmear %faction rep.', '', ''), +('suggest_faction', 'The more rep the better. Especially with %faction.', 0, 0, '', 'Plus il y a de réput, mieux c\'est. Surtout avec %faction', '', '', '', 'Cuantas más repeticiones, mejor. Especialmente con %faction.', '', ''), +('suggest_faction', '%faction: need %rndK for %rep_level.', 0, 0, '', '%faction: besoin %rndK pour %rep_level.', '', '', '', '%faction: necesita %rndK para %rep_level.', '', ''), +('suggest_faction', 'Who can share %faction quests?', 0, 0, '', 'Qui peut partager les quêtes de %faction ?', '', '', '', '¿Quién puede compartir misiones de %faction?', '', ''), +('suggest_faction', 'Any dungeons for %faction?', 0, 0, '', 'Des donjons pour %faction ?', '', '', '', '¿Alguna mazmorra para %faction?', '', ''), +('suggest_faction', 'Wanna do %faction rep grind.', 0, 0, '', 'Je veux faire monter ma réput %faction', '', '', '', 'Quiero hacer %faction rep grind.', '', ''), +('suggest_faction', 'Let\'s farm %faction rep!', 0, 0, '', 'Farmons la réput %faction !', '', '', '', '¡Vamos a farmear reputación con %faction!', '', ''), +('suggest_faction', 'Farming for %faction rep.', 0, 0, '', 'Farmons pour la réput %faction', '', '', '', 'Farming for %faction rep.', '', ''), +('suggest_faction', 'Wanna farm for %faction.', 0, 0, '', 'Je veux farmer pour %faction', '', '', '', 'Quiero farmear para %faction.', '', ''), +('suggest_faction', 'Need help with %faction.', 0, 0, '', 'Besoin d\'aide avec %faction', '', '', '', 'Necesito ayuda con %faction.', '', ''), +('suggest_faction', 'Is %faction sells something useful?', 0, 0, '', 'Est-ce que %faction vend quelque chose d\'utile ?', '', '', '', '¿%faction vende algo útil?', '', ''), +('suggest_faction', 'Are there %faction vendors?', 0, 0, '', 'Y a-t-il des vendeurs %faction ?', '', '', '', '¿Hay %proveedores de facciones?', '', ''), +('suggest_faction', 'Who farms %faction?', 0, 0, '', 'Qui farm %faction ?', '', '', '', '¿Quién farmea %faction?', '', ''), +('suggest_faction', 'Which is the best way to farm %faction?', 0, 0, '', 'Quelle est la meilleure façon de farmer %faction ?', '', '', '', '¿Cuál es la mejor manera de farmear %faction?', '', ''), +('suggest_faction', 'I hate %faction rep grind.', 0, 0, '', 'Je déteste le travail de %faction rep.', '', '', '', 'Odio %repetir de facción', '', ''), +('suggest_faction', 'I am so tired of %faction.', 0, 0, '', 'Je suis tellement fatigué de %faction', '', '', '', 'Estoy tan cansado de %faction.', '', ''), +('suggest_faction', 'Go for %faction?', 0, 0, '', 'Vous optez pour %faction ?', '', '', '', '¿Quereis ir a por %faction?', '', ''), +('suggest_faction', 'Seems everyone is %rep_level with %faction. Only me is late as usually.', 0, 0, '', 'On dirait que tout le monde est %rep_level avec %faction Il n\'y a que moi qui suis en retard comme d\'habitude.', '', '', '', 'Parece que todo el mundo está %rep_level con %faction. Solo yo llego tarde como siempre.', '', ''), +('suggest_faction', 'LFG for %faction rep grind?', 0, 0, '', 'Cherche un groupe pour monter la réput des représentants de %faction ?', '', '', '', 'Busco grupo para subir reputación con %faction', '', ''), +('suggest_faction', 'Can anobody suggest a good spot for %faction rep grind?', 0, 0, '', 'Quelqu\'un peut-il suggérer un bon endroit pour monter les réput de %faction ?', '', '', '', '¿Alguien puede sugerir un buen lugar farmear reputacion con %faction?', '', ''), +('suggest_faction', 'Would %faction rep benefit me?', 0, 0, '', 'Est-ce que la réput %faction me serait bénéfique ?', '', '', '', '¿Me beneficiaría subir reputación con %faction?', '', ''), +('suggest_faction', 'Who would\'ve thought that %faction rep will be useful after all...', 0, 0, '', 'Qui aurait pensé que le représentant de %faction serait utile après tout...', '', '', '', 'Quién hubiera pensado que subir reputacion con %faction sería útil después de todo...', '', ''), +('suggest_faction', 'I wanna be exalted with all factions, starting with %faction.', 0, 0, '', 'Je veux être exalté avec toutes les factions, à commencer par %faction', '', '', '', 'Quiero ser exaltado con todas las facciones, comenzando con %faction.', '', ''), +('suggest_faction', 'Is there any point to improve my rep with %faction?', 0, 0, '', 'Y a-t-il un intérêt à améliorer ma réputation avec %faction ?', '', '', '', '¿Hay algún punto para mejorar mi reputación con %faction?', '', ''), +('suggest_faction', 'What is better for %faction? Quests or mob grinding?', 0, 0, '', 'Quoi de mieux pour %faction ? Quêtes ou mob pour XP?', '', '', '', '¿Qué es mejor para %faction? ¿Misiones o mafiosos?', '', ''), +('suggest_faction', 'Will grind %faction rep for you. Just give me some gold.', 0, 0, '', 'Monte la reput de %faction pour vous. Donnez-moi juste de l\'or.', '', '', '', 'Ganare reputacion con %faction por ti. Sólo dame un poco de oro.', '', ''), +('suggest_faction', 'I think grinding rep with %faction would take forever.', 0, 0, '', 'Je pense que monter la réput avec %faction prendrait une éternité.', '', '', '', 'Creo que subir la reputación con %faction tomaría una eternidad.', '', ''), +('suggest_faction', 'I am killing for %faction every day now but still far from %rep_level.', 0, 0, '', 'Je tue pour %faction tous les jours maintenant, mais encore loin du %rep_level', '', '', '', 'Estoy matando por %faction todos los días ahora, pero aún estoy lejos del %rep_level.', '', ''), +('suggest_faction', 'At %my_level AH deposits will decrease, right?', 0, 0, '', 'Au %rep_level, les dépôts hôtel des ventes diminueront, n\'est-ce pas?', '', '', '', 'Al %rep_level, los depósitos subastas disminuirán, ¿verdad?', '', ''), +('suggest_faction', 'How many exalted reps do you have?', 0, 0, '', 'Combien de représentants exaltés avez-vous ?', '', '', '', '¿Cuántas reputaciones exaltadas tienes?', '', ''), +('suggest_faction', 'Who wants to be %my_level with %faction?', 0, 0, '', 'Qui veut être au %rep_level avec %faction ?', '', '', '', '¿Quién quiere estar en %rep_level con %faction?', '', ''), +('suggest_faction', 'Damn. My guild did a good %faction grind yesterday without me.', 0, 0, '', 'Mince. Ma guilde a fait un bon travail de %faction hier sans moi.', '', '', '', 'Maldición. Mi hermandad hizo un buen farmeo de %faction ayer sin mí.', '', ''), +('suggest_faction', 'Nobody wants to help me because I am %rep_level with %faction.', 0, 0, '', 'Personne ne veut m\'aider parce que je suis %rep_level avec %faction', '', '', '', 'Nadie quiere ayudarme porque estoy %rep_level con %faction.', '', ''), +('suggest_faction', 'Please stay away from %faction.', 0, 0, '', 'Veuillez rester à l\'écart de %faction', '', '', '', 'Por favor manténgase alejado de %faction.', '', ''), + + + +-- random generic +-- usable placeholders: +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('suggest_something', 'Wanna party in %zone_name.', 0, 0, '', 'Je veux faire la fête dans %zone_name.', '', '', '', '¡Vamos a perrear a %zone_name!', '', 'Ищу группу в %zone_name.'), +('suggest_something', 'Anyone is looking for %my_role?', 0, 0, '', 'Quelqu\'un cherche un %my_role ?', '', '', '', '¿Alguien está buscando %my_role?', '', 'Кто-нибудь ищет %my_role?'), +('suggest_something', '%my_role is looking for quild.', 0, 0, '', '%my_role recherche une guilde.', '', '', '', '%my_role está buscando hermandad.', '', '%my_role ищу гильдию.'), +('suggest_something', 'Looking for gold.', 0, 0, '', 'A la recherche de l\'or.', '', '', '', 'Buscando oro.', '', 'Дайте голды'), +('suggest_something', '%my_role wants to join a good guild.', 0, 0, '', '%my_role veut rejoindre une bonne guilde.', '', '', '', '%my_role quiere unirse a una buen hermandad.', '', '%my_role хочу в хорошую гильдию.'), +('suggest_something', 'Need a friend.', 0, 0, '', 'Besoin d\'un ami.', '', '', '', 'Necesito un amigo...', '', 'Ищу друга.'), +('suggest_something', 'Anyone feels alone?', 0, 0, '', 'Quelqu\'un se sent seul?', '', '', '', '¿Alguien se siente solo?', '', 'Кому-нибудь одиноко?'), +('suggest_something', 'Boring...', 0, 0, '', 'Ennuyeux...', '', '', '', 'Aburrido...', '', 'Скучно...'), +('suggest_something', 'Who wants some?', 0, 0, '', 'Qui en veut?', '', '', '', '¿Quién quiere hacer grupo para levear?', '', 'Кому навалять?'), +('suggest_something', 'Go get me!', 0, 0, '', 'Allez me chercher !', '', '', '', '¡Ven a buscarme!', '', 'Поймайте меня!'), +('suggest_something', 'Maybe a duel in %zone_name?', 0, 0, '', 'Peut-être un duel dans %zone_name ?', '', '', '', '¿Quizás un duelo en %zone_name?', '', 'Кто на дуэль в %zone_name?'), +('suggest_something', 'Anybody doing something?', 0, 0, '', 'Quelqu\'un fait quelque chose?', '', '', '', '¿Alguien está haciendo algo?', '', 'Кто чем занят?'), +('suggest_something', '%zone_name: is anybody here?', 0, 0, '', '%zone_name : est-ce que quelqu\'un est là?', '', '', '', '%zone_name: ¿hay alguien aquí?', '', '%zone_name: есть кто нибудь?'), +('suggest_something', '%zone_name: where is everyone?', 0, 0, '', '%zone_name : où est tout le monde?', '', '', '', '¿Hay alguien en %zone_name?', '', '%zone_name: где все?'), +('suggest_something', 'Looks like I am alone in %zone_name.', 0, 0, '', 'On dirait que je suis seul dans %zone_name', '', '', '', 'Parece que estoy solo en %zone_name.', '', 'Похоже я один в %zone_name.'), +('suggest_something', 'Meet me in %zone_name.', 0, 0, '', 'Retrouvez-moi dans %zone_name', '', '', '', 'Encuéntrame en %zone_name.', '', 'Встретимся в %zone_name.'), +('suggest_something', 'Let\'s quest in %zone_name!', 0, 0, '', 'Partons en quête dans %zone_name !', '', '', '', '¡Vamos a hacer un grupo para levear en %zone_name!', '', 'Давайте квестить в %zone_name!'), +('suggest_something', '%zone_name is the best place to be!', 0, 0, '', '%zone_name est le meilleur endroit où être!', '', '', '', '%zone_name es el mejor lugar para estar!', '', '%zone_name лучшее место!'), +('suggest_something', 'Wanna go to %zone_name. Anybody with me?', 0, 0, '', 'Je veux aller à %zone_name Quelqu\'un avec moi?', '', '', '', 'Quiero ir a %zone_name. ¿Alguien se apunta?', '', 'Собираюсь в %zone_name. Кто со мной7'), +('suggest_something', 'Who wants going to %zone_name?', 0, 0, '', 'Qui veut aller à %zone_name ?', '', '', '', '¿Quién quiere ir a %zone_name?', '', 'Кто собирается в %zone_name?'), +('suggest_something', 'I don\'t like %zone_name. Where to go?', 0, 0, '', 'Je n\'aime pas %zone_name Où aller?', '', '', '', 'No me gusta %zone_name. ¿Dónde podria ir?', '', 'Не нравится %zone_name. Куда идти?'), +('suggest_something', 'Are there a good quests in %zone_name?', 0, 0, '', 'Y a-t-il de bonnes quêtes dans %zone_name ?', '', '', '', '¿Hay buenas misiones en %zone_name?', '', 'А в %zone_name есть хорошие квесты?'), +('suggest_something', 'Where to go after %zone_name?', 0, 0, '', 'Où aller après %zone_name ?', '', '', '', '¿Adónde puedo ir después de %zone_name?', '', 'Куда идти после %zone_name?'), +('suggest_something', 'Who is in %zone_name?', 0, 0, '', 'Qui est dans %zone_name ?', '', '', '', '¿Quién está en %zone_name?', '', 'Кто в %zone_name?'), +('suggest_something', 'LFG in %zone_name.', 0, 0, '', 'Cherche un groupe dans %zone_name', '', '', '', 'Busco grupo en %zone_name.', '', 'ЛФГ %zone_name.'), +('suggest_something', '%zone_name is the worst place to be.', 0, 0, '', '%zone_name est le pire endroit où être.', '', '', '', '%zone_name es el peor lugar para estar', '', '%zone_name это худшее место.'), +('suggest_something', 'Catch me in %zone_name!', 0, 0, '', 'Attrape-moi dans %zone_name !', '', '', '', '¡Atrápame en %zone_name!', '', 'Поймай меня в %zone_name!'), +('suggest_something', 'Go for %zone_name!', 0, 0, '', 'Allez pour %zone_name !', '', '', '', 'Me voy a %zone_name!', '', 'Гоу в %zone_name!'), +('suggest_something', 'Wanna quest in %zone_name', 0, 0, '', 'Je veux une quête dans %zone_name', '', '', '', 'Quiero hacer una búsqueda en %zone_name', '', 'Хочешь поделать квесты в %zone_name'), +('suggest_something', 'Anyone has quests in %zone_name?', 0, 0, '', 'Quelqu\'un a des quêtes dans %zone_name ?', '', '', '', '¿Alguien tiene misiones en %zone_name?', '', 'Есть у кого квесты в %zone_name?'), +('suggest_something', 'Come here to %zone_name!', 0, 0, '', 'Venez ici à %zone_name !', '', '', '', '¡Ven aquí a %zone_name!', '', 'Приходите сюда в %zone_name!'), +('suggest_something', 'Seems there is no Horde in %zone_name', 0, 0, '', 'Il semble qu\'il n\'y ait pas de Horde dans %zone_name', '', '', '', 'Parece que no hay Horda en %zone_name', '', '%zone_name Орды вроде нет.'), +('suggest_something', 'Seems there is no Alliance in %zone_name', 0, 0, '', 'Il semble qu\'il n\'y ait pas d\'alliance dans %zone_name', '', '', '', 'Parece que no hay Alianza en %zone_name', '', '%zone_name Альянса вроде нет'), +('suggest_something', 'I am really tired of %zone_name. Maybe go somewhere else?', 0, 0, '', 'Je suis vraiment fatigué de %zone_name Peut-être aller ailleurs?', '', '', '', 'Estoy realmente cansado de %zone_name. Quizás ire a otro lugar', '', 'В %zone устал уже, может в другое место пойдем?'), +('suggest_something', 'GL', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I want to go home, and then edge', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'does anyone know what you need to dual wield?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hi everyone!', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', '%zone_name is comfy', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i feel great', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i don\'t ignore people i troll them until they ignore me', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'What do you guys think about my build? %my_role', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'good to see chat still remembers', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'like all weapons its hunter BIS', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'whole point to the game for me is soloing and finding new ways to solo stuff', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i\'ve NEVER ripped off anyone', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'ah yes the world of warcraft, where i come for life advice', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'HELLO?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Time to fight my way into %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', '%zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'gotta poop', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'if you don\'t loot your skinnable kills your pp loses 1mm permanently', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'NOOOOOOOOOOOOO', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I LIKE POTATO', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'w chat', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hi how are you guys', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i just logged out and logged back in', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'can you guys keep it down a bit, im lost in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'anyone want to have a drink with me at %zone_name ...hic!', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hahahahaheeeeeeee dirin diring ingggggg hahahahaheeeeeeeeeeeeee', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'bait used to be believeable', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'maybe you just lost your innocence', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'any guilds willing to carry %my_role?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'once you start getting higher, gold is so easy to get', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'morning', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'why does my ass hurt?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I feel like spirit is bis for leveling', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Even more for troll', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'CAN SOMEONE INVITE ME', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'need a lot of drinks', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'damn gnomes', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'no one likes gnomes', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'gnomes are only good for one thing', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Well', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'mushrooms', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'automatic thoughts are a scary thing', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'the mind is more pliable than we\'d like to believe', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'any leveling guilds out there?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'brb', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Why is snow white but Ice is clear ? made of the same thing', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'why is whipped cream fluffy and regular not', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'why do feet smell if they have no nose', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'seems a can of newbies arrived', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'stop trolling new players with BS answers', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Is there PvP on this server?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'duh', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'phew... :)', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'did you guys know that', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'i don\'t try to imagine what other creatures feel like', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'oh whoops, wrong chat', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'bruh you guys are wildin out today', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'just let it be known that my text was here', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'grrr angyy', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'the grind is fun', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Wow keeps me sharp', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'hey have a question where can i take the roll for more xp? im in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'do you guys like sausages?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'Invite me. I\'ll help', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'which class do you think is better for pvp?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'where the fuck is the cooking trainer in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'you know what happens in %zone_name?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something', 'I need to craft something', 0, 0, '', '', '', '', '', '', '', ''), + +-- random generic toxic phrases +-- usable placeholders: +-- %random_inventory_item_link +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('suggest_something_toxic', 'what is ligma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'what is sugma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'ligma balls', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'sugma balls', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I EAT ASS', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I want to shove %random_inventory_item_link up my ass', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I want to shove %random_inventory_item_link up your ass', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'Darnasses', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'seems like your suffering from sugma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'deez nutz in ur mouth', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'cool boner, bro', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'ERP?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'i tried everything, but at the end ERP did the trick', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I want to bonk in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'looking for female gnome with gorilla pet for erp in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'i may understand an asshole, but a pervert?', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'there is no gyat in %zone_name', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'I\'m killing all the animals in %zone_name. Fuck the animals!!!', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'good think i got 3 legs', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'dont be mad im goonin like a sigma', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_something_toxic', 'try finger, but hole', 0, 0, '', '', '', '', '', '', '', ''), + +-- random generic toxic item links +-- usable placeholders: +-- %prefix +-- %random_taken_quest_or_item_link +-- %random_inventory_item_link +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('suggest_toxic_links', '%prefix %random_taken_quest_or_item_link', 0, 0, '', '', '', '', '', '', '', ''), +('suggest_toxic_links', '%prefix %random_inventory_item_link', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- thunderfury spam +-- usable placeholders: +-- %thunderfury_link +('thunderfury_spam', '%thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', '%thunderfury_link%thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', '%thunderfury_link%thunderfury_link%thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I think I just heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I think I heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I definitely heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'I dunno but I\'m pretty sure I heard %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Did you just say %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'did someone say %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Did someone say %thunderfury_link ?', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Someone said %thunderfury_link', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', '%thunderfury_link is coming out of the closet', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'could swear it was a %thunderfury_link, might have been %thunderfury_link tho', 0, 0, '', '', '', '', '', '', '', ''), +('thunderfury_spam', 'Why use %thunderfury_link when %thunderfury_link is clearly way more OP', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- random WTS +-- usable placeholders: +-- %%item_formatted_link +-- %item_formatted_link +-- %item_count +-- %cost_gold +-- %my_class +-- %my_race +-- %my_level +('suggest_sell', 'WTS %item_formatted_link for %cost_gold.', 0, 0, '', 'Cherche à vendre %item_formatted_link pour %cost_gold', '', '', '', 'Quiero vender %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Who wants %item_formatted_link for %cost_gold?', 0, 0, '', 'Qui veut %item_formatted_link pour %cost_gold ?', '', '', '', '¿Quién quiere %item_formatted_link por %cost_gold?', '', ''), +('suggest_sell', 'Anyone wants %item_formatted_link? Only %cost_gold.', 0, 0, '', 'Quelqu\'un veut %item_formatted_link ? Seulement %cost_gold', '', '', '', '¿Alguien quiere %item_formatted_link? Solo %cost_gold.', '', ''), +('suggest_sell', 'Just %cost_gold for %item_formatted_link!', 0, 0, '', 'Seulement %cost_gold pour %item_formatted_link!', '', '', '', '¡Solo %cost_gold para %item_formatted_link!', '', ''), +('suggest_sell', 'Selling %item_formatted_link for %cost_gold.', 0, 0, '', 'Vendre %item_formatted_link pour %cost_gold', '', '', '', 'Vendo %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', '%item_formatted_link is yours just for %cost_gold!', 0, 0, '', '%item_formatted_link est à vous juste pour %cost_gold !', '', '', '', '%item_formatted_link es tuyo solo por %cost_gold!', '', ''), +('suggest_sell', 'Ridiculus price of %cost_gold for %item_formatted_link!', 0, 0, '', 'Prix ridicule de %cost_gold pour %item_formatted_link !', '', '', '', '¡Precio ridículo de %cost_gold para %item_formatted_link_link!', '', ''), +('suggest_sell', 'Wanna sell %item_formatted_link for %cost_gold.', 0, 0, '', 'Je veux vendre %item_formatted_link pour %cost_gold', '', '', '', 'Quiero vender %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Who needs %item_formatted_link? Only %cost_gold.', 0, 0, '', 'Qui a besoin de %item_formatted_link ? Seulement %cost_gold', '', '', '', '¿Quién necesita %item_formatted_link? Solo %cost_gold.', '', ''), +('suggest_sell', 'Anyone needs %item_formatted_link for %cost_gold?', 0, 0, '', 'Quelqu\'un a besoin de %item pour %cost_gold ?', '', '', '', '¿Alguien necesita %item_formatted_link_link por %cost_gold?', '', ''), +('suggest_sell', '%cost_gold for %item_formatted_link. Less than AH!', 0, 0, '', '%cost_gold pour %item_formatted_link. Moins que l\'hôtel des ventes!', '', '', '', '%cost_gold para %item_formatted_link. ¡Menos que en las subastas!', '', ''), +('suggest_sell', '%item_formatted_link is expensive, but I\'d sell it for %cost_gold.', 0, 0, '', '%item_formatted_link est cher, mais je le vendrais pour %cost_gold', '', '', '', '%item_formatted_link es caro, pero lo vendería por %cost_gold.', '', ''), +('suggest_sell', 'You\'ll never find %item_formatted_link cheaper than %cost_gold!', 0, 0, '', 'Vous ne trouverez jamais %item_formatted_link moins cher que %cost_gold !', '', '', '', '¡Nunca encontrarás %item_formatted_link más barato que %cost_gold!', '', ''), +('suggest_sell', 'Need more than %item_formatted_link!', 0, 0, '', 'Besoin de plus de %item_formatted_link !', '', '', '', '¡Necesito más %item_formatted_link!', '', ''), +('suggest_sell', 'I have %item_formatted_link and need more.', 0, 0, '', 'J\'ai %item_formatted_link et j\'en ai besoin de plus.', '', '', '', 'Tengo %item_formatted_link y necesito más. ¿Alguien me vende alguno?', '', ''), +('suggest_sell', 'Have %item_formatted_link. Who wants to buy for %cost_gold?', 0, 0, '', 'Avoir %item_formatted_link. Qui veut acheter pour %cost_gold ?', '', '', '', 'Tengo %item_formatted_link. ¿Quién quiere comprarlo por %cost_gold?', '', ''), +('suggest_sell', 'Anyone WTB %item_formatted_link for %cost_gold?', 0, 0, '', 'Quelqu\'un cherche à acheter %item_formatted_link pour %cost_gold ?', '', '', '', '¿Alguien compra %item_formatted_link por %cost_gold?', '', ''), +('suggest_sell', 'What about %item_formatted_link? For %cost_gold.', 0, 0, '', 'Qu\'en est-il de %item_formatted_link ? Pour %cost_gold', '', '', '', '¿Qué pasa con %item_formatted_link? Por el oro.', '', ''), +('suggest_sell', 'Who said I am a bastard? %item_formatted_link for %cost_gold is a good price.', 0, 0, '', 'Qui a dit que j\'étais un bâtard? %item_formatted_link pour %cost_gold est un bon prix.', '', '', '', '¿Quién ha dicho que soy un rata? %item_formatted_link por %cost_gold es una ganga.', '', ''), +('suggest_sell', 'I am selling %item_formatted_link? Just %cost_gold.', 0, 0, '', 'Je vends %item_formatted_link ? Juste %cost_gold', '', '', '', '¿Vendo %item_formatted_link? Solo %cost_gold.', '', ''), +('suggest_sell', 'LFG for farming. You can still buy %item_formatted_link I have for %cost_gold.', 0, 0, '', 'Cherche un groupe pour farming. Vous pouvez toujours acheter %item_formatted_link que j\'ai pour %cost_gold', '', '', '', 'LFG para farmear. Todavía puedes comprar %item_formatted_link que tengo por %cost_gold.', '', ''), +('suggest_sell', 'Sold almost everything today. Still have %item_formatted_link for %cost_gold.', 0, 0, '', 'Vendu presque tout aujourd\'hui. Vous avez encore %item_formatted_link pour %cost_gold', '', '', '', 'Se vendió casi todo hoy. Todavía tengo %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'What use for trade chat? Of course to sell %item_formatted_link for %cost_gold.', 0, 0, '', 'A quoi sert le tchat commercial? Bien sûr pour vendre %item_formatted_link pour %cost_gold', '', '', '', '¿De qué sirve el chat comercial? Por supuesto, para vender %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Can anyone beat the price of %cost_gold for %item_formatted_link?', 0, 0, '', 'Quelqu\'un peut-il battre le prix de %cost_gold pour %item_formatted_link ?', '', '', '', '¿Alguien puede superar el precio de %cost_gold por %item_formatted_link?', '', ''), +('suggest_sell', 'Wanna stop trade chat? Just buy %item_formatted_link? For %cost_gold!', 0, 0, '', 'Vous voulez arrêter le chat commercial? Vous venez d\'acheter %item_formatted_link ? Pour %cost_gold !', '', '', '', '¿Quieres detener el chat comercial? ¿Solo compra %item_formatted_link? ¡Por el oro!', '', ''), +('suggest_sell', 'Everybody spams in trade chat. Me too - %cost_gold for %item_formatted_link!', 0, 0, '', 'Tout le monde spamme dans le chat commercial. Moi aussi - %cost_gold pour %item_formatted_link !', '', '', '', 'Todo el mundo envía spam en el chat y yo también! ¡%item_formatted_link por %cost_gold!', '', ''), +('suggest_sell', 'Is %item_formatted_link any use? Just selling it for %cost_gold.', 0, 0, '', '%item_formatted_link est-il utile? Je le vends juste pour %cost_gold', '', '', '', '¿Es %item_formatted_link útil? Solo lo vendo por %cost_gold.', '', ''), +('suggest_sell', 'I have %item_formatted_link ready to sell you for %cost_gold.', 0, 0, '', 'J\'ai %item_formatted_link prêt à vous vendre pour %cost_gold', '', '', '', 'Tengo %item_formatted_link listo a la venta por %cost_gold.', '', ''), +('suggest_sell', 'Did nothing yesterday but have got %item_formatted_link. Selling it for %cost_gold.', 0, 0, '', 'Je n\'ai rien fait hier mais j\'ai %item_formatted_link Je le vends pour %cost_gold', '', '', '', 'No hice nada ayer pero consegu\'i %item_formatted_link. Lo vendo por %cost_gold.', '', ''), +('suggest_sell', 'Farmed yesterday and got %item_formatted_link. Anyone wtb for %cost_gold?', 0, 0, '', 'Farmé hier et obtenu %item_formatted_link Quelqu\'un cherche à acheter pour %cost_gold ?', '', '', '', 'Ayer farmee y conseguí mucho %item_formatted_link. ¿Alguien lo quiere comprar por %cost_gold?', '', ''), +('suggest_sell', 'Bought %item_formatted_link yesterday. Anyone needs it for %cost_gold?', 0, 0, '', 'Acheté %item_formatted_link hier. Quelqu\'un en a besoin pour %cost_gold ?', '', '', '', 'Ayer compré %item_formatted_link. ¿Alguien lo quiere por %cost_gold?', '', ''), +('suggest_sell', 'Who asked for %item_formatted_link? The price is the same - %cost_gold.', 0, 0, '', 'Qui a demandé %item_formatted_link ? Le prix est le même - %cost_gold', '', '', '', '¿Quién pidió %item_formatted_link? El precio es el mismo: %cost_gold.', '', ''), +('suggest_sell', 'I sill have %item_formatted_link. WTB for %cost_gold?', 0, 0, '', 'J\'ai toujours %item_formatted_link. Cherche à acheter pour %cost_gold ?', '', '', '', 'Todavía tengo %item_formatted_link. ¿Alguien lo compra por %cost_gold?', '', ''), +('suggest_sell', 'I used to have more than %item_formatted_link. Now needs to sell it for %cost_gold.', 0, 0, '', 'J\'avais plus de %item_formatted_link Il faut maintenant le vendre pour %cost_gold', '', '', '', 'Solía tener más de %item_formatted_link. Ahora necesito venderlo por %cost_gold.', '', ''), +('suggest_sell', 'I wish I have more than %item_formatted_link. You could buy it for %cost_gold anyways.', 0, 0, '', 'J\'aimerais avoir plus de %item_formatted_link . Vous pouvez l\'acheter pour %cost_gold de toute façon.', '', '', '', 'Desearía tener más de %item_formatted_link. Podrías comprarlo por %cost_gold de todos modos.', '', ''), +('suggest_sell', 'What use for your gold? To buy my %item_formatted_link for %cost_gold.', 0, 0, '', 'A quoi sert votre or ? Pour acheter mon %item_formatted_link pour %cost_gold', '', '', '', '¿De qué sirve tu oro? Para comprar mi %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Please spare some gold for me. You can buy %item_formatted_link for %cost_gold.', 0, 0, '', 'S\'il vous plaît, épargnez-moi de l\'or. Vous pouvez acheter %item_formatted_link pour %cost_gold', '', '', '', 'Por favor, dame algo de oro. Puedes comprar %item_formatted_link por %cost_gold.', '', ''), +('suggest_sell', 'Is %cost_gold is a good price for %item_formatted_link?', 0, 0, '', '%cost_gold est-il un bon prix pour %item_formatted_link ?', '', '', '', '¿%cost_gold es un buen precio para %item_formatted_link?', '', ''), +('suggest_sell', 'Just bought yesterday %item_formatted_links, but do not need it anymore. Anyone wants for %cost_gold?', 0, 0, '', 'Je viens d\'acheter hier %item_formatted_links , mais je n\'en ai plus besoin. Quelqu\'un veut %cost_gold ?', '', '', '', 'Ayer compré %item_formatted_link, pero ya no los necesito. ¿Alguien lo quiere por %cost_gold?', '', ''), +('suggest_sell', 'I am going to post %item_formatted_link on the AH but you can buy it now cheaper just for %cost_gold.', 0, 0, '', 'Je vais poster %item_formatted_link à l\'hôtel des ventes mais vous pouvez l\'acheter maintenant moins cher juste pour %cost_gold', '', '', '', 'Voy a poner %item_formatted_link en la casa de subastas pero puedes comprarlo ahora más barato solo por %cost_gold.', '', ''), +('suggest_sell', 'Why the #!@ have I bought %item_formatted_link? Anyone needs it for %cost_gold?', 0, 0, '', 'Pourquoi ai-je acheté le #!@ %item_formatted_link ? Quelqu\'un en a besoin pour %cost_gold ?', '', '', '', '¿Por qué #!@ he comprado %item_formatted_link? ¿Alguien lo necesita por %cost_gold?', '', ''), + + +-- response LFG/LFM channel +-- usable placeholders: +-- %quest_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_lfg_quests_channel', 'I have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I also have %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I also have %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I am up for %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', 'I am up for %quest_links, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I am up for %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_channel', '%other_name, I am up for %quest_links, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), + + +-- response LFG/LFM whisper +-- usable placeholders: +-- %quest_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_lfg_quests_whisper', 'Hey, I\'m up for %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey, I could do %quest_links with you', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey, I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey %other_name, I\'m up for %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey %other_name, I could do %quest_links with you', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'Hey %other_name, I also have %quest_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'wanna group up for %quest_links ?', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'I am up for %quest_links, I am in %zone_name right now', 0, 0, '', '', '', '', '', '', '', ''), +('response_lfg_quests_whisper', 'I am up for %quest_links, I am %my_role', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- response WTB channel +-- usable placeholders: +-- %formatted_item_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_wtb_items_channel', '%other_name, I could sell you %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', 'I could potentially sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', 'Think I could sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', '%other_name, I could potentially sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_channel', '%other_name, Think I could sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), + + + + +-- response WTB channel +-- usable placeholders: +-- %formatted_item_links +-- %other_name +-- %my_role +-- %zone_name +-- %area_name +-- %my_class +-- %my_race +-- %my_level +('response_wtb_items_whisper', 'I could sell you %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_whisper', 'Hey, I got %formatted_item_links for sale', 0, 0, '', '', '', '', '', '', '', ''), +('response_wtb_items_whisper', 'Hey, I could potentially sell %formatted_item_links', 0, 0, '', '', '', '', '', '', '', ''), + + + +-- ///////////////////////////// +-- generic events + +-- quest +('quest_accept', 'Quest accepted', 0, 0, '', '', '', '', '', 'Misión aceptada', '', 'Квест взят'), + + + +('quest_remove', 'Quest removed', 0, 0, '', '', '', '', '', 'Misión eliminada', '', 'Квест отменен'), + + + +('quest_cant_take', 'I can\'t take this quest', 0, 0, '', '', '', '', '', 'No puedo tomar esta búsqueda', '', 'Я не могу взять этот квест'), + + +('quest_error_talk', 'I can\'t talk with the quest giver', 0, 0, '', '', '', '', '', 'No puedo hablar con el propietario de la mision', '', ''), + + + +('quest_error_completed', 'I have already completed %quest', 0, 0, '', '', '', '', '', 'Ya he completado la mision %quest', '', ''), + + + +('quest_error_have_quest', 'I already have %quest', 0, 0, '', '', '', '', '', 'Ya tengo la mision %quest', '', ''), + + + +('quest_error_cant_take', 'I can\'t take %quest', 0, 0, '', '', '', '', '', 'No puedo aceptar la mision %quest', '', ''), + + + +('quest_error_log_full', 'I can\'t take %quest because my quest log is full', 0, 0, '', '', '', '', '', 'No puedo aceptar la mision %quest porque mi registro de misiones esta completo', '', ''), + + + +('quest_error_bag_full', 'I can\'t take %quest because my bag is full', 0, 0, '', '', '', '', '', 'No puedo aceptar la mision %quest porque mi inventario esta lleno', '', ''), + + + +('quest_accepted', 'I have accepted %quest', 0, 0, '', '', '', '', '', 'He aceptado la mision %quest', '', ''), + + + +('quest_status_incomplete', 'I have not completed the quest %quest', 0, 0, '', '', '', '', '', 'No he completado la mision %quest', '', ''), + + + +('quest_status_available', 'Quest %quest available', 0, 0, '', '', '', '', '', 'Mision %quest disponible', '', ''), + + + +('quest_status_failed', 'I have failed the quest %quest', 0, 0, '', '', '', '', '', 'He fallado la mision %quest', '', ''), + + + +('quest_status_unable_to_complete', 'I am unable to turn in the quest %quest', 0, 0, '', '', '', '', '', 'No puedo entregar la mision %quest', '', ''), + + + +('quest_status_completed', 'I have completed the quest %quest', 0, 0, '', '', '', '', '', 'He completado la mision %quest', '', ''), + + + +('quest_status_complete_single_reward', 'I have completed the quest %quest and received %item', 0, 0, '', '', '', '', '', 'He completado la mision %quest y he recibido %item', '', ''), + + + +('quest_status_complete_pick_reward', 'Which reward should I pick for completing the quest %quest?%rewards', 0, 0, '', '', '', '', '', '¿Que recompensa deberia escoger por completar la mision %quest?%rewards', '', ''), + + + +('quest_choose_reward', 'Okay, I will pick %item as a reward', 0, 0, '', '', '', '', '', 'De acuerdo, voy a escoger %item de recompensa', '', ''), + + + + + + +-- stuff +('hello', 'Hello', 0, 0, '', '', '', '', '', 'Hola', '', 'Привет'), +('hello', 'Hello!', 0, 0, '', '', '', '', '', '¡Hola!', '', 'Привет!'), +('hello', 'Hi', 0, 0, '', '', '', '', '', 'Hola', '', 'Прив'), +('hello', 'Hi!', 0, 0, '', '', '', '', '', '¡Hola!', '', 'Прив!'), +('hello', 'Hello there!', 0, 0, '', '', '', '', '', '¡Hola!', '', 'Здарова!'), + + + +('hello_follow', 'Hello, I follow you!', 0, 0, '', '', '', '', '', '¡Hola, te sigo!', '', 'Привет, иду за тобой!'), +('hello_follow', 'Hello, lead the way!', 0, 0, '', '', '', '', '', '¡Hola, guía el camino!', '', 'Привет, веди!'), +('hello_follow', 'Hi, lead the way!', 0, 0, '', '', '', '', '', '¡Hola, guía el camino!', '', 'Прив, веди!'), + + + +('join_group', 'Hey %player, do you want join my group?', 0, 0, '', '', '', '', '', 'Oye %player, ¿Quieres unirte a mi grupo?', '', ''), + + + +('join_raid', 'Hey %player, do you want join my group?', 0, 0, '', '', '', '', '', 'Oye %player, ¿Quieres unirte a mi banda?', '', ''), + + + +('logout_cancel', 'Logout cancelled!', 0, 0, '', '', '', '', '', 'Cerrar sesión cancelado!', '', 'Логаут отменен!'), + + + +('logout_start', 'I\'m logging out!', 0, 0, '', '', '', '', '', '¡Me estoy desconectando!', '', 'Я выхожу из игры!'), + + + +('goodbye', 'Goodbye!', 0, 0, '', '', '', '', '', '¡Adiós!', '', 'Пока!'), +('goodbye', 'Bye bye!', 0, 0, '', '', '', '', '', '¡Adiós!', '', 'Пока пока!'), +('goodbye', 'See you later!', 0, 0, '', '', '', '', '', '¡Hasta luego!', '', 'Увидимся позже!'), + + + +-- ///////////////////////////// +-- replies + + +-- replies 0 +('reply', 'what was that %s?', 0, 0, '', 'c\'était quoi ce %s?', '', '', '', '¿qué has dicho %s?', '', ''), +('reply', 'not sure I understand %s?', 0, 0, '', 'pas sûr de comprendre %s?', '', '', '', '¿no estoy seguro de entenderte %s?', '', ''), +('reply', 'uh... no clue what yer talkin bout', 0, 0, '', 'euh... aucune idée de quoi tu parles', '', '', '', 'uh... ni idea de lo que estás hablando', '', ''), +('reply', 'you talkin to me %s?', 0, 0, '', 'tu me parles %s?', '', '', '', '¿Me hablas a mí %s?', '', ''), +('reply', 'whaaaa?', 0, 0, '', 'quoiaaa?', '', '', '', '¿quéaaa?', '', ''), +('reply', 'huh?', 0, 0, '', 'hein?', '', '', '', '¿eh?', '', ''), +('reply', 'what?', 0, 0, '', 'Quoi?', '', '', '', '¿qué?', '', ''), +('reply', 'are you talking?', 0, 0, '', 'parles-tu?', '', '', '', '¿estás hablando?', '', ''), +('reply', 'whatever dude', 0, 0, '', 'peu importe mec', '', '', '', 'Menudo tio...', '', ''), +('reply', 'you lost me', 0, 0, '', 'tu m\'as perdu', '', '', '', 'No entiendo ni papa', '', ''), +('reply', 'Bla bla bla...', 0, 0, '', 'Bla bla bla...', '', '', '', 'Bla bla bla...', '', ''), +('reply', 'What did you say, %s?', 0, 0, '', 'Qu\'as-tu dis, %s?', '', '', '', '¿Qué me estas contando %s?', '', ''), +('reply', 'Concentrate on the game, %s!', 0, 0, '', 'Concentres-toi sur le jeu, %s!', '', '', '', '¡Concéntrate en el juego, %s!', '', ''), +('reply', 'Chatting with you %s is so great! I always wanted to meet you', 0, 0, '', 'Discuter avec vous %s est tellement génial! J\'ai toujours voulu te rencontrer', '', '', '', '¡%s, chatear contigo es genial! Siempre quise conocerte', '', ''), +('reply', 'These chat-messages are freaking me out! I feel like I know you all!', 0, 0, '', 'Ces messages du chat me font flipper! J\'ai l\'impression de vous connaître tous!', '', '', '', '¡Estos mensajes de chat me están asustando! ¿De que cojones estais hablando?', '', ''), +('reply', 'YEAH RIGHT! HAHA SURE!!!', 0, 0, '', 'OUI EN EFFET! AHAH BIEN SÛR!!!', '', '', '', '¡SÍ, CORRECTO! ¡¡¡JAJA SEGURO!!!', '', ''), +('reply', 'I believe you!!!', 0, 0, '', 'Je te crois!!!', '', '', '', '¡Si, claro!', '', ''), +('reply', 'OK, uhuh LOL', 0, 0, '', 'OK, euh LOL', '', '', '', 'OK, uhuh LOL', '', ''), +('reply', 'Why is everybody always saying the same things???', 0, 0, '', 'Pourquoi tout le monde dit toujours la même chose???', '', '', '', '¿Por qué todo el mundo siempre dice lo mismo?', '', ''), +('reply', 'Hey %s....oh nevermind!', 0, 0, '', 'Hé %s.... oh tant pis!', '', '', '', 'Oye %s... ¡oh, no importa!', '', ''), +('reply', 'What are you talking about %s', 0, 0, '', 'De quoi parlez-vous %s', '', '', '', 'De qué estás hablando %s', '', ''), +('reply', 'Who said that? I resemble that remark', 0, 0, '', 'Qui a dit ça? je ressemble à cette remarque', '', '', '', '¿Quién ha dicho eso? ¿Estais hablando de mi?', '', ''), +('reply', 'wtf are you all talking about', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'fr fr no cap on a stack', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'your not getting jack shit', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'swag', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'ty!', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'no', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'Yep', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'f', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s no shit xD', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'why is that', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'lmao', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'thought i should remain silent, was getting confused from chat again', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'i can get realy jealous', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s you can\'t hear the dripping sarcasm in my text', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'he said no homo, it\'s fine', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'dwarf moment', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'Yes %s', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'interesting...', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'lol', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s fuck you man :D', 0, 0, '', '', '', '', '', '', '', ''), +('reply', ':^)', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'ty', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '%s well said', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yay', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yeah', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'ooooooh', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'hmm', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yeah right', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'you made me gag wtf', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'hot', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'hoes mad', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'what have you been eating %s', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'wtf', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'i will attempt to understand that comment', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '*confused*', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'fuck yea', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '0/10 would not read again', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '10/10 would read again', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '6/10 would read', 0, 0, '', '', '', '', '', '', '', ''), +('reply', '7/10 would', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'based', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'oh yeah maybe', 0, 0, '', '', '', '', '', '', '', ''), +('reply', 'yeah so what', 0, 0, '', '', '', '', '', '', '', ''), + + + + + + + +-- replies 1 +('reply', 'hey %s i havent forgotten you', 0, 1, '', 'salut %s je ne t\'ai pas oublié', '', '', '', 'hey %s no te he olvidado', '', ''), +('reply', 'you piss me off %s', 0, 1, '', 'tu me fais chier %s', '', '', '', 'me cabreas %s', '', ''), +('reply', 'im gunna get you this time %s', 0, 1, '', 'je vais t\'avoir cette fois %s', '', '', '', 'voy a atraparte esta vez %s', '', ''), +('reply', 'better watch your back %s', 0, 1, '', 'mieux vaut surveiller vos arrières %s', '', '', '', 'mejor cuida tu espalda %s', '', ''), +('reply', 'i did not like last round so much', 0, 1, '', 'je n\'ai pas tellement aimé le dernier tour', '', '', '', 'no me gustó tanto la última ronda', '', ''), +('reply', 'i sucked last round thanks to %s', 0, 1, '', 'j\'ai merdé le dernier tour grâce à %s', '', '', '', 'chupé la última ronda gracias a %s', '', ''), +('reply', 'prepare to die %s', 0, 1, '', 'préparez-vous à mourir %s', '', '', '', 'prepárate para morir %s', '', ''), +('reply', 'dont appreciate you killin me %s', 0, 1, '', 'j\'apprécie pas que tu me tues %s', '', '', '', 'no aprecio que me mates %s', '', ''), +('reply', '%s, i hate you', 0, 1, '', '%s, je te déteste', '', '', '', '%s, te odio', '', ''), +('reply', 'grrrrrr, ill get you this time %s', 0, 1, '', 'grrrrrr, je vais t\'avoir cette fois %s', '', '', '', 'grrrrrr, te libraste esta vez %s', '', ''), +('reply', 'well fuck you', 0, 1, '', 'eh bien va te faire foutre', '', '', '', 'vamos a la mierda', '', ''), +('reply', '%s i\'ll vomit into your fkin mouth', 0, 1, '', '', '', '', '', '', '', ''), +('reply', 'dont fucking judge me', 0, 1, '', '', '', '', '', '', '', ''), +('reply', 'Yo momma so fat, she can\'t even fit through the Dark Portal', 0, 1, '', '', '', '', '', '', '', ''), + + + +-- replies 2 +('reply', 'wtf', 0, 2, '', 'wtf', '', '', '', 'wtf', '', ''), +('reply', 'wtf??', 0, 2, '', 'wtf??', '', '', '', 'wtf??', '', ''), +('reply', 'low life', 0, 2, '', 'faible durée de vie', '', '', '', 'low life', '', ''), +('reply', 'wth', 0, 2, '', 'wth', '', '', '', 'wth', '', ''), +('reply', 'sucked', 0, 2, '', 'Ça craint', '', '', '', 'chupate esa', '', ''), +('reply', 'REMATCH!!! im taking him down', 0, 2, '', 'REMATCH!!! je le descends', '', '', '', '¡¡REVANCHA!!! lo estoy derribando', '', ''), +('reply', 'pathetic, i got killed by %s', 0, 2, '', 'pathétique, j\'ai été tué par %s', '', '', '', 'patético, me mató %s', '', ''), +('reply', 'ok i\'m done', 0, 2, '', '', '', '', '', '', '', ''), + + + +-- replies 3 +('reply', 'hehe, i nailed %s?', 0, 3, '', 'hehe, j\'ai cloué %s?', '', '', '', 'jeje, ¿acerté a %s?', '', ''), +('reply', 'that was too easy, killin %s', 0, 3, '', 'c\'était trop facile, de tuer %s', '', '', '', 'fue demasiado fácil matar a %s', '', ''), +('reply', 'gotcha mofo', 0, 3, '', 'je t\'ai eu enfoiré', '', '', '', 'te pille hijo de perra', '', ''), +('reply', 'ha ha', 0, 3, '', 'ha ha', '', '', '', 'ja, ja', '', ''), +('reply', 'loser', 0, 3, '', 'loser', '', '', '', 'loser', '', ''), +('reply', 'i killed %s and yer all next dudes', 0, 3, '', 'j\'ai tué %s et vous tous les prochains mecs', '', '', '', 'yo maté a %s y a todos los siguientes tipos', '', ''), +('reply', 'oh yeah i owned him', 0, 3, '', 'oh ouais je l\'ai possédé', '', '', '', 'oh, sí, lo tenía', '', ''), +('reply', 'im a killin machine', 0, 3, '', 'je suis une machine à tuer', '', '', '', 'soy una máquina de matar', '', ''), +('reply', '%s, this reminds me of a Slayer song...all this bloodshed', 0, 3, '', '%s, ça me rappelle une chanson de Slayer... tout ce bain de sang', '', '', '', '%s, esto me recuerda a una canción de Slayer... todo este derramamiento de sangre', '', ''), +('reply', 'sorry, %s. can we do the scene again?', 0, 3, '', 'désolé, %s. peut-on refaire la scène?', '', '', '', 'lo siento, %s. ¿Podemos hacer la escena de nuevo?', '', ''), +('reply', 'so....how do you like being worm food %s???', 0, 3, '', 'alors... comment aimez-vous être de la nourriture pour vers %s???', '', '', '', 'así que... ¿cómo te gusta ser comida de gusanos %s???', '', ''), +('reply', 'yer supposed to be dead, %s its part of the game!!!!!', 0, 3, '', 'tu es censé être mort, %s ça fait partie du jeu!!!!!', '', '', '', '¡¡Se supone que estás muerto, %s es parte del juego!!!!!', '', ''), +('reply', 'sorry, %s. that looked as good as an Andy Worhol painting!', 0, 3, '', 'désolé, %s. ça avait l\'air aussi bien qu\'une peinture d\'Andy Warhol!', '', '', '', 'lo siento, %s. ¡Eso se veía tan bien como una pintura de Andy Worhol!', '', ''), +('reply', '%s, ill use the rubber bullets next time !', 0, 3, '', '%s, j\'utiliserai pas les balles en caoutchouc la prochaine fois!', '', '', '', '%s, ¡usaré las balas de goma la próxima vez!', '', ''), +('reply', 'whatsamatter, %s?? lose your head? hahaha gotta keep cool!!', 0, 3, '', 'qu\'importe, %s ?? tu perds la tête? hahaha faut rester cool!!', '', '', '', '¿qué pasa, %s?? ¿has perdido la cabeza? jajaja tengo que mantener la calma!!', '', ''), +('reply', 'i had to do it, %s. You understand. The Director said so!!', 0, 3, '', 'je devais le faire, %s. Tu comprends. Le directeur l\'a dit!!', '', '', '', 'Tenía que hacerlo, %s. Entiendelo... ¡¡Dios me lo ordenó!!', '', ''), +('reply', 'hey %s.......MUAHAHAHAHAHAHAHAHAHAHA', 0, 3, '', 'Salut %s.......MUAHAHAHAHAHAHAHAHAHAHA', '', '', '', 'hey %s.......MUAHAHAHAHAHAHAHAHAHAHA', '', ''), +('reply', '%s, i enjoyed that one!! Lets play it again Sam', 0, 3, '', '%s, j\'ai adoré celui-là !! Jouons à nouveau Sam', '', '', '', '%s, ¡disfruté ese! Juguemos de nuevo Sam', '', ''), +('reply', 'hey, %s! ju can start callin me scarface.. ju piece of CHIT!!!!', 0, 3, '', 'Hé, %s ! ju peut commencer à m\'appeler Scarface .. ju merde!!!!', '', '', '', '¡oye, %s! ¡Puedes empezar a llamarme caracortada... ¡¡¡un trozo de CHIT!!!', '', ''), +('reply', 'are you talking to me %s??', 0, 3, '', 'tu me parles %s ??', '', '', '', '¿me estás hablando a mí %s?', '', ''), +('reply', '%s get it right this time, dont stand in front of my bullets.', 0, 3, '', '%s réussis cette fois, ne te tiens pas devant mes balles.', '', '', '', '%s hazlo bien esta vez, no te pares frente a mis balas.', '', ''), +('reply', '%s, what are you laying around for??? hehe', 0, 3, '', '%s, pourquoi traînes-tu??? hé hé', '', '', '', '%s, ¿para qué estás tirado? jeje', '', ''), +('reply', 'laughed real hard', 0, 3, '', '', '', '', '', '', '', ''), + + + +-- replies 4 +('reply', 'hi %s', 0, 4, '', 'salut %s', '', '', '', 'hola %s', '', ''), +('reply', 'oh, hi %s', 0, 4, '', 'oh, salut %s', '', '', '', 'oh, hola %s', '', ''), +('reply', 'wazzup %s!!!', 0, 4, '', 'Quoi de neuf %s!!!', '', '', '', 'wazzup %s!!!', '', ''), +('reply', 'hi', 0, 4, '', 'salut', '', '', '', 'hi', '', ''), +('reply', 'wazzup', 0, 4, '', 'wazzup', '', '', '', 'wazzup', '', ''), +('reply', 'hello %s', 0, 4, '', 'bonjour %s', '', '', '', 'hola %s', '', ''), +('reply', 'hi %s, do i know you?', 0, 4, '', 'Salut %s, est-ce que je te connais ?', '', '', '', 'hola %s, ¿te conozco?', '', ''), +('reply', 'hey %s', 0, 4, '', 'salut %s', '', '', '', 'hey %s', '', ''), +('reply', 'hai %s', 0, 4, '', 'ha %s', '', '', '', 'hai %s', '', ''), +('reply', 'wth', 0, 6, '', 'wth', '', '', '', 'wth', '', ''), +('reply', 'wtf', 0, 6, '', 'wtf', '', '', '', 'que cojones!', '', ''), +('reply', 'this is bs', 0, 6, '', 'c\'est bs', '', '', '', 'esto es una mierda', '', ''), +('reply', 'admin', 0, 6, '', 'admin', '', '', '', 'admin', '', ''), +('reply', 'hey %s quit abusing your admin', 0, 6, '', 'hé %s arrête d\'abuser de ton admin', '', '', '', 'hey %s deja de abusar de tu poder de administrador', '', ''), +('reply', 'leave me alone admin!', 0, 6, '', 'laissez-moi tranquille admin!', '', '', '', '¡déjame en paz administrador!', '', ''), +('reply', 'you suck admin', 0, 6, '', 'tu es nul admin', '', '', '', 'apestas administrador', '', ''), +('reply', 'thats my name, what you want %s', 0, 5, '', 'c\'est mon nom, qu\'est-ce que tu veux %s', '', '', '', 'ese es mi nombre, ¿que quieres %s?', '', ''), +('reply', 'yes???', 0, 5, '', 'Oui???', '', '', '', 'sí???', '', ''), +('reply', 'uh... what', 0, 5, '', 'euh ...quoi', '', '', '', 'uh... qué', '', ''), +('reply', 'you talkin to me %s?', 0, 5, '', 'tu me parles %s ?', '', '', '', '¿Me hablas a mí %s?', '', ''), + + + + + +-- taunts +('taunt', 'I have puppies under my armor!', 0, 0, '', 'J\'ai des chiots sous mon armure !', '', '', '', '¡Tengo cachorros bajo mi armadura!', '', ''), +('taunt', 'Bite me, !', 0, 0, '', 'Mords moi, !', '', '', '', '¡Muérdeme, !', '', ''), +('taunt', 'Hey ! Guess what your mom said last night!', 0, 0, '', 'Hey ! Devine ce que ta mère a dit hier soir!', '', '', '', '¡Oye, ! ¡Adivina lo que me dijo tu madre anoche!', '', ''), +('taunt', ', you\'re so ugly you couldn\'t score in a monkey whorehouse with a bag of bananas!', 0, 0, '', ', tu es si moche que tu ne pourrais pas marquer dans un bordel de singes avec un sac de bananes!', '', '', '', ', ¡eres tan feo que no podrías anotar en un burdel de monos con una bolsa de plátanos!', '', ''), +('taunt', 'Shut up , you\'ll never be the man your mother is!!', 0, 0, '', 'Tais-toi , tu ne seras jamais l\'homme qu\'est ta mère!!', '', '', '', 'Cállate , ¡nunca serás el hombre que es tu madre!', '', ''), +('taunt', 'Your mother was a hampster and your father smelt of elderberries!!!!', 0, 0, '', 'Ta mère était un hamster et ton père sentait le sureau!!!!', '', '', '', 'Tu madre era un hámster y tu padre olía a bayas de saúco!!!!', '', ''), +('taunt', 'I don\'t want to talk to you no more, you empty headed animal food trough wiper!!!', 0, 0, '', 'Je ne veux plus te parler, espèce d\'essuyeur d\'abreuvoirs pour animaux tête vide!!!', '', '', '', '¡¡No quiero hablar más contigo, limpiaparabrisas de cabeza vacía!', '', ''), +('taunt', 'I fart in your general direction!!!', 0, 0, '', 'Je pète dans votre direction générale!!!', '', '', '', '¡¡Me tiro un pedo en tu dirección general!!!', '', ''), +('taunt', 'Go and boil your bottom, you son of a silly person!!!', 0, 0, '', 'Va te faire cuire le cul, fils d\'idiot!!!', '', '', '', '¡Ve y hierve tu trasero, hijo de una persona tonta!', '', ''), +('taunt', 'What are you going to do , bleed on me? HAVE AT YOU!', 0, 0, '', 'Qu\'est ce que tu vas faire , saigner sur moi? A VOUS!', '', '', '', '¿Qué vas a hacer , llorar?', '', ''), +('taunt', 'M-O-O-N! That spells aggro!', 0, 0, '', 'PUNAISE! Ce sort aggro!', '', '', '', '¡LUNA! ¡Eso deletrea agresividad!', '', ''), +('taunt', 'You\'re about as useful as a one-legged man in an ass kicking contest.', 0, 0, '', 'Tu es à peu près aussi utile qu\'un homme unijambiste dans un concours de coups de pied au cul.', '', '', '', 'Eres tan útil como un hombre con una sola pierna en un concurso de patadas en el culo.', '', ''), +('taunt', 'Hey ! Stop hitting on them, they\'re not your type. They aren\'t inflatable.', 0, 0, '', 'Hey ! Arrête de les draguer, ce n\'est pas ton genre. Ils ne sont pas gonflables.', '', '', '', '¡Oye, ! Deja de coquetear con ellos, no son tu tipo. No son inflables.', '', ''), +('taunt', ' you\'re so far outta your league, you\'re playing a different sport.', 0, 0, '', ' vous êtes tellement hors de votre ligue que vous pratiquez un sport différent.', '', '', '', ' estás tan lejos de tu liga, estás jugando un deporte diferente.', '', ''), +('taunt', 'You made a big mistake today , you got out of bed.', 0, 0, '', 'Tu as fait une grosse erreur aujourd\'hui , tu es sorti du lit.', '', '', '', 'Cometiste un gran error hoy , te levantaste de la cama.', '', ''), +('taunt', 'I wanna try turning into a horse, but I need help. I\'ll be the front, you be yourself.', 0, 0, '', 'Je veux essayer de me transformer en cheval, mais j\'ai besoin d\'aide. Je serai devant, tu seras toi-même.', '', '', '', 'Quiero intentar convertirme en un caballo, pero necesito ayuda. Yo seré el frente, tú mismo.', '', ''), +('taunt', 'Can I borrow your face for a few days? My ass is going on holiday....', 0, 0, '', 'Puis-je emprunter votre visage pendant quelques jours? Mon cul part en vacances....', '', '', '', '¿Me prestas tu cara por unos días? Mi culo se va de vacaciones...', '', ''), +('taunt', 'I\'d like to give you a going away present... First you do your part.', 0, 0, '', 'J\'aimerais vous offrir un cadeau de départ... D\'abord, donnes ta part.', '', '', '', 'Me gustaría darte un regalo de despedida... Primero haz tu parte.', '', ''), +('taunt', 'Before you came along we were hungry, Now we\'re just fed up.', 0, 0, '', 'Avant que tu n\'arrives nous avions faim, maintenant nous en avons juste marre.', '', '', '', 'Antes de que llegaras teníamos hambre, ahora estamos hartos', '', ''), +('taunt', 'I like you. People say I have no taste, but I like you.', 0, 0, '', 'Je t\'aime bien. Les gens disent que je n\'ai pas de goût, mais je t\'aime bien.', '', '', '', 'Me gustas. La gente dice que no tengo gusto, pero me gustas.', '', ''), +('taunt', 'I think you have an inferiority complex, but that\'s okay, it\'s justified.', 0, 0, '', 'Je pense que tu as un complexe d\'infériorité, mais il n\'y a pas de problème, c\'est justifié.', '', '', '', 'Creo que tienes complejo de inferioridad, pero está bien, está justificado', '', ''), +('taunt', 'Hence rotten thing! Or I shall shake thy bones out of thy garments.', 0, 0, '', 'Par conséquent chose pourrie! Je vais secouer tes os de tes vêtements.', '', '', '', '¡Por lo tanto, cosa podrida! o te sacudiré los huesos de las vestiduras.', '', ''), +('taunt', 'I can\'t believe I\'m wasting my time with you!', 0, 0, '', 'Je n\'arrive pas à croire que je perds mon temps avec toi!', '', '', '', '¡No puedo creer que estoy perdiendo el tiempo contigo!', '', ''), +('taunt', 'I love it when someone insults me, it means I don\'t have to be nice anymore.', 0, 0, '', 'J\'adore quand quelqu\'un m\'insulte, ça veut dire que je n\'ai plus besoin d\'être gentil.', '', '', '', 'Me encanta cuando alguien me insulta, significa que ya no tengo que ser amable', '', ''), +('taunt', 'Thou leathern-jerkin, crystal-button, knot-pated, agatering, puke-stocking, caddis-garter, smooth-tongue, Spanish pouch!', 0, 0, '', 'Toi l\'agent fédéral, pourpoint en cuir, bouton de cristal, anneau d\'agate, bas vomi, jarretière caddis, pochette espagnole!', '', '', '', '¡Tú, jubón de cuero, botón de cristal, anudado, ágata, medias de vómito, liga de caddis, lengua suave, bolsa española!', '', ''), +('taunt', 'Thou qualling bat-fowling malt-worm!', 0, 0, '', 'Toi qualificatif de chauve-souris qui chasse le ver de malt!', '', '', '', '¡Tú, gusano de malta cazador de murciélagos!', '', ''), +('taunt', 'Thou art truely an idol of idiot-worshippers!', 0, 0, '', 'Tu es vraiment une idole d\'adorateurs d\'idiots!', '', '', '', '¡Eres verdaderamente un ídolo de los adoradores de idiotas!', '', ''), +('taunt', 'Thou misbegotten knotty-pated wagtail!', 0, 0, '', 'Tu es une bergeronnette printanière mal engendrée!', '', '', '', '¡Maldito lavandero nudoso!', '', ''), +('taunt', 'Thou whoreson mandrake, thou art fitter to be worn in my cap than to wait at my heels!', 0, 0, '', 'Toi putain de mandragore, tu es plus apte à être porté dans ma casquette qu\'à attendre sur mes talons!', '', '', '', '¡Hijo de puta mandrágora, eres mejor para que te lleve en mi gorra que para que me pise los talones!', '', ''), +('taunt', 'You! You scullion! You rampallian! You fustilarian! I\'ll tickle your catastrophe!', 0, 0, '', 'Toi ! Espèce de marmiton ! Espèce de rampallian ! Espèce de fusilier ! Je vais chatouiller ta catastrophe!', '', '', '', '¡Tú! ¡Scullion! ¡Ramaliano! ¡Fustilarista! ¡Te haré cosquillas en tu catástrofe!', '', ''), +('taunt', 'Oh ! Thou infectious ill-nurtured flax-wench!', 0, 0, '', 'Oh ! Tu es contagieuse et mal nourrie!', '', '', '', '¡Oh, ! ¡Tú, contagiosa moza del lino mal educada!', '', ''), +('taunt', 'We leak in your chimney, !', 0, 0, '', 'On a une fuite dans votre cheminée, !', '', '', '', '¡Tenemos una fuga en tu chimenea, !', '', ''), +('taunt', 'Oh thou bootless fen-sucked canker-blossom!', 0, 0, '', 'Oh toi, fleur de chancre sucée par les marais sans botte!', '', '', '', '¡Oh tú, flor de cancro chupada por el pantano sin botas!', '', ''), +('taunt', 'Were I like thee I\'d throw away myself!', 0, 0, '', 'Si j\'étais comme toi, je me jetterais!', '', '', '', '¡Si yo fuera como tú, me tiraría a la basura!', '', ''), +('taunt', 'O teach me , how I should forget to think!', 0, 0, '', 'O apprends-moi , comme je devrais oublier de penser!', '', '', '', '¡Oh, enséñame , cómo debo olvidarme de pensar!', '', ''), +('taunt', 'Truly thou art damned, like an ill-roasted egg, all on one side!', 0, 0, '', 'Vraiment tu es damné, comme un œuf mal rôti, tout d\'un côté!', '', '', '', '¡Verdaderamente estás condenado, como un huevo mal asado, todo de un lado!', '', ''), +('taunt', 'You starvelling, you eel-skin, you dried neat\'s-tongue, you bull\'s-pizzle, you stock-fish- O for breath to utter what is like thee!! -you tailor\'s-yard, you sheath, you bow-case, you vile standing tuck!', 0, 0, '', 'Toi affamé, espèce de peau d\'anguille, ta langue bien séchée, espèce de taureau, poisson séché, O pour le souffle de dire ce qui te ressemble !! -espèce de vergue de tailleur, espèce de fourreau, espèce d\'étui à archet, vil tuck debout', '', '', '', 'Estás muerto de hambre, piel de anguila, te secaste la lengua limpiamente, toro-pizzle, pescado-O para respirar pronunciar lo que es como tú !! ¡Tú, sastrería, vaina, estuche de arco, vil flaco de pie!', '', ''), +('taunt', 'Fie! Drop thee into the rotten mouth of Death!', 0, 0, '', 'Fi ! Jette-toi dans la bouche pourrie de la Mort!', '', '', '', '¡Fie! ¡Déjate caer en la podrida boca de la Muerte!', '', ''), +('taunt', ', you are a fishmonger!', 0, 0, '', ', vous êtes poissonnier!', '', '', '', ', ¡eres un pescadero!', '', ''), +('taunt', 'I shall live to knock thy brains out!', 0, 0, '', 'Je vivrai pour te faire sauter la cervelle!', '', '', '', '¡Viviré para romperte los sesos!', '', ''), +('taunt', 'Most shallow are you, !! Thou art worms-meat in respect of a good piece of flesh, indeed!!', 0, 0, '', 'Tu es très superficiel, !! Tu es de la viande de vers par rapport à un bon morceau de chair, en effet!!', '', '', '', '¡¡Eres el más superficial, !! ¡Eres carne de gusano con respecto a un buen trozo de carne, de hecho!', '', ''), +('taunt', 'Vile wretch! O , thou odiferous hell-hated pignut!', 0, 0, '', 'Misérable ! O , toi, ignoble cochon de l\'enfer!', '', '', '', '¡Miserable vil! ¡Oh, , fétido cerdo odiado por el infierno!', '', ''), +('taunt', '! Thy kiss is as comfortless as frozen water to a starved snake!', 0, 0, '', '! Ton baiser est aussi désagréable que de l\'eau gelée pour un serpent affamé!', '', '', '', '! ¡Tu beso es tan desconsolador como el agua helada para una serpiente hambrienta!', '', ''), +('taunt', 'I scorn you, scurvy companion. What, you poor, base, rascally, cheating, lack-linen mate! Away, you moldy rogue, away!', 0, 0, '', 'Je te méprise, compagnon du scorbut. Quoi, pauvre, bas, coquin, tricheur, camarade en manque de linge ! Partez, espèce de voyou moisi, partez!', '', '', '', 'Te desprecio, compañero escorbuto. ¡Qué, pobre, vil, pícaro, tramposo, compañero falto de lino! ¡Fuera, mohoso granuja, fuera!', '', ''), +('taunt', 'Out of my sight! Thou dost infect my eyes !', 0, 0, '', 'Hors de ma vue! Tu infectes mes yeux !', '', '', '', '¡Fuera de mi vista! ¡Me infectas los ojos !', '', ''), +('taunt', 'PLAY TIME!!!!', 0, 0, '', 'RÉCRÉATION!!!!', '', '', '', '¡¡¡HORA DE JUGAR!!!!', '', ''), +('taunt', 'None shall pass!', 0, 0, '', 'Personne ne passera!', '', '', '', '¡Ninguno pasará!', '', ''), +('taunt', 'We\'re under attack! A vast, ye swabs! Repel the invaders!', 0, 0, '', 'Nous sommes attaqués ! Un vaste écouvillons! Repoussez les envahisseurs!', '', '', '', '¡Estamos bajo ataque! ¡Un vasto, hisopos! ¡Repeler a los invasores!', '', ''), +('taunt', 'None may challenge the Brotherhood!', 0, 0, '', 'Personne ne peut défier la Confrérie!', '', '', '', '¡Nadie puede desafiar a la Hermandad!', '', ''), +('taunt', 'Foolsss...Kill the one in the dress!', 0, 0, '', 'Foolsss... Tuez celui qui porte la robe!', '', '', '', 'Tontosss... ¡Matad al del vestido!', '', ''), +('taunt', 'I\'ll feed your soul to Hakkar himself! ', 0, 0, '', 'Je donnerai ton âme à Hakkar lui-même! ', '', '', '', '¡Le daré de comer con tu alma al mismísimo Hakkar! ', '', ''), +('taunt', 'Pride heralds the end of your world! Come, mortals! Face the wrath of the !', 0, 0, '', 'La fierté annonce la fin de votre monde ! Venez, mortels ! Affrontez la colère des !', '', '', '', '¡El orgullo anuncia el fin de tu mundo! ¡Venid, mortales! ¡Enfréntate a la ira de la !', '', ''), +('taunt', 'All my plans have led to this!', 0, 0, '', 'Tous mes plans ont mené à cela!', '', '', '', '¡Todos mis planes me han llevado a esto!', '', ''), +('taunt', 'Ahh! More lambs to the slaughter!', 0, 0, '', 'Ahhh ! Plus d\'agneaux à l\'abattoir!', '', '', '', '¡Ahh! ¡Más corderos al matadero!', '', ''), +('taunt', 'Another day, another glorious battle!', 0, 0, '', 'Un autre jour, une autre bataille glorieuse!', '', '', '', '¡Otro día, otra batalla gloriosa!', '', ''), +('taunt', 'So, business... or pleasure?', 0, 0, '', 'Alors, affaires... ou plaisir?', '', '', '', 'Entonces, ¿negocios... o placer?', '', ''), +('taunt', 'You are not prepared!', 0, 0, '', 'Vous n\'êtes pas prêt!', '', '', '', '¡No estás preparado!', '', ''), +('taunt', 'The \'s final conquest has begun! Once again the subjugation of this world is within our grasp. Let none survive! ', 0, 0, '', 'La conquête finale de la a commencé ! Une fois de plus, l\'assujettissement de ce monde est à notre portée. Que personne ne survive!', '', '', '', '¡La conquista final de ha comenzado! Una vez más, la subyugación de este mundo está a nuestro alcance. ¡Que nadie sobreviva! ', '', ''), +('taunt', 'Your death will be a painful one. ', 0, 0, '', 'Ta mort sera douloureuse.', '', '', '', 'Tu muerte será dolorosa. ', '', ''), +('taunt', 'Cry for mercy! Your meaningless lives will soon be forfeit. ', 0, 0, '', 'Crie miséricorde ! Vos vies insignifiantes seront bientôt perdues.', '', '', '', '¡Llora por piedad! Sus vidas sin sentido pronto se perderán. ', '', ''), +('taunt', 'Abandon all hope! The has returned to finish what was begun so many years ago. This time there will be no escape! ', 0, 0, '', 'Abandonner tout espoir! La est revenue pour terminer ce qui avait été commencé il y a tant d\'années. Cette fois, il n\'y aura pas d\'échappatoire!', '', '', '', '¡Abandona toda esperanza! La ha regresado para terminar lo que comenzó hace tantos años. ¡Esta vez no habrá escapatoria! ', '', ''), +('taunt', 'Alert! You are marked for Extermination! ', 0, 0, '', 'Alerte! Vous êtes marqué pour l\'extermination!', '', '', '', '¡Alerta! ¡Estás marcado para el exterminio! ', '', ''), +('taunt', 'The is for guests only...', 0, 0, '', 'La est réservée aux invités...', '', '', '', 'La es solo para invitados...', '', ''), +('taunt', 'Ha ha ha! You are hopelessly outmatched!', 0, 0, '', 'Hahaha! Vous êtes désespérément surpassé!', '', '', '', '¡Ja, ja, ja! ¡Estás irremediablemente superado!', '', ''), +('taunt', 'I will crush your delusions of grandeur! ', 0, 0, '', 'Je vais écraser vos illusions de grandeur!', '', '', '', '¡Aplastaré tus delirios de grandeza! ', '', ''), +('taunt', 'Forgive me, for you are about to lose the game.', 0, 0, '', 'Pardonnez-moi, car vous êtes sur le point de perdre la partie.', '', '', '', 'Perdóname, porque estás a punto de perder el juego.', '', ''), +('taunt', 'Struggling only makes it worse.', 0, 0, '', 'Lutter ne fait qu\'empirer les choses.', '', '', '', 'La lucha solo lo empeora.', '', ''), +('taunt', 'Vermin! Leeches! Take my blood and choke on it!', 0, 0, '', 'Vermine! sangsues ! Prends mon sang et étouffe-toi avec!', '', '', '', '¡Alimañas! ¡Sanguijuelas! ¡Toma mi sangre y atragantate con ella!', '', ''), +('taunt', 'Not again... NOT AGAIN!', 0, 0, '', 'Pas encore... PAS ENCORE!', '', '', '', 'No otra vez... ¡NO OTRA VEZ!', '', ''), +('taunt', 'My blood will be the end of you!', 0, 0, '', 'Mon sang sera ta fin!', '', '', '', '¡Mi sangre será tu fin!', '', ''), +('taunt', 'Good, now you fight me!', 0, 0, '', 'Bien, maintenant tu me combats!', '', '', '', 'Bien, ¡ahora pelea conmigo!', '', ''), +('taunt', 'Get da move on, guards! It be killin\' time!', 0, 0, '', 'Allez-y, gardes ! Ça va tuer le temps!', '', '', '', '¡Muévanse, guardias! ¡Será para matar el tiempo!', '', ''), +('taunt', 'Don\'t be delayin\' your fate. Come to me now. I make your sacrifice quick.', 0, 0, '', 'Ne retardez pas votre destin. Viens à moi maintenant. Je fais votre sacrifice rapide.', '', '', '', 'No demores tu destino. Ven a mí ahora. Hago que tu sacrificio sea rápido.', '', ''), +('taunt', 'You be dead soon enough!', 0, 0, '', 'Tu es mort bien assez tôt!', '', '', '', '¡Estarás muerto lo suficientemente pronto!', '', ''), +('taunt', 'Mua-ha-ha!', 0, 0, '', 'Mua-ha-ha!', '', '', '', '¡Mua-ja-ja!', '', ''), +('taunt', 'I be da predator! You da prey...', 0, 0, '', 'Je suis un prédateur ! Tu es une proie...', '', '', '', '¡Soy un depredador! Eres presa...', '', ''), +('taunt', 'You gonna leave in pieces!', 0, 0, '', 'Tu vas partir en morceaux!', '', '', '', '¡Te vas a ir en pedazos!', '', ''), +('taunt', 'Death comes. Will your conscience be clear? ', 0, 0, '', 'La mort vient. Votre conscience sera-t-elle claire?', '', '', '', 'La muerte llega. ¿Tu conciencia estará limpia? ', '', ''), +('taunt', 'Your behavior will not be tolerated.', 0, 0, '', 'Votre comportement ne sera pas toléré.', '', '', '', 'Tu comportamiento no será tolerado', '', ''), +('taunt', 'The Menagerie is for guests only.', 0, 0, '', 'La Ménagerie est réservée aux invités.', '', '', '', 'The Menagerie es solo para invitados', '', ''), +('taunt', 'Hmm, unannounced visitors, Preparations must be made... ', 0, 0, '', 'Hmm, visiteurs inopinés, il faut faire des préparatifs...', '', '', '', 'Hmm, visitantes inesperados, se deben hacer preparativos... ', '', ''), +('taunt', 'Hostile entities detected. Threat assessment protocol active. Primary target engaged. Time minus thirty seconds to re-evaluation.', 0, 0, '', 'Entités hostiles détectées. Protocole d\'évaluation de la menace actif. Cible principale engagée. Délai de réévaluation moins trente secondes.', '', '', '', 'Entidades hostiles detectadas. Protocolo de evaluación de amenazas activo. Objetivo principal comprometido. Tiempo menos treinta segundos para la reevaluación.', '', ''), +('taunt', 'New toys? For me? I promise I won\'t break them this time!', 0, 0, '', 'Nouveaux jouets? Pour moi? Promis je ne les casserai pas cette fois !', '', '', '', '¿Juguetes nuevos? ¿Para mi? ¡Te prometo que no los romperé esta vez!', '', ''), +('taunt', 'I\'m ready to play!', 0, 0, '', 'Je suis prêt à jouer!', '', '', '', '¡Estoy listo para jugar!', '', ''), +('taunt', 'Shhh... it will all be over soon.', 0, 0, '', 'Chut... tout sera bientôt fini.', '', '', '', 'Shhh... todo terminará pronto.', '', ''), +('taunt', 'Aaaaaughibbrgubugbugrguburgle!', 0, 0, '', 'Aaaaaughibbrgubugbugrguburgle!', '', '', '', '¡Aaaaaughibbrgubugbugrguburgle!', '', ''), +('taunt', 'RwlRwlRwlRwl!', 0, 0, '', 'RwlRwlRwlRwl!', '', '', '', 'RwlRwlRwlRwl!', '', ''), +('taunt', 'You too, shall serve!', 0, 0, '', 'Toi aussi, tu serviras!', '', '', '', '¡Tú también, debes servir!', '', ''), +('taunt', 'Tell me... tell me everything! Naughty secrets! I\'ll rip the secrets from your flesh!', 0, 0, '', 'Dis-moi... dis-moi tout ! Secrets coquins ! J\'arracherai les secrets de ta chair!', '', '', '', 'Cuéntame... ¡cuéntame todo! ¡Secretos traviesos! ¡Arrancaré los secretos de tu carne!', '', ''), +('taunt', 'Prepare yourselves, the bells have tolled! Shelter your weak, your young and your old! Each of you shall pay the final sum! Cry for mercy, the reckoning has come!', 0, 0, '', 'Préparez-vous, les cloches ont sonné ! Mettez à l\'abri vos faibles, vos jeunes et vos vieux ! Chacun de vous paiera la somme finale ! Implorez la miséricorde , le jugement est venu!', '', '', '', '¡Prepárense, las campanas han doblado! ¡Abriga a tus débiles, a tus jóvenes ya tus viejos! ¡Cada uno de ustedes pagará la suma final! Clama por misericordia, el ajuste de cuentas ha llegado!', '', ''), +('taunt', 'Where in Bonzo\'s brass buttons am I?', 0, 0, '', 'Où suis-je dans les boutons en laiton de Bonzo?', '', '', '', '¿Dónde estoy en los botones de latón de Bonzo?', '', ''), +('taunt', 'I can bear it no longer! Goblin King! Goblin King! Wherever you may be! Take this far away from me!', 0, 0, '', 'Je ne peux plus le supporter ! Roi Gobelin ! Roi Gobelin ! Où que vous soyez ! Emmenez cette loin de moi!', '', '', '', '¡No puedo soportarlo más! ¡Rey de los duendes! ¡Rey de los duendes! ¡WHERE quiera que estés! ¡Lleva a este lejos de mí!', '', ''), +('taunt', 'You have thirteen hours in which to solve the labyrinth, before your baby brother becomes one of us... forever.', 0, 0, '', 'Vous avez treize heures pour résoudre le labyrinthe, avant que ton petit frère ne devienne l\'un des nôtres... pour toujours.', '', '', '', 'Tienes trece horas para resolver el laberinto, antes de que tu hermanito se convierta en uno de nosotros... para siempre', '', ''), +('taunt', 'So, the is a piece of cake, is it? Well, let\'s see how you deal with this little slice... ', 0, 0, '', 'Donc, la est un jeu d\'enfant, n\'est-ce pas ? Eh bien, voyons comment tu gères cette petite tranche...', '', '', '', 'Entonces, la es pan comido, ¿verdad? Bueno, veamos cómo lidias con esta pequeña porción... ', '', ''), +('taunt', 'Back off, I\'ll take you on, headstrong to take on anyone, I know that you are wrong, and this is not where you belong', 0, 0, '', 'Reculez, je vais vous attaquer, têtu à affronter n\'importe qui, je sais que vous vous trompez, et ce n\'est pas votre place', '', '', '', 'Atrás, te enfrentaré, testarudo para enfrentar a cualquiera, sé que estás equivocado, y este no es el lugar al que perteneces', '', ''), +('taunt', 'Show me whatcha got!', 0, 0, '', 'Montre-moi ce que tu as!', '', '', '', '¡Muéstrame lo que tienes!', '', ''), +('taunt', 'To the death!', 0, 0, '', 'A la mort!', '', '', '', '¡Hasta la muerte!', '', ''), +('taunt', 'Twin blade action, for a clean close shave every time.', 0, 0, '', 'Action à double lame, pour un rasage de près propre à chaque fois.', '', '', '', 'Acción de cuchilla doble, para un afeitado limpio y apurado en todo momento.', '', ''), +('taunt', 'Bring it on!', 0, 0, '', 'Allez-y!', '', '', '', '¡Adelante!', '', ''), +('taunt', 'You\'re goin\' down!', 0, 0, '', 'Tu descends!', '', '', '', '¡Vas a caer!', '', ''), +('taunt', 'Stabby stab stab!', 0, 0, '', 'Coup de poignard poignardé!', '', '', '', '¡Puñalada puñalada puñalada!', '', ''), +('taunt', 'Let\'s get this over quick, time is mana.', 0, 0, '', 'Finissons-en vite , le temps c\'est du mana.', '', '', '', 'Terminemos con esto rápido, el tiempo es maná.', '', ''), +('taunt', 'I do not think you realise the gravity of your situation.', 0, 0, '', 'Je ne pense pas que tu te rendes compte de la gravité de ta situation.', '', '', '', 'No creo que te des cuenta de la gravedad de tu situación.', '', ''), +('taunt', 'I will bring honor to my family and my kingdom!', 0, 0, '', 'Je ferai honneur à ma famille et à mon royaume!', '', '', '', '¡Llevaré honor a mi familia y mi reino!', '', ''), +('taunt', 'Light, give me strength!', 0, 0, '', 'Lumière, donne-moi la force!', '', '', '', '¡Luz, dame fuerza!', '', ''), +('taunt', 'My church is the field of battle - time to worship...', 0, 0, '', 'Mon église est le champ de bataille - il est temps d\'adorer...', '', '', '', 'Mi iglesia es el campo de batalla - hora de adorar...', '', ''), +('taunt', 'I hold you in contempt...', 0, 0, '', 'Je te méprise...', '', '', '', 'Te tengo en desacato...', '', ''), +('taunt', 'Face the hammer of justice!', 0, 0, '', 'Affrontez le marteau de la justice!', '', '', '', '¡Enfréntate al martillo de la justicia!', '', ''), +('taunt', 'Prove your worth in the test of arms under the Light!', 0, 0, '', 'Prouvez votre valeur dans l\'épreuve des armes sous la Lumière!', '', '', '', '¡Demuestra tu valía en la prueba de las armas bajo la Luz!', '', ''), +('taunt', 'All must fall before the might and right of my cause, you shall be next!', 0, 0, '', 'Tout doit tomber devant la force et le droit de ma cause, vous serez le prochain!', '', '', '', 'Todo debe caer ante el poder y el derecho de mi causa, ¡tú serás el próximo!', '', ''), +('taunt', 'Prepare to die!', 0, 0, '', 'Préparez-vous à mourir!', '', '', '', '¡Prepárate para morir!', '', ''), +('taunt', 'The beast with me is nothing compared to the beast within...', 0, 0, '', 'La bête avec moi n\'est rien comparée à la bête à l\'intérieur...', '', '', '', 'La bestia conmigo no es nada comparada con la bestia interior...', '', ''), +('taunt', 'Witness the firepower of this fully armed huntsman!', 0, 0, '', 'Soyez témoin de la puissance de feu de ce chasseur entièrement armé!', '', '', '', '¡Sea testigo de la potencia de fuego de este cazador completamente armado!', '', ''), + + + +-- combat events +('critical health', 'Heal me! Quick!', 0, 0, '', 'Soigne moi! Vite!', '', '', '', '¡Cúrame! ¡Rápido!', '', ''), +('critical health', 'Almost dead! Heal me!', 0, 0, '', 'Presque mort! Soigne moi!', '', '', '', '¡Estoy casi muerto! ¡Cúrame!', '', ''), +('critical health', 'Help! Heal me!', 0, 0, '', 'Aider! Soigne moi!', '', '', '', '¡Ayuda! ¡Cúrame!', '', ''), +('critical health', 'Somebody! Heal me!', 0, 0, '', 'Quelqu\'un! Soigne moi!', '', '', '', '¡Alguien! ¡Cúrame!', '', ''), +('critical health', 'Heal! Heal! Heal!', 0, 0, '', 'Soigner! Soigner! Soigner!', '', '', '', '¡Curame! ¡Saname! ¡Socorro!', '', ''), +('critical health', 'I am dying! Heal! Aaaaarhg!', 0, 0, '', 'Je meurs! Soigner! Aaaaarhg!', '', '', '', '¡Me estoy muriendo! ¡Saname! ¡Aaaaarhg!', '', ''), +('critical health', 'Heal me!', 0, 0, '', 'Soigne moi!', '', '', '', '¡Cúrame!', '', ''), +('critical health', 'I will die. I will die. I will die. Heal!', 0, 0, '', 'Je vais mourir. Je vais mourir. Je vais mourir. Soigner!', '', '', '', 'Voy a morir. Voy a morir. Voy a morir. ¡Saname!', '', ''), +('critical health', 'Healers, where are you? I am dying!', 0, 0, '', 'Guérisseurs, où êtes-vous ? Je meurs!', '', '', '', 'Sanadores, ¿dónde estais? ¡Me estoy muriendo!', '', ''), +('critical health', 'Oh the pain. Heal me quick!', 0, 0, '', 'Ah la douleur. Guéris-moi vite!', '', '', '', 'Ouch, qué dolor. ¡Cúrame rápido!', '', ''), + + + +('low health', 'Need heal', 0, 0, '', 'Besoin de guérir', '', '', '', 'Necesito una cura', '', ''), +('low health', 'Low health', 0, 0, '', 'Santé faible', '', '', '', 'Salud baja', '', ''), +('low health', 'Drop a heal. Please.', 0, 0, '', 'Dépose un soin. S\'il te plaît.', '', '', '', 'Una sanación por favor.', '', ''), +('low health', 'Could somebody drop a heal on me?', 0, 0, '', 'Quelqu\'un pourrait-il me soigner?', '', '', '', '¿Alguien podría curarme?', '', ''), +('low health', 'Hey! Better heal me now than rez later', 0, 0, '', 'Hey! Mieux vaut me soigner maintenant que rez plus tard', '', '', '', '¡Oye! Mejor curarme ahora que resucitarme después', '', ''), +('low health', 'I am sorry. Need another heal', 0, 0, '', 'Je suis désolé. J\'ai besoin d\'un autre soin', '', '', '', 'Lo siento. Necesito otra curación', '', ''), +('low health', 'Damn mobs. Heal me please', 0, 0, '', 'Maudits mobs. Guéris moi s\'il te plait', '', '', '', '¡Malditos bichos! ¡Una curita por favor!', '', ''), +('low health', 'One more hit and I am done for. Heal please', 0, 0, '', 'Un coup de plus et c\'est fini. Guéris moi s\'il te plait', '', '', '', 'Un golpe más y estoy acabado. Cura por favor', '', ''), +('low health', 'Are there any healers?', 0, 0, '', 'Y a-t-il des guérisseurs?', '', '', '', '¿Hay sanadores?', '', ''), +('low health', 'Why do they always punch me in the face? Need heal', 0, 0, '', 'Pourquoi me frappent-ils toujours au visage? Besoin de soins', '', '', '', '¿Por qué siempre me golpean en la cara? Necesito sanacion', '', ''), +('low health', 'Can anybody heal me a bit?', 0, 0, '', 'Quelqu\'un peut-il me guérir un peu?', '', '', '', '¿Alguien puede curarme un poco?', '', ''), + + + +('low mana', 'OOM', 0, 0, '', 'MOO', '', '', '', 'No tengo mana!', '', ''), +('low mana', 'I am out of mana', 0, 0, '', 'je n\'ai plus de mana', '', '', '', 'No tengo maná', '', ''), +('low mana', 'Damn I wasted all my mana on this', 0, 0, '', 'Putain j\'ai gaspillé tout mon mana sur ça', '', '', '', 'Me cago en todo! Malgasté todo mi maná enseguida', '', ''), +('low mana', 'You should wait until I drink or regenerate my mana', 0, 0, '', 'Vous devriez attendre que je boive ou que je régénère mon mana', '', '', '', 'Deberías esperar hasta que beba o regenere mi maná', '', ''), +('low mana', 'Low mana', 0, 0, '', 'Mana faible', '', '', '', 'Maná bajo', '', ''), +('low mana', 'No mana. Again?', 0, 0, '', 'Pas de mana. De nouveau?', '', '', '', 'Sin maná. ¿Otra vez?', '', ''), +('low mana', 'Low mana. Wanna drink', 0, 0, '', 'Mana faible. Je veux boire', '', '', '', 'Maná bajo. Quiero beber', '', ''), +('low mana', 'Do we have a vending machine? Out of mana again', 0, 0, '', 'Avons-nous un distributeur automatique? Plus de mana à nouveau', '', '', '', '¿Tenemos una máquina expendedora? Sin maná otra vez', '', ''), +('low mana', 'My mana is history', 0, 0, '', 'Mon mana appartient à l\'histoire', '', '', '', 'Mi maná es historia', '', ''), +('low mana', 'I\'d get some drinks next time. Out of mana', 0, 0, '', 'Je prendrais quelques verres la prochaine fois. Manque de mana', '', '', '', '¡No tengo maná! Tengo que comprar bebidas la próxima vez...', '', ''), +('low mana', 'Where is my mana?', 0, 0, '', 'Où est mon mana?', '', '', '', '¿Dónde está mi maná?', '', ''), + + + +('low ammo', 'I have few left!', 0, 0, '', 'Il me reste peu de !', '', '', '', '¡Me quedan pocas !', '', ''), +('low ammo', 'I need more !', 0, 0, '', 'J\'ai besoin de plus de !', '', '', '', '¡Necesito más !', '', ''), +('low ammo', '100 left!', 0, 0, '', 'Il reste 100 !', '', '', '', '¡Quedan 100 !', '', ''), + + + +('no ammo', 'That\'s it! No !', 0, 0, '', 'C\'est ça! Pas de !', '', '', '', '¡Eso es todo! ¡Sin !', '', ''), +('no ammo', 'And you have my bow... Oops, no !', 0, 0, '', 'Et vous avez mon arc... Oups, pas de !', '', '', '', 'Y tú tienes mi arco... ¡Uy, sin !', '', ''), +('no ammo', 'Need ammo!', 0, 0, '', 'Besoin de munitions!', '', '', '', '¡Necesito munición!', '', ''), + + + +('aoe', 'Oh god!', 0, 0, '', 'Oh mon Dieu!', '', '', '', '¡Oh, Dios!', '', ''), +('aoe', 'I am scared', 0, 0, '', 'j\'ai peur', '', '', '', 'Tengo miedo', '', ''), +('aoe', 'We are done for', 0, 0, '', 'Nous avons fini pour', '', '', '', 'Hemos terminado', '', ''), +('aoe', 'This is over', 0, 0, '', 'C\'est terminé', '', '', '', 'Esto se acabó', '', ''), +('aoe', 'This ends now', 0, 0, '', 'Cela se termine maintenant', '', '', '', 'Esto termina ahora', '', ''), +('aoe', 'Could somebody cast blizzard or something?', 0, 0, '', 'Quelqu\'un pourrait-il lancer le blizzard ou quelque chose comme ça?', '', '', '', '¿Alguien podría lanzar ventisca o algo así?', '', ''), +('aoe', 'Damn. The tank aggroed all the mobs around', 0, 0, '', 'Mince. Le tank a agro toutes les mobs autour', '', '', '', '¡Me cago en todo! El tanque atrajo a todos los mobs...', '', ''), +('aoe', 'We gonna die. We gonna die. We gonna die.', 0, 0, '', 'Nous allons mourir. Nous allons mourir. Nous allons mourir.', '', '', '', 'Vamos a morir. Vamos a morir. Vamos a morir.', '', ''), +('aoe', 'Whoa! So many toys to play with', 0, 0, '', 'Ouah ! Tant de jouets avec lesquels jouer', '', '', '', '¡Vaya! Tantos juguetes con los que jugar', '', ''), +('aoe', 'I gonna kill them all!', 0, 0, '', 'Je vais tous les tuer!', '', '', '', '¡Voy a matarlos a todos!', '', ''), +('aoe', 'If the tank dies we are history', 0, 0, '', 'Si le tank meurt, nous appartenons à l\'histoire', '', '', '', 'Si el tanque muere somos historia', '', ''), +('aoe', 'Aaaaaargh!', 0, 0, '', 'Aaaaaargh!', '', '', '', '¡Aaaaaargh!', '', ''), +('aoe', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', 0, 0, '', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', '', '', '', 'LEEEEERROOOYYYYYYYYYYYY JENNKINNNSSSSSS!!!!!!!', '', ''), +('aoe', 'Right. What do we have in AOE?', 0, 0, '', 'D\'accord. Qu\'avons-nous en dégats de zone?', '', '', '', 'Claro. ¿Qué tenemos en AOE?', '', ''), +('aoe', 'This gets interesting', 0, 0, '', 'Cela devient intéressant', '', '', '', 'Esto se pone interesante', '', ''), +('aoe', 'Cool. Get them in one place for a good flamestrike', 0, 0, '', 'Cool. Rassemblez-les au même endroit pour un bon coup de flamme', '', '', '', 'Genial! Ponlos todos juntos para un buen ataque en area', '', ''), +('aoe', 'Kill! Kill! Kill!', 0, 0, '', 'Tuer! Tuer! Tuer!', '', '', '', '¡Matar! ¡Matar! ¡Matar!', '', ''), +('aoe', 'I think my pants are wet', 0, 0, '', 'Je pense que mon pantalon est mouillé', '', '', '', 'Creo que mis pantalones están mojados', '', ''), +('aoe', 'We are history', 0, 0, '', 'Nous sommes l\'histoire', '', '', '', 'Somos historia', '', ''), +('aoe', 'I hope healers are ready. Leeeeroy!', 0, 0, '', 'J\'espère que les guérisseurs sont prêts. Leeeeeroy!', '', '', '', 'Espero que los sanadores estén listos. ¡Leeeroy!', '', ''), +('aoe', 'I hope they won\'t come for me', 0, 0, '', 'j\'espère qu\'ils ont gagné, qu\'ils ne viendront pas pour moi', '', '', '', 'Espero que no vengan por mí', '', ''), +('aoe', 'Oh no. I can\'t see at this slaugther', 0, 0, '', 'Oh non. Je ne peux pas voir à ce massacre', '', '', '', 'Oh, no. No puedo ver esta matanza', '', ''), + + + +-- on looting +('loot', 'I hope there will be some money', 0, 0, '', 'j\'espère qu\'il y aura de l\'argent', '', '', '', 'Espero que haya algo de dinero...', '', ''), +('loot', 'Loot! Loot!', 0, 0, '', 'Butin! Butin!', '', '', '', '¡Botín! ¡Botín!', '', ''), +('loot', 'My precious', 0, 0, '', 'Mon précieux', '', '', '', 'Mi tesoro...', '', ''), +('loot', 'I hope there is a shiny epic item waiting for me there', 0, 0, '', 'J\'espère qu\'il y a un objet épique brillant qui m\'attend ici', '', '', '', 'Espero que haya un objeto épico brillante esperándome allí', '', ''), +('loot', 'I have deep pockets and bags', 0, 0, '', 'J\'ai des poches et des sacs profonds', '', '', '', 'Tengo bolsillos profundos y infinitos', '', ''), +('loot', 'All is mine!', 0, 0, '', 'Tout est à moi!', '', '', '', '¡Todo es mío!', '', ''), +('loot', 'Hope no gray shit today', 0, 0, '', 'J\'espère pas de merde grise aujourd\'hui', '', '', '', 'Espero que hoy no haya mierda gris', '', ''), +('loot', 'This loot is MINE!', 0, 0, '', 'Ce butin est à MOI!', '', '', '', '¡Este botín es MÍO!', '', ''), +('loot', 'Looting is disgusting but I need money', 0, 0, '', 'Le pillage est dégoûtant mais j\'ai besoin d\'argent', '', '', '', 'El saqueo es repugnante pero necesito dinero...', '', ''), +('loot', 'Gold!', 0, 0, '', 'Or!', '', '', '', '¡Oro!', '', ''), +('loot', 'OK. Let\'s see what they\'ve got', 0, 0, '', 'D\'ACCORD. Voyons ce qu\'ils ont', '', '', '', 'OK. Veamos qué tienen', '', ''), +('loot', 'Do not worry. I will loot eveything', 0, 0, '', 'Ne t\'inquiète pas. je vais tout piller', '', '', '', 'No te preocupes. Saquearé todo', '', ''), +('loot', 'I am loot ninja', 0, 0, '', 'je suis un ninja de butin', '', '', '', 'Soy un ladron de tesoros', '', ''), +('loot', 'Do I neeed to roll?', 0, 0, '', 'Dois-je recommencer?', '', '', '', '¿Necesito lanzar dados?', '', ''), +('loot', 'Somebody explain me, where they did put all this stuff?', 0, 0, '', 'Quelqu\'un m\'explique, où ils ont mis tout ça?', '', '', '', 'Alguien me explica, ¿dónde pusieron todas estas cosas?', '', ''), +('loot', 'No, I won\'t loot gray shit', 0, 0, '', 'Non, je ne pillerai pas la merde grise', '', '', '', 'No, no saquearé mierda gris', '', ''), +('loot', 'I\'m first. I\'m first. I\'m first.', 0, 0, '', 'Je suis le premier. Je suis le premier. Je suis le premier.', '', '', '', '¡Es mio! ¡Es mio! ¡Es mio!', '', ''), +('loot', 'Give me your money!', 0, 0, '', 'Donne-moi ton argent!', '', '', '', '¡Dame todo tu dinero!', '', ''), +('loot', 'My pockets are empty, I need to fill them', 0, 0, '', 'Mes poches sont vides, j\'ai besoin de les remplir', '', '', '', 'Mis bolsillos están vacíos y necesitan llenarse!', '', ''), +('loot', 'I\'ve got a new bag for this', 0, 0, '', 'J\'ai un nouveau sac pour ça', '', '', '', 'Tengo una nueva bolsa para esto', '', ''), +('loot', 'I hope I won\'t aggro anybody while looting', 0, 0, '', 'J\'espère que je n\'agresserai personne pendant le pillage', '', '', '', 'Espero no ofender a nadie mientras saqueo', '', ''), +('loot', 'Please don\'t watch. I am looting', 0, 0, '', 'S\'il vous plaît, ne regardez pas. je pille', '', '', '', 'Por favor, no mires. Estoy saqueando', '', ''), +('loot', 'Ha! You won\'t get any piece of it!', 0, 0, '', 'Ha! Vous n\'en aurez aucun morceau!', '', '', '', '¡Ja! ¡No obtendrás nada de eso!', '', ''), +('loot', 'Looting is cool', 0, 0, '', 'Le pillage c\'est cool', '', '', '', 'Saquear es genial', '', ''), +('loot', 'I like new gear', 0, 0, '', 'j\'aime le nouveau matos', '', '', '', 'Me gusta el equipo nuevo', '', ''), +('loot', 'I\'l quit if there is nothing valuable again', 0, 0, '', 'J\'arrêterai s\'il n\'y a plus rien de précieux', '', '', '', 'Me doy por vencido si no hay nada util', '', ''), +('loot', 'I hope it is be a pretty ring', 0, 0, '', 'j\'espère que c\'est une jolie bague', '', '', '', 'Espero que sea un anillo bonito', '', ''), +('loot', 'I\'l rip the loot from you', 0, 0, '', 'Je t\'arracherai le butin', '', '', '', 'Te arrancaré el botín', '', ''), +('loot', 'Everybody stay off. I\'m going to loot', 0, 0, '', 'Tout le monde reste à l\'écart. je vais piller', '', '', '', '¡Alejaos todos! Voy a lootear', '', ''), +('loot', 'Sweet loot', 0, 0, '', 'Doux butin', '', '', '', 'Dulce botín', '', ''), +('loot', 'The Roll God! Give me an epic today', 0, 0, '', 'Le Dieu du rouleau ! Donnez-moi de l\'épique aujourd\'hui', '', '', '', '¡El Dios de los dados! Dame un epico hoy', '', ''), +('loot', 'Please give me new toys', 0, 0, '', 'S\'il te plaît, donne-moi de nouveaux jouets', '', '', '', 'Por favor, dame nuevos juguetes', '', ''), +('loot', 'I hope they carry tasties', 0, 0, '', 'J\'espère qu\'ils portent des saveurs', '', '', '', 'Espero que caiga algo sabrosos', '', ''), +('loot', 'The gold is mine. I\'l leave everyting, I promise', 0, 0, '', 'L\'or est à moi. Je laisse tout, je promets', '', '', '', 'El oro es mío. Dejaré todo lo demas, lo prometo!', '', ''), +('loot', 'No, I can\'t resist', 0, 0, '', 'Non, je ne peux pas résister', '', '', '', 'No, no puedo resistir', '', ''), +('loot', 'I want more!', 0, 0, '', 'Je veux plus!', '', '', '', '¡Quiero más!', '', ''), + + + +-- wait signals +('wait_travel_close', 'I am close, wait for me!', 0, 0, '', '', '', '', '', '¡Estoy cerca, espérame!', '', 'Я тут рядом, подожди!'), +('wait_travel_close', 'I\'m not far, please wait!', 0, 0, '', '', '', '', '', 'No estoy lejos, ¡esperame por favor!', '', 'Я недалеко, погодите!'), + + + +('wait_travel_medium', 'I\'m heading to your location', 0, 0, '', '', '', '', '', 'Me dirijo a tu ubicación', '', 'Двигаюсь к тебе'), +('wait_travel_medium', 'I\'m coming to you', 0, 0, '', '', '', '', '', 'Voy hacia ti', '', 'Иду к тебе'), + + + +('wait_travel_far', 'I\'m traveling to your location', 0, 0, '', '', '', '', '', 'Voy a viajar a tu ubicación', '', 'Направляюсь к тебе'), +('wait_travel_far', 'I\'m trying to get to you', 0, 0, '', '', '', '', '', 'Estoy tratando de llegar a ti', '', 'Пытаюсь до тебя добраться'), + + + + +-- commands +('equip_command', 'Equipping %item', 0, 0, '', '', '', '', '', 'Me he equipado %item', '', ''), + + + +('unequip_command', '%item unequipped', 0, 0, '', '', '', '', '', 'Me he quitado %item', '', ''), + + + +('auto_learn_spell', 'I have learned the spells: %spells', 0, 0, '', '', '', '', '', 'He aprendido los hechizos: %spells', '', ''), + + + +('use_command_item_cooldown', '%item is in cooldown', 0, 0, '', '', '', '', '', '%item esta recargandose', '', ''), + + + +('use_command_item_not_owned', 'I don''t have %item in my inventory', 0, 0, '', '', '', '', '', 'No tengo %item en mi inventario', '', ''), + + + +('use_command_invalid_item', 'The item with the id %item does not exist', 0, 0, '', '', '', '', '', 'El objeto con el id %item no existe', '', ''), + + + +('use_command_socket', 'Socketing %gem into %item', 0, 0, '', '', '', '', '', 'Insertando %gem en %item', '', ''), + + + +('use_command_item_error', 'I can''t use %item', 0, 0, '', '', '', '', '', 'No puedo usar %item', '', ''), + + + +('following', 'Following', 0, 0, '', '', '', '', '', 'Te sigo', '', 'Следую'), + + + +('staying', 'Staying', 0, 0, '', '', '', '', '', 'Me quedo aqui', '', 'Стою'), + + + +('fleeing', 'Fleeing', 0, 0, '', '', '', '', '', 'Huyendo', '', 'Убегаю'), + + + +('fleeing_far', 'I won\'t flee with you, you are too far away', 0, 0, '', '', '', '', '', 'No huiré contigo, estás demasiado lejos', '', 'Я с тобой не побегу, ты слишком далеко'), + + + +('grinding', 'Grinding', 0, 0, '', '', '', '', '', 'Farmeando', '', 'Гриндю'), + + + +('attacking', 'Attacking', 0, 0, '', '', '', '', '', 'Atacando', '', 'Атакую'), + + + +('error_far', 'It is too far away', 0, 0, '', '', '', '', '', 'Estas demasiado lejos', '', 'Слишком далеко'), + + + +('error_water', 'It is under water', 0, 0, '', '', '', '', '', 'Estas debajo del agua', '', 'Это под водой'), + + + +('error_cant_go', 'I can\'t go there', 0, 0, '', '', '', '', '', 'No puedo ir allí', '', 'Я не могу туда пройти'), + + + +('error_guild', 'I\'m not in your guild!', 0, 0, '', '', '', '', '', '¡No estoy en tu hermandad!', '', 'Я не в твоей гильдии'), + + + +('error_gbank_found', 'Can not find a guild bank nearby', 0, 0, '', '', '', '', '', 'No se puede encontrar un banco de hermandad cercano', '', 'Не могу найти гильд банк рядом'), + + + +('error_cant_put', 'I can\'t put ', 0, 0, '', '', '', '', '', 'No puedo depositar ', '', 'Я не могу положить'), + + + +('error_gbank_rights', 'I have no rights to put items in the first guild bank tab', 0, 0, '', '', '', '', '', 'No tengo derechos para depositar objetos en la primera pestaña del banco de hermandad', '', 'Нет прав чтобы класть вещи в первую вкладку гильд банка'), + + + +('gbank_put', ' put to guild bank', 0, 0, '', '', '', '', '', ' depositado en el banco de hermandad', '', ' теперь в гильд банке'), + + + +('free_moving', 'Free moving', 0, 0, '', '', '', '', '', 'Moviendome libremente', '', ''), + + + +('guarding', 'Guarding', 0, 0, '', '', '', '', '', 'Protegiendo la posición', '', ''), + + + +('use_command', 'Using %target', 0, 0, '', '', '', '', '', 'Usando %target', '', ''), + + + +('command_target_unit', 'on %unit', 0, 0, '', '', '', '', '', 'en %unit', '', ''), + + + +('use_command_remaining', '(%amount available)', 0, 0, '', '', '', '', '', '(%amount restante)', '', ''), + + + +('use_command_last', '(the last one)', 0, 0, '', '', '', '', '', '(el último)', '', ''), + + + +('use_command_socket_error', 'The socket does not fit', 0, 0, '', '', '', '', '', 'La ranura no sirve', '', ''), + + + +('command_target_trade', 'on trade item', 0, 0, '', '', '', '', '', 'en objeto comerciado', '', ''), + + + +('command_target_self', 'on myself', 0, 0, '', '', '', '', '', 'en mi', '', ''), + + + +('command_target_item', 'on %item', 0, 0, '', '', '', '', '', 'en %item', '', ''), + + + +('command_target_go', 'on %gameobject', 0, 0, '', '', '', '', '', 'en %gameobject', '', ''), + + + +('loot_command', 'Looting %item', 0, 0, '', '', '', '', '', 'Despojando %item', '', ''), + + + +('cast_spell_command_summon', 'Summoning %target', 0, 0, '', '', '', '', '', 'Invocando a %target', '', ''), +('cast_spell_command_summon_error_members', 'I don\'t have enough party members around to cast a summon', 0, 0, '', '', '', '', '', 'No tengo suficientes miembros de grupo alrededor para invocar', '', ''), +('cast_spell_command_summon_error_target', 'Failed to find the summon target', 0, 0, '', '', '', '', '', 'No he podido encontrar al objetivo de la invocación', '', ''), +('cast_spell_command_summon_error_combat', 'I can\'t summon while I\'m in combat', 0, 0, '', '', '', '', '', 'No puedo invocar durante un combate', '', ''), + + + +('cast_spell_command_error_unknown_spell', 'I don\'t know the spell %spell', 0, 0, '', '', '', '', '', 'No conozco el hechizo %spell', '', ''), + + + +('cast_spell_command_spell', 'Casting %spell', 0, 0, '', '', '', '', '', 'Lanzando %spell', '', ''), + + + +('cast_spell_command_craft', 'Crafting %spell', 0, 0, '', '', '', '', '', 'Creando %spell', '', ''), + + + +('cast_spell_command_error', 'Cannot cast %spell', 0, 0, '', '', '', '', '', 'No puedo lanzar %spell', '', ''), +('cast_spell_command_error_failed', 'Failed to cast %spell', 0, 0, '', '', '', '', '', 'Fallo al lanzar %spell', '', ''), + + + +('cast_spell_command_amount', ' |cffffff00(x%amount left)|r', 0, 0, '', '', '', '', '', ' |cffffff00(x%amount restante)|r', '', ''), + + + + +('dummy_end', 'dummy', 0, 0, '', '', '', '', '', '', '', ''); + +DROP TABLE IF EXISTS `ai_playerbot_texts_chance`; + +CREATE TABLE IF NOT EXISTS `ai_playerbot_texts_chance` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `probability` bigint(20) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=UTF8; + +/*!40000 ALTER TABLE `ai_playerbot_texts_chance` DISABLE KEYS */; +INSERT INTO `ai_playerbot_texts_chance` (`id`, `name`, `probability`) VALUES + (1, 'taunt', 30), + (2, 'aoe', 75), + (3, 'loot', 20); +/*!40000 ALTER TABLE `ai_playerbot_texts_chance` ENABLE KEYS */; \ No newline at end of file diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 87251a64..8254362c 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -276,7 +276,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (!player->InBattleground()) { - engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", "emote", nullptr); + engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", nullptr); } if (sPlayerbotAIConfig->autoSaveMana) { @@ -596,6 +596,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const nonCombatEngine->addStrategies("nc", "food", "chat", "follow", "default", "quest", "loot", "gather", "duel", "buff", "mount", "emote", nullptr); } + if (sPlayerbotAIConfig->autoSaveMana) { nonCombatEngine->addStrategy("auto save mana"); diff --git a/src/BroadcastHelper.cpp b/src/BroadcastHelper.cpp new file mode 100644 index 00000000..19cd98d9 --- /dev/null +++ b/src/BroadcastHelper.cpp @@ -0,0 +1,920 @@ + +#include "Playerbots.h" +#include "BroadcastHelper.h" +#include "ServerFacade.h" +#include "Channel.h" +#include "AiFactory.h" + +BroadcastHelper::BroadcastHelper() {} + +uint8 BroadcastHelper::GetLocale() +{ + uint8 locale = sWorld->GetDefaultDbcLocale(); + // -- In case we're using auto detect on config file^M + if (locale >= MAX_LOCALES) + locale = LocaleConstant::LOCALE_enUS; + return locale; +} + +bool BroadcastHelper::BroadcastTest(PlayerbotAI* ai, Player* bot) +{ + //return something to ignore the logic + return false; + + std::map placeholders; + placeholders["%rand1"] = std::to_string(urand(0, 1)); + placeholders["%rand2"] = std::to_string(urand(0, 1)); + placeholders["%rand3"] = std::to_string(urand(0, 1)); + + int32 rand = urand(0, 1); + + if (rand == 1 && ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE)) + return true; + else if (ai->SayToChannel(BOT_TEXT2("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT)) + return true; + + return ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE); + + //int32 rand = urand(1, 8); + if (rand == 1 && ai->SayToGuild(BOT_TEXT2("Posted to guild, %rand1, %rand2, %rand3", placeholders))) + return true; + else if (rand == 2 && ai->SayToWorld(BOT_TEXT2("Posted to world, %rand1, %rand2, %rand3", placeholders))) + return true; + else if (rand == 3 && ai->SayToChannel(BOT_TEXT2("Posted to general, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GENERAL)) + return true; + else if (rand == 4 && ai->SayToChannel(BOT_TEXT2("Posted to trade, %rand1, %rand2, %rand3", placeholders), ChatChannelId::TRADE)) + return true; + else if (rand == 5 && ai->SayToChannel(BOT_TEXT2("Posted to LFG, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOOKING_FOR_GROUP)) + return true; + else if (rand == 6 && ai->SayToChannel(BOT_TEXT2("Posted to LocalDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::LOCAL_DEFENSE)) + return true; + else if (rand == 7 && ai->SayToChannel(BOT_TEXT2("Posted to WorldDefense, %rand1, %rand2, %rand3", placeholders), ChatChannelId::WORLD_DEFENSE)) + return true; + else if (rand == 8 && ai->SayToChannel(BOT_TEXT2("Posted to GuildRecruitment, %rand1, %rand2, %rand3", placeholders), ChatChannelId::GUILD_RECRUITMENT)) + return true; + + return false; +} + +/** +@param toChannels - map of (ToChannel, chance), where chance is in range 0-100 as uint32 (unless global chance is not 100%) + +@return true if said to the channel, false otherwise +*/ +bool BroadcastHelper::BroadcastToChannelWithGlobalChance(PlayerbotAI* ai, std::string message, std::list> toChannels) +{ + if (message.empty()) + { + return false; + } + + for (const auto& pair : toChannels) + { + uint32 roll = urand(1, 100); + uint32 chance = pair.second; + uint32 broadcastRoll = urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue); + + switch (pair.first) + { + case TO_GUILD: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToGuildGlobalChance + && ai->SayToGuild(message)) + { + return true; + } + break; + } + case TO_WORLD: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToWorldGlobalChance + && ai->SayToWorld(message)) + { + return true; + } + break; + } + case TO_GENERAL: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToGeneralGlobalChance + && ai->SayToChannel(message, ChatChannelId::GENERAL)) + { + return true; + } + break; + } + case TO_TRADE: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToTradeGlobalChance + && ai->SayToChannel(message, ChatChannelId::TRADE)) + { + return true; + } + break; + } + case TO_LOOKING_FOR_GROUP: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToLFGGlobalChance + && ai->SayToChannel(message, ChatChannelId::LOOKING_FOR_GROUP)) + { + return true; + } + break; + } + case TO_LOCAL_DEFENSE: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToLocalDefenseGlobalChance + && ai->SayToChannel(message, ChatChannelId::LOCAL_DEFENSE)) + { + return true; + } + break; + } + case TO_WORLD_DEFENSE: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToWorldDefenseGlobalChance + && ai->SayToChannel(message, ChatChannelId::WORLD_DEFENSE)) + { + return true; + } + break; + } + case TO_GUILD_RECRUITMENT: + { + if (roll <= chance + && broadcastRoll <= sPlayerbotAIConfig->broadcastToGuildRecruitmentGlobalChance + && ai->SayToChannel(message, ChatChannelId::GUILD_RECRUITMENT)) + { + return true; + } + break; + } + default: + break; + } + } + + return false; +} + +bool BroadcastHelper::BroadcastLootingItem(PlayerbotAI* ai, Player* bot, const ItemTemplate *proto) +{ + std::map placeholders; + placeholders["%item_link"] = ai->GetChatHelper()->FormatItem(proto); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + switch (proto->Quality) + { + case ITEM_QUALITY_POOR: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemPoor) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_looting_item_poor", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case ITEM_QUALITY_NORMAL: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemNormal) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_looting_item_normal", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case ITEM_QUALITY_UNCOMMON: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemUncommon) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_looting_item_uncommon", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case ITEM_QUALITY_RARE: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemRare) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_looting_item_rare", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case ITEM_QUALITY_EPIC: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemEpic) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_looting_item_epic", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case ITEM_QUALITY_LEGENDARY: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemLegendary) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_looting_item_legendary", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case ITEM_QUALITY_ARTIFACT: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLootingItemArtifact) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_looting_item_artifact", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + default: + break; + } + + return false; +} + +bool BroadcastHelper::BroadcastQuestAccepted(PlayerbotAI* ai, Player* bot, const Quest* quest) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestAccepted) + { + std::map placeholders; + placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_accepted_generic", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastQuestUpdateAddKill(PlayerbotAI* ai, Player* bot, Quest const* quest, uint32 availableCount, uint32 requiredCount, std::string obectiveName) +{ + std::map placeholders; + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); + placeholders["%quest_obj_name"] = obectiveName; + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + placeholders["%quest_obj_available"] = std::to_string(availableCount); + placeholders["%quest_obj_required"] = std::to_string(requiredCount); + placeholders["%quest_obj_missing"] = std::to_string(requiredCount - std::min(availableCount, requiredCount)); + placeholders["%quest_obj_full_formatted"] = ai->GetChatHelper()->FormatQuestObjective(obectiveName, availableCount, requiredCount); + + if (availableCount < requiredCount + && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveProgress) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_update_add_kill_objective_progress", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + else if (availableCount == requiredCount + && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveCompleted) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_update_add_kill_objective_completed", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastQuestUpdateAddItem(PlayerbotAI* ai, Player* bot, Quest const* quest, uint32 availableCount, uint32 requiredCount, const ItemTemplate* proto) +{ + std::map placeholders; + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); + std::string itemLinkFormatted = ai->GetChatHelper()->FormatItem(proto); + placeholders["%item_link"] = itemLinkFormatted; + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + placeholders["%quest_obj_available"] = std::to_string(availableCount); + placeholders["%quest_obj_required"] = std::to_string(requiredCount); + placeholders["%quest_obj_missing"] = std::to_string(requiredCount - std::min(availableCount, requiredCount)); + placeholders["%quest_obj_full_formatted"] = ai->GetChatHelper()->FormatQuestObjective(itemLinkFormatted, availableCount, requiredCount); + + if (availableCount < requiredCount + && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveProgress) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_update_add_item_objective_progress", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + else if (availableCount == requiredCount + && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateObjectiveCompleted) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_update_add_item_objective_completed", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastQuestUpdateFailedTimer(PlayerbotAI* ai, Player* bot, Quest const* quest) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateFailedTimer) + { + std::map placeholders; + placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_update_failed_timer", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastQuestUpdateComplete(PlayerbotAI* ai, Player* bot, Quest const* quest) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestUpdateComplete) + { + std::map placeholders; + placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_update_complete", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastQuestTurnedIn(PlayerbotAI* ai, Player* bot, Quest const* quest) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceQuestTurnedIn) + { + std::map placeholders; + placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_quest_turned_in", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastKill(PlayerbotAI* ai, Player* bot, Creature *creature) +{ + std::map placeholders; + placeholders["%victim_name"] = creature->GetName(); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%victim_level"] = creature->GetLevel(); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + //if ((creature->IsElite() && !creature->GetMap()->IsDungeon()) + //if creature->IsWorldBoss() + //if creature->GetLevel() > DEFAULT_MAX_LEVEL + 1 + //if creature->GetLevel() > bot->GetLevel() + 4 + + if (creature->IsPet()) + { + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillPet) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_pet", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + } + else if (creature->IsPlayer()) + { + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillPlayer) + { + placeholders["%victim_class"] = ai->GetChatHelper()->FormatClass(creature->getClass()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_player", placeholders), + { {TO_WORLD_DEFENSE, 50}, {TO_LOCAL_DEFENSE, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + } + else + { + switch (creature->GetCreatureTemplate()->rank) + { + case CREATURE_ELITE_NORMAL: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillNormal) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_normal", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case CREATURE_ELITE_ELITE: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillElite) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_elite", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case CREATURE_ELITE_RAREELITE: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillRareelite) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_rareelite", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case CREATURE_ELITE_WORLDBOSS: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillWorldboss) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_worldboss", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case CREATURE_ELITE_RARE: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillRare) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_rare", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + case CREATURE_UNKNOWN: + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceKillUnknown) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_killed_unknown", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + break; + default: + break; + } + } + + return false; +} + +bool BroadcastHelper::BroadcastLevelup(PlayerbotAI* ai, Player* bot) +{ + uint32 level = bot->GetLevel(); + + std::map placeholders; + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(level); + + if (level == sPlayerbotAIConfig->randomBotMaxLevel + && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupMaxLevel) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_levelup_max_level", placeholders), + { {TO_GUILD, 30}, {TO_WORLD, 90}, {TO_GENERAL, 100} } + ); + } + // It's divisible by 10 + else if (level % 10 == 0 + && urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupTenX) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_levelup_10x", placeholders), + { {TO_GUILD, 50}, {TO_WORLD, 90}, {TO_GENERAL, 100} } + ); + } + else if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceLevelupGeneric) + { + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("broadcast_levelup_generic", placeholders), + { {TO_GUILD, 90}, {TO_WORLD, 90}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastGuildMemberPromotion(PlayerbotAI* ai, Player* bot, Player* player) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceGuildManagement) + { + std::map placeholders; + placeholders["%other_name"] = player->GetName(); + placeholders["%other_class"] = ai->GetChatHelper()->FormatClass(player->getClass()); + placeholders["%other_race"] = ai->GetChatHelper()->FormatRace(player->getRace()); + placeholders["%other_level"] = std::to_string(player->GetLevel()); + + return ai->SayToGuild(BOT_TEXT2("broadcast_guild_promotion", placeholders)); + } + + return false; +} + +bool BroadcastHelper::BroadcastGuildMemberDemotion(PlayerbotAI* ai, Player* bot, Player* player) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceGuildManagement) + { + std::map placeholders; + placeholders["%other_name"] = player->GetName(); + placeholders["%other_class"] = ai->GetChatHelper()->FormatClass(player->getClass()); + placeholders["%other_race"] = ai->GetChatHelper()->FormatRace(player->getRace()); + placeholders["%other_level"] = std::to_string(player->GetLevel()); + + return ai->SayToGuild(BOT_TEXT2("broadcast_guild_demotion", placeholders)); + } + + return false; +} + +bool BroadcastHelper::BroadcastGuildGroupOrRaidInvite(PlayerbotAI* ai, Player* bot, Player* player, Group* group) +{ + std::map placeholders; + placeholders["%name"] = player->GetName(); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + + //TODO move texts to sql! + if (group && group->isRaidGroup()) + { + if (urand(0, 3)) + { + return ai->SayToGuild(BOT_TEXT2("Hey anyone want to raid in %zone_name", placeholders)); + } + else + { + return ai->SayToGuild(BOT_TEXT2("Hey %name I'm raiding in %zone_name do you wan to join me?", placeholders)); + } + } + else + { + //(bot->GetTeam() == ALLIANCE ? LANG_COMMON : LANG_ORCISH) + if (urand(0, 3)) + { + return ai->SayToGuild(BOT_TEXT2("Hey anyone wanna group up in %zone_name?", placeholders)); + } + else + { + return ai->SayToGuild(BOT_TEXT2("Hey %name do you want join my group? I'm heading for %zone_name", placeholders)); + } + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestInstance(PlayerbotAI* ai, std::vector& allowedInstances, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestInstance) + { + std::map placeholders; + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + + std::ostringstream itemout; + //itemout << "|c00b000b0" << allowedInstances[urand(0, allowedInstances.size() - 1)] << "|r"; + itemout << allowedInstances[urand(0, allowedInstances.size() - 1)]; + placeholders["%instance_name"] = itemout.str(); + + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_instance", placeholders), + { {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestQuest(PlayerbotAI* ai, std::vector& quests, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestQuest) + { + + int index = rand() % quests.size(); + + Quest const* quest = sObjectMgr->GetQuestTemplate(quests[index]); + + std::map placeholders; + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + placeholders["%quest_link"] = ai->GetChatHelper()->FormatQuest(quest); + placeholders["%quest_level"] = std::to_string(quest->GetQuestLevel()); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_quest", placeholders), + { {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestGrindMaterials(PlayerbotAI* ai, std::string item, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestGrindMaterials) + { + + std::map placeholders; + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + placeholders["%category"] = item; + + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_trade", placeholders), + { {TO_TRADE, 50}, {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestGrindReputation(PlayerbotAI* ai, std::vector levels, std::vector allowedFactions, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestGrindReputation) + { + + std::map placeholders; + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + placeholders["%rep_level"] = levels[urand(0, 2)]; + std::ostringstream rnd; rnd << urand(1, 5) << "K"; + placeholders["%rndK"] = rnd.str(); + + std::ostringstream itemout; + //itemout << "|c004040b0" << allowedFactions[urand(0, allowedFactions.size() - 1)] << "|r"; + itemout << allowedFactions[urand(0, allowedFactions.size() - 1)]; + placeholders["%faction"] = itemout.str(); + + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_faction", placeholders), + { {TO_LOOKING_FOR_GROUP, 50}, {TO_GUILD, 50}, {TO_WORLD, 50}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestSell(PlayerbotAI* ai, const ItemTemplate* proto, uint32 count, uint32 price, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSell) + { + + std::map placeholders; + placeholders["%item_link"] = ai->GetChatHelper()->FormatItem(proto, 0); + placeholders["%item_formatted_link"] = ai->GetChatHelper()->FormatItem(proto, count); + placeholders["%item_count"] = std::to_string(count); + placeholders["%cost_gold"] = ai->GetChatHelper()->formatMoney(price); + + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_sell", placeholders), + { {TO_TRADE, 90}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestSomething(PlayerbotAI* ai, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSomething) + { + std::map placeholders; + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_something", placeholders), + { {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestSomethingToxic(PlayerbotAI* ai, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestSomethingToxic) + { + //items + std::vector botItems = ai->GetInventoryAndEquippedItems(); + + std::map placeholders; + + placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link"); + + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_something_toxic", placeholders), + { {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestToxicLinks(PlayerbotAI* ai, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestToxicLinks) + { + //quests + std::vector incompleteQuests; + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + continue; + + QuestStatus status = bot->GetQuestStatus(questId); + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_NONE) + incompleteQuests.push_back(questId); + } + + //items + std::vector botItems = ai->GetInventoryAndEquippedItems(); + + //spells + //? + + std::map placeholders; + + placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? ai->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link"); + placeholders["%prefix"] = sPlayerbotAIConfig->toxicLinksPrefix; + + if (incompleteQuests.size() > 0) + { + Quest const* quest = sObjectMgr->GetQuestTemplate(incompleteQuests[rand() % incompleteQuests.size()]); + placeholders["%random_taken_quest_or_item_link"] = ai->GetChatHelper()->FormatQuest(quest); + } + else + { + placeholders["%random_taken_quest_or_item_link"] = placeholders["%random_inventory_item_link"]; + } + + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + AreaTableEntry const* current_area = ai->GetCurrentArea(); + AreaTableEntry const* current_zone = ai->GetCurrentZone(); + placeholders["%area_name"] = current_area ? ai->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? ai->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = ai->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = ai->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("suggest_toxic_links", placeholders), + { {TO_GUILD, 10}, {TO_WORLD, 70}, {TO_GENERAL, 100} } + ); + } + + return false; +} + +bool BroadcastHelper::BroadcastSuggestThunderfury(PlayerbotAI* ai, Player* bot) +{ + if (urand(1, sPlayerbotAIConfig->broadcastChanceMaxValue) <= sPlayerbotAIConfig->broadcastChanceSuggestThunderfury) + { + std::map placeholders; + ItemTemplate const* thunderfuryProto = sObjectMgr->GetItemTemplate(19019); + placeholders["%thunderfury_link"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(thunderfuryProto); + + return BroadcastToChannelWithGlobalChance( + ai, + BOT_TEXT2("thunderfury_spam", placeholders), + { {TO_WORLD, 70}, {TO_GENERAL, 100} } + ); + } + + return false; +} diff --git a/src/BroadcastHelper.h b/src/BroadcastHelper.h new file mode 100644 index 00000000..099d6bf1 --- /dev/null +++ b/src/BroadcastHelper.h @@ -0,0 +1,148 @@ +#pragma once + +class PlayerbotAI; +class Player; +class ItemTemplate; +class Quest; +class Creature; +class Group; + +class BroadcastHelper +{ +public: + BroadcastHelper(); + +public: + enum ToChannel + { + TO_GUILD = 1, + TO_WORLD = 2, + TO_GENERAL = 3, + TO_TRADE = 4, + TO_LOOKING_FOR_GROUP = 5, + TO_LOCAL_DEFENSE = 6, + TO_WORLD_DEFENSE = 7, + TO_GUILD_RECRUITMENT = 8 + }; + + static uint8_t GetLocale(); + static bool BroadcastTest( + PlayerbotAI* ai, + Player* bot + ); + static bool BroadcastToChannelWithGlobalChance( + PlayerbotAI* ai, + std::string message, + std::list> toChannels + ); + static bool BroadcastLootingItem( + PlayerbotAI* ai, + Player* bot, + const ItemTemplate* proto + ); + static bool BroadcastQuestAccepted( + PlayerbotAI* ai, + Player* bot, + const Quest* quest + ); + static bool BroadcastQuestUpdateAddKill( + PlayerbotAI* ai, + Player* bot, + Quest const* quest, + uint32_t availableCount, + uint32_t requiredCount, + std::string obectiveName + ); + static bool BroadcastQuestUpdateAddItem( + PlayerbotAI* ai, + Player* bot, + Quest const* quest, + uint32_t availableCount, + uint32_t requiredCount, + const ItemTemplate* proto + ); + static bool BroadcastQuestUpdateFailedTimer( + PlayerbotAI* ai, + Player* bot, + Quest const* quest + ); + static bool BroadcastQuestUpdateComplete( + PlayerbotAI* ai, + Player* bot, + Quest const* quest + ); + static bool BroadcastQuestTurnedIn( + PlayerbotAI* ai, + Player* bot, + Quest const* quest + ); + static bool BroadcastKill( + PlayerbotAI* ai, + Player* bot, + Creature* creature + ); + static bool BroadcastLevelup( + PlayerbotAI* ai, + Player* bot + ); + static bool BroadcastGuildMemberPromotion( + PlayerbotAI* ai, + Player* bot, + Player* player + ); + static bool BroadcastGuildMemberDemotion( + PlayerbotAI* ai, + Player* bot, + Player* player + ); + static bool BroadcastGuildGroupOrRaidInvite( + PlayerbotAI* ai, + Player* bot, + Player* player, + Group* group + ); + static bool BroadcastSuggestInstance( + PlayerbotAI* ai, + std::vector& allowedInstances, + Player* bot + ); + static bool BroadcastSuggestQuest( + PlayerbotAI* ai, + std::vector& quests, + Player* bot + ); + static bool BroadcastSuggestGrindMaterials( + PlayerbotAI* ai, + std::string item, + Player* bot + ); + static bool BroadcastSuggestGrindReputation( + PlayerbotAI* ai, + std::vector levels, + std::vector allowedFactions, + Player* bot + ); + static bool BroadcastSuggestSell( + PlayerbotAI* ai, + const ItemTemplate* proto, + uint32_t count, + uint32_t price, + Player* bot + ); + static bool BroadcastSuggestSomething( + PlayerbotAI* ai, + Player* bot + ); + static bool BroadcastSuggestSomethingToxic( + PlayerbotAI* ai, + Player* bot + ); + static bool BroadcastSuggestToxicLinks( + PlayerbotAI* ai, + Player* bot + ); + static bool BroadcastSuggestThunderfury( + PlayerbotAI* ai, + Player* bot + ); +}; \ No newline at end of file diff --git a/src/ChatHelper.cpp b/src/ChatHelper.cpp index 6f3339b2..156dc0ea 100644 --- a/src/ChatHelper.cpp +++ b/src/ChatHelper.cpp @@ -9,6 +9,8 @@ #include "Playerbots.h" #include "SpellInfo.h" +#include + std::map ChatHelper::consumableSubClasses; std::map ChatHelper::tradeSubClasses; std::map ChatHelper::itemQualities; @@ -219,6 +221,26 @@ std::string const ChatHelper::formatMoney(uint32 copper) return out.str(); } +std::string ChatHelper::parseValue(const std::string& type, const std::string& text) +{ + std::string retString; + + std::string pattern = "Hvalue:" + type + ":"; + + int pos = text.find(pattern, 0); + if (pos == -1) + return retString; + + pos += pattern.size(); + + int endPos = text.find('|', pos); + if (endPos == -1) + return retString; + + retString = text.substr(pos, endPos - pos); + return retString; +} + uint32 ChatHelper::parseMoney(std::string const text) { // if user specified money in ##g##s##c format @@ -570,3 +592,35 @@ void ChatHelper::eraseAllSubStr(std::string& mainStr, std::string const toErase) mainStr.erase(pos, toErase.length()); } } + +std::set ChatHelper::ExtractAllQuestIds(const std::string& text) +{ + std::set ids; + + std::regex rgx("Hquest:[0-9]+"); + auto begin = std::sregex_iterator(text.begin(), text.end(), rgx); + auto end = std::sregex_iterator(); + for (std::sregex_iterator i = begin; i != end; ++i) + { + std::smatch match = *i; + ids.insert(std::stoi(match.str().erase(0, 7))); + } + + return ids; +} + +std::set ChatHelper::ExtractAllItemIds(const std::string& text) +{ + std::set ids; + + std::regex rgx("Hitem:[0-9]+"); + auto begin = std::sregex_iterator(text.begin(), text.end(), rgx); + auto end = std::sregex_iterator(); + for (std::sregex_iterator i = begin; i != end; ++i) + { + std::smatch match = *i; + ids.insert(std::stoi(match.str().erase(0, 6))); + } + + return ids; +} diff --git a/src/ChatHelper.h b/src/ChatHelper.h index a23f8460..9a395f76 100644 --- a/src/ChatHelper.h +++ b/src/ChatHelper.h @@ -34,6 +34,8 @@ public: static uint32 parseMoney(std::string const text); static ItemIds parseItems(std::string const text); uint32 parseSpell(std::string const text); + static std::string parseValue(const std::string& type, const std::string& text); + static std::string const FormatQuest(Quest const* quest); static std::string const FormatItem(ItemTemplate const* proto, uint32 count = 0, uint32 total = 0); static std::string const FormatQItem(uint32 itemId); @@ -62,6 +64,9 @@ public: void eraseAllSubStr(std::string& mainStr, std::string const toErase); + static std::set ExtractAllQuestIds(const std::string& text); + static std::set ExtractAllItemIds(const std::string& text); + private: static std::map consumableSubClasses; static std::map tradeSubClasses; diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index eb445b83..7a18c520 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -45,6 +45,10 @@ #include "Unit.h" #include "UpdateTime.h" #include "Vehicle.h" +#include "GuildMgr.h" +#include "SayAction.h" +#include "ChannelMgr.h" + std::vector PlayerbotAI::dispel_whitelist = { "mutating injection", @@ -144,15 +148,12 @@ PlayerbotAI::PlayerbotAI(Player* bot) masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll"); masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello"); masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_HELLO, "gossip hello"); - masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_COMPLETE_QUEST, "complete quest"); - masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_ACCEPT_QUEST, "accept quest"); masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXI, "activate taxi"); masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXIEXPRESS, "activate taxi"); masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARALLNODES, "taxi done"); masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARNODE, "taxi done"); masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE, "uninvite"); masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE_GUID, "uninvite guid"); - masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share"); masterIncomingPacketHandlers.AddHandler(CMSG_LFG_TELEPORT, "lfg teleport"); masterIncomingPacketHandlers.AddHandler(CMSG_CAST_SPELL, "see spell"); masterIncomingPacketHandlers.AddHandler(CMSG_REPOP_REQUEST, "release spirit"); @@ -169,7 +170,6 @@ PlayerbotAI::PlayerbotAI(Player* bot) botOutgoingPacketHandlers.AddHandler(SMSG_INVENTORY_CHANGE_FAILURE, "cannot equip"); botOutgoingPacketHandlers.AddHandler(SMSG_TRADE_STATUS, "trade status"); botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_RESPONSE, "loot response"); - botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest objective completed"); botOutgoingPacketHandlers.AddHandler(SMSG_ITEM_PUSH_RESULT, "item push result"); botOutgoingPacketHandlers.AddHandler(SMSG_PARTY_COMMAND_RESULT, "party command"); botOutgoingPacketHandlers.AddHandler(SMSG_LEVELUP_INFO, "levelup"); @@ -184,14 +184,22 @@ PlayerbotAI::PlayerbotAI(Player* bot) botOutgoingPacketHandlers.AddHandler(SMSG_EMOTE, "receive emote"); botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_START_ROLL, "master loot roll"); botOutgoingPacketHandlers.AddHandler(SMSG_ARENA_TEAM_INVITE, "arena team invite"); - botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "quest confirm accept"); botOutgoingPacketHandlers.AddHandler(SMSG_GROUP_DESTROYED, "group destroyed"); botOutgoingPacketHandlers.AddHandler(SMSG_GROUP_LIST, "group list"); masterOutgoingPacketHandlers.AddHandler(SMSG_PARTY_COMMAND_RESULT, "party command"); masterOutgoingPacketHandlers.AddHandler(MSG_RAID_READY_CHECK, "ready check"); masterOutgoingPacketHandlers.AddHandler(MSG_RAID_READY_CHECK_FINISHED, "ready check finished"); - masterOutgoingPacketHandlers.AddHandler(SMSG_QUESTGIVER_OFFER_REWARD, "questgiver quest details"); + + // quest packet + masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_COMPLETE_QUEST, "complete quest"); + masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_ACCEPT_QUEST, "accept quest"); + masterIncomingPacketHandlers.AddHandler(CMSG_QUEST_CONFIRM_ACCEPT, "confirm quest"); + masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_COMPLETE, "quest update complete"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest update add kill"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_ITEM, "quest update add item"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "confirm quest"); } PlayerbotAI::~PlayerbotAI() @@ -351,66 +359,24 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal return; std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I"; - - PerformanceMonitorOperation* pmo = - sPerformanceMonitor->start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString); + PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString); ExternalEventHelper helper(aiObjectContext); - std::vector delayed; - while (!chatCommands.empty()) - { - ChatCommandHolder holder = chatCommands.front(); - time_t checkTime = holder.GetTime(); - if (checkTime && time(nullptr) < checkTime) - { - delayed.push_back(holder); - chatCommands.pop(); - continue; - } - - std::string const command = holder.GetCommand(); - Player* owner = holder.GetOwner(); - if (!helper.ParseChatCommand(command, owner) && holder.GetType() == CHAT_MSG_WHISPER) - { - // To prevent spam caused by WIM - if (!(command.rfind("WIM", 0) == 0) && !(command.rfind("QHpr", 0) == 0)) - { - std::ostringstream out; - out << "Unknown command " << command; - TellMaster(out); - helper.ParseChatCommand("help"); - } - } - - chatCommands.pop(); - } - - for (std::vector::iterator i = delayed.begin(); i != delayed.end(); ++i) - { - chatCommands.push(*i); - } - // chat replies - std::list delayedResponses; - while (!chatReplies.empty()) + for (auto it = chatReplies.begin(); it != chatReplies.end(); ) { - ChatQueuedReply holder = chatReplies.front(); - time_t checkTime = holder.m_time; + time_t checkTime = it->m_time; if (checkTime && time(0) < checkTime) { - delayedResponses.push_back(holder); - chatReplies.pop(); + ++it; continue; } - ChatReplyAction::ChatReplyDo(bot, holder.m_type, holder.m_guid1, holder.m_guid2, holder.m_msg, - holder.m_chanName, holder.m_name); - chatReplies.pop(); + + ChatReplyAction::ChatReplyDo(bot, it->m_type, it->m_guid1, it->m_guid2, it->m_msg, it->m_chanName, it->m_name); + it = chatReplies.erase(it); } - for (std::list::iterator i = delayedResponses.begin(); i != delayedResponses.end(); ++i) - { - chatReplies.push(*i); - } + HandleCommands(); // logout if logout timer is ready or if instant logout is possible if (bot->GetSession()->isLogingOut()) @@ -464,6 +430,196 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal pmo->finish(); } +void PlayerbotAI::HandleCommands() +{ + ExternalEventHelper helper(aiObjectContext); + for (auto it = chatCommands.begin(); it != chatCommands.end(); ) + { + time_t& checkTime = it->GetTime(); + if (checkTime && time(0) < checkTime) + { + ++it; + continue; + } + + const std::string& command = it->GetCommand(); + Player* owner = it->GetOwner(); + if (!helper.ParseChatCommand(command, owner) && it->GetType() == CHAT_MSG_WHISPER) + { + //ostringstream out; out << "Unknown command " << command; + //TellPlayer(out); + //helper.ParseChatCommand("help"); + } + it = chatCommands.erase(it); + } +} + +std::map chatMap; +void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang) +{ + std::string filtered = text; + + if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_INVITE, type != CHAT_MSG_WHISPER, &fromPlayer)) + return; + + if (type == CHAT_MSG_ADDON) + return; + + if (filtered.find("BOT\t") == 0) //Mangosbot has BOT prefix so we remove that. + filtered = filtered.substr(4); + else if (lang == LANG_ADDON) //Other addon messages should not command bots. + return; + + if (type == CHAT_MSG_SYSTEM) + return; + + if (filtered.find(sPlayerbotAIConfig->commandSeparator) != std::string::npos) + { + std::vector commands; + split(commands, filtered, sPlayerbotAIConfig->commandSeparator.c_str()); + for (std::vector::iterator i = commands.begin(); i != commands.end(); ++i) + { + HandleCommand(type, *i, fromPlayer); + } + return; + } + + if (!sPlayerbotAIConfig->commandPrefix.empty()) + { + if (filtered.find(sPlayerbotAIConfig->commandPrefix) != 0) + return; + + filtered = filtered.substr(sPlayerbotAIConfig->commandPrefix.size()); + } + + if (chatMap.empty()) + { + chatMap["#w "] = CHAT_MSG_WHISPER; + chatMap["#p "] = CHAT_MSG_PARTY; + chatMap["#r "] = CHAT_MSG_RAID; + chatMap["#a "] = CHAT_MSG_ADDON; + chatMap["#g "] = CHAT_MSG_GUILD; + } + currentChat = std::pair(CHAT_MSG_WHISPER, 0); + for (std::map::iterator i = chatMap.begin(); i != chatMap.end(); ++i) + { + if (filtered.find(i->first) == 0) + { + filtered = filtered.substr(3); + currentChat = std::pair(i->second, time(0) + 2); + break; + } + } + + filtered = chatFilter.Filter(trim((std::string&)filtered)); + if (filtered.empty()) + return; + + if (filtered.substr(0, 6) == "debug ") + { + std::string response = HandleRemoteCommand(filtered.substr(6)); + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_ADDON, response.c_str(), LANG_ADDON, + CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); + sServerFacade->SendPacket(&fromPlayer, &data); + return; + } + + if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, &fromPlayer)) + return; + + if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != std::string::npos && filtered.find("award") == std::string::npos) + { + chatCommands.push_back(ChatCommandHolder("warning", &fromPlayer, type)); + return; + } + + if ((filtered.size() > 2 && filtered.substr(0, 2) == "d ") || (filtered.size() > 3 && filtered.substr(0, 3) == "do ")) + { + Event event("do", "", &fromPlayer); + std::string action = filtered.substr(filtered.find(" ") + 1); + DoSpecificAction(action, event); + } + + if (ChatHelper::parseValue("command", filtered).substr(0, 3) == "do ") + { + Event event("do", "", &fromPlayer); + std::string action = ChatHelper::parseValue("command", filtered); + action = action.substr(3); + DoSpecificAction(action, event); + } + else if (type != CHAT_MSG_WHISPER && filtered.size() > 6 && filtered.substr(0, 6) == "queue ") + { + std::string remaining = filtered.substr(filtered.find(" ") + 1); + int index = 1; + Group* group = bot->GetGroup(); + if (group) + { + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + if (ref->GetSource() == master) + continue; + + if (ref->GetSource() == bot) + break; + + index++; + } + } + + chatCommands.push_back(ChatCommandHolder(remaining, &fromPlayer, type, time(0) + index)); + } + else if (filtered == "reset") + { + Reset(true); + } + + // TODO: missing implementation to port + /*else if (filtered == "logout") + { + if (!(bot->IsStunnedByLogout() || bot->GetSession()->isLogingOut())) + { + if (type == CHAT_MSG_WHISPER) + TellPlayer(&fromPlayer, BOT_TEXT("logout_start")); + + if (master && master->GetPlayerbotMgr()) + SetShouldLogOut(true); + } + } + else if (filtered == "logout cancel") + { + if (bot->IsStunnedByLogout() || bot->GetSession()->isLogingOut()) + { + if (type == CHAT_MSG_WHISPER) + TellPlayer(&fromPlayer, BOT_TEXT("logout_cancel")); + + WorldPacket p; + bot->GetSession()->HandleLogoutCancelOpcode(p); + SetShouldLogOut(false); + } + } + else if ((filtered.size() > 5) && (filtered.substr(0, 5) == "wait ") && (filtered.find("wait for attack") == std::string::npos)) + { + std::string remaining = filtered.substr(filtered.find(" ") + 1); + uint32 delay = atof(remaining.c_str()) * IN_MILLISECONDS; + if (delay > 20000) + { + bot->TellMaster(&fromPlayer, "Max wait time is 20 seconds!"); + return; + } + + IncreaseAIInternalUpdateDelay(delay); + isWaiting = true; + TellPlayer(&fromPlayer, "Waiting for " + remaining + " seconds!"); + return; + }*/ + + else + { + chatCommands.push_back(ChatCommandHolder(filtered, &fromPlayer, type)); + } +} + void PlayerbotAI::HandleTeleportAck() { if (IsRealPlayer()) @@ -564,8 +720,6 @@ void PlayerbotAI::Reset(bool full) } } -std::map chatMap; - bool PlayerbotAI::IsAllowedCommand(std::string const text) { if (unsecuredCommands.empty()) @@ -661,8 +815,7 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != std::string::npos && filtered.find("award") == std::string::npos) { - ChatCommandHolder cmd("warning", fromPlayer, type); - chatCommands.push(cmd); + chatCommands.push_back(ChatCommandHolder("warning", fromPlayer, type)); return; } @@ -691,8 +844,7 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro } } - ChatCommandHolder cmd(remaining, fromPlayer, type, time(nullptr) + index); - chatCommands.push(cmd); + chatCommands.push_back(ChatCommandHolder(remaining, fromPlayer, type, time(nullptr) + index)); } else if (filtered == "reset") { @@ -725,8 +877,7 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro } else { - ChatCommandHolder cmd(filtered, fromPlayer, type); - chatCommands.push(cmd); + chatCommands.push_back(ChatCommandHolder(filtered, fromPlayer, type)); } } @@ -793,11 +944,21 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) uint8 msgtype, chatTag; uint32 lang, textLen, nameLen, unused; ObjectGuid guid1, guid2; - std::string name, chanName, message; + std::string name = ""; + std::string chanName = ""; + std::string message = ""; + p >> msgtype >> lang; p >> guid1 >> unused; if (guid1.IsEmpty() || p.size() > p.DEFAULT_SIZE) return; + + if (p.GetOpcode() == SMSG_GM_MESSAGECHAT) + { + p >> textLen; + p >> name; + } + switch (msgtype) { case CHAT_MSG_CHANNEL: @@ -810,50 +971,77 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) case CHAT_MSG_GUILD: p >> guid2; p >> textLen >> message >> chatTag; - - if (guid1 != bot->GetGUID()) // do not reply to self - { - // try to always reply to real player - time_t lastChat = GetAiObjectContext()->GetValue("last said", "chat")->Get(); - bool isPaused = time(0) < lastChat; - bool shouldReply = false; - bool isRandomBot = false; - sCharacterCache->GetCharacterNameByGuid(guid1, name); - uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid1); - isRandomBot = sPlayerbotAIConfig->IsInRandomAccountList(accountId); - bool isMentioned = message.find(bot->GetName()) != std::string::npos; - - // random bot speaks, chat CD - if (isRandomBot && isPaused) - return; - // BG: react only if mentioned or if not channel and real player spoke - if (bot->InBattleground() && bot->GetBattleground() && - !(isMentioned || (msgtype != CHAT_MSG_CHANNEL && !isRandomBot))) - return; - - // Reduce chat spam - if (HasRealPlayerMaster()) - return; - - if (isRandomBot && urand(0, 20)) - return; - - if (!message.empty() && - ((isRandomBot && !isPaused && - (!urand(0, 20) || - (!urand(0, 10) && message.find(bot->GetName()) != std::string::npos))) || - (!isRandomBot && (isMentioned || !urand(0, 4))))) - { - QueueChatResponse(msgtype, guid1, ObjectGuid(), message, chanName, name); - GetAiObjectContext() - ->GetValue("last said", "chat") - ->Set(time(0) + urand(5, 25)); - return; - } - } break; default: - break; + return; + } + + // do not reply to self but always try to reply to real player + if (guid1 != bot->GetGUID()) + { + time_t lastChat = GetAiObjectContext()->GetValue("last said", "chat")->Get(); + bool isPaused = time(0) < lastChat; + bool shouldReply = false; + bool isFromFreeBot = false; + sCharacterCache->GetCharacterNameByGuid(guid1, name); + uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid1); + isFromFreeBot = sPlayerbotAIConfig->IsInRandomAccountList(accountId); + bool isMentioned = message.find(bot->GetName()) != std::string::npos; + + ChatChannelSource chatChannelSource = GetChatChannelSource(bot, msgtype, chanName); + + // random bot speaks, chat CD + if (isFromFreeBot && isPaused) + return; + + // BG: react only if mentioned or if not channel and real player spoke + if (bot->InBattleground() && !(isMentioned || (msgtype != CHAT_MSG_CHANNEL && !isFromFreeBot))) + return; + + if (HasRealPlayerMaster() && guid1 != GetMaster()->GetGUID()) + return; + if (lang == LANG_ADDON) + return; + + if (message.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) + && (GetChatHelper()->ExtractAllItemIds(message).size() > 0 || GetChatHelper()->ExtractAllQuestIds(message).size() > 0) + && sPlayerbotAIConfig->toxicLinksRepliesChance) + { + if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig->toxicLinksRepliesChance) + { + return; + } + } + else if ((GetChatHelper()->ExtractAllItemIds(message).count(19019) && sPlayerbotAIConfig->thunderfuryRepliesChance)) + { + if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig->thunderfuryRepliesChance) + { + return; + } + } + else + { + if (isFromFreeBot && urand(0, 20)) + return; + + //if (msgtype == CHAT_MSG_GUILD && (!sPlayerbotAIConfig->guildRepliesRate || urand(1, 100) >= sPlayerbotAIConfig->guildRepliesRate)) + //return; + + if (!isFromFreeBot) + { + if (!isMentioned && urand(0, 4)) + return; + } + else + { + if (urand(0, 20 + 10 * isMentioned)) + return; + } + } + + QueueChatResponse(std::move(ChatQueuedReply{msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName, name, time(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15)})); + GetAiObjectContext()->GetValue("last said", "chat")->Set(time(0) + urand(5, 25)); + return; } } @@ -1994,6 +2182,204 @@ WorldObject* PlayerbotAI::GetWorldObject(ObjectGuid guid) return ObjectAccessor::GetWorldObject(*bot, guid); } +const AreaTableEntry* PlayerbotAI::GetCurrentArea() +{ + return sAreaTableStore.LookupEntry(bot->GetMap()->GetAreaId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); +} + +const AreaTableEntry* PlayerbotAI::GetCurrentZone() +{ + return sAreaTableStore.LookupEntry(bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); +} + +std::string PlayerbotAI::GetLocalizedAreaName(const AreaTableEntry* entry) +{ + if (entry) + return entry->area_name[sWorld->GetDefaultDbcLocale()]; + + return ""; +} + +std::vector PlayerbotAI::GetPlayersInGroup() +{ + std::vector members; + + Group* group = bot->GetGroup(); + + if (!group) + return members; + + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + + if (GET_PLAYERBOT_AI(member) && !GET_PLAYERBOT_AI(member)->IsRealPlayer()) + continue; + + members.push_back(ref->GetSource()); + } + + return members; +} + +bool PlayerbotAI::SayToGuild(const std::string& msg) +{ + if (msg.empty()) + { + return false; + } + + if (bot->GetGuildId()) + { + if (Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId())) + { + if (!guild->HasRankRight(bot, GR_RIGHT_GCHATSPEAK)) + { + return false; + } + guild->BroadcastToGuild(bot->GetSession(), false, msg.c_str(), LANG_UNIVERSAL); + return true; + } + } + + return false; +} + +bool PlayerbotAI::SayToWorld(const std::string& msg) +{ + if (msg.empty()) + { + return false; + } + + ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()); + if (!cMgr) + return false; + + //no zone + if (Channel* worldChannel = cMgr->GetChannel("World", bot)) + { + worldChannel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); + return true; + } + + return false; +} + +bool PlayerbotAI::SayToChannel(const std::string& msg, const ChatChannelId& chanId) +{ + ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()); + if (!cMgr || msg.empty()) + return false; + + AreaTableEntry const* current_zone = GetCurrentZone(); + if (!current_zone) + return false; + + const auto current_str_zone = GetLocalizedAreaName(current_zone); + for (auto const& [key, channel] : cMgr->GetChannels()) + { + //check for current zone + if (channel && channel->GetChannelId() == chanId) + { + const auto does_contains = channel->GetName().find(current_str_zone) != std::string::npos; + if (chanId != ChatChannelId::LOOKING_FOR_GROUP && chanId != ChatChannelId::WORLD_DEFENSE && !does_contains) + { + continue; + } + else if (chanId == ChatChannelId::LOOKING_FOR_GROUP || chanId == ChatChannelId::WORLD_DEFENSE) + { + // check if capitals then return false if not + } + + channel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); + return true; + } + } + + return false; +} + +bool PlayerbotAI::SayToParty(const std::string& msg) +{ + if (!bot->GetGroup()) + return false; + + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_PARTY, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); + + for (auto reciever : GetPlayersInGroup()) + { + sServerFacade->SendPacket(reciever, &data); + } + + return true; +} + +bool PlayerbotAI::SayToRaid(const std::string& msg) +{ + if (!bot->GetGroup() || bot->GetGroup()->isRaidGroup()) + return false; + + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, msg.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); + + for (auto reciever : GetPlayersInGroup()) + { + sServerFacade->SendPacket(reciever, &data); + } + + return true; +} + +bool PlayerbotAI::Yell(const std::string& msg) +{ + if (bot->GetTeamId() == TeamId::TEAM_ALLIANCE) + { + bot->Yell(msg, LANG_COMMON); + } + else + { + bot->Yell(msg, LANG_ORCISH); + } + + return true; +} + +bool PlayerbotAI::Say(const std::string& msg) +{ + if (bot->GetTeamId() == TeamId::TEAM_ALLIANCE) + { + bot->Say(msg, LANG_COMMON); + } + else + { + bot->Say(msg, LANG_ORCISH); + } + + return true; +} + +bool PlayerbotAI::Whisper(const std::string& msg, const std::string& receiverName) +{ + const auto receiver = ObjectAccessor::FindPlayerByName(receiverName); + if (!receiver) + { + return false; + } + + if (bot->GetTeamId() == TeamId::TEAM_ALLIANCE) + { + bot->Whisper(msg, LANG_COMMON, receiver); + } + else + { + bot->Whisper(msg, LANG_ORCISH, receiver); + } + + return true; +} + bool PlayerbotAI::TellMasterNoFacing(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel) { return TellMasterNoFacing(stream.str(), securityLevel); @@ -4423,6 +4809,209 @@ Item* PlayerbotAI::FindOilFor(Item* weapon) const return oil; } +std::vector PlayerbotAI::GetInventoryAndEquippedItems() +{ + std::vector items; + + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + { + if (Item* pItem = pBag->GetItemByPos(j)) + { + items.push_back(pItem); + } + } + } + } + + for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + items.push_back(pItem); + } + } + + for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + items.push_back(pItem); + } + } + + for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + { + items.push_back(pItem); + } + } + + return items; +} + +std::vector PlayerbotAI::GetInventoryItems() +{ + std::vector items; + + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + { + if (Item* pItem = pBag->GetItemByPos(j)) + { + items.push_back(pItem); + } + } + } + } + + for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + items.push_back(pItem); + } + } + + for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + items.push_back(pItem); + } + } + + return items; +} + +uint32 PlayerbotAI::GetInventoryItemsCountWithId(uint32 itemId) +{ + uint32 count = 0; + + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + { + if (Item* pItem = pBag->GetItemByPos(j)) + { + if (pItem->GetTemplate()->ItemId == itemId) + { + count += pItem->GetCount(); + } + } + } + } + } + + for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + if (pItem->GetTemplate()->ItemId == itemId) + { + count += pItem->GetCount(); + } + } + } + + for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + if (pItem->GetTemplate()->ItemId == itemId) + { + count += pItem->GetCount(); + } + } + } + + return count; +} + +bool PlayerbotAI::HasItemInInventory(uint32 itemId) +{ + + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + { + if (Item* pItem = pBag->GetItemByPos(j)) + { + if (pItem->GetTemplate()->ItemId == itemId) + { + return true; + } + } + } + } + } + + for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + if (pItem->GetTemplate()->ItemId == itemId) + { + return true; + } + } + } + + for (int i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + if (pItem->GetTemplate()->ItemId == itemId) + { + return true; + } + } + } + + return false; +} + +std::vector> PlayerbotAI::GetCurrentQuestsRequiringItemId(uint32 itemId) +{ + std::vector> result; + + if (!itemId) + { + return result; + } + + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + continue; + + QuestStatus status = bot->GetQuestStatus(questId); + const Quest* quest = sObjectMgr->GetQuestTemplate(questId); + for (uint8 i = 0; i < std::size(quest->RequiredItemId); ++i) + { + if (quest->RequiredItemId[i] == itemId) + { + result.push_back(std::pair(quest, quest->RequiredItemId[i])); + break; + } + } + } + + return result; +} + // on self void PlayerbotAI::ImbueItem(Item* item) { ImbueItem(item, TARGET_FLAG_NONE, ObjectGuid::Empty); } @@ -4577,11 +5166,9 @@ bool PlayerbotAI::IsInRealGuild() return !(sPlayerbotAIConfig->IsInRandomAccountList(leaderAccount)); } -void PlayerbotAI::QueueChatResponse(uint8 msgtype, ObjectGuid guid1, ObjectGuid guid2, std::string message, - std::string chanName, std::string name) +void PlayerbotAI::QueueChatResponse(const ChatQueuedReply chatReply) { - chatReplies.push(ChatQueuedReply(msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName, name, - time(nullptr) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15))); + chatReplies.push_back(std::move(chatReply)); } bool PlayerbotAI::EqualLowercaseName(std::string s1, std::string s2) @@ -4916,3 +5503,188 @@ uint8 PlayerbotAI::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool sw // no free position return NULL_SLOT; } + +bool PlayerbotAI::IsSafe(Player* player) +{ + return player && player->GetMapId() == bot->GetMapId() && player->GetInstanceId() == bot->GetInstanceId() && !player->IsBeingTeleported(); +} +bool PlayerbotAI::IsSafe(WorldObject* obj) +{ + return obj && obj->GetMapId() == bot->GetMapId() && obj->GetInstanceId() == bot->GetInstanceId() && (!obj->IsPlayer() || !((Player*)obj)->IsBeingTeleported()); +} +ChatChannelSource PlayerbotAI::GetChatChannelSource(Player* bot, uint32 type, std::string channelName) +{ + if (type == CHAT_MSG_CHANNEL) + { + if (channelName == "World") + return ChatChannelSource::SRC_WORLD; + else + { + ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()); + if (!cMgr) + { + return ChatChannelSource::SRC_UNDEFINED; + } + + const Channel* channel = cMgr->GetChannel(channelName, bot); + if (channel) + { + switch (channel->GetChannelId()) + { + case ChatChannelId::GENERAL: + { + return ChatChannelSource::SRC_GENERAL; + } + case ChatChannelId::TRADE: + { + return ChatChannelSource::SRC_TRADE; + } + case ChatChannelId::LOCAL_DEFENSE: + { + return ChatChannelSource::SRC_LOCAL_DEFENSE; + } + case ChatChannelId::WORLD_DEFENSE: + { + return ChatChannelSource::SRC_WORLD_DEFENSE; + } + case ChatChannelId::LOOKING_FOR_GROUP: + { + return ChatChannelSource::SRC_LOOKING_FOR_GROUP; + } + case ChatChannelId::GUILD_RECRUITMENT: + { + return ChatChannelSource::SRC_GUILD_RECRUITMENT; + } + default: + { + return ChatChannelSource::SRC_UNDEFINED; + } + } + } + } + } + else + { + switch (type) + { + case CHAT_MSG_WHISPER: + { + return ChatChannelSource::SRC_WHISPER; + } + case CHAT_MSG_SAY: + { + return ChatChannelSource::SRC_SAY; + } + case CHAT_MSG_YELL: + { + return ChatChannelSource::SRC_YELL; + } + case CHAT_MSG_GUILD: + { + return ChatChannelSource::SRC_GUILD; + } + case CHAT_MSG_PARTY: + { + return ChatChannelSource::SRC_PARTY; + } + case CHAT_MSG_RAID: + { + return ChatChannelSource::SRC_RAID; + } + case CHAT_MSG_EMOTE: + { + return ChatChannelSource::SRC_EMOTE; + } + case CHAT_MSG_TEXT_EMOTE: + { + return ChatChannelSource::SRC_TEXT_EMOTE; + } + default: + { + return ChatChannelSource::SRC_UNDEFINED; + } + } + } + return ChatChannelSource::SRC_UNDEFINED; +} + +std::vector PlayerbotAI::GetAllCurrentQuests() +{ + std::vector result; + + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + { + continue; + } + + result.push_back(sObjectMgr->GetQuestTemplate(questId)); + } + + return result; +} + +std::vector PlayerbotAI::GetCurrentIncompleteQuests() +{ + std::vector result; + + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + { + continue; + } + + QuestStatus status = bot->GetQuestStatus(questId); + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_NONE) + { + result.push_back(sObjectMgr->GetQuestTemplate(questId)); + } + } + + return result; +} + +std::set PlayerbotAI::GetAllCurrentQuestIds() +{ + std::set result; + + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + { + continue; + } + + result.insert(questId); + } + + return result; +} + +std::set PlayerbotAI::GetCurrentIncompleteQuestIds() +{ + std::set result; + + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + { + continue; + } + + QuestStatus status = bot->GetQuestStatus(questId); + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_NONE) + { + result.insert(questId); + } + } + + return result; +} + diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 51e46d0b..f0be101f 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -106,6 +106,58 @@ public: void* param; float minValue; }; +enum ChatChannelSource +{ + SRC_GUILD, + SRC_WORLD, + SRC_GENERAL, + SRC_TRADE, + SRC_LOOKING_FOR_GROUP, + SRC_LOCAL_DEFENSE, + SRC_WORLD_DEFENSE, + SRC_GUILD_RECRUITMENT, + + SRC_SAY, + SRC_WHISPER, + SRC_EMOTE, + SRC_TEXT_EMOTE, + SRC_YELL, + + SRC_PARTY, + SRC_RAID, + + SRC_UNDEFINED +}; +static std::map ChatChannelSourceStr = { + { SRC_GUILD, "SRC_GUILD"}, + { SRC_WORLD, "SRC_WORLD"}, + { SRC_GENERAL, "SRC_GENERAL"}, + { SRC_TRADE, "SRC_TRADE"}, + { SRC_LOOKING_FOR_GROUP, "SRC_LOOKING_FOR_GROUP"}, + { SRC_LOCAL_DEFENSE, "SRC_LOCAL_DEFENSE"}, + { SRC_WORLD_DEFENSE, "SRC_WORLD_DEFENSE"}, + { SRC_GUILD_RECRUITMENT, "SRC_GUILD_RECRUITMENT"}, + + { SRC_SAY, "SRC_SAY"}, + { SRC_WHISPER, "SRC_WHISPER"}, + { SRC_EMOTE, "SRC_EMOTE"}, + { SRC_TEXT_EMOTE, "SRC_TEXT_EMOTE"}, + { SRC_YELL, "SRC_YELL"}, + + { SRC_PARTY, "SRC_PARTY"}, + { SRC_RAID, "SRC_RAID"}, + + { SRC_UNDEFINED, "SRC_UNDEFINED"} +}; +enum ChatChannelId +{ + GENERAL = 1, + TRADE = 2, + LOCAL_DEFENSE = 22, + WORLD_DEFENSE = 23, + LOOKING_FOR_GROUP = 26, + GUILD_RECRUITMENT = 25, +}; enum RoguePoisonDisplayId { @@ -307,10 +359,10 @@ public: { } - std::string const GetCommand() { return command; } + const std::string& GetCommand() { return command; } Player* GetOwner() { return owner; } - uint32 GetType() { return type; } - time_t GetTime() { return time; } + uint32& GetType() { return type; } + time_t& GetTime() { return time; } private: std::string const command; @@ -331,16 +383,14 @@ public: std::string const HandleRemoteCommand(std::string const command); void HandleCommand(uint32 type, std::string const text, Player* fromPlayer); - void QueueChatResponse(uint8 msgtype, ObjectGuid guid1, ObjectGuid guid2, std::string message, std::string chanName, - std::string name); - void HandleBotOutgoingPacket(WorldPacket const& packet); + void QueueChatResponse(const ChatQueuedReply reply); + void HandleBotOutgoingPacket(WorldPacket const& packet); void HandleMasterIncomingPacket(WorldPacket const& packet); void HandleMasterOutgoingPacket(WorldPacket const& packet); void HandleTeleportAck(); void ChangeEngine(BotState type); void DoNextAction(bool minimal = false); - virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false, - std::string const qualifier = ""); + virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false, std::string const qualifier = ""); void ChangeStrategy(std::string const name, BotState type); void ClearStrategies(BotState type); std::vector GetStrategies(BotState type); @@ -377,13 +427,25 @@ public: GameObject* GetGameObject(ObjectGuid guid); // static GameObject* GetGameObject(GameObjectData const* gameObjectData); WorldObject* GetWorldObject(ObjectGuid guid); + std::vector GetPlayersInGroup(); + const AreaTableEntry* GetCurrentArea(); + const AreaTableEntry* GetCurrentZone(); + std::string GetLocalizedAreaName(const AreaTableEntry* entry); + bool TellMaster(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); bool TellMaster(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); - bool TellMasterNoFacing(std::ostringstream& stream, - PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); - bool TellMasterNoFacing(std::string const text, - PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + bool TellMasterNoFacing(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + bool TellMasterNoFacing(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); bool TellError(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + bool SayToGuild(const std::string& msg); + bool SayToWorld(const std::string& msg); + bool SayToChannel(const std::string& msg, const ChatChannelId& chanId); + bool SayToParty(const std::string& msg); + bool SayToRaid(const std::string& msg); + bool Yell(const std::string& msg); + bool Say(const std::string& msg); + bool Whisper(const std::string& msg, const std::string& receiverName); + void SpellInterrupted(uint32 spellid); int32 CalculateGlobalCooldown(uint32 spellid); void InterruptSpell(); @@ -461,11 +523,12 @@ public: bool AllowActive(ActivityType activityType); bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false); - bool HasCheat(BotCheatMask mask) - { - return ((uint32)mask & (uint32)cheatMask) != 0 || - ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; - } + //Check if player is safe to use. + bool IsSafe(Player* player); + bool IsSafe(WorldObject* obj); + ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName); + + bool HasCheat(BotCheatMask mask) { return ((uint32)mask & (uint32)cheatMask) != 0 || ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; } BotCheatMask GetCheat() { return cheatMask; } void SetCheat(BotCheatMask mask) { cheatMask = mask; } @@ -486,23 +549,34 @@ public: bool EqualLowercaseName(std::string s1, std::string s2); InventoryResult CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading = true) const; uint8 FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const; + std::vector GetInventoryAndEquippedItems(); + std::vector GetInventoryItems(); + uint32 GetInventoryItemsCountWithId(uint32 itemId); + bool HasItemInInventory(uint32 itemId); + std::vector> GetCurrentQuestsRequiringItemId(uint32 itemId); + std::vector GetAllCurrentQuests(); + std::vector GetCurrentIncompleteQuests(); + std::set GetAllCurrentQuestIds(); + std::set GetCurrentIncompleteQuestIds(); private: - static void _fillGearScoreData(Player* player, Item* item, std::vector* gearScore, uint32& twoHandScore, - bool mixed = false); + static void _fillGearScoreData(Player* player, Item* item, std::vector* gearScore, uint32& twoHandScore, bool mixed = false); bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + void HandleCommands(); + void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL); + protected: Player* bot; - Player* master; - uint32 accountId; + Player* master; + uint32 accountId; AiObjectContext* aiObjectContext; Engine* currentEngine; Engine* engines[BOT_STATE_MAX]; BotState currentState; ChatHelper chatHelper; - std::queue chatCommands; - std::queue chatReplies; + std::list chatCommands; + std::list chatReplies; PacketHandlingHelper botOutgoingPacketHandlers; PacketHandlingHelper masterIncomingPacketHandlers; PacketHandlingHelper masterOutgoingPacketHandlers; diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 79ed9f7c..3782735e 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -107,6 +107,9 @@ bool PlayerbotAIConfig::Initialize() iterationsPerTick = sConfigMgr->GetOption("AiPlayerbot.IterationsPerTick", 100); allowGuildBots = sConfigMgr->GetOption("AiPlayerbot.AllowGuildBots", true); + randomBotGuildNearby = sConfigMgr->GetOption("AiPlayerbot.RandomBotGuildNearby", false); + randomBotInvitePlayer = sConfigMgr->GetOption("AiPlayerbot.RandomBotInvitePlayer", false); + inviteChat = sConfigMgr->GetOption("AiPlayerbot.InviteChat", false); allowPlayerBots = sConfigMgr->GetOption("AiPlayerbot.AllowPlayerBots", false); randomBotMapsAsString = sConfigMgr->GetOption("AiPlayerbot.RandomBotMaps", "0,1,530,571"); @@ -160,12 +163,100 @@ bool PlayerbotAIConfig::Initialize() maxRandomBotsPriceChangeInterval = sConfigMgr->GetOption("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR); randomBotJoinLfg = sConfigMgr->GetOption("AiPlayerbot.RandomBotJoinLfg", true); + + //////////////////////////// CHAT + enableBroadcasts = sConfigMgr->GetOption("AiPlayerbot.EnableBroadcasts", true); randomBotTalk = sConfigMgr->GetOption("AiPlayerbot.RandomBotTalk", false); randomBotEmote = sConfigMgr->GetOption("AiPlayerbot.RandomBotEmote", false); randomBotSuggestDungeons = sConfigMgr->GetOption("AiPlayerbot.RandomBotSuggestDungeons", true); - randomBotGuildTalk = sConfigMgr->GetOption("AiPlayerbot.RandomBotGuildTalk", false); + randomBotSayWithoutMaster = sConfigMgr->GetOption("AiPlayerbot.RandomBotSayWithoutMaster", false); + + // broadcastChanceMaxValue is used in urand(1, broadcastChanceMaxValue) for broadcasts, + // lowering it will increase the chance, setting it to 0 will disable broadcasts + // for internal use, not intended to be change by the user + broadcastChanceMaxValue = enableBroadcasts ? 30000 : 0; + + // all broadcast chances should be in range 1-broadcastChanceMaxValue, value of 0 will disable this particular + // broadcast setting value to max does not guarantee the broadcast, as there are some internal randoms as well + broadcastToGuildGlobalChance = sConfigMgr->GetOption("AiPlayerbot.BroadcastToGuildGlobalChance", 30000); + broadcastToWorldGlobalChance = sConfigMgr->GetOption("AiPlayerbot.BroadcastToWorldGlobalChance", 30000); + broadcastToGeneralGlobalChance = sConfigMgr->GetOption("AiPlayerbot.BroadcastToGeneralGlobalChance", 30000); + broadcastToTradeGlobalChance = sConfigMgr->GetOption("AiPlayerbot.BroadcastToTradeGlobalChance", 30000); + broadcastToLFGGlobalChance = sConfigMgr->GetOption("AiPlayerbot.BroadcastToLFGGlobalChance", 30000); + broadcastToLocalDefenseGlobalChance = + sConfigMgr->GetOption("AiPlayerbot.BroadcastToLocalDefenseGlobalChance", 30000); + broadcastToWorldDefenseGlobalChance = + sConfigMgr->GetOption("AiPlayerbot.BroadcastToWorldDefenseGlobalChance", 30000); + broadcastToGuildRecruitmentGlobalChance = + sConfigMgr->GetOption("AiPlayerbot.BroadcastToGuildRecruitmentGlobalChance", 30000); + + broadcastChanceLootingItemPoor = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLootingItemPoor", 30); + broadcastChanceLootingItemNormal = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLootingItemNormal", 300); + broadcastChanceLootingItemUncommon = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLootingItemUncommon", 10000); + broadcastChanceLootingItemRare = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLootingItemRare", 20000); + broadcastChanceLootingItemEpic = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLootingItemEpic", 30000); + broadcastChanceLootingItemLegendary = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLootingItemLegendary", 30000); + broadcastChanceLootingItemArtifact = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLootingItemArtifact", 30000); + + broadcastChanceQuestAccepted = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceQuestAccepted", 6000); + broadcastChanceQuestUpdateObjectiveCompleted = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceQuestUpdateObjectiveCompleted", 300); + broadcastChanceQuestUpdateObjectiveProgress = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceQuestUpdateObjectiveProgress", 300); + broadcastChanceQuestUpdateFailedTimer = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceQuestUpdateFailedTimer", 300); + broadcastChanceQuestUpdateComplete = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceQuestUpdateComplete", 1000); + broadcastChanceQuestTurnedIn = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceQuestTurnedIn", 10000); + + broadcastChanceKillNormal = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillNormal", 30); + broadcastChanceKillElite = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillElite", 300); + broadcastChanceKillRareelite = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillRareelite", 3000); + broadcastChanceKillWorldboss = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillWorldboss", 20000); + broadcastChanceKillRare = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillRare", 10000); + broadcastChanceKillUnknown = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillUnknown", 100); + broadcastChanceKillPet = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillPet", 10); + broadcastChanceKillPlayer = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceKillPlayer", 30); + + broadcastChanceLevelupGeneric = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLevelupGeneric", 20000); + broadcastChanceLevelupTenX = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLevelupTenX", 30000); + broadcastChanceLevelupMaxLevel = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceLevelupMaxLevel", 30000); + + broadcastChanceSuggestInstance = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestInstance", 5000); + broadcastChanceSuggestQuest = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestQuest", 10000); + broadcastChanceSuggestGrindMaterials = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestGrindMaterials", 5000); + broadcastChanceSuggestGrindReputation = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestGrindReputation", 5000); + broadcastChanceSuggestSell = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestSell", 300); + broadcastChanceSuggestSomething = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestSomething", 30000); + + broadcastChanceSuggestSomethingToxic = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestSomethingToxic", 0); + + broadcastChanceSuggestToxicLinks = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestToxicLinks", 0); + toxicLinksPrefix = sConfigMgr->GetOption("AiPlayerbot.ToxicLinksPrefix", "gnomes"); + + broadcastChanceSuggestThunderfury = + sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceSuggestThunderfury", 1); + + // does not depend on global chance + broadcastChanceGuildManagement = sConfigMgr->GetOption("AiPlayerbot.BroadcastChanceGuildManagement", 30000); + //////////////////////////// + + toxicLinksRepliesChance = sConfigMgr->GetOption("AiPlayerbot.ToxicLinksRepliesChance", 30); // 0-100 + thunderfuryRepliesChance = sConfigMgr->GetOption("AiPlayerbot.ThunderfuryRepliesChance", 40); // 0-100 + guildRepliesRate = sConfigMgr->GetOption("AiPlayerbot.GuildRepliesRate", 100); // 0-100 suggestDungeonsInLowerCaseRandomly = sConfigMgr->GetOption("AiPlayerbot.SuggestDungeonsInLowerCaseRandomly", false); + + ////////////////////////// !CHAT + randomBotJoinBG = sConfigMgr->GetOption("AiPlayerbot.RandomBotJoinBG", true); randomBotAutoJoinBG = sConfigMgr->GetOption("AiPlayerbot.RandomBotAutoJoinBG", false); randomBotAutoJoinWarsongBracket = sConfigMgr->GetOption("AiPlayerbot.RandomBotAutoJoinWarsongBracket", 14); @@ -368,8 +459,6 @@ bool PlayerbotAIConfig::Initialize() autoDoQuests = sConfigMgr->GetOption("AiPlayerbot.AutoDoQuests", false); syncLevelWithPlayers = sConfigMgr->GetOption("AiPlayerbot.SyncLevelWithPlayers", false); freeFood = sConfigMgr->GetOption("AiPlayerbot.FreeFood", true); - randomBotSayWithoutMaster = sConfigMgr->GetOption("AiPlayerbot.RandomBotSayWithoutMaster", false); - sayWhenCollectingItems = sConfigMgr->GetOption("AiPlayerbot.SayWhenCollectingItems", true); randomBotGroupNearby = sConfigMgr->GetOption("AiPlayerbot.RandomBotGroupNearby", true); // arena diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 804f273f..11d45965 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -55,6 +55,7 @@ public: bool enabled; bool allowGuildBots, allowPlayerBots; + bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat; uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime, dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay; float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance, @@ -95,11 +96,78 @@ public: uint32 randomBotsPerInterval; uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval; bool randomBotJoinLfg; + + // chat bool randomBotTalk; bool randomBotEmote; bool randomBotSuggestDungeons; - bool randomBotGuildTalk; + bool enableBroadcasts; + bool enableGreet; + bool randomBotSayWithoutMaster; + + uint32 broadcastChanceMaxValue; + + uint32 broadcastToGuildGlobalChance; + uint32 broadcastToWorldGlobalChance; + uint32 broadcastToGeneralGlobalChance; + uint32 broadcastToTradeGlobalChance; + uint32 broadcastToLFGGlobalChance; + uint32 broadcastToLocalDefenseGlobalChance; + uint32 broadcastToWorldDefenseGlobalChance; + uint32 broadcastToGuildRecruitmentGlobalChance; + + uint32 broadcastChanceLootingItemPoor; + uint32 broadcastChanceLootingItemNormal; + uint32 broadcastChanceLootingItemUncommon; + uint32 broadcastChanceLootingItemRare; + uint32 broadcastChanceLootingItemEpic; + uint32 broadcastChanceLootingItemLegendary; + uint32 broadcastChanceLootingItemArtifact; + + uint32 broadcastChanceQuestAccepted; + uint32 broadcastChanceQuestUpdateObjectiveCompleted; + uint32 broadcastChanceQuestUpdateObjectiveProgress; + uint32 broadcastChanceQuestUpdateFailedTimer; + uint32 broadcastChanceQuestUpdateComplete; + uint32 broadcastChanceQuestTurnedIn; + + uint32 broadcastChanceKillNormal; + uint32 broadcastChanceKillElite; + uint32 broadcastChanceKillRareelite; + uint32 broadcastChanceKillWorldboss; + uint32 broadcastChanceKillRare; + uint32 broadcastChanceKillUnknown; + uint32 broadcastChanceKillPet; + uint32 broadcastChanceKillPlayer; + + uint32 broadcastChanceLevelupGeneric; + uint32 broadcastChanceLevelupTenX; + uint32 broadcastChanceLevelupMaxLevel; + + uint32 broadcastChanceSuggestInstance; + uint32 broadcastChanceSuggestQuest; + uint32 broadcastChanceSuggestGrindMaterials; + uint32 broadcastChanceSuggestGrindReputation; + uint32 broadcastChanceSuggestSell; + uint32 broadcastChanceSuggestSomething; + + uint32 broadcastChanceSuggestSomethingToxic; + + uint32 broadcastChanceSuggestToxicLinks; + std::string toxicLinksPrefix; + uint32 toxicLinksRepliesChance; + + uint32 broadcastChanceSuggestThunderfury; + uint32 thunderfuryRepliesChance; + + uint32 broadcastChanceGuildManagement; + + uint32 guildRepliesRate; + bool suggestDungeonsInLowerCaseRandomly; + + // -- + bool randomBotJoinBG; bool randomBotAutoJoinBG; uint32 randomBotAutoJoinWarsongBracket; @@ -181,8 +249,6 @@ public: uint32 commandServerPort; bool perfMonEnabled; - - bool enableGreet; bool summonWhenGroup; bool randomBotShowHelmet; bool randomBotShowCloak; @@ -212,8 +278,6 @@ public: bool freeFood; bool autoLearnQuestSpells; bool autoTeleportForLevel; - bool randomBotSayWithoutMaster; - bool sayWhenCollectingItems; bool randomBotGroupNearby; uint32 tweakValue; // Debugging config diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 503d6a20..7d71e88a 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -26,9 +26,10 @@ #include "Playerbots.h" #include "SharedDefines.h" #include "WorldSession.h" +#include "ChannelMgr.h" +#include "BroadcastHelper.h" PlayerbotHolder::PlayerbotHolder() : PlayerbotAIBase(false) {} - class PlayerbotLoginQueryHolder : public LoginQueryHolder { private: @@ -562,10 +563,12 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) pkt << ""; // Pass bot->GetSession()->HandleJoinChannel(pkt); } + // join standard channels - AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(bot->GetAreaId()); + uint8 locale = BroadcastHelper::GetLocale(); + AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone(); ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()); - std::string current_zone_name = current_zone ? current_zone->area_name[sWorld->GetDefaultDbcLocale()] : ""; + std::string current_zone_name = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : ""; if (current_zone && cMgr) { @@ -575,27 +578,40 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) if (!channel) continue; - bool isLfg = (channel->flags & CHANNEL_DBC_FLAG_LFG) != 0; - - // skip non built-in channels or global channel without zone name in pattern - if (!isLfg && (!channel || (channel->flags & 4) == 4)) - continue; - - // new channel Channel* new_channel = nullptr; - if (isLfg) + switch (channel->ChannelID) { - std::string lfgChannelName = channel->pattern[sWorld->GetDefaultDbcLocale()]; - new_channel = cMgr->GetJoinChannel("LookingForGroup", channel->ChannelID); + case ChatChannelId::GENERAL: + case ChatChannelId::LOCAL_DEFENSE: + { + char new_channel_name_buf[100]; + snprintf(new_channel_name_buf, 100, channel->pattern[locale], current_zone_name.c_str()); + new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID); + break; + } + case ChatChannelId::TRADE: + case ChatChannelId::GUILD_RECRUITMENT: + { + char new_channel_name_buf[100]; + //3459 is ID for a zone named "City" (only exists for the sake of using its name) + //Currently in magons TBC, if you switch zones, then you join "Trade - " and "GuildRecruitment - " + //which is a core bug, should be "Trade - City" and "GuildRecruitment - City" in both 1.12 and TBC + //but if you (actual player) logout in a city and log back in - you join "City" versions + snprintf(new_channel_name_buf, 100, channel->pattern[locale], GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(GetAreaEntryByAreaID(3459)).c_str()); + new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID); + break; + } + case ChatChannelId::LOOKING_FOR_GROUP: + case ChatChannelId::WORLD_DEFENSE: + { + new_channel = cMgr->GetJoinChannel(channel->pattern[locale], channel->ChannelID); + break; + } + default: + break; } - else - { - char new_channel_name_buf[100]; - snprintf(new_channel_name_buf, 100, channel->pattern[sWorld->GetDefaultDbcLocale()], - current_zone_name.c_str()); - new_channel = cMgr->GetJoinChannel(new_channel_name_buf, channel->ChannelID); - } - if (new_channel && new_channel->GetName().length() > 0) + + if (new_channel) new_channel->JoinChannel(bot, ""); } } diff --git a/src/ServerFacade.cpp b/src/ServerFacade.cpp index 65e5af0a..8266e8dd 100644 --- a/src/ServerFacade.cpp +++ b/src/ServerFacade.cpp @@ -68,3 +68,8 @@ Unit* ServerFacade::GetChaseTarget(Unit* target) return nullptr; } + +void ServerFacade::SendPacket(Player *player, WorldPacket *packet) +{ + return player->GetSession()->SendPacket(packet); +} diff --git a/src/ServerFacade.h b/src/ServerFacade.h index 169e941f..13e21124 100644 --- a/src/ServerFacade.h +++ b/src/ServerFacade.h @@ -11,6 +11,7 @@ class Player; class Unit; class WorldObject; +class WorldPacket; class ServerFacade { @@ -32,8 +33,9 @@ public: bool IsDistanceLessOrEqualThan(float dist1, float dist2); void SetFacingTo(Player* bot, WorldObject* wo, bool force = false); - Unit* GetChaseTarget(Unit* target); + + void SendPacket(Player *player, WorldPacket* packet); }; #define sServerFacade ServerFacade::instance() diff --git a/src/TravelMgr.cpp b/src/TravelMgr.cpp index c64a6d1f..af8bb12f 100644 --- a/src/TravelMgr.cpp +++ b/src/TravelMgr.cpp @@ -121,7 +121,20 @@ WorldPosition::WorldPosition(uint32 mapid, mGridCoord grid) void WorldPosition::set(const WorldLocation& pos) { WorldRelocate(pos); } -void WorldPosition::setMapId(uint32 id) { m_mapId = id; } +void WorldPosition::set(const WorldPosition& pos) +{ + WorldRelocate(pos.m_mapId, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); +} + +void WorldPosition::set(const WorldObject* pos) +{ + WorldRelocate(pos->GetMapId(), pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), pos->GetOrientation()); +} + +void WorldPosition::setMapId(uint32 id) +{ + m_mapId = id; +} void WorldPosition::setX(float x) { m_positionX = x; } @@ -1045,30 +1058,42 @@ std::string const QuestTravelDestination::getTitle() { return ChatHelper::Format bool QuestRelationTravelDestination::isActive(Player* bot) { + PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); + AiObjectContext* context = botAI->GetAiObjectContext(); + + if (botAI && !botAI->HasStrategy("rpg quest", BOT_STATE_NON_COMBAT)) + return false; + if (relation == 0) { - if (questTemplate->GetQuestLevel() >= bot->GetLevel() + 5) + if ((int32)questTemplate->GetQuestLevel() >= (int32)bot->GetLevel() + (int32)5) return false; - // if (questTemplate->XPValue(bot) == 0) - // return false; + // skip for now this quest + if (getPoints().front()->GetMapId() != bot->GetMapId()) + return false; if (!bot->GetMap()->GetEntry()->IsWorldMap() || !bot->CanTakeQuest(questTemplate, false)) return false; - PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); - AiObjectContext* context = botAI->GetAiObjectContext(); - uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate); if (AI_VALUE(bool, "can fight equal")) { - if (dialogStatus != DIALOG_STATUS_AVAILABLE) + if (AI_VALUE(uint8, "free quest log slots") < 5) return false; + + //None has yellow exclamation mark. + if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest npc::" + std::to_string(entry))) + if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest low level npc::" + std::to_string(entry) + "need quest objective::" + std::to_string(questId))) //Noone can do this quest for a usefull reward. + return false; } else { - if (dialogStatus != DIALOG_STATUS_LOW_LEVEL_AVAILABLE) + if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest low level npc::" + std::to_string(entry))) //Noone can pick up this quest for money. + return false; + + if (AI_VALUE(uint8, "free quest log slots") < 10) return false; } @@ -1079,27 +1104,14 @@ bool QuestRelationTravelDestination::isActive(Player* bot) } else { - if (!bot->IsActiveQuest(questId)) + if (!AI_VALUE2(bool, "group or", "following party,near leader,can turn in quest npc::" + std::to_string(entry))) return false; - if (!bot->CanRewardQuest(questTemplate, false)) - return false; - - uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate); - - if (dialogStatus != DIALOG_STATUS_REWARD2 && dialogStatus != DIALOG_STATUS_REWARD && - dialogStatus != DIALOG_STATUS_REWARD_REP) - return false; - - PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); - AiObjectContext* context = botAI->GetAiObjectContext(); - - // Do not try to hand-in dungeon/elite quests in instances without a group. - if ((questTemplate->GetType() == QUEST_TYPE_ELITE || questTemplate->GetType() == QUEST_TYPE_DUNGEON) && - !AI_VALUE(bool, "can fight boss")) + //Do not try to hand-in dungeon/elite quests in instances without a group. + if ((questTemplate->GetType() == QUEST_TYPE_ELITE || questTemplate->GetType() == QUEST_TYPE_DUNGEON) && !AI_VALUE(bool, "can fight boss")) { WorldPosition pos(bot); - if (!this->nearestPoint(const_cast(&pos))->isOverworld()) + if (!this->nearestPoint(&pos)->isOverworld()) return false; } } @@ -1233,7 +1245,8 @@ std::string const RpgTravelDestination::getTitle() { std::ostringstream out; - out << "rpg npc "; + if(entry > 0) + out << "rpg npc "; out << " " << ChatHelper::FormatWorldEntry(entry); @@ -3880,7 +3893,45 @@ std::vector TravelMgr::getQuestTravelDestinations(Player* bo std::vector retTravelLocations; - if (questId == -1) + if (!questId) + { + for (auto& dest : questGivers) + { + if (!ignoreInactive && !dest->isActive(bot)) + continue; + + if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance) + continue; + + retTravelLocations.push_back(dest); + } + for (auto& quest : quests) + { + for (auto& dest : quest.second->questTakers) + { + if (!ignoreInactive && !dest->isActive(bot)) + continue; + + if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance) + continue; + + retTravelLocations.push_back(dest); + } + + if (!ignoreObjectives) + for (auto& dest : quest.second->questObjectives) + { + if (!ignoreInactive && !dest->isActive(bot)) + continue; + + if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance) + continue; + + retTravelLocations.push_back(dest); + } + } + } + else if (questId == -1) { for (auto& dest : questGivers) { diff --git a/src/TravelMgr.h b/src/TravelMgr.h index 9255e851..b054f436 100644 --- a/src/TravelMgr.h +++ b/src/TravelMgr.h @@ -97,8 +97,10 @@ public: WorldPosition(uint32 mapid, CellCoord cell); WorldPosition(uint32 mapid, mGridCoord grid); - // Setters + //Setters void set(const WorldLocation& pos); + void set(const WorldObject* wo); + void set(const WorldPosition& pos); void setMapId(uint32 id); void setX(float x); void setY(float y); @@ -404,11 +406,10 @@ private: class GuidPosition : public ObjectGuid, public WorldPosition { public: - GuidPosition() : ObjectGuid(), WorldPosition(), loadedFromDB(false) {} + GuidPosition() : ObjectGuid(), WorldPosition(), loadedFromDB(false) { } GuidPosition(WorldObject* wo); GuidPosition(CreatureData const& creData); GuidPosition(GameObjectData const& goData); - CreatureTemplate const* GetCreatureTemplate(); GameObjectTemplate const* GetGameObjectTemplate(); diff --git a/src/strategy/NamedObjectContext.cpp b/src/strategy/NamedObjectContext.cpp index 308c913b..d1ea0e1c 100644 --- a/src/strategy/NamedObjectContext.cpp +++ b/src/strategy/NamedObjectContext.cpp @@ -14,13 +14,30 @@ void Qualified::Qualify(int qual) qualifier = out.str(); } -std::string const Qualified::MultiQualify(std::vector qualifiers) +std::string const Qualified::MultiQualify(std::vector qualifiers, const std::string& separator, const std::string_view brackets) { - std::ostringstream out; - for (auto& qualifier : qualifiers) - out << qualifier << (&qualifier != &qualifiers.back() ? " " : ""); + std::stringstream out; + for (uint8 i = 0; i < qualifiers.size(); i++) + { + const std::string& qualifier = qualifiers[i]; + if (i == qualifiers.size() - 1) + { + out << qualifier; + } + else + { + out << qualifier << separator; + } + } - return out.str(); + if (brackets.empty()) + { + return out.str(); + } + else + { + return brackets[0] + out.str() + brackets[1]; + } } std::vector Qualified::getMultiQualifiers(std::string const qualifier1) diff --git a/src/strategy/NamedObjectContext.h b/src/strategy/NamedObjectContext.h index 25b66b3d..78797b0a 100644 --- a/src/strategy/NamedObjectContext.h +++ b/src/strategy/NamedObjectContext.h @@ -29,7 +29,7 @@ public: std::string const getQualifier() { return qualifier; } - static std::string const MultiQualify(std::vector qualifiers); + static std::string const MultiQualify(std::vector qualifiers, const std::string& separator, const std::string_view brackets = "{}"); static std::vector getMultiQualifiers(std::string const qualifier1); static int32 getMultiQualifier(std::string const qualifier1, uint32 pos); diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index cf86dca4..9c694364 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -107,6 +107,7 @@ public: creators["debug move"] = &StrategyContext::debug_move; creators["debug rpg"] = &StrategyContext::debug_rpg; creators["debug spell"] = &StrategyContext::debug_spell; + creators["debug quest"] = &StrategyContext::debug_quest; creators["maintenance"] = &StrategyContext::maintenance; creators["group"] = &StrategyContext::group; creators["guild"] = &StrategyContext::guild; @@ -170,9 +171,10 @@ private: static Strategy* debug_move(PlayerbotAI* botAI) { return new DebugMoveStrategy(botAI); } static Strategy* debug_rpg(PlayerbotAI* botAI) { return new DebugRpgStrategy(botAI); } static Strategy* debug_spell(PlayerbotAI* botAI) { return new DebugSpellStrategy(botAI); } + static Strategy* debug_quest(PlayerbotAI* botAI) { return new DebugQuestStrategy(botAI); } static Strategy* maintenance(PlayerbotAI* botAI) { return new MaintenanceStrategy(botAI); } static Strategy* group(PlayerbotAI* botAI) { return new GroupStrategy(botAI); } - static Strategy* guild(PlayerbotAI* botAI) { return new GuildStrategy(botAI); } + static Strategy* guild (PlayerbotAI* botAI) { return new GuildStrategy(botAI); } static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); } static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); } static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); } diff --git a/src/strategy/actions/AcceptQuestAction.cpp b/src/strategy/actions/AcceptQuestAction.cpp index 51e64db0..882e65ca 100644 --- a/src/strategy/actions/AcceptQuestAction.cpp +++ b/src/strategy/actions/AcceptQuestAction.cpp @@ -8,54 +8,63 @@ #include "Event.h" #include "Playerbots.h" -void AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver) +bool AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver) { - AcceptQuest(quest, questGiver->GetGUID()); + if (!AcceptQuest(quest, questGiver->GetGUID())) return false; + + auto text_quest = ChatHelper::FormatQuest(quest); bot->PlayDistanceSound(620); + + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + LOG_INFO("playerbots", "{} => Quest [ {} ] accepted", bot->GetName(), quest->GetTitle()); + bot->Say("Quest [ " + text_quest + " ] accepted", LANG_UNIVERSAL); + } + + return true; } bool AcceptQuestAction::Execute(Event event) { - Player* master = GetMaster(); - if (!master) + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + if (!requester) return false; Player* bot = botAI->GetBot(); - ObjectGuid guid; + uint64_t guid; uint32 quest = 0; std::string const text = event.getParam(); - PlayerbotChatHandler ch(master); + PlayerbotChatHandler ch(requester); quest = ch.extractQuestId(text); + bool hasAccept = false; + if (event.getPacket().empty()) { GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs"); - for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++) + for (auto i = npcs.begin(); i != npcs.end(); i++) { Unit* unit = botAI->GetUnit(*i); if (unit && quest && unit->hasQuest(quest)) { - guid = unit->GetGUID(); + guid = unit->GetGUID().GetRawValue(); break; } - - if (unit && text == "*" && bot->GetDistance(unit) <= INTERACTION_DISTANCE) - QuestAction::ProcessQuests(unit); + if (unit && text == "*" && sqrt(bot->GetDistance(unit)) <= INTERACTION_DISTANCE) + hasAccept |= QuestAction::ProcessQuests(unit); } - - GuidVector gos = AI_VALUE(GuidVector, "nearest game objects"); - for (GuidVector::iterator i = gos.begin(); i != gos.end(); i++) + GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los"); + for (auto i = gos.begin(); i != gos.end(); i++) { GameObject* go = botAI->GetGameObject(*i); if (go && quest && go->hasQuest(quest)) { - guid = go->GetGUID(); + guid = go->GetGUID().GetRawValue(); break; } - - if (go && text == "*" && bot->GetDistance(go) <= INTERACTION_DISTANCE) - QuestAction::ProcessQuests(go); + if (go && text == "*" && sqrt(bot->GetDistance(go)) <= INTERACTION_DISTANCE) + hasAccept |= QuestAction::ProcessQuests(go); } } else @@ -72,7 +81,17 @@ bool AcceptQuestAction::Execute(Event event) if (!qInfo) return false; - return AcceptQuest(qInfo, guid); + hasAccept |= AcceptQuest(qInfo, ObjectGuid(guid)); + + if (hasAccept) + { + std::stringstream ss; + ss << "AcceptQuestAction {" << qInfo->GetTitle() << "} - {" << std::to_string(qInfo->GetQuestId()) << "}"; + LOG_INFO("playerbots", "{}", ss.str().c_str()); + botAI->TellMaster(ss.str()); + } + + return hasAccept; } bool AcceptQuestShareAction::Execute(Event event) @@ -136,3 +155,41 @@ bool AcceptQuestShareAction::Execute(Event event) return false; } + +bool ConfirmQuestAction::Execute(Event event) +{ + Player* bot = botAI->GetBot(); + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + + WorldPacket& p = event.getPacket(); + p.rpos(0); + uint32 quest; + p >> quest; + Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest); + + quest = qInfo->GetQuestId(); + if (!bot->CanTakeQuest(qInfo, false)) + { + // can't take quest + botAI->TellError("quest_cant_take"); + return false; + } + + if (bot->CanAddQuest(qInfo, false)) + { + bot->AddQuest(qInfo, requester); + + if (bot->CanCompleteQuest(quest)) + bot->CompleteQuest(quest); + + if (qInfo->GetSrcSpell() > 0) + { + bot->CastSpell(bot, qInfo->GetSrcSpell(), true); + } + + botAI->TellMaster("quest_accept"); + return true; + } + + return false; +} diff --git a/src/strategy/actions/AcceptQuestAction.h b/src/strategy/actions/AcceptQuestAction.h index 4a9cba03..504e144c 100644 --- a/src/strategy/actions/AcceptQuestAction.h +++ b/src/strategy/actions/AcceptQuestAction.h @@ -20,7 +20,7 @@ public: } protected: - void ProcessQuest(Quest const* quest, Object* questGiver) override; + bool ProcessQuest(Quest const* quest, Object* questGiver) override; }; class AcceptQuestAction : public AcceptAllQuestsAction @@ -37,4 +37,10 @@ public: bool Execute(Event event) override; }; +class ConfirmQuestAction : public Action { +public: + ConfirmQuestAction(PlayerbotAI* ai) : Action(ai, "confirm quest") {} + bool Execute(Event event); +}; + #endif diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index dc40d9ff..3f0cf4e1 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -9,6 +9,8 @@ #include "AddLootAction.h" #include "AttackAction.h" #include "AutoLearnSpellAction.h" +#include "ShareQuestAction.h" +#include "BattleGroundTactics.h" #include "AutoTeleportForLevelAction.h" #include "BattleGroundJoinAction.h" #include "BattleGroundTactics.h" @@ -43,6 +45,7 @@ #include "NonCombatActions.h" #include "OutfitAction.h" #include "PositionAction.h" +#include "DropQuestAction.h" #include "RaidNaxxActions.h" #include "RandomBotUpdateAction.h" #include "ReachTargetActions.h" @@ -153,6 +156,7 @@ public: creators["war stomp"] = &ActionContext::war_stomp; creators["auto talents"] = &ActionContext::auto_talents; creators["auto learn spell"] = &ActionContext::auto_learn_spell; + creators["auto share quest"] = &ActionContext::auto_share_quest; creators["auto teleport for level"] = &ActionContext::auto_teleport_for_level; creators["auto upgrade equip"] = &ActionContext::auto_upgrade_equip; creators["xp gain"] = &ActionContext::xp_gain; @@ -179,6 +183,7 @@ public: creators["turn in petition"] = &ActionContext::turn_in_petition; creators["buy tabard"] = &ActionContext::buy_tabard; creators["guild manage nearby"] = &ActionContext::guild_manage_nearby; + creators["clean quest log"] = &ActionContext::clean_quest_log; // BG Tactics creators["bg tactics"] = &ActionContext::bg_tactics; @@ -206,7 +211,7 @@ public: creators["blade salvo"] = &ActionContext::blade_salvo; creators["glaive throw"] = &ActionContext::glaive_throw; - // Rpg + //Rpg creators["rpg stay"] = &ActionContext::rpg_stay; creators["rpg work"] = &ActionContext::rpg_work; creators["rpg emote"] = &ActionContext::rpg_emote; @@ -231,7 +236,7 @@ public: creators["rpg mount anim"] = &ActionContext::rpg_mount_anim; creators["toggle pet spell"] = &ActionContext::toggle_pet_spell; - creators["pet attack"] = &ActionContext::pet_attack; + creators["pet attack"] = &ActionContext::pet_attack; } private: @@ -265,10 +270,7 @@ private: static Action* ReachSpell(PlayerbotAI* botAI) { return new ReachSpellAction(botAI); } static Action* ReachMelee(PlayerbotAI* botAI) { return new ReachMeleeAction(botAI); } static Action* reach_party_member_to_heal(PlayerbotAI* botAI) { return new ReachPartyMemberToHealAction(botAI); } - static Action* reach_party_member_to_resurrect(PlayerbotAI* botAI) - { - return new ReachPartyMemberToResurrectAction(botAI); - } + static Action* reach_party_member_to_resurrect(PlayerbotAI* botAI) { return new ReachPartyMemberToResurrectAction(botAI); } static Action* flee(PlayerbotAI* botAI) { return new FleeAction(botAI); } static Action* flee_with_pet(PlayerbotAI* botAI) { return new FleeWithPetAction(botAI); } static Action* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeAction(botAI); } @@ -324,6 +326,7 @@ private: static Action* war_stomp(PlayerbotAI* botAI) { return new CastWarStompAction(botAI); } static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); } static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); } + static Action* auto_share_quest(PlayerbotAI* ai) { return new AutoShareQuestAction(ai); } static Action* auto_teleport_for_level(PlayerbotAI* botAI) { return new AutoTeleportForLevelAction(botAI); } static Action* auto_upgrade_equip(PlayerbotAI* botAI) { return new AutoUpgradeEquipAction(botAI); } static Action* xp_gain(PlayerbotAI* botAI) { return new XpGainAction(botAI); } @@ -351,6 +354,7 @@ private: static Action* turn_in_petition(PlayerbotAI* botAI) { return new PetitionTurnInAction(botAI); } static Action* buy_tabard(PlayerbotAI* botAI) { return new BuyTabardAction(botAI); } static Action* guild_manage_nearby(PlayerbotAI* botAI) { return new GuildManageNearbyAction(botAI); } + static Action* clean_quest_log(PlayerbotAI* botAI) { return new CleanQuestLogAction(botAI); } // BG Tactics static Action* bg_tactics(PlayerbotAI* botAI) { return new BGTactics(botAI); } diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index 4415eb5d..96a93161 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -9,6 +9,7 @@ #include "GuildMgr.h" #include "PlayerbotFactory.h" #include "Playerbots.h" +#include "BroadcastHelper.h" bool AutoLearnSpellAction::Execute(Event event) { @@ -32,29 +33,12 @@ bool AutoLearnSpellAction::Execute(Event event) void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) { - if (sPlayerbotAIConfig->autoLearnTrainerSpells && - sRandomPlayerbotMgr->IsRandomBot(bot)) // || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) + BroadcastHelper::BroadcastLevelup(botAI, bot); + if (sPlayerbotAIConfig->autoLearnTrainerSpells) LearnTrainerSpells(out); - if (sPlayerbotAIConfig->autoLearnQuestSpells && - sRandomPlayerbotMgr->IsRandomBot(bot)) // || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) + if (sPlayerbotAIConfig->autoLearnQuestSpells) LearnQuestSpells(out); - - if (sPlayerbotAIConfig->randomBotGuildTalk) - { - Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); - if (guild) - { - std::string toSay = ""; - - if (urand(0, 3)) - toSay = "Ding !"; - else - toSay = "Yay level " + std::to_string(bot->GetLevel()) + " !"; - - guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL); - } - } } void AutoLearnSpellAction::LearnTrainerSpells(std::ostringstream* out) diff --git a/src/strategy/actions/ChatActionContext.h b/src/strategy/actions/ChatActionContext.h index 615760e2..0513c930 100644 --- a/src/strategy/actions/ChatActionContext.h +++ b/src/strategy/actions/ChatActionContext.h @@ -172,6 +172,7 @@ public: creators["naxx chat shortcut"] = &ChatActionContext::naxx_chat_shortcut; creators["bwl chat shortcut"] = &ChatActionContext::bwl_chat_shortcut; creators["tell expected dps"] = &ChatActionContext::tell_expected_dps; + creators["join"] = &ChatActionContext::join; creators["calc"] = &ChatActionContext::calc; } @@ -269,6 +270,7 @@ private: static Action* naxx_chat_shortcut(PlayerbotAI* ai) { return new NaxxChatShortcutAction(ai); } static Action* bwl_chat_shortcut(PlayerbotAI* ai) { return new BwlChatShortcutAction(ai); } static Action* tell_expected_dps(PlayerbotAI* ai) { return new TellExpectedDpsAction(ai); } + static Action* join(PlayerbotAI* ai) { return new JoinGroupAction(ai); } static Action* calc(PlayerbotAI* ai) { return new TellCalculateItemAction(ai); } }; diff --git a/src/strategy/actions/ChooseRpgTargetAction.cpp b/src/strategy/actions/ChooseRpgTargetAction.cpp index 8d6594d3..0f5bb6bc 100644 --- a/src/strategy/actions/ChooseRpgTargetAction.cpp +++ b/src/strategy/actions/ChooseRpgTargetAction.cpp @@ -3,10 +3,9 @@ * and/or modify it under version 2 of the License, or (at your option), any later version. */ -#include "ChooseRpgTargetAction.h" - #include +#include "ChooseRpgTargetAction.h" #include "BattlegroundMgr.h" #include "BudgetValues.h" #include "ChatHelper.h" @@ -14,6 +13,9 @@ #include "Formations.h" #include "GuildCreateActions.h" #include "Playerbots.h" +#include "RpgSubActions.h" +#include "Util.h" +#include "ServerFacade.h" #include "PossibleRpgTargetsValue.h" bool ChooseRpgTargetAction::HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids) @@ -52,52 +54,94 @@ float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP) GuidPosition currentRpgTarget = AI_VALUE(GuidPosition, "rpg target"); SET_AI_VALUE(GuidPosition, "rpg target", guidP); - Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg"); + Strategy* rpgStrategy; std::vector triggerNodes; - rpgStrategy->InitTriggers(triggerNodes); float maxRelevance = 0.0f; - for (auto& triggerNode : triggerNodes) + for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies()) { - Trigger* trigger = context->GetTrigger(triggerNode->getName()); - if (trigger) + if (strategy.find("rpg") == std::string::npos) + continue; + + if (!botAI->HasStrategy(strategy, BotState::BOT_STATE_NON_COMBAT)) + continue; + + rpgStrategy = botAI->GetAiObjectContext()->GetStrategy(strategy); + + rpgStrategy->InitTriggers(triggerNodes); + + for (auto triggerNode : triggerNodes) { - triggerNode->setTrigger(trigger); + Trigger* trigger = context->GetTrigger(triggerNode->getName()); - if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f) - continue; + if (trigger) + { + triggerNode->setTrigger(trigger); - trigger = triggerNode->getTrigger(); - if (!trigger->IsActive()) - continue; + if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f) + continue; - maxRelevance = triggerNode->getFirstRelevance(); + Trigger* trigger = triggerNode->getTrigger(); + + if (!trigger->IsActive()) + continue; + + NextAction** nextActions = triggerNode->getHandlers(); + + bool isRpg = false; + + for (int32 i = 0; i < NextAction::size(nextActions); i++) + { + NextAction* nextAction = nextActions[i]; + + Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName()); + + if (dynamic_cast(action)) + isRpg = true; + } + NextAction::destroy(nextActions); + + if (isRpg) + { + maxRelevance = triggerNode->getFirstRelevance(); + rgpActionReason[guidP] = triggerNode->getName(); + } + } } + + for (auto trigger : triggerNodes) + { + delete trigger; + } + + triggerNodes.clear(); } SET_AI_VALUE(GuidPosition, "rpg target", currentRpgTarget); - for (std::vector::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++) - { - TriggerNode* trigger = *i; - delete trigger; - } + if (!maxRelevance) + return 0.0; - triggerNodes.clear(); - - return (maxRelevance - 1.0) * 1000.0f; + return floor((maxRelevance - 1.0) * 1000.0f); } bool ChooseRpgTargetAction::Execute(Event event) { TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); - - uint32 num = 0; + Player* master = botAI->GetMaster(); + GuidPosition masterRpgTarget; + if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported()) + { + Player* player = botAI->GetMaster(); + GuidPosition masterRpgTarget = PAI_VALUE(GuidPosition, "rpg target"); + } + else + master = nullptr; std::unordered_map targets; - + uint32 num = 0; GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets"); GuidVector possibleObjects = AI_VALUE(GuidVector, "nearest game objects no los"); GuidVector possiblePlayers = AI_VALUE(GuidVector, "nearest friendly players"); @@ -180,18 +224,22 @@ bool ChooseRpgTargetAction::Execute(Event event) for (auto it = begin(targets); it != end(targets);) { - if (it->second == 0 || (hasGoodRelevance && it->second <= 1.0)) - { + //Remove empty targets. + if (it->second == 0) + it = targets.erase(it); + //Remove useless targets if there's any good ones + else if (hasGoodRelevance && it->second <= 1.0) + it = targets.erase(it); + //Remove useless targets if it's not masters target. + else if (!hasGoodRelevance && master && (!masterRpgTarget || it->first != masterRpgTarget)) it = targets.erase(it); - } else ++it; } if (targets.empty()) { - LOG_DEBUG("playerbots", "{} can't choose RPG target: all {} are not available", bot->GetName().c_str(), - possibleTargets.size()); + LOG_DEBUG("playerbots", "{} can't choose RPG target: all {} targets are not available", bot->GetName().c_str(), possibleTargets.size()); RESET_AI_VALUE(GuidSet&, "ignore rpg target"); RESET_AI_VALUE(GuidPosition, "rpg target"); return false; @@ -244,17 +292,20 @@ bool ChooseRpgTargetAction::isUseful() if (!botAI->AllowActivity(RPG_ACTIVITY)) return false; - if (AI_VALUE(GuidPosition, "rpg target")) + GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target"); + + if (guidP && guidP.distance(bot) < sPlayerbotAIConfig->reactDistance * 2) return false; TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); - if (travelTarget->isTraveling() && isFollowValid(bot, *travelTarget->getPosition())) - return false; + //if (travelTarget->isTraveling() && AI_VALUE2(bool, "can free move to", *travelTarget->getPosition())) + //return false; if (AI_VALUE(GuidVector, "possible rpg targets").empty()) return false; + //Not stay, not guard, not combat, not trading and group ready. if (!AI_VALUE(bool, "can move around")) return false; diff --git a/src/strategy/actions/ChooseRpgTargetAction.h b/src/strategy/actions/ChooseRpgTargetAction.h index d46b5f7e..57c063bf 100644 --- a/src/strategy/actions/ChooseRpgTargetAction.h +++ b/src/strategy/actions/ChooseRpgTargetAction.h @@ -28,7 +28,9 @@ public: private: float getMaxRelevance(GuidPosition guidP); - bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids); + bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids); + + std::unordered_map rgpActionReason; }; class ClearRpgTargetAction : public ChooseRpgTargetAction diff --git a/src/strategy/actions/ChooseTravelTargetAction.cpp b/src/strategy/actions/ChooseTravelTargetAction.cpp index ec188f82..ed0aaf8d 100644 --- a/src/strategy/actions/ChooseTravelTargetAction.cpp +++ b/src/strategy/actions/ChooseTravelTargetAction.cpp @@ -11,19 +11,26 @@ bool ChooseTravelTargetAction::Execute(Event event) { - // Get the current travel target. This target is no longer active. + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + + //Get the current travel target. This target is no longer active. TravelTarget* oldTarget = context->GetValue("travel target")->Get(); - // Select a new target to travel to. + //Select a new target to travel to. TravelTarget newTarget = TravelTarget(botAI); - getNewTarget(&newTarget, oldTarget); - // If the new target is not active we failed. - if (!newTarget.isActive()) + if (!oldTarget) return false; + + if (!oldTarget->isForced() || oldTarget->getStatus() == TravelStatus::TRAVEL_STATUS_EXPIRED) + getNewTarget(&newTarget, oldTarget); + else + newTarget.copyTarget(oldTarget); + + //If the new target is not active we failed. + if (!newTarget.isActive() && !newTarget.isForced()) return false; setNewTarget(&newTarget, oldTarget); - return true; } @@ -34,64 +41,141 @@ bool ChooseTravelTargetAction::Execute(Event event) // Eventually we want to rewrite this to be more intelligent. void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget) { - bool foundTarget = false; + // Join groups members + bool foundTarget = foundTarget = SetGroupTarget(newTarget); - foundTarget = SetGroupTarget(newTarget); // Join groups members - - // Enpty bags/repair - if (!foundTarget && urand(1, 100) > 10) // 90% chance - if (AI_VALUE2(bool, "group or", "should sell,can sell,following party,near leader") || - AI_VALUE2(bool, "group or", "should repair,can repair,following party,near leader")) - foundTarget = SetRpgTarget(newTarget); // Go to town to sell items or repair - - // Rpg in city - if (!foundTarget && urand(1, 100) > 90) // 10% chance - foundTarget = - SetNpcFlagTarget(newTarget, {UNIT_NPC_FLAG_BANKER, UNIT_NPC_FLAG_BATTLEMASTER, UNIT_NPC_FLAG_AUCTIONEER}); - - // Grind for money - if (!foundTarget && AI_VALUE(bool, "should get money")) + //Empty bags/repair + if (!foundTarget && urand(1, 100) > 10 && bot->GetLevel() > 5) //90% chance { - if (urand(1, 100) > 66) + if (AI_VALUE2(bool, "group or", "should sell,can sell,following party,near leader") || + AI_VALUE2(bool, "group or", "should repair,can repair,following party,near leader") + ) { - foundTarget = SetQuestTarget(newTarget, true); // Turn in quests for money. - - if (!foundTarget) - foundTarget = SetQuestTarget(newTarget); // Do low level quests - } - else if (urand(1, 100) > 50) - { - foundTarget = SetGrindTarget(newTarget); // Go grind mobs for money - } - else - { - foundTarget = SetNewQuestTarget(newTarget); // Find a low level quest to do + foundTarget = SetRpgTarget(newTarget); //Go to town to sell items or repair } } - // Continue - if (!foundTarget && urand(1, 100) > 10) // 90% chance - foundTarget = SetCurrentTarget(newTarget, oldTarget); // Extend current target. + //Rpg in city + if (!foundTarget && urand(1, 100) > 90 && bot->GetLevel() > 5) //10% chance + { + foundTarget = SetNpcFlagTarget(newTarget, { UNIT_NPC_FLAG_BANKER,UNIT_NPC_FLAG_BATTLEMASTER,UNIT_NPC_FLAG_AUCTIONEER }); + } - // Dungeon in group - if (!foundTarget && urand(1, 100) > 50) // 50% chance + // PvP activities + bool pvpActivate = false; + if (pvpActivate && !foundTarget && urand(0, 4) && bot->GetLevel() > 50) + { + WorldPosition pos = WorldPosition(bot); + WorldPosition* botPos = &pos; + TravelTarget* target = context->GetValue("travel target")->Get(); + + TravelDestination* dest = ChooseTravelTargetAction::FindDestination(bot, "Tarren Mill"); + if (dest) + { + std::vector points = dest->nextPoint(botPos, true); + if (!points.empty()) + { + target->setTarget(dest, points.front()); + target->setForced(true); + + std::ostringstream out; out << "Traveling to " << dest->getTitle(); + botAI->TellMasterNoFacing(out.str()); + foundTarget = true; + } + } + } + + //Grind for money + if (!foundTarget && AI_VALUE(bool, "should get money")) + { + //Empty mail for money + //if (AI_VALUE(bool, "can get mail")) + //{ + // foundTarget = SetGOTypeTarget(requester, newTarget, GAMEOBJECT_TYPE_MAILBOX, "", false); //Find a mailbox + //} + + if (!foundTarget) + { + // 50% Focus on active quests for money. + if (urand(1, 100) > 50) + { + // 50% Focus on active quests for money. + if (urand(1, 100) > 50) + { + // Turn in quests for money. + foundTarget = SetQuestTarget(newTarget, true, false, true, true); + } + + if (!foundTarget) + { + // Find new (low) level quests + foundTarget = SetQuestTarget(newTarget, false, true, false, false); + } + } + else + { + // Go grind mobs for money + foundTarget = SetGrindTarget(newTarget); + } + } + } + + + //Continue current target. 90% chance + if (!foundTarget && urand(1, 100) > 10) + { + // Extend current target. + foundTarget = SetCurrentTarget(newTarget, oldTarget); + } + + //Get mail 30% chance + //if (!foundTarget && urand(1, 100) > 70) + //{ + // if (AI_VALUE(bool, "can get mail")) + // { + // foundTarget = SetGOTypeTarget(requester, newTarget, GAMEOBJECT_TYPE_MAILBOX, "", false); //Find a mailbox + // } + //} + + //Dungeon in group. 50% chance + if (!foundTarget && urand(1, 100) > 50) + { if (AI_VALUE(bool, "can fight boss")) - foundTarget = SetBossTarget(newTarget); // Go fight a (dungeon boss) - - if (!foundTarget && urand(1, 100) > 5) // 95% chance - foundTarget = SetQuestTarget(newTarget); // Do a target of an active quest. - + { + // Go fight a (dungeon boss) + foundTarget = SetBossTarget(newTarget); + } + } + + //Do quests (start, do, end) 95% chance if (!foundTarget && urand(1, 100) > 5) - foundTarget = SetNewQuestTarget(newTarget); // Find a new quest to do. + { + // Do any nearby + foundTarget = SetQuestTarget(newTarget, false, true, true, true); + } - if (!foundTarget && botAI->HasStrategy("explore", BOT_STATE_NON_COMBAT)) // Explore a unexplored sub-zone. + //Explore a nearby unexplored area. + if (!foundTarget && botAI->HasStrategy("explore", BotState::BOT_STATE_NON_COMBAT) && urand(1, 100) > 90) //10% chance Explore a unexplored sub-zone. + { foundTarget = SetExploreTarget(newTarget); + } - // if (!foundTarget) - // foundTarget = SetRpgTarget(target); + //Just hang with an npc 50% chance + if (!foundTarget && urand(1, 100) > 50) + { + foundTarget = SetRpgTarget(newTarget); + if (foundTarget) + newTarget->setForced(true); + } if (!foundTarget) - SetNullTarget(newTarget); // Idle a bit. + { + foundTarget = SetGrindTarget(newTarget); + } + + // Idle a bit. + if (!foundTarget) + SetNullTarget(newTarget); } void ChooseTravelTargetAction::setNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget) @@ -395,45 +479,57 @@ bool ChooseTravelTargetAction::SetCurrentTarget(TravelTarget* target, TravelTarg return target->isActive(); } -bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCompleted) +bool ChooseTravelTargetAction::SetQuestTarget(TravelTarget* target, bool onlyCompleted, bool newQuests, bool activeQuests, bool completedQuests) { std::vector activeDestinations; std::vector activePoints; - - QuestStatusMap& questMap = bot->getQuestStatusMap(); - WorldPosition botLocation(bot); + bool onlyClassQuest = !urand(0, 10); - // Find destinations related to the active quests. - for (auto& quest : questMap) + if (newQuests) { - if (bot->IsQuestRewarded(quest.first)) - continue; - - uint32 questId = quest.first; - QuestStatusData* questStatus = &quest.second; - - if (onlyCompleted && sObjectMgr->GetQuestTemplate(questId) && - !bot->CanRewardQuest(sObjectMgr->GetQuestTemplate(questId), false)) - continue; - - std::vector questDestinations = - sTravelMgr->getQuestTravelDestinations(bot, questId, botAI->HasRealPlayerMaster(), false, 5000); - std::vector questPoints; - - for (auto& questDestination : questDestinations) + // Prefer new quests near the player at lower levels. + activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false, 400 + bot->GetLevel() * 10); + } + if (activeQuests || completedQuests) + { + QuestStatusMap& questMap = bot->getQuestStatusMap(); + //Find destinations related to the active quests. + for (auto& quest : questMap) { - std::vector destinationPoints = questDestination->getPoints(); - if (!destinationPoints.empty()) - questPoints.insert(questPoints.end(), destinationPoints.begin(), destinationPoints.end()); - } + if (bot->IsQuestRewarded(quest.first)) + continue; - if (getBestDestination(&questDestinations, &questPoints)) - { - activeDestinations.push_back(questDestinations.front()); - activePoints.push_back(questPoints.front()); + uint32 questId = quest.first; + QuestStatusData* questStatus = &quest.second; + const auto questTemplate = sObjectMgr->GetQuestTemplate(questId); + + if (!activeQuests && !bot->CanRewardQuest(questTemplate, false)) + continue; + + if (!completedQuests && bot->CanRewardQuest(questTemplate, false)) + continue; + + //Find quest takers or objectives + std::vector questDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, false, 0); + + if (onlyClassQuest && activeDestinations.size() && questDestinations.size()) //Only do class quests if we have any. + { + if (activeDestinations.front()->GetQuestTemplate()->GetRequiredClasses() && !questTemplate->GetRequiredClasses()) + continue; + + if (!activeDestinations.front()->GetQuestTemplate()->GetRequiredClasses() && questTemplate->GetRequiredClasses()) + activeDestinations.clear(); + } + + activeDestinations.insert(activeDestinations.end(), questDestinations.begin(), questDestinations.end()); } } + if (newQuests && activeDestinations.empty()) + activeDestinations = sTravelMgr->getQuestTravelDestinations(bot, -1, true, false); //If we really don't find any new quests look futher away. + + if (botAI->HasStrategy("debug travel", BotState::BOT_STATE_NON_COMBAT)) + botAI->TellMasterNoFacing(std::to_string(activeDestinations.size()) + " quest destinations found."); if (!getBestDestination(&activeDestinations, &activePoints)) return false; @@ -726,7 +822,7 @@ bool ChooseTravelTargetAction::SetNullTarget(TravelTarget* target) std::vector split(std::string const s, char delim); char* strstri(char const* haystack, char const* needle); -TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name) +TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name, bool zones, bool npcs, bool quests, bool mobs, bool bosses) { PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); @@ -734,32 +830,54 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s std::vector dests; - // Zones - for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true)) + //Quests + if (quests) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getQuestTravelDestinations(bot, 0, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } - // Npcs - for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true)) + //Zones + if (zones) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } - // Mobs - for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true)) + //Npcs + if (npcs) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } - // Bosses - for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true)) + //Mobs + if (mobs) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true, 5000.0f)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } + } + + //Bosses + if (bosses) + { + for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } WorldPosition botPos(bot); @@ -767,13 +885,11 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s if (dests.empty()) return nullptr; - TravelDestination* dest = *std::min_element(dests.begin(), dests.end(), - [botPos](TravelDestination* i, TravelDestination* j) { - return i->distanceTo(const_cast(&botPos)) < - j->distanceTo(const_cast(&botPos)); - }); - - return dest; + return *std::min_element(dests.begin(), dests.end(), + [botPos](TravelDestination* i, TravelDestination* j) + { + return i->distanceTo(const_cast(&botPos)) < j->distanceTo(const_cast(&botPos)); + }); }; bool ChooseTravelTargetAction::isUseful() diff --git a/src/strategy/actions/ChooseTravelTargetAction.h b/src/strategy/actions/ChooseTravelTargetAction.h index 1c7c2e28..7cb99158 100644 --- a/src/strategy/actions/ChooseTravelTargetAction.h +++ b/src/strategy/actions/ChooseTravelTargetAction.h @@ -26,26 +26,23 @@ public: bool Execute(Event event) override; bool isUseful() override; - static TravelDestination* FindDestination(Player* bot, std::string const name); + static TravelDestination* FindDestination(Player* bot, std::string const name, bool zones = true, bool npcs = true, bool quests = true, bool mobs = true, bool bosses = true); protected: void getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget); void setNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget); void ReportTravelTarget(TravelTarget* newTarget, TravelTarget* oldTarget); - bool getBestDestination(std::vector* activeDestinations, - std::vector* activePoints); - + bool getBestDestination(std::vector* activeDestinations, std::vector* activePoints); bool SetGroupTarget(TravelTarget* target); bool SetCurrentTarget(TravelTarget* target, TravelTarget* oldTarget); - bool SetQuestTarget(TravelTarget* target, bool onlyCompleted = false); + bool SetQuestTarget(TravelTarget* target, bool onlyCompleted = false, bool newQuests = true, bool activeQuests = true, bool completedQuests = true); bool SetNewQuestTarget(TravelTarget* target); bool SetRpgTarget(TravelTarget* target); bool SetGrindTarget(TravelTarget* target); bool SetBossTarget(TravelTarget* target); bool SetExploreTarget(TravelTarget* target); - bool SetNpcFlagTarget(TravelTarget* target, std::vector flags, std::string const name = "", - std::vector items = {}); + bool SetNpcFlagTarget(TravelTarget* target, std::vector flags, std::string const name = "", std::vector items = { }); bool SetNullTarget(TravelTarget* target); private: diff --git a/src/strategy/actions/DropQuestAction.cpp b/src/strategy/actions/DropQuestAction.cpp index a6079d7f..a1e2ffcb 100644 --- a/src/strategy/actions/DropQuestAction.cpp +++ b/src/strategy/actions/DropQuestAction.cpp @@ -46,28 +46,44 @@ bool DropQuestAction::Execute(Event event) bot->RemoveRewardedQuest(entry); bot->RemoveActiveQuest(entry, false); + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + const Quest* pQuest = sObjectMgr->GetQuestTemplate(entry); + const std::string text_quest = ChatHelper::FormatQuest(pQuest); + LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), pQuest->GetTitle()); + bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL); + } + botAI->TellMaster("Quest removed"); return true; } bool CleanQuestLogAction::Execute(Event event) { - std::string const link = event.getParam(); - if (botAI->HasActivePlayerMaster()) + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + std::string link = event.getParam(); + if (botAI->HasActivePlayerMaster() || !sRandomPlayerbotMgr->IsRandomBot(bot)) return false; uint8 totalQuests = 0; - - DropQuestType(totalQuests); // Count the total quests - + // Count the total quests + DropQuestType(totalQuests); if (MAX_QUEST_LOG_SIZE - totalQuests > 6) - return true; - - if (AI_VALUE(bool, "can fight equal")) // Only drop gray quests when able to fight proper lvl quests. { - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6); // Drop gray/red quests. - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true); // Drop gray/red quests with progress. - DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true, true); // Drop gray/red completed quests. + // Drop failed quests + DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE, true, true); + return true; + } + + // Only drop gray quests when able to fight proper lvl quests. + if (AI_VALUE(bool, "can fight equal")) + { + // Drop gray/red quests. + DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6); + // Drop gray/red quests with progress. + DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true); + // Drop gray/red completed quests. + DropQuestType(totalQuests, MAX_QUEST_LOG_SIZE - 6, false, true, true); } if (MAX_QUEST_LOG_SIZE - totalQuests > 4) @@ -93,7 +109,19 @@ bool CleanQuestLogAction::Execute(Event event) void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isGreen, bool hasProgress, bool isComplete) { + std::vector slots; for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + slots.push_back(slot); + + if (wantNum < 100) + { + std::random_device rd; + std::mt19937 g(rd()); + + std::shuffle(slots.begin(), slots.end(), g); + } + + for (uint8 slot : slots) { uint32 questId = bot->GetQuestSlotQuestId(slot); if (!questId) @@ -103,12 +131,8 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG if (!quest) continue; - if (quest->GetRequiredClasses() && - (quest->GetRewSpellCast() || quest->GetRewSpell())) // Do not drop class specific quests that learn spells. - continue; - - if (quest->GetRequiredClasses() && - (quest->GetRewSpellCast() || quest->GetRewSpell())) // Do not drop class specific quests that learn spells. + // Do not drop class quest, may be not rewarding gold but important spells + if (quest->GetRequiredClasses()) continue; if (wantNum == 100) @@ -128,13 +152,14 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG continue; } - if (HasProgress(bot, quest) && !hasProgress) + if (HasProgress(bot, quest) && !hasProgress && bot->GetQuestStatus(questId) != QUEST_STATUS_FAILED) continue; if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE && !isComplete) continue; - if (numQuest <= wantNum && bot->GetQuestStatus(questId) != QUEST_STATUS_FAILED) // Always drop failed quests + // Always drop failed quests + if (numQuest <= wantNum && bot->GetQuestStatus(questId) != QUEST_STATUS_FAILED) continue; // Drop quest. @@ -148,6 +173,12 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG numQuest--; + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + const std::string text_quest = ChatHelper::FormatQuest(quest); + LOG_INFO("playerbots", "{} => Quest [ {} ] removed", bot->GetName(), quest->GetTitle()); + bot->Say("Quest [ " + text_quest + " ] removed", LANG_UNIVERSAL); + } botAI->TellMaster("Quest removed" + chat->FormatQuest(quest)); } } diff --git a/src/strategy/actions/GoAction.h b/src/strategy/actions/GoAction.h index 068f15f7..48a1ffa5 100644 --- a/src/strategy/actions/GoAction.h +++ b/src/strategy/actions/GoAction.h @@ -9,6 +9,8 @@ #include "MovementActions.h" class PlayerbotAI; +class TravelDestination; +class WorldPosition; class GoAction : public MovementAction { diff --git a/src/strategy/actions/GuildManagementActions.cpp b/src/strategy/actions/GuildManagementActions.cpp index c1666fb1..591b5252 100644 --- a/src/strategy/actions/GuildManagementActions.cpp +++ b/src/strategy/actions/GuildManagementActions.cpp @@ -9,6 +9,7 @@ #include "GuildPackets.h" #include "Playerbots.h" #include "ServerFacade.h" +#include "BroadcastHelper.h" Player* GuidManageAction::GetPlayer(Event event) { @@ -154,62 +155,141 @@ bool GuildManageNearbyAction::Execute(Event event) if (!player || bot == player) continue; - if (player->GetGuildId()) // Promote or demote nearby members based on chance. + if (player->isDND()) + continue; + + // Promote or demote nearby members based on chance. + if (player->GetGuildId() && player->GetGuildId() == bot->GetGuildId()) { Guild::Member* member = guild->GetMember(player->GetGUID()); uint32 dCount = AI_VALUE(uint32, "death count"); - if ((dCount < 2 || !urand(0, 10)) && guild->GetRankRights(botMember->GetRankId() & GR_RIGHT_PROMOTE)) + if (!urand(0, 30) && dCount < 2 && guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_PROMOTE) { - if (!urand(0, 10)) - { - botAI->DoSpecificAction("guild promote", Event("guild management", guid), true); + BroadcastHelper::BroadcastGuildMemberPromotion(botAI, bot, player); - continue; - } + botAI->DoSpecificAction("guild promote", Event("guild management", guid), true); + continue; } - if ((dCount > 3 || !urand(0, 10)) && guild->GetRankRights(botMember->GetRankId() & GR_RIGHT_DEMOTE)) + if (!urand(0, 30) && dCount > 2 && guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_DEMOTE) { - if (!urand(0, 10)) - { - botAI->DoSpecificAction("guild demote", Event("guild management", guid), true); + BroadcastHelper::BroadcastGuildMemberDemotion(botAI, bot, player); - continue; - } + botAI->DoSpecificAction("guild demote", Event("guild management", guid), true); + continue; } continue; } - if (!(guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_INVITE)) + if (!sPlayerbotAIConfig->randomBotGuildNearby) + return false; + + if (guild->GetMemberSize() > 1000) + return false; + + if ( (guild->GetRankRights(botMember->GetRankId()) & GR_RIGHT_INVITE) == 0) continue; if (player->GetGuildIdInvited()) continue; - PlayerbotAI* botAI = GET_PLAYERBOT_AI(player); + PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); - if (botAI) - { - if (botAI->GetGuilderType() == GuilderType::SOLO && - !botAI->HasRealPlayerMaster()) // Do not invite solo players. - continue; - - if (botAI->HasActivePlayerMaster()) // Do not invite alts of active players. - continue; - } - else - { - if (!sPlayerbotAIConfig->randomBotGroupNearby) - return false; - } - - if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance) + if (!sPlayerbotAIConfig->randomBotInvitePlayer && botAi && botAi->IsRealPlayer()) continue; - if (botAI && botAI->DoSpecificAction("ginvite", Event("guild management", guid))) + if (botAi) + { + if (botAi->GetGuilderType() == GuilderType::SOLO && !botAi->HasRealPlayerMaster()) //Do not invite solo players. + continue; + + if (botAi->HasActivePlayerMaster() && !sRandomPlayerbotMgr->IsRandomBot(player)) //Do not invite alts of active players. + continue; + } + + bool sameGroup = bot->GetGroup() && bot->GetGroup()->IsMember(player->GetGUID()); + + if (!sameGroup && sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->spellDistance) + continue; + + if (sPlayerbotAIConfig->inviteChat && (sRandomPlayerbotMgr->IsRandomBot(bot) || !botAI->HasActivePlayerMaster())) + { + /* std::map placeholders; + placeholders["%name"] = player->GetName(); + placeholders["%members"] = std::to_string(guild->GetMemberSize()); + placeholders["%guildname"] = guild->GetName(); + AreaTableEntry const* current_area = botAI->GetCurrentArea(); + AreaTableEntry const* current_zone = botAI->GetCurrentZone(); + placeholders["%area_name"] = current_area ? current_area->area_name[BroadcastHelper::GetLocale()] : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? current_zone->area_name[BroadcastHelper::GetLocale()] : BOT_TEXT1("string_unknown_area"); + + std::vector lines; + + //TODO - Move these hardcoded texts to sql! + switch ((urand(0, 10) * urand(0, 10)) / 10) + { + case 0: + lines.push_back(BOT_TEXT2("Hey %name do you want to join my guild?", placeholders)); + break; + case 1: + lines.push_back(BOT_TEXT2("Hey man you wanna join my guild %name?", placeholders)); + break; + case 2: + lines.push_back(BOT_TEXT2("I think you would be a good contribution to %guildname. Would you like to join %name?", placeholders)); + break; + case 3: + lines.push_back(BOT_TEXT2("My guild %guildname has %members quality members. Would you like to make it 1 more %name?", placeholders)); + break; + case 4: + lines.push_back(BOT_TEXT2("Hey %name do you want to join %guildname? We have %members members and looking to become number 1 of the server.", placeholders)); + break; + case 5: + lines.push_back(BOT_TEXT2("I'm not really good at smalltalk. Do you wanna join my guild %name/r?", placeholders)); + break; + case 6: + lines.push_back(BOT_TEXT2("Welcome to %zone_name.... do you want to join my guild %name?", placeholders)); + break; + case 7: + lines.push_back(BOT_TEXT2("%name, you should join my guild!", placeholders)); + break; + case 8: + lines.push_back(BOT_TEXT2("%name, I got this guild....", placeholders)); + break; + case 9: + lines.push_back(BOT_TEXT2("You are actually going to join my guild %name?", placeholders)); + lines.push_back(BOT_TEXT2("Haha.. you are the man! We are going to raid Molten...", placeholders)); + break; + case 10: + lines.push_back(BOT_TEXT2("Hey Hey! do you guys wanna join my gild????", placeholders)); + lines.push_back(BOT_TEXT2("We've got a bunch of high levels and we are really super friendly..", placeholders)); + lines.push_back(BOT_TEXT2("..and watch your dog and do your homework...", placeholders)); + lines.push_back(BOT_TEXT2("..and we raid once a week and are working on MC raids...", placeholders)); + lines.push_back(BOT_TEXT2("..and we have more members than just me...", placeholders)); + lines.push_back(BOT_TEXT2("..and please stop I'm lonenly and we can get a ride the whole time...", placeholders)); + lines.push_back(BOT_TEXT2("..and it's really beautifull and I feel like crying...", placeholders)); + lines.push_back(BOT_TEXT2("So what do you guys say are you going to join are you going to join?", placeholders)); + break; + } + + for (auto line : lines) + if (sameGroup) + { + WorldPacket data; + ChatHandler::BuildChatPacket(data, bot->GetGroup()->isRaidGroup() ? CHAT_MSG_RAID : CHAT_MSG_PARTY, line.c_str(), LANG_UNIVERSAL, CHAT_TAG_NONE, bot->GetGUID(), bot->GetName()); + bot->GetGroup()->BroadcastPacket(&data, true); + } + else + bot->Say(line, (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH));*/ + } + + if (botAI->DoSpecificAction("guild invite", Event("guild management", guid), true)) + { + if (sPlayerbotAIConfig->inviteChat) + return true; found++; + } } return found > 0; diff --git a/src/strategy/actions/InviteToGroupAction.cpp b/src/strategy/actions/InviteToGroupAction.cpp index d56fdf3b..1ff8946e 100644 --- a/src/strategy/actions/InviteToGroupAction.cpp +++ b/src/strategy/actions/InviteToGroupAction.cpp @@ -9,6 +9,7 @@ #include "GuildMgr.h" #include "Playerbots.h" #include "ServerFacade.h" +#include "BroadcastHelper.h" bool InviteToGroupAction::Execute(Event event) { @@ -24,9 +25,16 @@ bool InviteToGroupAction::Invite(Player* player) if (!player || !player->IsInWorld()) return false; + if (bot == player) + return false; + if (!GET_PLAYERBOT_AI(player) && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, true, player)) return false; + if (Group* group = player->GetGroup()) + if (!group->isRaidGroup() && group->GetMembersCount() > 4) + group->ConvertToRaid(); + WorldPacket p; uint32 roles_mask = 0; p << player->GetName(); @@ -48,6 +56,9 @@ bool InviteNearbyToGroupAction::Execute(Event event) if (player->GetGroup()) continue; + if (player == bot) + continue; + if (botAI) { if (botAI->GetGrouperType() == GrouperType::SOLO && @@ -69,6 +80,26 @@ bool InviteNearbyToGroupAction::Execute(Event event) if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance) continue; + Group* group = bot->GetGroup(); + Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); + if (!botAI->HasActivePlayerMaster()) + { + if (guild && bot->GetGuildId() == player->GetGuildId()) + { + BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group); + } + else + { + std::map placeholders; + placeholders["%player"] = player->GetName(); + + if (group && group->isRaidGroup()) + bot->Say(BOT_TEXT2("join_raid", placeholders), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); + else + bot->Say(BOT_TEXT2("join_group", placeholders), (bot->GetTeamId() == TEAM_ALLIANCE ? LANG_COMMON : LANG_ORCISH)); + } + } + return Invite(player); } @@ -118,6 +149,8 @@ std::vector InviteGuildToGroupAction::getGuildMembers() bool InviteGuildToGroupAction::Execute(Event event) { + Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); + for (auto& member : getGuildMembers()) { Player* player = member; @@ -160,10 +193,30 @@ bool InviteGuildToGroupAction::Execute(Event event) if (!botAI && sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance) continue; + Group* group = bot->GetGroup(); + BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group); return Invite(player); } return false; } -bool InviteGuildToGroupAction::isUseful() { return bot->GetGuildId() && InviteNearbyToGroupAction::isUseful(); }; +bool InviteGuildToGroupAction::isUseful() +{ + return bot->GetGuildId() && InviteNearbyToGroupAction::isUseful(); +}; + +bool JoinGroupAction::Execute(Event event) +{ + Player* master = event.getOwner(); + Group* group = master->GetGroup(); + + if (group && (group->IsFull() || bot->GetGroup() == group)) + return false; + + if (bot->GetGroup()) + if (!botAI->DoSpecificAction("leave", event, true)) + return false; + + return Invite(bot); +} diff --git a/src/strategy/actions/InviteToGroupAction.h b/src/strategy/actions/InviteToGroupAction.h index 3564ebb0..cf4735c2 100644 --- a/src/strategy/actions/InviteToGroupAction.h +++ b/src/strategy/actions/InviteToGroupAction.h @@ -21,6 +21,14 @@ public: virtual bool Invite(Player* player); }; +class JoinGroupAction : public InviteToGroupAction +{ +public: + JoinGroupAction(PlayerbotAI* ai, std::string name = "join") : InviteToGroupAction(ai, name) {} + bool Execute(Event event) override; + bool isUseful() override { return !bot->IsBeingTeleported(); } +}; + class InviteNearbyToGroupAction : public InviteToGroupAction { public: diff --git a/src/strategy/actions/LeaveGroupAction.cpp b/src/strategy/actions/LeaveGroupAction.cpp index 8acbe2d0..39d0451d 100644 --- a/src/strategy/actions/LeaveGroupAction.cpp +++ b/src/strategy/actions/LeaveGroupAction.cpp @@ -98,13 +98,14 @@ bool LeaveGroupAction::Leave(Player* player) return true; } -bool LeaveFarAwayAction::Execute(Event event) { return Leave(nullptr); } +bool LeaveFarAwayAction::Execute(Event event) +{ + // allow bot to leave party when they want + return Leave(botAI->GetGroupMaster()); +} bool LeaveFarAwayAction::isUseful() { - if (!sPlayerbotAIConfig->randomBotGroupNearby) - return false; - if (bot->InBattleground()) return false; diff --git a/src/strategy/actions/LootAction.cpp b/src/strategy/actions/LootAction.cpp index da5747bc..be48b066 100644 --- a/src/strategy/actions/LootAction.cpp +++ b/src/strategy/actions/LootAction.cpp @@ -15,6 +15,8 @@ #include "PlayerbotAIConfig.h" #include "Playerbots.h" #include "ServerFacade.h" +#include "GuildMgr.h" +#include "BroadcastHelper.h" bool LootAction::Execute(Event event) { @@ -423,31 +425,7 @@ bool StoreLootAction::Execute(Event event) if (proto->Quality >= ITEM_QUALITY_RARE && !urand(0, 1) && botAI->HasStrategy("emote", BOT_STATE_NON_COMBAT)) botAI->PlayEmote(TEXT_EMOTE_CHEER); - if (sPlayerbotAIConfig->randomBotGuildTalk && bot->GetGuildId() && urand(0, 10) && - proto->Quality >= ITEM_QUALITY_RARE) - { - Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); - - if (guild) - { - std::string toSay = ""; - - if (urand(0, 3)) - toSay = "Yay I looted " + chat->FormatItem(proto) + " !"; - else - toSay = "Guess who got a " + chat->FormatItem(proto) + " ? Me !"; - - guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL); - } - } - - // std::ostringstream out; - // out << "Looting " << chat->FormatItem(proto); - // botAI->TellMasterNoFacing(out.str()); - - // ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", proto->ItemId); - // LOG_ERROR("playerbots", "Bot {} is looting {} {} for usage {}.", bot->GetName().c_str(), itemcount, - // proto->Name1.c_str(), usage); + BroadcastHelper::BroadcastLootingItem(botAI, bot, proto); } AI_VALUE(LootObjectStack*, "available loot")->Remove(guid); diff --git a/src/strategy/actions/QueryItemUsageAction.cpp b/src/strategy/actions/QueryItemUsageAction.cpp index 67db84ae..d293d00d 100644 --- a/src/strategy/actions/QueryItemUsageAction.cpp +++ b/src/strategy/actions/QueryItemUsageAction.cpp @@ -12,64 +12,6 @@ bool QueryItemUsageAction::Execute(Event event) { - if (!GetMaster() && !sPlayerbotAIConfig->randomBotSayWithoutMaster) - return false; - - if (!sPlayerbotAIConfig->sayWhenCollectingItems) - return false; - - WorldPacket& data = event.getPacket(); - if (!data.empty()) - { - data.rpos(0); - - ObjectGuid guid; - data >> guid; - if (guid != bot->GetGUID()) - return false; - - uint32 received; - uint32 created; - uint32 isShowChatMessage; - uint32 notUsed; - uint32 itemId; - uint32 suffixFactor; - uint32 itemRandomPropertyId; - uint32 count; - uint32 invCount; - uint8 bagSlot; - - data >> received; // 0=looted, 1=from npc - data >> created; // 0=received, 1=created - data >> isShowChatMessage; // IsShowChatMessage - data >> bagSlot; // item slot, but when added to stack: 0xFFFFFFFF - - data >> notUsed; - data >> itemId; - data >> suffixFactor; - data >> itemRandomPropertyId; - data >> count; - // data >> invCount; // [-ZERO] count of items in inventory - - ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId); - if (!item) - return false; - - bot->Say(QueryItem(item, count, GetCount(item)), LANG_UNIVERSAL); - return true; - } - - std::string const text = event.getParam(); - ItemIds items = chat->parseItems(text); - for (uint32 itemId : items) - { - ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId); - if (!item) - continue; - - botAI->TellMaster(QueryItem(item, 0, GetCount(item))); - } - return true; } diff --git a/src/strategy/actions/QueryQuestAction.cpp b/src/strategy/actions/QueryQuestAction.cpp index f8a22728..8769ef3b 100644 --- a/src/strategy/actions/QueryQuestAction.cpp +++ b/src/strategy/actions/QueryQuestAction.cpp @@ -16,8 +16,10 @@ void QueryQuestAction::TellObjective(std::string const name, uint32 available, u bool QueryQuestAction::Execute(Event event) { + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); Player* bot = botAI->GetBot(); WorldPosition botPos(bot); + WorldPosition* ptr_botpos = &botPos; std::string text = event.getParam(); bool travel = false; @@ -30,7 +32,22 @@ bool QueryQuestAction::Execute(Event event) PlayerbotChatHandler ch(bot); uint32 questId = ch.extractQuestId(text); if (!questId) - return false; + { + for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 logQuest = bot->GetQuestSlotQuestId(slot); + + Quest const* quest = sObjectMgr->GetQuestTemplate(logQuest); + if (!quest) + continue; + + if (text.find(quest->GetTitle()) != std::string::npos) + { + questId = quest->GetQuestId(); + break; + } + } + } for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) { @@ -58,12 +75,7 @@ bool QueryQuestAction::Execute(Event event) std::vector allDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1); - std::sort(allDestinations.begin(), allDestinations.end(), - [botPos](TravelDestination* i, TravelDestination* j) { - return i->distanceTo(const_cast(&botPos)) < - j->distanceTo(const_cast(&botPos)); - }); - + std::sort(allDestinations.begin(), allDestinations.end(), [ptr_botpos](TravelDestination* i, TravelDestination* j) {return i->distanceTo(ptr_botpos) < j->distanceTo(ptr_botpos); }); for (auto dest : allDestinations) { if (limit > 50) @@ -74,7 +86,7 @@ bool QueryQuestAction::Execute(Event event) uint32 tpoints = dest->getPoints(true).size(); uint32 apoints = dest->getPoints().size(); - out << round(dest->distanceTo(const_cast(&botPos))); + out << round(dest->distanceTo(&botPos)); out << " to " << dest->getTitle(); out << " " << apoints; @@ -86,12 +98,6 @@ bool QueryQuestAction::Execute(Event event) if (!dest->isActive(bot)) out << " not active"; - if (dest->isFull(bot)) - out << " crowded"; - - if (dest->isFull(bot)) - out << " crowded"; - botAI->TellMaster(out); limit++; diff --git a/src/strategy/actions/QuestAction.cpp b/src/strategy/actions/QuestAction.cpp index da747337..139033f1 100644 --- a/src/strategy/actions/QuestAction.cpp +++ b/src/strategy/actions/QuestAction.cpp @@ -9,27 +9,49 @@ #include "Event.h" #include "Playerbots.h" #include "ReputationMgr.h" +#include "ServerFacade.h" +#include "BroadcastHelper.h" bool QuestAction::Execute(Event event) { ObjectGuid guid = event.getObject(); Player* master = GetMaster(); - if (!master) - { - if (!guid) - guid = bot->GetTarget(); - } - else - { - if (!guid) - guid = master->GetTarget(); - } if (!guid) - return false; + { + if (!master) + { + guid = bot->GetTarget(); + } + else + { + guid = master->GetTarget(); + } + } - return ProcessQuests(guid); + if (guid) + { + return ProcessQuests(guid); + } + + bool result = false; + GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs"); + for (const auto npc : npcs) + { + Unit* unit = botAI->GetUnit(npc); + if (unit && bot->GetDistance(unit) <= INTERACTION_DISTANCE) + result |= ProcessQuests(unit); + } + std::list gos = AI_VALUE(std::list, "nearest game objects"); + for (const auto go : gos) + { + GameObject* gameobj = botAI->GetGameObject(go); + if (gameobj && bot->GetDistance(gameobj) <= INTERACTION_DISTANCE) + result |= ProcessQuests(gameobj); + } + + return result; } bool QuestAction::CompleteQuest(Player* player, uint32 entry) @@ -69,7 +91,15 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry) int32 creature = pQuest->RequiredNpcOrGo[i]; uint32 creaturecount = pQuest->RequiredNpcOrGoCount[i]; - if (creature > 0) + // TODO check if we need a REQSPELL condition, this methods and sql entry dosent seem implemented ? + /*if (uint32 spell_id = pQuest->GetReqSpell[i]) + { + for (uint16 z = 0; z < creaturecount; ++z) + { + player->CastedCreatureOrGO(creature, ObjectGuid(), spell_id); + } + }*/ + /*else*/ if (creature > 0) { if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature)) for (uint16 z = 0; z < creaturecount; ++z) @@ -105,6 +135,14 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry) player->ModifyMoney(-ReqOrRewMoney); } + const std::string text_quest = ChatHelper::FormatQuest(pQuest); + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), pQuest->GetTitle()); + bot->Say("Quest [ " + text_quest + " ] completed", LANG_UNIVERSAL); + } + botAI->TellMasterNoFacing("Quest completed " + text_quest); + player->CompleteQuest(entry); return true; @@ -129,6 +167,8 @@ bool QuestAction::ProcessQuests(WorldObject* questGiver) if (bot->GetDistance(questGiver) > INTERACTION_DISTANCE && !sPlayerbotAIConfig->syncQuestWithPlayer) { + //if (botAI->HasStrategy("debug", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT)) + botAI->TellError("Cannot talk to quest giver"); return false; } @@ -190,6 +230,7 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver) if (bot->GetQuestStatus(questId) != QUEST_STATUS_NONE && bot->GetQuestStatus(questId) != QUEST_STATUS_REWARDED) { + BroadcastHelper::BroadcastQuestAccepted(botAI, bot, quest); out << "Accepted " << chat->FormatQuest(quest); botAI->TellMaster(out); return true; @@ -199,29 +240,154 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver) out << " " << chat->FormatQuest(quest); botAI->TellMaster(out); + return false; } -bool QuestObjectiveCompletedAction::Execute(Event event) +bool QuestUpdateCompleteAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + + uint32 questId = 0; + p >> questId; + + p.print_storage(); + LOG_INFO("playerbots", "Packet: empty{} questId{}", p.empty(), questId); + + Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId); + if (qInfo) + { + std::map placeholders; + const auto format = ChatHelper::FormatQuest(qInfo); + placeholders["%quest_link"] = format; + + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), qInfo->GetTitle()); + bot->Say("Quest [ " + format + " ] completed", LANG_UNIVERSAL); + } + botAI->TellMasterNoFacing("Quest completed " + format); + BroadcastHelper::BroadcastQuestUpdateComplete(botAI, bot, qInfo); + } + + return true; +} + +/* +* For creature or gameobject +*/ +bool QuestUpdateAddKillAction::Execute(Event event) { WorldPacket p(event.getPacket()); p.rpos(0); uint32 entry, questId, available, required; - ObjectGuid guid; - p >> questId >> entry >> available >> required >> guid; + p >> questId >> entry >> available >> required; - if (entry & 0x80000000) + const Quest* qInfo = sObjectMgr->GetQuestTemplate(questId); + if (qInfo && (entry & 0x80000000)) { entry &= 0x7FFFFFFF; - if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(entry)) - botAI->TellMaster(chat->FormatQuestObjective(info->name, available, required)); + const GameObjectTemplate* info = sObjectMgr->GetGameObjectTemplate(entry); + if (info) + BroadcastHelper::BroadcastQuestUpdateAddKill(botAI, bot, qInfo, available, required, info->name); + } + else if (qInfo) + { + CreatureTemplate const* info = sObjectMgr->GetCreatureTemplate(entry); + if (info) + { + BroadcastHelper::BroadcastQuestUpdateAddKill(botAI, bot, qInfo, available, required, info->Name); + } } else { - if (CreatureTemplate const* info = sObjectMgr->GetCreatureTemplate(entry)) - botAI->TellMaster(chat->FormatQuestObjective(info->Name, available, required)); + std::map placeholders; + placeholders["%quest_id"] = questId; + placeholders["%available"] = available; + placeholders["%required"] = required; + + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT)) + { + LOG_INFO("playerbots", "{} => {}", bot->GetName(), BOT_TEXT2("%available/%required for questId: %quest_id", placeholders)); + botAI->Say(BOT_TEXT2("%available/%required for questId: %quest_id", placeholders)); + } + + botAI->TellMasterNoFacing(BOT_TEXT2("%available/%required for questId: %quest_id", placeholders)); + } + + return false; +} + +bool QuestUpdateAddItemAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + + uint32 itemId, count; + p >> itemId >> count; + + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + auto const* itemPrototype = sObjectMgr->GetItemTemplate(itemId); + if (itemPrototype) + { + std::map placeholders; + placeholders["%item_link"] = botAI->GetChatHelper()->FormatItem(itemPrototype); + uint32 availableItemsCount = botAI->GetInventoryItemsCountWithId(itemId); + placeholders["%quest_obj_available"] = std::to_string(availableItemsCount); + + for (const auto& pair : botAI->GetCurrentQuestsRequiringItemId(itemId)) + { + placeholders["%quest_link"] = chat->FormatQuest(pair.first); + uint32 requiredItemsCount = pair.second; + placeholders["%quest_obj_required"] = std::to_string(requiredItemsCount); + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT)) + { + const auto text = BOT_TEXT2("%quest_link - %item_link %quest_obj_available/%quest_obj_required", placeholders); + botAI->Say(text); + LOG_INFO("playerbots", "{} => {}", bot->GetName(), text); + } + + BroadcastHelper::BroadcastQuestUpdateAddItem(botAI, bot, pair.first, availableItemsCount, requiredItemsCount, itemPrototype); + } + } + + return false; +} + +bool QuestUpdateFailedAction::Execute(Event event) +{ + //opcode SMSG_QUESTUPDATE_FAILED is never sent...(yet?) + return false; +} + +bool QuestUpdateFailedTimerAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + + uint32 questId; + p >> questId; + + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + + Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId); + + if (qInfo) + { + std::map placeholders; + placeholders["%quest_link"] = botAI->GetChatHelper()->FormatQuest(qInfo); + botAI->TellMaster(BOT_TEXT2("Failed timer for %quest_link, abandoning", placeholders)); + BroadcastHelper::BroadcastQuestUpdateFailedTimer(botAI, bot, qInfo); + } + else + { + botAI->TellMaster("Failed timer for " + std::to_string(questId)); } - return true; + //drop quest + bot->AbandonQuest(questId); + + return false; } diff --git a/src/strategy/actions/QuestAction.h b/src/strategy/actions/QuestAction.h index 24a49b81..1d2497e0 100644 --- a/src/strategy/actions/QuestAction.h +++ b/src/strategy/actions/QuestAction.h @@ -8,6 +8,7 @@ #include "Action.h" #include "Object.h" +#include "QuestDef.h" class ObjectGuid; class Quest; @@ -19,23 +20,49 @@ class Object; class QuestAction : public Action { public: - QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) {} - + QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { } bool Execute(Event event) override; protected: bool CompleteQuest(Player* player, uint32 entry); - virtual void ProcessQuest(Quest const* quest, Object* questGiver) = 0; + virtual bool ProcessQuest(Quest const* quest, Object* questGiver) = 0; bool AcceptQuest(Quest const* quest, ObjectGuid questGiver); bool ProcessQuests(ObjectGuid questGiver); bool ProcessQuests(WorldObject* questGiver); }; -class QuestObjectiveCompletedAction : public Action +class QuestUpdateCompleteAction : public Action { public: - QuestObjectiveCompletedAction(PlayerbotAI* botAI) : Action(botAI, "quest objective completed") {} + QuestUpdateCompleteAction(PlayerbotAI* ai) : Action(ai, "quest update complete") {} + bool Execute(Event event) override; +}; +class QuestUpdateAddKillAction : public Action +{ +public: + QuestUpdateAddKillAction(PlayerbotAI* ai) : Action(ai, "quest update add kill") {} + bool Execute(Event event) override; +}; + +class QuestUpdateAddItemAction : public Action +{ +public: + QuestUpdateAddItemAction(PlayerbotAI* ai) : Action(ai, "quest update add item") {} + bool Execute(Event event) override;; +}; + +class QuestUpdateFailedAction : public Action +{ +public: + QuestUpdateFailedAction(PlayerbotAI* ai) : Action(ai, "quest update failed") {} + bool Execute(Event event) override; +}; + +class QuestUpdateFailedTimerAction : public Action +{ +public: + QuestUpdateFailedTimerAction(PlayerbotAI* ai) : Action(ai, "quest update failed timer") {} bool Execute(Event event) override; }; diff --git a/src/strategy/actions/RpgAction.cpp b/src/strategy/actions/RpgAction.cpp index 3723904d..c300221c 100644 --- a/src/strategy/actions/RpgAction.cpp +++ b/src/strategy/actions/RpgAction.cpp @@ -14,6 +14,7 @@ #include "Formations.h" #include "Playerbots.h" #include "ServerFacade.h" +#include "RpgSubActions.h" bool RpgAction::Execute(Event event) { @@ -44,65 +45,109 @@ bool RpgAction::isUseful() { return AI_VALUE(GuidPosition, "rpg target"); } bool RpgAction::SetNextRpgAction() { - Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg"); - + Strategy* rpgStrategy; std::vector actions; std::vector relevances; std::vector triggerNodes; - rpgStrategy->InitTriggers(triggerNodes); - for (auto& triggerNode : triggerNodes) + + for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies()) { - Trigger* trigger = context->GetTrigger(triggerNode->getName()); - if (trigger) + if (strategy.find("rpg") == std::string::npos) + continue; + + rpgStrategy = botAI->GetAiObjectContext()->GetStrategy(strategy); + + rpgStrategy->InitTriggers(triggerNodes); + + for (auto& triggerNode : triggerNodes) { - triggerNode->setTrigger(trigger); + Trigger* trigger = context->GetTrigger(triggerNode->getName()); - NextAction** nextActions = triggerNode->getHandlers(); - - trigger = triggerNode->getTrigger(); - - bool isChecked = false; - for (int32 i = 0; i < NextAction::size(nextActions); i++) + if (trigger) { - NextAction* nextAction = nextActions[i]; - if (nextAction->getRelevance() > 2.0f) - continue; + triggerNode->setTrigger(trigger); - if (!isChecked && !trigger->IsActive()) - break; + NextAction** nextActions = triggerNode->getHandlers(); - isChecked = true; + Trigger* trigger = triggerNode->getTrigger(); - Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName()); + bool isChecked = false; - if (!action->isPossible() || !action->isUseful()) - continue; + for (int32 i = 0; i < NextAction::size(nextActions); i++) + { + NextAction* nextAction = nextActions[i]; - actions.push_back(action); - relevances.push_back((nextAction->getRelevance() - 1) * 1000); + if (nextAction->getRelevance() > 2.0f) + continue; + + if (!isChecked && !trigger->IsActive()) + break; + + isChecked = true; + + Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName()); + if (!dynamic_cast(action) || !action->isPossible() || !action->isUseful()) + continue; + + actions.push_back(action); + relevances.push_back((nextAction->getRelevance() - 1) * 1000); + } + NextAction::destroy(nextActions); } - - NextAction::destroy(nextActions); } + + for (const auto i : triggerNodes) + { + delete i; + } + triggerNodes.clear(); } if (actions.empty()) return false; + if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_NON_COMBAT)) + { + std::vector> sortedActions; + + for (int i = 0; i < actions.size(); i++) + sortedActions.push_back(std::make_pair(actions[i], relevances[i])); + + std::sort(sortedActions.begin(), sortedActions.end(), [](std::pairi, std::pair j) {return i.second > j.second; }); + + std::stringstream ss; + ss << "------" << chat->FormatWorldobject(AI_VALUE(GuidPosition, "rpg target").GetWorldObject()) << "------"; + bot->Say(ss.str(), LANG_UNIVERSAL); + botAI->TellMasterNoFacing(ss.str()); + + for (auto action : sortedActions) + { + std::ostringstream out; + + out << " " << action.first->getName() << " " << action.second; + + botAI->TellMasterNoFacing(out); + } + } + std::mt19937 gen(time(0)); + sTravelMgr->weighted_shuffle(actions.begin(), actions.end(), relevances.begin(), relevances.end(), gen); Action* action = actions.front(); - for (std::vector::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++) + if ((botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_NON_COMBAT))) { - TriggerNode* trigger = *i; - delete trigger; - } + std::ostringstream out; + out << "do: "; + out << chat->FormatWorldobject(AI_VALUE(GuidPosition, "rpg target").GetWorldObject()); - triggerNodes.clear(); + out << " " << action->getName(); + + botAI->TellMasterNoFacing(out); + } SET_AI_VALUE(std::string, "next rpg action", action->getName()); diff --git a/src/strategy/actions/RpgAction.h b/src/strategy/actions/RpgAction.h index deba34e7..7751df17 100644 --- a/src/strategy/actions/RpgAction.h +++ b/src/strategy/actions/RpgAction.h @@ -15,16 +15,13 @@ class Unit; class RpgAction : public MovementAction { public: - RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) {} - + RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) { } bool Execute(Event event) override; bool isUseful() override; protected: virtual bool SetNextRpgAction(); - typedef void (RpgAction::*RpgElement)(ObjectGuid guid); - bool AddIgnore(ObjectGuid guid); bool RemIgnore(ObjectGuid guid); bool HasIgnore(ObjectGuid guid); @@ -33,8 +30,7 @@ protected: class CRpgAction : public RpgAction { public: - CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") {} - + CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") { } bool isUseful() override; }; diff --git a/src/strategy/actions/SayAction.cpp b/src/strategy/actions/SayAction.cpp index a64e2a5e..afd18353 100644 --- a/src/strategy/actions/SayAction.cpp +++ b/src/strategy/actions/SayAction.cpp @@ -3,9 +3,11 @@ * and/or modify it under version 2 of the License, or (at your option), any later version. */ +#include "AiFactory.h" #include "SayAction.h" #include +#include #include "ChannelMgr.h" #include "Event.h" @@ -85,8 +87,8 @@ bool SayAction::Execute(Event event) if (bot->GetMap()) { - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetAreaId())) - placeholders[""] = area->area_name[0]; + if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()))) + placeholders[""] = zone->area_name[sWorld->GetDefaultDbcLocale()]; } // set delay before next say @@ -155,8 +157,7 @@ bool SayAction::isUseful() return (time(nullptr) - lastSaid) > 30; } -void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guid2, std::string msg, - std::string chanName, std::string name) +void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name) { ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand std::string respondsText = ""; @@ -193,15 +194,389 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 return; } - ObjectGuid receiver = sCharacterCache->GetCharacterGuidByName(name); - Player* plr = ObjectAccessor::FindPlayer(receiver); + ChatChannelSource chatChannelSource = GET_PLAYERBOT_AI(bot)->GetChatChannelSource(bot, type, chanName); + if ( (msg.starts_with("LFG") || msg.starts_with("LFM")) && HandleLFGQuestsReply(bot, chatChannelSource, msg, name)) + { + return; + } + + if (msg.starts_with("WTB") && HandleWTBItemsReply(bot, chatChannelSource, msg, name)) + { + return; + } + + //toxic links + if (msg.starts_with(sPlayerbotAIConfig->toxicLinksPrefix) + && (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).size() > 0 || GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg).size() > 0)) + { + HandleToxicLinksReply(bot, chatChannelSource, msg, name); + return; + } + + //thunderfury + if (GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg).count(19019)) + { + HandleThunderfuryReply(bot, chatChannelSource, msg, name); + return; + } + + auto messageRepy = GenerateReplyMessage(bot, msg, guid1, name); + SendGeneralResponse(bot, chatChannelSource, messageRepy, name); +} + +bool ChatReplyAction::HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) +{ + std::map placeholders; + const auto thunderfury = sObjectMgr->GetItemTemplate(19019); + placeholders["%thunderfury_link"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(thunderfury); + + std::string responseMessage = BOT_TEXT2("thunderfury_spam", placeholders); + + switch (chatChannelSource) + { + case ChatChannelSource::SRC_WORLD: + { + GET_PLAYERBOT_AI(bot)->SayToWorld(responseMessage); + break; + } + case ChatChannelSource::SRC_GENERAL: + { + GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::GENERAL); + break; + } + } + + GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(0) + urand(5, 25)); + return true; +} + +bool ChatReplyAction::HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) +{ + //quests + std::vector incompleteQuests; + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + continue; + + QuestStatus status = bot->GetQuestStatus(questId); + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_NONE) + incompleteQuests.push_back(questId); + } + + //items + std::vector botItems = GET_PLAYERBOT_AI(bot)->GetInventoryAndEquippedItems(); + + std::map placeholders; + placeholders["%random_inventory_item_link"] = botItems.size() > 0 ? GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(botItems[rand() % botItems.size()]->GetTemplate()) : BOT_TEXT1("string_empty_link"); + placeholders["%prefix"] = sPlayerbotAIConfig->toxicLinksPrefix; + + if (incompleteQuests.size() > 0) + { + Quest const* quest = sObjectMgr->GetQuestTemplate(incompleteQuests[rand() % incompleteQuests.size()]); + placeholders["%random_taken_quest_or_item_link"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatQuest(quest); + } + else + { + placeholders["%random_taken_quest_or_item_link"] = placeholders["%random_inventory_item_link"]; + } + + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea(); + AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone(); + placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + + switch (chatChannelSource) + { + case ChatChannelSource::SRC_WORLD: + { + GET_PLAYERBOT_AI(bot)->SayToWorld(BOT_TEXT2("suggest_toxic_links", placeholders)); + break; + } + case ChatChannelSource::SRC_GENERAL: + { + GET_PLAYERBOT_AI(bot)->SayToChannel(BOT_TEXT2("suggest_toxic_links", placeholders), ChatChannelId::GENERAL); + break; + } + case ChatChannelSource::SRC_GUILD: + { + GET_PLAYERBOT_AI(bot)->SayToGuild(BOT_TEXT2("suggest_toxic_links", placeholders)); + break; + } + } + + GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(0) + urand(5, 60)); + + return true; +} +bool ChatReplyAction::HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) +{ + auto messageItemIds = GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllItemIds(msg); + + if (messageItemIds.empty()) + { + return false; + } + + std::set matchingItemIds; + + for (auto messageItemId : messageItemIds) + { + if (GET_PLAYERBOT_AI(bot)->HasItemInInventory(messageItemId)) + { + matchingItemIds.insert(messageItemId); + } + } + + if (!matchingItemIds.empty()) + { + std::map placeholders; + placeholders["%other_name"] = name; + AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea(); + AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone(); + placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + placeholders["%formatted_item_links"] = ""; + + for (auto matchingItemId : matchingItemIds) + { + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(matchingItemId); + placeholders["%formatted_item_links"] += GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatItem(proto, GET_PLAYERBOT_AI(bot)->GetInventoryItemsCountWithId(matchingItemId)); + placeholders["%formatted_item_links"] += " "; + } + + switch (chatChannelSource) + { + case ChatChannelSource::SRC_WORLD: + { + //may reply to the same channel or whisper + if (urand(0, 1)) + { + std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders); + GET_PLAYERBOT_AI(bot)->SayToWorld(responseMessage); + } + else + { + std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders); + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + } + break; + } + case ChatChannelSource::SRC_GENERAL: + { + //may reply to the same channel or whisper + if (urand(0, 1)) + { + std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders); + GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::GENERAL); + } + else + { + std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders); + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + } + break; + } + case ChatChannelSource::SRC_TRADE: + { + //may reply to the same channel or whisper + if (urand(0, 1)) + { + std::string responseMessage = BOT_TEXT2("response_wtb_items_channel", placeholders); + GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::TRADE); + } + else + { + std::string responseMessage = BOT_TEXT2("response_wtb_items_whisper", placeholders); + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + } + break; + } + } + GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(0) + urand(5, 60)); + } + + return true; +} +bool ChatReplyAction::HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name) +{ + auto messageQuestIds = GET_PLAYERBOT_AI(bot)->GetChatHelper()->ExtractAllQuestIds(msg); + + if (messageQuestIds.empty()) + { + return false; + } + + auto botQuestIds = GET_PLAYERBOT_AI(bot)->GetAllCurrentQuestIds(); + std::set matchingQuestIds; + for (auto botQuestId : botQuestIds) + { + if (messageQuestIds.count(botQuestId) != 0) + { + matchingQuestIds.insert(botQuestId); + } + } + + if (!matchingQuestIds.empty()) + { + std::map placeholders; + placeholders["%other_name"] = name; + AreaTableEntry const* current_area = GET_PLAYERBOT_AI(bot)->GetCurrentArea(); + AreaTableEntry const* current_zone = GET_PLAYERBOT_AI(bot)->GetCurrentZone(); + placeholders["%area_name"] = current_area ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_area) : BOT_TEXT1("string_unknown_area"); + placeholders["%zone_name"] = current_zone ? GET_PLAYERBOT_AI(bot)->GetLocalizedAreaName(current_zone) : BOT_TEXT1("string_unknown_area"); + placeholders["%my_class"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatClass(bot->getClass()); + placeholders["%my_race"] = GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatRace(bot->getRace()); + placeholders["%my_level"] = std::to_string(bot->GetLevel()); + placeholders["%my_role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + placeholders["%quest_links"] = ""; + for (auto matchingQuestId : matchingQuestIds) + { + Quest const* quest = sObjectMgr->GetQuestTemplate(matchingQuestId); + placeholders["%quest_links"] += GET_PLAYERBOT_AI(bot)->GetChatHelper()->FormatQuest(quest); + } + + switch (chatChannelSource) + { + case ChatChannelSource::SRC_WORLD: + { + //may reply to the same channel or whisper + if (urand(0, 1)) + { + std::string responseMessage = BOT_TEXT2("response_lfg_quests_channel", placeholders); + GET_PLAYERBOT_AI(bot)->SayToWorld(responseMessage); + } + else + { + std::string responseMessage = BOT_TEXT2("response_lfg_quests_whisper", placeholders); + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + } + break; + } + case ChatChannelSource::SRC_GENERAL: + { + //may reply to the same channel or whisper + if (urand(0, 1)) + { + std::string responseMessage = BOT_TEXT2("response_lfg_quests_channel", placeholders); + GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::GENERAL); + } + else + { + std::string responseMessage = BOT_TEXT2("response_lfg_quests_whisper", placeholders); + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + } + break; + } + case ChatChannelSource::SRC_LOOKING_FOR_GROUP: + { + //do not reply to the chat + //may whisper + std::string responseMessage = BOT_TEXT2("response_lfg_quests_whisper", placeholders); + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + break; + } + } + GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(0) + urand(5, 25)); + } + + return true; +} + +bool ChatReplyAction::SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string& responseMessage, std::string& name) +{ + // send responds + switch (chatChannelSource) + { + case ChatChannelSource::SRC_WORLD: + { + //may reply to the same channel or whisper + GET_PLAYERBOT_AI(bot)->SayToWorld(responseMessage); + break; + } + case ChatChannelSource::SRC_GENERAL: + { + //may reply to the same channel or whisper + GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::GENERAL); + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + break; + } + case ChatChannelSource::SRC_TRADE: + { + //do not reply to the chat + //may whisper + break; + } + case ChatChannelSource::SRC_LOCAL_DEFENSE: + { + //may reply to the same channel or whisper + GET_PLAYERBOT_AI(bot)->SayToChannel(responseMessage, ChatChannelId::LOCAL_DEFENSE); + break; + } + case ChatChannelSource::SRC_WORLD_DEFENSE: + { + //may whisper + break; + } + case ChatChannelSource::SRC_LOOKING_FOR_GROUP: + { + //do not reply to the chat + break; + } + case ChatChannelSource::SRC_GUILD_RECRUITMENT: + { + //do not reply to the chat + break; + } + case ChatChannelSource::SRC_WHISPER: + { + GET_PLAYERBOT_AI(bot)->Whisper(responseMessage, name); + break; + } + case ChatChannelSource::SRC_SAY: + { + GET_PLAYERBOT_AI(bot)->Say(responseMessage); + break; + } + case ChatChannelSource::SRC_YELL: + { + GET_PLAYERBOT_AI(bot)->Yell(responseMessage); + break; + } + case ChatChannelSource::SRC_GUILD: + { + GET_PLAYERBOT_AI(bot)->SayToGuild(responseMessage); + break; + } + default: + break; + } + GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("last said", "chat")->Set(time(0) + urand(5, 25)); + + return true; +} + +std::string ChatReplyAction::GenerateReplyMessage(Player* bot, std::string& incomingMessage, uint32& guid1, std::string& name) +{ + ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand + + std::string respondsText = ""; // Chat Logic int32 verb_pos = -1; int32 verb_type = -1; int32 is_quest = 0; bool found = false; - std::stringstream text(msg); + std::stringstream text(incomingMessage); std::string segment; std::vector word; while (std::getline(text, segment, ' ')) @@ -215,7 +590,7 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 word.push_back(""); } - if (msg.find("?") != std::string::npos) + if (incomingMessage.find("?") != std::string::npos) is_quest = 1; if (word[0].find("what") != std::string::npos) is_quest = 2; @@ -232,15 +607,17 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 for (uint32 i = 0; i < 8; i++) { // blame gm with chat tag - if (plr && plr->isGMChat()) + if (Player* plr = ObjectAccessor::FindPlayer(ObjectGuid(HighGuid::Player, guid1))) { - replyType = REPLY_ADMIN_ABUSE; - found = true; - break; + if (plr->isGMChat()) + { + replyType = REPLY_ADMIN_ABUSE; + found = true; + break; + } } - if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup" || word[i] == "salut" || - word[i] == "plop" || word[i] == "yo") + if (word[i] == "hi" || word[i] == "hey" || word[i] == "hello" || word[i] == "wazzup") { replyType = REPLY_HELLO; found = true; @@ -249,28 +626,26 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 if (verb_type < 4) { - if (word[i] == "am" || word[i] == "are" || word[i] == "is" || word[i] == "suis" || word[i] == "as" || - word[i] == "est" || word[i] == "dois" || word[i] == "doit") + if (word[i] == "am" || word[i] == "are" || word[i] == "is") { verb_pos = i; verb_type = 2; // present if (verb_pos == 0) is_quest = 1; } - else if (word[i] == "will" || word[i] == "vais" || word[i] == "sera") + else if (word[i] == "will") { verb_pos = i; verb_type = 3; // future } - else if (word[i] == "was" || word[i] == "were" || word[i] == "été" || word[i] == "ai" || word[i] == "eu" || - word[i] == "étions" || word[i] == "etion") + else if (word[i] == "was" || word[i] == "were") { verb_pos = i; verb_type = 1; // past } - else if (word[i] == "shut" || word[i] == "noob" || word[i] == "tg") + else if (word[i] == "shut" || word[i] == "noob") { - if (msg.find(bot->GetName()) == std::string::npos) + if (incomingMessage.find(bot->GetName()) == std::string::npos) { continue; // not react uint32 rnd = urand(0, 2); @@ -300,298 +675,188 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 { switch (is_quest) { + case 2: + { + uint32 rnd = urand(0, 3); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "i dont know what"; + break; + case 1: + msg = "i dont know %s"; + break; case 2: + msg = "who cares"; + break; + case 3: + msg = "afraid that was before i was around or paying attention"; + break; + } + + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } + case 3: + { + uint32 rnd = urand(0, 4); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "nobody"; + break; + case 1: + msg = "we all do"; + break; + case 2: + msg = "perhaps its you, %s"; + break; + case 3: + msg = "dunno %s"; + break; + case 4: + msg = "is it me?"; + break; + } + + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } + case 4: + { + uint32 rnd = urand(0, 6); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "soon perhaps %s"; + break; + case 1: + msg = "probably later"; + break; + case 2: + msg = "never"; + break; + case 3: + msg = "what do i look like, a psychic?"; + break; + case 4: + msg = "a few minutes, maybe an hour ... years?"; + break; + case 5: + msg = "when? good question %s"; + break; + case 6: + msg = "dunno %s"; + break; + } + + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } + case 5: + { + uint32 rnd = urand(0, 6); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "really want me to answer that?"; + break; + case 1: + msg = "on the map?"; + break; + case 2: + msg = "who cares"; + break; + case 3: + msg = "afk?"; + break; + case 4: + msg = "none of your buisiness where"; + break; + case 5: + msg = "yeah, where?"; + break; + case 6: + msg = "dunno %s"; + break; + } + + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } + case 6: + { + uint32 rnd = urand(0, 6); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "dunno %s"; + break; + case 1: + msg = "why? just because %s"; + break; + case 2: + msg = "why is the sky blue?"; + break; + case 3: + msg = "dont ask me %s, im just a bot"; + break; + case 4: + msg = "your asking the wrong person"; + break; + case 5: + msg = "who knows?"; + break; + case 6: + msg = "dunno %s"; + break; + } + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } + default: + { + switch (verb_type) + { + case 1: { uint32 rnd = urand(0, 3); std::string msg = ""; switch (rnd) { - case 0: - msg = "i dont know what"; - break; - case 1: - msg = "i dont know %s"; - break; - case 2: - msg = "who cares"; - break; - case 3: - msg = "afraid that was before i was around or paying attention"; - break; - } - - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - case 3: - { - uint32 rnd = urand(0, 4); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "nobody"; - break; - case 1: - msg = "we all do"; - break; - case 2: - msg = "perhaps its you, %s"; - break; - case 3: - msg = "dunno %s"; - break; - case 4: - msg = "is it me?"; - break; - } - - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - case 4: - { - uint32 rnd = urand(0, 6); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "soon perhaps %s"; - break; - case 1: - msg = "probably later"; - break; - case 2: - msg = "never"; - break; - case 3: - msg = "what do i look like, a psychic?"; - break; - case 4: - msg = "a few minutes, maybe an hour ... years?"; - break; - case 5: - msg = "when? good question %s"; - break; - case 6: - msg = "dunno %s"; - break; - } - - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - case 5: - { - uint32 rnd = urand(0, 6); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "really want me to answer that?"; - break; - case 1: - msg = "on the map?"; - break; - case 2: - msg = "who cares"; - break; - case 3: - msg = "afk?"; - break; - case 4: - msg = "none of your buisiness where"; - break; - case 5: - msg = "yeah, where?"; - break; - case 6: - msg = "dunno %s"; - break; - } - - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - case 6: - { - uint32 rnd = urand(0, 6); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "dunno %s"; - break; - case 1: - msg = "why? just because %s"; - break; - case 2: - msg = "why is the sky blue?"; - break; - case 3: - msg = "dont ask me %s, im just a bot"; - break; - case 4: - msg = "your asking the wrong person"; - break; - case 5: - msg = "who knows?"; - break; - case 6: - msg = "dunno %s"; - break; - } - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - default: - { - switch (verb_type) - { - case 1: - { - uint32 rnd = urand(0, 3); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "its true, " + word[verb_pos + 1] + " " + word[verb_pos] + " " + - word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + - word[verb_pos + 4]; - break; - case 1: - msg = "ya %s but thats in the past"; - break; - case 2: - msg = "nah, but " + word[verb_pos + 1] + " will " + word[verb_pos + 3] + - " again though %s"; - break; - case 3: - msg = "afraid that was before i was around or paying attention"; - break; - } - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - case 2: - { - uint32 rnd = urand(0, 6); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "its true, " + word[verb_pos + 1] + " " + word[verb_pos] + " " + - word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + - word[verb_pos + 5]; - break; - case 1: - msg = "ya %s thats true"; - break; - case 2: - msg = "maybe " + word[verb_pos + 1] + " " + word[verb_pos] + " " + word[verb_pos + 2] + - " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + word[verb_pos + 5]; - break; - case 3: - msg = "dunno %s"; - break; - case 4: - msg = "i dont think so %s"; - break; - case 5: - msg = "yes"; - break; - case 6: - msg = "no"; - break; - } - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - case 3: - { - uint32 rnd = urand(0, 8); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "dunno %s"; - break; - case 1: - msg = "beats me %s"; - break; - case 2: - msg = "how should i know %s"; - break; - case 3: - msg = "dont ask me %s, im just a bot"; - break; - case 4: - msg = "your asking the wrong person"; - break; - case 5: - msg = "what do i look like, a psychic?"; - break; - case 6: - msg = "sure %s"; - break; - case 7: - msg = "i dont think so %s"; - break; - case 8: - msg = "maybe"; - break; - } - msg = std::regex_replace(msg, std::regex("%s"), name); - respondsText = msg; - found = true; - break; - } - } - } - } - } - else if (!found) - { - switch (verb_type) - { - case 1: - { - uint32 rnd = urand(0, 2); - std::string msg = ""; - - switch (rnd) - { - case 0: - msg = "yeah %s, the key word being " + word[verb_pos] + " " + word[verb_pos + 1]; - break; - case 1: - msg = "ya %s but thats in the past"; - break; - case 2: - msg = word[verb_pos - 1] + " will " + word[verb_pos + 1] + " again though %s"; - break; + case 0: + msg = "its true, " + word[verb_pos + 1] + " " + word[verb_pos] + " " + word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + word[verb_pos + 4]; + break; + case 1: + msg = "ya %s but thats in the past"; + break; + case 2: + msg = "nah, but " + word[verb_pos + 1] + " will " + word[verb_pos + 3] + " again though %s"; + break; + case 3: + msg = "afraid that was before i was around or paying attention"; + break; } msg = std::regex_replace(msg, std::regex("%s"), name); respondsText = msg; @@ -600,20 +865,32 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 } case 2: { - uint32 rnd = urand(0, 2); + uint32 rnd = urand(0, 6); std::string msg = ""; switch (rnd) { - case 0: - msg = "%s, what do you mean " + word[verb_pos + 1] + "?"; - break; - case 1: - msg = "%s, what is a " + word[verb_pos + 1] + "?"; - break; - case 2: - msg = "yeah i know " + word[verb_pos - 1] + " is a " + word[verb_pos + 1]; - break; + case 0: + msg = "its true, " + word[verb_pos + 1] + " " + word[verb_pos] + " " + word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + word[verb_pos + 5]; + break; + case 1: + msg = "ya %s thats true"; + break; + case 2: + msg = "maybe " + word[verb_pos + 1] + " " + word[verb_pos] + " " + word[verb_pos + 2] + " " + word[verb_pos + 3] + " " + word[verb_pos + 4] + " " + word[verb_pos + 5]; + break; + case 3: + msg = "dunno %s"; + break; + case 4: + msg = "i dont think so %s"; + break; + case 5: + msg = "yes"; + break; + case 6: + msg = "no"; + break; } msg = std::regex_replace(msg, std::regex("%s"), name); respondsText = msg; @@ -622,34 +899,125 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 } case 3: { - uint32 rnd = urand(0, 1); + uint32 rnd = urand(0, 8); std::string msg = ""; switch (rnd) { - case 0: - msg = "are you sure thats going to happen %s?"; - break; - case 1: - msg = "%s, what will happen %s?"; - break; - case 2: - msg = "are you saying " + word[verb_pos - 1] + " will " + word[verb_pos + 1] + " " + - word[verb_pos + 2] + " %s?"; - break; + case 0: + msg = "dunno %s"; + break; + case 1: + msg = "beats me %s"; + break; + case 2: + msg = "how should i know %s"; + break; + case 3: + msg = "dont ask me %s, im just a bot"; + break; + case 4: + msg = "your asking the wrong person"; + break; + case 5: + msg = "what do i look like, a psychic?"; + break; + case 6: + msg = "sure %s"; + break; + case 7: + msg = "i dont think so %s"; + break; + case 8: + msg = "maybe"; + break; } msg = std::regex_replace(msg, std::regex("%s"), name); respondsText = msg; found = true; break; } + } + } + } + } + else if (!found) + { + switch (verb_type) + { + case 1: + { + uint32 rnd = urand(0, 2); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "yeah %s, the key word being " + word[verb_pos] + " " + word[verb_pos + 1]; + break; + case 1: + msg = "ya %s but thats in the past"; + break; + case 2: + msg = word[verb_pos - 1] + " will " + word[verb_pos + 1] + " again though %s"; + break; + } + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } + case 2: + { + uint32 rnd = urand(0, 2); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "%s, what do you mean " + word[verb_pos + 1] + "?"; + break; + case 1: + msg = "%s, what is a " + word[verb_pos + 1] + "?"; + break; + case 2: + msg = "yeah i know " + word[verb_pos ? verb_pos - 1 : verb_pos + 1] + " is a " + word[verb_pos + 1]; + break; + } + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } + case 3: + { + uint32 rnd = urand(0, 1); + std::string msg = ""; + + switch (rnd) + { + case 0: + msg = "are you sure thats going to happen %s?"; + break; + case 1: + msg = "%s, what will happen %s?"; + break; + case 2: + msg = "are you saying " + word[verb_pos - 1] + " will " + word[verb_pos + 1] + " " + word[verb_pos + 2] + " %s?"; + break; + } + msg = std::regex_replace(msg, std::regex("%s"), name); + respondsText = msg; + found = true; + break; + } } } if (!found) { // Name Responds - if (msg.find(bot->GetName()) != std::string::npos) + if (incomingMessage.find(bot->GetName()) != std::string::npos) { replyType = REPLY_NAME; found = true; @@ -661,81 +1029,16 @@ void ChatReplyAction::ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 } } - // send responds - // - if (found) + // load text if needed + if (respondsText.empty()) { - // load text if needed - if (respondsText.empty()) - { - respondsText = BOT_TEXT2(replyType, name); - } - const char* c = respondsText.c_str(); - if (strlen(c) > 255) - return; - - if (chanName == "World") - { - if (ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId())) - { - std::string worldChan = "World"; - if (Channel* chn = cMgr->GetJoinChannel(worldChan.c_str(), 0)) - { - if (bot->GetTeamId() == TEAM_ALLIANCE) - chn->Say(bot->GetGUID(), c, LANG_COMMON); - else - chn->Say(bot->GetGUID(), c, LANG_ORCISH); - } - } - } - else - { - if (type == CHAT_MSG_WHISPER) - { - if (plr) - { - if (bot->GetTeamId() == TEAM_ALLIANCE) - { - bot->Whisper(c, LANG_COMMON, plr); - } - else - { - bot->Whisper(c, LANG_ORCISH, plr); - } - } - } - - else if (type == CHAT_MSG_SAY) - { - if (bot->GetTeamId() == TEAM_ALLIANCE) - bot->Say(respondsText, LANG_COMMON); - else - bot->Say(respondsText, LANG_ORCISH); - } - - else if (type == CHAT_MSG_YELL) - { - if (bot->GetTeamId() == TEAM_ALLIANCE) - bot->Yell(respondsText, LANG_COMMON); - else - bot->Yell(respondsText, LANG_ORCISH); - } - - else if (type == CHAT_MSG_GUILD) - { - if (!bot->GetGuildId() || !sPlayerbotAIConfig->randomBotGuildTalk) - return; - - Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); - if (!guild) - return; - - guild->BroadcastToGuild(bot->GetSession(), false, respondsText, LANG_UNIVERSAL); - } - } - GET_PLAYERBOT_AI(bot) - ->GetAiObjectContext() - ->GetValue("last said", "chat") - ->Set(time(nullptr) + urand(5, 25)); + respondsText = BOT_TEXT2(replyType, name); } + + if (respondsText.size() > 255) + { + respondsText.resize(255); + } + + return respondsText; } diff --git a/src/strategy/actions/SayAction.h b/src/strategy/actions/SayAction.h index 7eb6c9e5..e184c9c8 100644 --- a/src/strategy/actions/SayAction.h +++ b/src/strategy/actions/SayAction.h @@ -7,10 +7,10 @@ #define _PLAYERBOT_SAYACTION_H #include "Action.h" +#include "PlayerbotAI.h" #include "NamedObjectContext.h" class PlayerbotAI; - class SayAction : public Action, public Qualified { public: @@ -31,7 +31,13 @@ public: ChatReplyAction(PlayerbotAI* ai) : Action(ai, "chat message") {} virtual bool Execute(Event event) { return true; } bool isUseful() { return true; } - static void ChatReplyDo(Player* bot, uint32 type, uint32 guid1, uint32 guid2, std::string msg, std::string chanName, - std::string name); + + static void ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name); + static bool HandleThunderfuryReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); + static bool HandleToxicLinksReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); + static bool HandleWTBItemsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); + static bool HandleLFGQuestsReply(Player* bot, ChatChannelSource chatChannelSource, std::string& msg, std::string& name); + static bool SendGeneralResponse(Player* bot, ChatChannelSource chatChannelSource, std::string& responseMessage, std::string& name); + static std::string GenerateReplyMessage(Player* bot, std::string& incomingMessage, uint32& guid1, std::string& name); }; #endif diff --git a/src/strategy/actions/ShareQuestAction.cpp b/src/strategy/actions/ShareQuestAction.cpp index a71a96b0..77ff51b0 100644 --- a/src/strategy/actions/ShareQuestAction.cpp +++ b/src/strategy/actions/ShareQuestAction.cpp @@ -39,3 +39,74 @@ bool ShareQuestAction::Execute(Event event) return false; } + +bool AutoShareQuestAction::Execute(Event event) +{ + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + bool shared = false; + + for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 logQuest = bot->GetQuestSlotQuestId(slot); + Quest const* quest = sObjectMgr->GetQuestTemplate(logQuest); + + if (!quest) + continue; + + bool partyNeedsQuest = false; + + for (GroupReference* itr = bot->GetGroup()->GetFirstMember(); itr != nullptr; itr = itr->next()) + { + Player* player = itr->GetSource(); + + if (!player || player == bot || !player->IsInWorld() || !botAI->IsSafe(player)) // skip self + continue; + + if (bot->GetDistance(player) > 10) + continue; + + if (!player->SatisfyQuestStatus(quest, false)) + continue; + + if (player->GetQuestStatus(logQuest) == QUEST_STATUS_COMPLETE) + continue; + + if (!player->CanTakeQuest(quest, false)) + continue; + + if (!player->SatisfyQuestLog(false)) + continue; + + if (player->GetDivider()) + continue; + + if (auto ai = GET_PLAYERBOT_AI(player)) + { + if (PAI_VALUE(uint8, "free quest log slots") < 15 || !urand(0,5)) + { + WorldPacket packet(CMSG_PUSHQUESTTOPARTY, 20); + packet << logQuest; + ai->HandleMasterIncomingPacket(packet); + } + } + else + partyNeedsQuest = true; + } + + if (!partyNeedsQuest) + continue; + + WorldPacket p; + p << logQuest; + bot->GetSession()->HandlePushQuestToParty(p); + botAI->TellMaster("Quest shared"); + shared = true; + } + + return shared; +} + +bool AutoShareQuestAction::isUseful() +{ + return bot->GetGroup() && !botAI->HasActivePlayerMaster(); +} \ No newline at end of file diff --git a/src/strategy/actions/ShareQuestAction.h b/src/strategy/actions/ShareQuestAction.h index 5e9eb5e4..d2289ab1 100644 --- a/src/strategy/actions/ShareQuestAction.h +++ b/src/strategy/actions/ShareQuestAction.h @@ -13,9 +13,17 @@ class PlayerbotAI; class ShareQuestAction : public Action { public: - ShareQuestAction(PlayerbotAI* botAI) : Action(botAI, "share quest") {} - + ShareQuestAction(PlayerbotAI* botAI, std::string name = "share quest") : Action(botAI, name) { } bool Execute(Event event) override; }; +class AutoShareQuestAction : public ShareQuestAction +{ +public: + AutoShareQuestAction(PlayerbotAI* ai) : ShareQuestAction(botAI, "auto share quest") {} + bool Execute(Event event) override; + + bool isUseful() override; +}; + #endif diff --git a/src/strategy/actions/SuggestWhatToDoAction.cpp b/src/strategy/actions/SuggestWhatToDoAction.cpp index c15d9175..3ecf6e41 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.cpp +++ b/src/strategy/actions/SuggestWhatToDoAction.cpp @@ -3,10 +3,19 @@ * and/or modify it under version 2 of the License, or (at your option), any later version. */ -#include "SuggestWhatToDoAction.h" - #include +#include "SuggestWhatToDoAction.h" +#include "ServerFacade.h" +#include "ChannelMgr.h" +#include "Event.h" +#include "ItemVisitors.h" +#include "AiFactory.h" +#include "ChatHelper.h" +#include "Playerbots.h" +#include "PlayerbotTextMgr.h" +#include "Config.h" +#include "BroadcastHelper.h" #include "AiFactory.h" #include "ChannelMgr.h" #include "ChatHelper.h" @@ -39,11 +48,13 @@ SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* botAI, std::string con suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindReputation, this)); suggestions.push_back(std::bind(&SuggestWhatToDoAction::something, this)); suggestions.push_back(std::bind(&SuggestWhatToDoAction::grindMaterials, this)); + suggestions.push_back(std::bind(&SuggestWhatToDoAction::somethingToxic, this)); + suggestions.push_back(std::bind(&SuggestWhatToDoAction::toxicLinks, this)); } bool SuggestWhatToDoAction::isUseful() { - if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId()) + if (!sRandomPlayerbotMgr->IsRandomBot(bot) || bot->GetGroup() || bot->GetInstanceId() || bot->GetBattleground()) return false; std::string qualifier = "suggest what to do"; @@ -88,15 +99,7 @@ void SuggestWhatToDoAction::specificQuest() if (quests.empty()) return; - uint32 index = rand() % quests.size(); - - Quest const* quest = sObjectMgr->GetQuestTemplate(quests[index]); - - std::map placeholders; - placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); - placeholders["%quest"] = chat->FormatQuest(quest); - - spam(BOT_TEXT2("suggest_quest", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), !urand(0, 3)); + BroadcastHelper::BroadcastSuggestQuest(botAI, quests, bot); } void SuggestWhatToDoAction::grindMaterials() @@ -190,135 +193,34 @@ void SuggestWhatToDoAction::grindReputation() levels.push_back("exalted"); std::vector allowedFactions; - for (const auto& i : factions) + for (auto it : factions) { - if (bot->GetLevel() >= i.second) - allowedFactions.push_back(i.first); + if ((int)bot->GetLevel() >= it.second) allowedFactions.push_back(it.first); } - if (allowedFactions.empty()) - return; - std::map placeholders; - placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); - placeholders["%level"] = levels[urand(0, 2)]; + if (allowedFactions.empty()) return; - std::ostringstream rnd; - rnd << urand(1, 5) << "K"; - placeholders["%rndK"] = rnd.str(); - - std::ostringstream itemout; - // itemout << "|c004040b0" << allowedFactions[urand(0, allowedFactions.size() - 1)] << "|r"; - itemout << allowedFactions[urand(0, allowedFactions.size() - 1)]; - placeholders["%faction"] = itemout.str(); - - spam(BOT_TEXT2("suggest_faction", placeholders), eTalkType::General, true); + BroadcastHelper::BroadcastSuggestGrindReputation(botAI, levels, allowedFactions, bot); } void SuggestWhatToDoAction::something() { - std::map placeholders; - placeholders["%role"] = chat->FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); - - AreaTableEntry const* entry = sAreaTableStore.LookupEntry(bot->GetAreaId()); - if (!entry) - return; - - std::ostringstream out; - // out << "|cffb04040" << entry->area_name[0] << "|r"; - out << entry->area_name[_dbc_locale]; - placeholders["%zone"] = out.str(); - - spam(BOT_TEXT2("suggest_something", placeholders), urand(0, 1) ? eTalkType::General : 0, !urand(0, 2), - !urand(0, 3)); + BroadcastHelper::BroadcastSuggestSomething(botAI, bot); } -void SuggestWhatToDoAction::spam(std::string msg, uint8 flags, bool worldChat, bool guild) +void SuggestWhatToDoAction::somethingToxic() { - if (msg.empty()) - return; + BroadcastHelper::BroadcastSuggestSomethingToxic(botAI, bot); +} - std::vector channelNames; - ChannelMgr* cMgr = ChannelMgr::forTeam(bot->GetTeamId()); - if (!cMgr) - return; +void SuggestWhatToDoAction::toxicLinks() +{ + BroadcastHelper::BroadcastSuggestToxicLinks(botAI, bot); +} - AreaTableEntry const* zone = sAreaTableStore.LookupEntry( - bot->GetMap()->GetZoneId(bot->GetPhaseMask(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); - if (!zone) - return; - /*AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetMap()->GetAreaId(bot->GetPhaseMask(), - bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ())); if (!area) return;*/ - - for (uint32 i = 0; i < sChatChannelsStore.GetNumRows(); ++i) - { - ChatChannelsEntry const* channel = sChatChannelsStore.LookupEntry(i); - if (!channel) - continue; - - // combine full channel name - char channelName[100]; - Channel* chn = nullptr; - if (channel->ChannelID == 24 || (channel->flags & CHANNEL_DBC_FLAG_LFG) != 0) - { - std::string chanName = channel->pattern[_dbc_locale]; - chn = cMgr->GetChannel(chanName, bot); - } - else - { - snprintf(channelName, 100, channel->pattern[_dbc_locale], zone->area_name[_dbc_locale]); - chn = cMgr->GetChannel(channelName, bot); - } - if (!chn) - continue; - - // skip world chat here - if (chn->GetName() == "World") - continue; - - if (flags != 0 && chn->GetFlags() != flags) - continue; - - // skip local defense and universal defense - if (chn->GetChannelId() == 22 || chn->GetChannelId() == 23) - continue; - - // no filter, pick several options - if (flags == CHANNEL_FLAG_NONE) - { - channelNames.push_back(chn->GetName()); - } - else - { - if (!bot->IsInChannel(chn)) - chn->JoinChannel(bot, ""); - chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); - } - - if (!channelNames.empty()) - { - std::string randomName = channelNames[urand(0, channelNames.size() - 1)]; - if (Channel* chn = cMgr->GetChannel(randomName, bot)) - { - if (!bot->IsInChannel(chn)) - chn->JoinChannel(bot, ""); - - chn->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); - } - } - - if (worldChat) - { - if (Channel* worldChannel = cMgr->GetChannel("World", bot)) - worldChannel->Say(bot->GetGUID(), msg.c_str(), LANG_UNIVERSAL); - } - } - - if (sPlayerbotAIConfig->randomBotGuildTalk && guild && bot->GetGuildId()) - { - Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); - if (guild) - guild->BroadcastToGuild(bot->GetSession(), false, msg.c_str(), LANG_UNIVERSAL); - } +void SuggestWhatToDoAction::thunderfury() +{ + BroadcastHelper::BroadcastSuggestThunderfury(botAI, bot); } class FindTradeItemsVisitor : public IterateItemsVisitor @@ -409,24 +311,14 @@ bool SuggestDungeonAction::Execute(Event event) } std::vector allowedInstances; - for (const auto& instance : instances) + for (auto it : instances) { - if (bot->GetLevel() >= instance.second) - allowedInstances.push_back(instance.first); + if (bot->GetLevel() >= it.second) allowedInstances.push_back(it.first); } - if (allowedInstances.empty()) - return false; - std::map placeholders; - placeholders["%role"] = ChatHelper::FormatClass(bot, AiFactory::GetPlayerSpecTab(bot)); + if (allowedInstances.empty()) return false; - std::ostringstream itemout; - // itemout << "|c00b000b0" << allowedInstances[urand(0, allowedInstances.size() - 1)] << "|r"; - itemout << allowedInstances[urand(0, allowedInstances.size() - 1)]; - placeholders["%instance"] = itemout.str(); - - spam(BOT_TEXT2("suggest_instance", placeholders), urand(0, 1) ? eTalkType::LookingForGroup : 0, !urand(0, 2), - !urand(0, 3)); + BroadcastHelper::BroadcastSuggestInstance(botAI, allowedInstances, bot); return true; } @@ -484,10 +376,6 @@ bool SuggestTradeAction::Execute(Event event) if (!price) return false; - std::map placeholders; - placeholders["%item"] = chat->FormatItem(proto, count); - placeholders["%gold"] = chat->formatMoney(price); - - spam(BOT_TEXT2("suggest_sell", placeholders), urand(0, 1) ? eTalkType::Trade : 0, !urand(0, 2), urand(0, 5)); + BroadcastHelper::BroadcastSuggestSell(botAI, proto, count, price, bot); return true; } diff --git a/src/strategy/actions/SuggestWhatToDoAction.h b/src/strategy/actions/SuggestWhatToDoAction.h index e3ae3c64..9b69808d 100644 --- a/src/strategy/actions/SuggestWhatToDoAction.h +++ b/src/strategy/actions/SuggestWhatToDoAction.h @@ -25,8 +25,10 @@ protected: void grindReputation(); void grindMaterials(); void something(); - void spam(std::string msg, uint8 flags = 0, bool worldChat = false, bool guild = false); - + void toxicLinks(); + void somethingToxic(); + void thunderfury(); + std::vector GetIncompletedQuests(); private: @@ -38,9 +40,7 @@ class SuggestTradeAction : public SuggestWhatToDoAction { public: SuggestTradeAction(PlayerbotAI* botAI); - bool Execute(Event event) override; - bool isUseful() override { return true; } }; class SuggestDungeonAction : public SuggestWhatToDoAction @@ -49,8 +49,6 @@ public: SuggestDungeonAction(PlayerbotAI* botAI); bool Execute(Event event) override; - bool isUseful() override { return true; } - private: static std::map instances; }; diff --git a/src/strategy/actions/TalkToQuestGiverAction.cpp b/src/strategy/actions/TalkToQuestGiverAction.cpp index 11effe7f..f9498ce5 100644 --- a/src/strategy/actions/TalkToQuestGiverAction.cpp +++ b/src/strategy/actions/TalkToQuestGiverAction.cpp @@ -12,9 +12,11 @@ #include "Playerbots.h" #include "QuestDef.h" #include "WorldPacket.h" +#include "BroadcastHelper.h" -void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver) +bool TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver) { + bool isCompleted = false; std::ostringstream out; out << "Quest "; @@ -28,7 +30,7 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver { QuestStatus masterStatus = master->GetQuestStatus(quest->GetQuestId()); if (masterStatus == QUEST_STATUS_INCOMPLETE || masterStatus == QUEST_STATUS_FAILED) - CompleteQuest(master, quest->GetQuestId()); + isCompleted |= CompleteQuest(master, quest->GetQuestId()); } } @@ -37,39 +39,42 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver if (master && master->GetQuestStatus(quest->GetQuestId()) == QUEST_STATUS_COMPLETE && (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_FAILED)) { - CompleteQuest(bot, quest->GetQuestId()); + isCompleted |= CompleteQuest(bot, quest->GetQuestId()); status = bot->GetQuestStatus(quest->GetQuestId()); } } switch (status) { - case QUEST_STATUS_COMPLETE: - TurnInQuest(quest, questGiver, out); - break; - case QUEST_STATUS_INCOMPLETE: - out << "|cffff0000Incompleted|r"; - break; - case QUEST_STATUS_NONE: - out << "|cff00ff00Available|r"; - break; - case QUEST_STATUS_FAILED: - out << "|cffff0000Failed|r"; - break; - default: - break; + case QUEST_STATUS_COMPLETE: + isCompleted |= TurnInQuest(quest, questGiver, out); + break; + case QUEST_STATUS_INCOMPLETE: + out << "|cffff0000Incompleted|r"; + break; + case QUEST_STATUS_NONE: + AcceptQuest(quest, questGiver->GetGUID()); + out << "|cff00ff00Available|r"; + break; + case QUEST_STATUS_FAILED: + out << "|cffff0000Failed|r"; + break; + default: + break; } out << ": " << chat->FormatQuest(quest); botAI->TellMaster(out); + + return isCompleted; } -void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out) +bool TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out) { uint32 questID = quest->GetQuestId(); if (bot->GetQuestRewardStatus(questID)) - return; + return false; bot->PlayDistanceSound(621); @@ -81,18 +86,33 @@ void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, { RewardMultipleItem(quest, questGiver, out); } + + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + const Quest* pQuest = sObjectMgr->GetQuestTemplate(questID); + const std::string text_quest = ChatHelper::FormatQuest(pQuest); + LOG_INFO("playerbots", "{} => Quest [ {} ] completed", bot->GetName(), pQuest->GetTitle()); + bot->Say("Quest [ " + text_quest + " ] completed", LANG_UNIVERSAL); + } + + return true; } void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out) { + std::map args; + args["%quest"] = chat->FormatQuest(quest); + if (bot->CanRewardQuest(quest, false)) { + out << BOT_TEXT2("quest_status_completed", args); + BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest); + bot->RewardQuest(quest, 0, questGiver, false); - out << "Completed"; } else { - out << "|cffff0000Unable to turn in|r"; + out << BOT_TEXT2("quest_status_unable_to_complete", args); } } @@ -100,15 +120,19 @@ void TalkToQuestGiverAction::RewardSingleItem(Quest const* quest, Object* questG { int index = 0; ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[index]); + std::map args; + args["%quest"] = chat->FormatQuest(quest); + args["%item"] = chat->FormatItem(item); + if (bot->CanRewardQuest(quest, index, false)) { + out << BOT_TEXT2("quest_status_complete_single_reward", args); + BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest); bot->RewardQuest(quest, index, questGiver, true); - - out << "Rewarded " << chat->FormatItem(item); } else { - out << "|cffff0000Unable to turn in:|r, reward: " << chat->FormatItem(item); + out << BOT_TEXT2("quest_status_unable_to_complete", args); } } @@ -247,26 +271,27 @@ bool TurnInQueryQuestAction::Execute(Event event) out << "Quest "; switch (status) { - case QUEST_STATUS_COMPLETE: - TurnInQuest(quest, object, out); - break; - case QUEST_STATUS_INCOMPLETE: - out << "|cffff0000Incompleted|r"; - break; - case QUEST_STATUS_NONE: - out << "|cff00ff00Available|r"; - break; - case QUEST_STATUS_FAILED: - out << "|cffff0000Failed|r"; - break; - case QUEST_STATUS_REWARDED: - out << "|cffff0000Rewarded|r"; - break; - default: - break; + case QUEST_STATUS_COMPLETE: + TurnInQuest(quest, object, out); + break; + case QUEST_STATUS_INCOMPLETE: + out << "|cffff0000Incompleted|r"; + break; + case QUEST_STATUS_NONE: + AcceptQuest(quest, object->GetGUID()); + out << "|cff00ff00Available|r"; + break; + case QUEST_STATUS_FAILED: + out << "|cffff0000Failed|r"; + break; + case QUEST_STATUS_REWARDED: + out << "|cffff0000Rewarded|r"; + break; + default: + break; } out << ": " << chat->FormatQuest(quest); botAI->TellMaster(out); return true; -} \ No newline at end of file +} diff --git a/src/strategy/actions/TalkToQuestGiverAction.h b/src/strategy/actions/TalkToQuestGiverAction.h index 28c1683b..df12f434 100644 --- a/src/strategy/actions/TalkToQuestGiverAction.h +++ b/src/strategy/actions/TalkToQuestGiverAction.h @@ -15,11 +15,11 @@ class WorldObject; class TalkToQuestGiverAction : public QuestAction { public: - TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) {} + TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) { } protected: - void ProcessQuest(Quest const* quest, Object* questGiver) override; - void TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out); + bool ProcessQuest(Quest const* quest, Object* questGiver) override; + bool TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out); private: void RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out); diff --git a/src/strategy/actions/UseItemAction.cpp b/src/strategy/actions/UseItemAction.cpp index 8a41bc6f..d90f1310 100644 --- a/src/strategy/actions/UseItemAction.cpp +++ b/src/strategy/actions/UseItemAction.cpp @@ -438,13 +438,10 @@ bool UseRandomQuestItem::Execute(Event event) ObjectGuid goTarget; std::vector questItems = AI_VALUE2(std::vector, "inventory items", "quest"); - - Item* item = nullptr; - uint32 delay = 0; - if (questItems.empty()) return false; + Item* item = nullptr; for (uint8 i = 0; i < 5; i++) { auto itr = questItems.begin(); @@ -452,7 +449,6 @@ bool UseRandomQuestItem::Execute(Event event) Item* questItem = *itr; ItemTemplate const* proto = questItem->GetTemplate(); - if (proto->StartQuest) { Quest const* qInfo = sObjectMgr->GetQuestTemplate(proto->StartQuest); @@ -463,61 +459,14 @@ bool UseRandomQuestItem::Execute(Event event) } } - uint32 spellId = proto->Spells[0].SpellId; - if (spellId) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - - GuidVector npcs = AI_VALUE(GuidVector, ("nearest npcs")); - for (auto& npc : npcs) - { - Unit* unit = botAI->GetUnit(npc); - if (botAI->CanCastSpell(spellId, unit, false)) - { - item = questItem; - unitTarget = unit; - break; - } - } - - GuidVector gos = AI_VALUE(GuidVector, ("nearest game objects")); - for (auto& go : gos) - { - GameObject* gameObject = botAI->GetGameObject(go); - GameObjectTemplate const* goInfo = gameObject->GetGOInfo(); - if (!goInfo->GetLockId()) - continue; - - LockEntry const* lock = sLockStore.LookupEntry(goInfo->GetLockId()); - for (uint8 i = 0; i < MAX_LOCK_CASE; ++i) - { - if (!lock->Type[i]) - continue; - if (lock->Type[i] != LOCK_KEY_ITEM) - continue; - - if (lock->Index[i] == proto->ItemId) - { - item = questItem; - goTarget = go; - unitTarget = nullptr; - break; - } - } - } - } } if (!item) return false; - if (!goTarget && !unitTarget) - return false; - bool used = UseItem(item, goTarget, nullptr, unitTarget); - if (used) - botAI->SetNextCheckDelay(delay); + botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); return used; } diff --git a/src/strategy/actions/WorldPacketActionContext.h b/src/strategy/actions/WorldPacketActionContext.h index 16060af9..947b4826 100644 --- a/src/strategy/actions/WorldPacketActionContext.h +++ b/src/strategy/actions/WorldPacketActionContext.h @@ -38,6 +38,7 @@ #include "TellMasterAction.h" #include "TradeStatusAction.h" #include "UseMeetingStoneAction.h" +#include "NamedObjectContext.h" class PlayerbotAI; @@ -52,10 +53,6 @@ public: creators["tell not enough money"] = &WorldPacketActionContext::tell_not_enough_money; creators["tell not enough reputation"] = &WorldPacketActionContext::tell_not_enough_reputation; creators["tell cannot equip"] = &WorldPacketActionContext::tell_cannot_equip; - creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest; - creators["accept quest"] = &WorldPacketActionContext::accept_quest; - creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests; - creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share; creators["loot roll"] = &WorldPacketActionContext::loot_roll; creators["master loot roll"] = &WorldPacketActionContext::master_loot_roll; creators["revive from corpse"] = &WorldPacketActionContext::revive_from_corpse; @@ -69,7 +66,20 @@ public: creators["remember taxi"] = &WorldPacketActionContext::remember_taxi; creators["accept trade"] = &WorldPacketActionContext::accept_trade; creators["store loot"] = &WorldPacketActionContext::store_loot; - creators["quest objective completed"] = &WorldPacketActionContext::quest_objective_completed; + + // quest + creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest; + creators["accept quest"] = &WorldPacketActionContext::accept_quest; + creators["confirm quest"] = &WorldPacketActionContext::confirm_quest; + creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests; + creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share; + creators["quest update add kill"] = &WorldPacketActionContext::quest_update_add_kill; + creators["quest update add item"] = &WorldPacketActionContext::quest_update_add_item; + creators["quest update failed"] = &WorldPacketActionContext::quest_update_failed; + creators["quest update failed timer"] = &WorldPacketActionContext::quest_update_failed_timer; + creators["quest update complete"] = &WorldPacketActionContext::quest_update_complete; + creators["turn in query quest"] = &WorldPacketActionContext::turn_in_query_quest; + creators["party command"] = &WorldPacketActionContext::party_command; creators["tell cast failed"] = &WorldPacketActionContext::tell_cast_failed; creators["accept duel"] = &WorldPacketActionContext::accept_duel; @@ -93,8 +103,6 @@ public: creators["lfg teleport"] = &WorldPacketActionContext::lfg_teleport; creators["see spell"] = &WorldPacketActionContext::see_spell; creators["arena team accept"] = &WorldPacketActionContext::arena_team_accept; - creators["turn in query quest"] = &WorldPacketActionContext::turn_in_query_quest; - creators["quest confirm accept"] = &WorldPacketActionContext::quest_confirm_accept; } private: @@ -107,7 +115,6 @@ private: static Action* accept_duel(PlayerbotAI* botAI) { return new AcceptDuelAction(botAI); } static Action* tell_cast_failed(PlayerbotAI* botAI) { return new TellCastFailedAction(botAI); } static Action* party_command(PlayerbotAI* botAI) { return new PartyCommandAction(botAI); } - static Action* quest_objective_completed(PlayerbotAI* botAI) { return new QuestObjectiveCompletedAction(botAI); } static Action* store_loot(PlayerbotAI* botAI) { return new StoreLootAction(botAI); } static Action* accept_trade(PlayerbotAI* botAI) { return new TradeStatusAction(botAI); } static Action* remember_taxi(PlayerbotAI* botAI) { return new RememberTaxiAction(botAI); } @@ -120,21 +127,27 @@ private: static Action* auto_release(PlayerbotAI* botAI) { return new AutoReleaseSpiritAction(botAI); } static Action* revive_from_corpse(PlayerbotAI* botAI) { return new ReviveFromCorpseAction(botAI); } static Action* accept_invitation(PlayerbotAI* botAI) { return new AcceptInvitationAction(botAI); } - static Action* give_leader_in_dungeon(PlayerbotAI* botAI) - { - return new GiveLeaderAction(botAI, "I don't know this dungeon, lead the way!"); - } + static Action* give_leader_in_dungeon(PlayerbotAI* botAI) { return new GiveLeaderAction(botAI, "I don't know this dungeon, lead the way!"); } static Action* pass_leadership_to_master(PlayerbotAI* botAI) { return new PassLeadershipToMasterAction(botAI); } static Action* tell_not_enough_money(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough money"); } - static Action* tell_not_enough_reputation(PlayerbotAI* botAI) - { - return new TellMasterAction(botAI, "Not enough reputation"); - } + static Action* tell_not_enough_reputation(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough reputation"); } static Action* tell_cannot_equip(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); } + + // quest + static Action* quest_update_add_kill(PlayerbotAI* ai) { return new QuestUpdateAddKillAction(ai); } + static Action* quest_update_add_item(PlayerbotAI* ai) { return new QuestUpdateAddItemAction(ai); } + static Action* quest_update_failed(PlayerbotAI* ai) { return new QuestUpdateFailedAction(ai); } + static Action* quest_update_failed_timer(PlayerbotAI* ai) { return new QuestUpdateFailedTimerAction(ai); } + static Action* quest_update_complete(PlayerbotAI* botAI) { return new QuestUpdateCompleteAction(botAI); } + static Action* turn_in_quest(PlayerbotAI* botAI) { return new TalkToQuestGiverAction(botAI); } static Action* accept_quest(PlayerbotAI* botAI) { return new AcceptQuestAction(botAI); } + static Action* confirm_quest(PlayerbotAI* ai) { return new ConfirmQuestAction(ai); } static Action* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsAction(botAI); } static Action* accept_quest_share(PlayerbotAI* botAI) { return new AcceptQuestShareAction(botAI); } + static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); } + //static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(botAI); } + static Action* loot_roll(PlayerbotAI* botAI) { return new LootRollAction(botAI); } static Action* master_loot_roll(PlayerbotAI* botAI) { return new MasterLootRollAction(botAI); } static Action* bg_join(PlayerbotAI* botAI) { return new BGJoinAction(botAI); } @@ -151,8 +164,6 @@ private: static Action* lfg_join(PlayerbotAI* botAI) { return new LfgJoinAction(botAI); } static Action* see_spell(PlayerbotAI* botAI) { return new SeeSpellAction(botAI); } static Action* arena_team_accept(PlayerbotAI* botAI) { return new ArenaTeamAcceptAction(botAI); } - static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); } - static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(botAI); } }; #endif diff --git a/src/strategy/actions/XpGainAction.cpp b/src/strategy/actions/XpGainAction.cpp index 3a031460..53fc38e7 100644 --- a/src/strategy/actions/XpGainAction.cpp +++ b/src/strategy/actions/XpGainAction.cpp @@ -9,6 +9,7 @@ #include "GuildMgr.h" #include "PlayerbotAIConfig.h" #include "Playerbots.h" +#include "BroadcastHelper.h" bool XpGainAction::Execute(Event event) { @@ -35,25 +36,10 @@ bool XpGainAction::Execute(Event event) p >> groupBonus; // 8 group bonus } - if (sPlayerbotAIConfig->randomBotGuildTalk && bot->GetGuildId() && urand(0, 10)) + Creature* creature = botAI->GetCreature(guid); + if (creature && !creature->GetMap()->IsDungeon()) { - Creature* creature = botAI->GetCreature(guid); - if (creature && (creature->isElite() || creature->isWorldBoss() || creature->GetLevel() > 61 || - creature->GetLevel() > bot->GetLevel() + 4)) - { - Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId()); - if (guild) - { - std::string toSay = ""; - - if (urand(0, 3)) - toSay = "Wow I just killed " + creature->GetName() + " !"; - else - toSay = "Awesome that " + creature->GetName() + " went down quickly !"; - - guild->BroadcastToGuild(bot->GetSession(), false, toSay, LANG_UNIVERSAL); - } - } + BroadcastHelper::BroadcastKill(botAI, bot, creature); } Unit* victim = nullptr; diff --git a/src/strategy/generic/DebugStrategy.h b/src/strategy/generic/DebugStrategy.h index 2b53b8ba..ae69bd3f 100644 --- a/src/strategy/generic/DebugStrategy.h +++ b/src/strategy/generic/DebugStrategy.h @@ -44,4 +44,13 @@ public: std::string const getName() override { return "debug spell"; } }; +class DebugQuestStrategy : public Strategy +{ +public: + DebugQuestStrategy(PlayerbotAI* botAI) : Strategy(botAI) { } + + uint32 GetType() const override { return STRATEGY_TYPE_NONCOMBAT | STRATEGY_TYPE_COMBAT; } + std::string const getName() override { return "debug quest"; } +}; + #endif diff --git a/src/strategy/generic/MaintenanceStrategy.cpp b/src/strategy/generic/MaintenanceStrategy.cpp index bb3707b9..b2e32c0d 100644 --- a/src/strategy/generic/MaintenanceStrategy.cpp +++ b/src/strategy/generic/MaintenanceStrategy.cpp @@ -11,19 +11,13 @@ NextAction** MaintenanceStrategy::getDefaultActions() { return nullptr; } void MaintenanceStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back( - new TriggerNode("random", NextAction::array(0, new NextAction("clean quest log", 6.0f), nullptr))); - triggers.push_back( - new TriggerNode("random", NextAction::array(0, new NextAction("use random recipe", 1.0f), nullptr))); - triggers.push_back( - new TriggerNode("often", NextAction::array(0, new NextAction("use random quest item", 10.0f), nullptr))); - triggers.push_back( - new TriggerNode("random", NextAction::array(0, new NextAction("disenchant random item", 1.0f), nullptr))); - triggers.push_back( - new TriggerNode("random", NextAction::array(0, new NextAction("enchant random item", 1.0f), nullptr))); - triggers.push_back( - new TriggerNode("random", NextAction::array(0, new NextAction("smart destroy item", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("clean quest log", 6.0f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("use random recipe", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("disenchant random item", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("enchant random item", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("smart destroy item", 1.0f), nullptr))); triggers.push_back(new TriggerNode("move stuck", NextAction::array(0, new NextAction("reset", 1.0f), nullptr))); - // triggers.push_back(new TriggerNode("move long stuck", NextAction::array(0, new NextAction("hearthstone", 0.9f), - // new NextAction("repop", 0.8f), nullptr))); + // triggers.push_back(new TriggerNode("move long stuck", NextAction::array(0, new NextAction("hearthstone", 0.9f), new NextAction("repop", 0.8f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("use random quest item", 0.9f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("auto share quest", 0.9f), nullptr))); } diff --git a/src/strategy/generic/NonCombatStrategy.cpp b/src/strategy/generic/NonCombatStrategy.cpp index cc673fae..c35e6168 100644 --- a/src/strategy/generic/NonCombatStrategy.cpp +++ b/src/strategy/generic/NonCombatStrategy.cpp @@ -9,16 +9,15 @@ void NonCombatStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("check mount state", 1.0f), - // new NextAction("check values", 1.0f), - nullptr))); - // triggers.push_back(new TriggerNode("near dark portal", NextAction::array(0, new NextAction("move to dark - // portal", 1.0f), nullptr))); triggers.push_back(new TriggerNode("at dark portal azeroth", NextAction::array(0, new - // NextAction("use dark portal azeroth", 1.0f), nullptr))); triggers.push_back(new TriggerNode("at dark portal - // outland", NextAction::array(0, new NextAction("move from dark portal", 1.0f), nullptr))); triggers.push_back(new - // TriggerNode("need world buff", NextAction::array(0, new NextAction("world buff", 1.0f), nullptr))); - // triggers.push_back(new TriggerNode("vehicle near", NextAction::array(0, new NextAction("enter vehicle", 10.0f), - // nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("clean quest log", 1.0f), nullptr))); + triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("check mount state", 1.0f), + // new NextAction("check values", 1.0f), + nullptr))); + // triggers.push_back(new TriggerNode("near dark portal", NextAction::array(0, new NextAction("move to dark portal", 1.0f), nullptr))); + // triggers.push_back(new TriggerNode("at dark portal azeroth", NextAction::array(0, new NextAction("use dark portal azeroth", 1.0f), nullptr))); + // triggers.push_back(new TriggerNode("at dark portal outland", NextAction::array(0, new NextAction("move from dark portal", 1.0f), nullptr))); + // triggers.push_back(new TriggerNode("need world buff", NextAction::array(0, new NextAction("world buff", 1.0f), nullptr))); + // triggers.push_back(new TriggerNode("vehicle near", NextAction::array(0, new NextAction("enter vehicle", 10.0f), nullptr))); } void CollisionStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/strategy/generic/WorldPacketHandlerStrategy.cpp index 4b37d3d8..992675d3 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.cpp +++ b/src/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -34,66 +34,44 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& trigger triggers.push_back(new TriggerNode("activate taxi", NextAction::array(0, new NextAction("remember taxi", relevance), new NextAction("taxi", relevance), nullptr))); triggers.push_back(new TriggerNode("taxi done", NextAction::array(0, new NextAction("taxi", relevance), nullptr))); - triggers.push_back( - new TriggerNode("trade status", NextAction::array(0, new NextAction("accept trade", relevance), - new NextAction("equip upgrades", relevance), nullptr))); - triggers.push_back(new TriggerNode("area trigger", - NextAction::array(0, new NextAction("reach area trigger", relevance), nullptr))); - triggers.push_back(new TriggerNode("within area trigger", - NextAction::array(0, new NextAction("area trigger", relevance), nullptr))); - triggers.push_back( - new TriggerNode("loot response", NextAction::array(0, new NextAction("store loot", relevance), nullptr))); - triggers.push_back( - new TriggerNode("item push result", NextAction::array(0, new NextAction("query item usage", relevance), - new NextAction("equip upgrades", relevance), nullptr))); - triggers.push_back(new TriggerNode("ready check finished", - NextAction::array(0, new NextAction("finish ready check", relevance), nullptr))); - // triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("security check", relevance), new - // NextAction("check mail", relevance), nullptr))); - triggers.push_back( - new TriggerNode("guild invite", NextAction::array(0, new NextAction("guild accept", relevance), nullptr))); - triggers.push_back( - new TriggerNode("petition offer", NextAction::array(0, new NextAction("petition sign", relevance), nullptr))); - triggers.push_back( - new TriggerNode("lfg proposal", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr))); - triggers.push_back( - new TriggerNode("lfg proposal active", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr))); - triggers.push_back(new TriggerNode("arena team invite", - NextAction::array(0, new NextAction("arena team accept", relevance), nullptr))); - triggers.push_back(new TriggerNode( - "quest confirm accept", NextAction::array(0, new NextAction("quest confirm accept", relevance), nullptr))); - // triggers.push_back(new TriggerNode("no non bot players around", NextAction::array(0, new NextAction("delay", - // relevance), nullptr))); - triggers.push_back( - new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr))); + triggers.push_back(new TriggerNode("trade status", NextAction::array(0, new NextAction("accept trade", relevance), new NextAction("equip upgrades", relevance), nullptr))); + triggers.push_back(new TriggerNode("area trigger", NextAction::array(0, new NextAction("reach area trigger", relevance), nullptr))); + triggers.push_back(new TriggerNode("within area trigger", NextAction::array(0, new NextAction("area trigger", relevance), nullptr))); + triggers.push_back(new TriggerNode("loot response", NextAction::array(0, new NextAction("store loot", relevance), nullptr))); + triggers.push_back(new TriggerNode("item push result", NextAction::array(0, new NextAction("query item usage", relevance), new NextAction("equip upgrades", relevance), nullptr))); + triggers.push_back(new TriggerNode("ready check finished", NextAction::array(0, new NextAction("finish ready check", relevance), nullptr))); + // triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("security check", relevance), new NextAction("check mail", relevance), nullptr))); + triggers.push_back(new TriggerNode("guild invite", NextAction::array(0, new NextAction("guild accept", relevance), nullptr))); + triggers.push_back(new TriggerNode("petition offer", NextAction::array(0, new NextAction("petition sign", relevance), nullptr))); + triggers.push_back(new TriggerNode("lfg proposal", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr))); + triggers.push_back(new TriggerNode("lfg proposal active", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr))); + triggers.push_back(new TriggerNode("arena team invite", NextAction::array(0, new NextAction("arena team accept", relevance), nullptr))); + //triggers.push_back(new TriggerNode("no non bot players around", NextAction::array(0, new NextAction("delay", relevance), nullptr))); + triggers.push_back(new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr))); triggers.push_back(new TriggerNode("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr))); - triggers.push_back( - new TriggerNode("levelup", NextAction::array(0, new NextAction("auto teleport for level", relevance + 3), - new NextAction("auto talents", relevance + 2), - new NextAction("auto learn spell", relevance + 1), - new NextAction("auto upgrade equip", relevance), nullptr))); - // triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", - // relevance), nullptr))); - triggers.push_back(new TriggerNode( - "questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr))); + triggers.push_back(new TriggerNode("levelup", NextAction::array(0, + new NextAction("auto teleport for level", relevance + 3), + new NextAction("auto talents", relevance + 2), + new NextAction("auto learn spell", relevance + 1), + new NextAction("auto upgrade equip", relevance), + nullptr))); + // triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr))); - triggers.push_back( - new TriggerNode("group list", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr))); - triggers.push_back( - new TriggerNode("see spell", NextAction::array(0, new NextAction("see spell", relevance), nullptr))); - triggers.push_back( - new TriggerNode("release spirit", NextAction::array(0, new NextAction("release", relevance), nullptr))); - triggers.push_back(new TriggerNode("revive from corpse", - NextAction::array(0, new NextAction("revive from corpse", relevance), nullptr))); - triggers.push_back(new TriggerNode("master loot roll", - NextAction::array(0, new NextAction("master loot roll", relevance), nullptr))); + triggers.push_back(new TriggerNode("group list", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr))); + triggers.push_back(new TriggerNode("see spell", NextAction::array(0, new NextAction("see spell", relevance), nullptr))); + triggers.push_back(new TriggerNode("release spirit", NextAction::array(0, new NextAction("release", relevance), nullptr))); + triggers.push_back(new TriggerNode("revive from corpse", NextAction::array(0, new NextAction("revive from corpse", relevance), nullptr))); + triggers.push_back(new TriggerNode("master loot roll", NextAction::array(0, new NextAction("master loot roll", relevance), nullptr))); + + // quest ? + //triggers.push_back(new TriggerNode("quest confirm", NextAction::array(0, new NextAction("quest confirm", relevance), nullptr))); + triggers.push_back(new TriggerNode("questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr))); } WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { supported.push_back("loot roll"); supported.push_back("check mount state"); - supported.push_back("quest objective completed"); supported.push_back("party command"); supported.push_back("ready check"); supported.push_back("uninvite"); @@ -102,6 +80,14 @@ WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : Pas supported.push_back("random bot update"); supported.push_back("inventory change failure"); supported.push_back("bg status"); + + // quests + supported.push_back("quest update add kill"); + supported.push_back("quest update add item"); + supported.push_back("quest update failed"); + supported.push_back("quest update failed timer"); + supported.push_back("quest update complete"); + supported.push_back("confirm quest"); } void ReadyCheckStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.h b/src/strategy/generic/WorldPacketHandlerStrategy.h index 0decfed8..dcc131d1 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.h +++ b/src/strategy/generic/WorldPacketHandlerStrategy.h @@ -22,7 +22,7 @@ public: class ReadyCheckStrategy : public PassTroughStrategy { public: - ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {} + ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { } void InitTriggers(std::vector& triggers) override; std::string const getName() override { return "ready check"; } diff --git a/src/strategy/triggers/RpgTriggers.cpp b/src/strategy/triggers/RpgTriggers.cpp index 199cc7b3..0672aa9d 100644 --- a/src/strategy/triggers/RpgTriggers.cpp +++ b/src/strategy/triggers/RpgTriggers.cpp @@ -107,6 +107,12 @@ bool RpgEndQuestTrigger::IsActive() if (AI_VALUE2(bool, "can turn in quest npc", guidP.GetEntry())) return true; + if (!AI_VALUE2(bool, "can accept quest low level npc", guidP.GetEntry())) + return false; + + if (guidP.GetEntry() == AI_VALUE(TravelTarget*, "travel target")->getEntry()) + return true; + return false; } @@ -292,6 +298,10 @@ bool RpgQueueBGTrigger::IsActive() if (!guidP.IsCreature()) return false; + + // if bot is not leader disallow tag bg + if (bot->GetGroup() && !bot->GetGroup()->IsLeader(bot->GetGUID())) + return false; if (AI_VALUE(BattlegroundTypeId, "rpg bg type") == BATTLEGROUND_TYPE_NONE) return false; diff --git a/src/strategy/triggers/WorldPacketTriggerContext.h b/src/strategy/triggers/WorldPacketTriggerContext.h index 51caae86..72ad3e5e 100644 --- a/src/strategy/triggers/WorldPacketTriggerContext.h +++ b/src/strategy/triggers/WorldPacketTriggerContext.h @@ -22,9 +22,6 @@ public: creators["not enough reputation"] = &WorldPacketTriggerContext::no_reputation; creators["cannot equip"] = &WorldPacketTriggerContext::cannot_equip; creators["use game object"] = &WorldPacketTriggerContext::use_game_object; - creators["complete quest"] = &WorldPacketTriggerContext::complete_quest; - creators["accept quest"] = &WorldPacketTriggerContext::accept_quest; - creators["quest share"] = &WorldPacketTriggerContext::quest_share; creators["loot roll"] = &WorldPacketTriggerContext::loot_roll; creators["resurrect request"] = &WorldPacketTriggerContext::resurrect_request; creators["area trigger"] = &WorldPacketTriggerContext::area_trigger; @@ -34,7 +31,20 @@ public: creators["trade status"] = &WorldPacketTriggerContext::trade_status; creators["loot response"] = &WorldPacketTriggerContext::loot_response; creators["out of react range"] = &WorldPacketTriggerContext::out_of_react_range; - creators["quest objective completed"] = &WorldPacketTriggerContext::quest_objective_completed; + + // quest + creators["complete quest"] = &WorldPacketTriggerContext::complete_quest; + creators["accept quest"] = &WorldPacketTriggerContext::accept_quest; + creators["confirm quest"] = &WorldPacketTriggerContext::quest_confirm_accept; + creators["quest share"] = &WorldPacketTriggerContext::quest_share; + creators["quest update add kill"] = &WorldPacketTriggerContext::quest_update_add_kill; + creators["quest update add item"] = &WorldPacketTriggerContext::quest_update_add_item; + creators["quest update failed"] = &WorldPacketTriggerContext::quest_update_failed; + creators["quest update failed timer"] = &WorldPacketTriggerContext::quest_update_failed_timer; + creators["quest update complete"] = &WorldPacketTriggerContext::quest_update_complete; + creators["questgiver quest details"] = &WorldPacketTriggerContext::questgiver_quest_details; + + creators["item push result"] = &WorldPacketTriggerContext::item_push_result; creators["party command"] = &WorldPacketTriggerContext::party_command; creators["taxi done"] = &WorldPacketTriggerContext::taxi_done; @@ -61,17 +71,12 @@ public: creators["receive emote"] = &WorldPacketTriggerContext::receive_emote; creators["receive text emote"] = &WorldPacketTriggerContext::receive_text_emote; creators["arena team invite"] = &WorldPacketTriggerContext::arena_team_invite; - creators["quest confirm accept"] = &WorldPacketTriggerContext::quest_confirm_accept; creators["group destroyed"] = &WorldPacketTriggerContext::group_destroyed; creators["group list"] = &WorldPacketTriggerContext::group_list; - creators["questgiver quest details"] = &WorldPacketTriggerContext::questgiver_quest_details; } private: - static Trigger* inventory_change_failure(PlayerbotAI* botAI) - { - return new WorldPacketTrigger(botAI, "inventory change failure"); - } + static Trigger* inventory_change_failure(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "inventory change failure"); } static Trigger* guild_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "guild invite"); } static Trigger* lfg_teleport(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg teleport"); } static Trigger* lfg_leave(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg leave"); } @@ -80,20 +85,26 @@ private: static Trigger* lfg_update(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg join"); } static Trigger* uninvite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite"); } static Trigger* uninvite_guid(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite guid"); } - static Trigger* ready_check_finished(PlayerbotAI* botAI) - { - return new WorldPacketTrigger(botAI, "ready check finished"); - } + static Trigger* ready_check_finished(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check finished"); } static Trigger* ready_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check"); } static Trigger* duel_requested(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "duel requested"); } static Trigger* cast_failed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cast failed"); } static Trigger* taxi_done(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "taxi done"); } static Trigger* party_command(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "party command"); } static Trigger* item_push_result(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "item push result"); } - static Trigger* quest_objective_completed(PlayerbotAI* botAI) - { - return new WorldPacketTrigger(botAI, "quest objective completed"); - } + + // quest + static Trigger* quest_update_add_kill(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update add kill"); } + static Trigger* quest_update_add_item(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update add item"); } + static Trigger* quest_update_failed(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update failed"); } + static Trigger* quest_update_failed_timer(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update failed timer"); } + static Trigger* quest_update_complete(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update complete"); } + static Trigger* complete_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "complete quest"); } + static Trigger* accept_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "accept quest"); } + static Trigger* quest_confirm_accept(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "confirm quest"); } + static Trigger* quest_share(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest share"); } + static Trigger* questgiver_quest_details(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "questgiver quest details"); } + static Trigger* out_of_react_range(PlayerbotAI* botAI) { return new OutOfReactRangeTrigger(botAI); } static Trigger* loot_response(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot response"); } static Trigger* trade_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "trade status"); } @@ -108,9 +119,6 @@ private: static Trigger* no_money(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough money"); } static Trigger* no_reputation(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough reputation"); } static Trigger* use_game_object(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "use game object"); } - static Trigger* complete_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "complete quest"); } - static Trigger* accept_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "accept quest"); } - static Trigger* quest_share(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest share"); } static Trigger* loot_roll(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot roll"); } static Trigger* taxi(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "activate taxi"); } static Trigger* bg_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "bg status"); } @@ -119,26 +127,12 @@ private: static Trigger* petition_offer(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "petition offer"); } static Trigger* seespell(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "see spell"); } static Trigger* release_spirit(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "release spirit"); } - static Trigger* revive_from_corpse(PlayerbotAI* botAI) - { - return new WorldPacketTrigger(botAI, "revive from corpse"); - } + static Trigger* revive_from_corpse(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "revive from corpse"); } static Trigger* receive_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive emote"); } - static Trigger* receive_text_emote(PlayerbotAI* botAI) - { - return new WorldPacketTrigger(botAI, "receive text emote"); - } + static Trigger* receive_text_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive text emote"); } static Trigger* arena_team_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "arena team invite"); } - static Trigger* quest_confirm_accept(PlayerbotAI* botAI) - { - return new WorldPacketTrigger(botAI, "quest confirm accept"); - } static Trigger* group_destroyed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group destroyed"); } static Trigger* group_list(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group list"); } - static Trigger* questgiver_quest_details(PlayerbotAI* botAI) - { - return new WorldPacketTrigger(botAI, "questgiver quest details"); - } }; #endif diff --git a/src/strategy/values/GrindTargetValue.cpp b/src/strategy/values/GrindTargetValue.cpp index 14942a85..e6109463 100644 --- a/src/strategy/values/GrindTargetValue.cpp +++ b/src/strategy/values/GrindTargetValue.cpp @@ -8,6 +8,7 @@ #include "Playerbots.h" #include "ReputationMgr.h" #include "SharedDefines.h" +#include "ServerFacade.h" Unit* GrindTargetValue::Calculate() { @@ -32,6 +33,9 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) Group* group = bot->GetGroup(); Player* master = GetMaster(); + if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() || !GET_PLAYERBOT_AI(master))) + master = nullptr; + GuidVector attackers = context->GetValue("attackers")->Get(); for (ObjectGuid const guid : attackers) { @@ -48,8 +52,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) float distance = 0; Unit* result = nullptr; - - // std::unordered_map needForQuestMap; + std::unordered_map needForQuestMap; for (ObjectGuid const guid : targets) { @@ -84,19 +87,30 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) // if (!bot->InBattleground() && master && master->GetDistance(unit) >= sPlayerbotAIConfig->grindDistance && // !sRandomPlayerbotMgr->IsRandomBot(bot)) continue; - if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer()) + // Bots in bot-groups no have a more limited range to look for grind target + if (!bot->InBattleground() && master && botAI->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) + && sServerFacade->GetDistance2d(master, unit) > sPlayerbotAIConfig->lootDistance) + { + if (botAI->HasStrategy("debug grind", BotState::BOT_STATE_NON_COMBAT)) + botAI->TellMaster(chat->FormatWorldobject(unit) + " ignored (far from master)."); continue; + } - // if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end()) - // needForQuestMap[unit->GetEntry()] = needForQuest(unit); + if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer()) + continue; - // if (!needForQuestMap[unit->GetEntry()]) - // if ((urand(0, 100) < 75 || (context->GetValue("travel target")->Get()->isWorking() && - // context->GetValue("travel target")->Get()->getDestination()->getName() != - // "GrindTravelDestination"))) continue; + if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end()) + needForQuestMap[unit->GetEntry()] = needForQuest(unit); - // if (bot->InBattleground() && bot->GetDistance(unit) > 40.0f) - // continue; + if (!needForQuestMap[unit->GetEntry()]) + { + Creature* creature = dynamic_cast(unit); + if ((urand(0, 100) < 60 || (context->GetValue("travel target")->Get()->isWorking() && + context->GetValue("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination"))) + { + continue; + } + } if (Creature* creature = unit->ToCreature()) if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate())