From f416cdc44322246f51e0192e5b8aebe49c29a8e2 Mon Sep 17 00:00:00 2001 From: ike3 Date: Fri, 1 Dec 2023 16:41:04 +0300 Subject: [PATCH 1/4] Fix q [quest] command if quest is not a link or for some addons such as EQL --- .../strategy/actions/QueryQuestAction.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/playerbot/strategy/actions/QueryQuestAction.cpp b/playerbot/strategy/actions/QueryQuestAction.cpp index da5c6397e..8bc39f660 100644 --- a/playerbot/strategy/actions/QueryQuestAction.cpp +++ b/playerbot/strategy/actions/QueryQuestAction.cpp @@ -21,6 +21,24 @@ bool QueryQuestAction::Execute(Event& event) PlayerbotChatHandler ch(bot); uint32 questId = ch.extractQuestId(text); + if (!questId) + { + 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()) != string::npos) + { + questId = quest->GetQuestId(); + break; + } + } + } + if (!questId) return false; From 2744d3d86901e4468ee89bdbe63ba112a972c694 Mon Sep 17 00:00:00 2001 From: ike3 Date: Mon, 4 Dec 2023 06:28:30 +0300 Subject: [PATCH 2/4] PlayAttackEmote with chance reduced --- playerbot/PlayerbotAI.cpp | 27 +++++++++++++++------ playerbot/PlayerbotAI.h | 1 + playerbot/PlayerbotAIConfig.cpp | 2 +- playerbot/strategy/actions/AttackAction.cpp | 10 +------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/playerbot/PlayerbotAI.cpp b/playerbot/PlayerbotAI.cpp index ba77fd9b0..d1425c66d 100644 --- a/playerbot/PlayerbotAI.cpp +++ b/playerbot/PlayerbotAI.cpp @@ -3331,14 +3331,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget, bool if (spellSuccess != SPELL_CAST_OK) return false; - if (urand(0, 100) < sPlayerbotAIConfig.attackEmoteChance * 600 && bot->IsInCombat()) - { - vector sounds; - sounds.push_back(TEXTEMOTE_OPENFIRE); - sounds.push_back(305); - sounds.push_back(307); - PlaySound(sounds[urand(0, sounds.size() - 1)]); - } + PlayAttackEmote(6); if(waitForSpell) { @@ -6033,3 +6026,21 @@ void PlayerbotAI::QueueChatResponse(uint8 msgtype, ObjectGuid guid1, ObjectGuid { chatReplies.push(ChatQueuedReply(msgtype, guid1.GetCounter(), guid2.GetCounter(), message, chanName, name, time(0) + urand(inCombat ? 10 : 5, inCombat ? 25 : 15))); } + + +bool PlayerbotAI::PlayAttackEmote(float chanceMultiplier) +{ + auto group = bot->GetGroup(); + if (group) chanceMultiplier /= (group->GetMembersCount() - 1); + if ((float)urand(0, 10000) * chanceMultiplier < sPlayerbotAIConfig.attackEmoteChance * 10000.0f && bot->IsInCombat()) + { + vector sounds; + sounds.push_back(TEXTEMOTE_OPENFIRE); + sounds.push_back(305); + sounds.push_back(307); + PlaySound(sounds[urand(0, sounds.size() - 1)]); + return true; + } + + return false; +} \ No newline at end of file diff --git a/playerbot/PlayerbotAI.h b/playerbot/PlayerbotAI.h index 30819eb04..b45661ff3 100644 --- a/playerbot/PlayerbotAI.h +++ b/playerbot/PlayerbotAI.h @@ -348,6 +348,7 @@ class PlayerbotAI : public PlayerbotAIBase void WaitForSpellCast(Spell *spell); bool PlaySound(uint32 emote); bool PlayEmote(uint32 emote); + bool PlayAttackEmote(float chanceDivider); void Ping(float x, float y); void Poi(float x, float y, string icon_name = "This way", Player* player = nullptr, uint32 flags = 99, uint32 icon = 6 /* red flag */, uint32 icon_data = 0); Item * FindPoison() const; diff --git a/playerbot/PlayerbotAIConfig.cpp b/playerbot/PlayerbotAIConfig.cpp index d1301ac0c..0a96cea1e 100644 --- a/playerbot/PlayerbotAIConfig.cpp +++ b/playerbot/PlayerbotAIConfig.cpp @@ -140,7 +140,7 @@ bool PlayerbotAIConfig::Initialize() randomBotMaxLevelChance = config.GetFloatDefault("AiPlayerbot.RandomBotMaxLevelChance", 0.15f); randomBotRpgChance = config.GetFloatDefault("AiPlayerbot.RandomBotRpgChance", 0.35f); usePotionChance = config.GetFloatDefault("AiPlayerbot.UsePotionChance", 1.0f); - attackEmoteChance = config.GetFloatDefault("AiPlayerbot.AttackEmoteChance", 0.01f); + attackEmoteChance = config.GetFloatDefault("AiPlayerbot.AttackEmoteChance", 0.0f); iterationsPerTick = config.GetIntDefault("AiPlayerbot.IterationsPerTick", 100); diff --git a/playerbot/strategy/actions/AttackAction.cpp b/playerbot/strategy/actions/AttackAction.cpp index ce62604d8..b7204c5ef 100644 --- a/playerbot/strategy/actions/AttackAction.cpp +++ b/playerbot/strategy/actions/AttackAction.cpp @@ -148,15 +148,7 @@ bool AttackAction::Attack(Player* requester, Unit* target) // Don't attack target if it is waiting for attack or in stealth if (!ai->HasStrategy("stealthed", BotState::BOT_STATE_COMBAT) && !isWaitingForAttack) { - if (urand(0, 100) < sPlayerbotAIConfig.attackEmoteChance * 100) - { - vector sounds; - sounds.push_back(TEXTEMOTE_OPENFIRE); - sounds.push_back(305); - sounds.push_back(307); - ai->PlaySound(sounds[urand(0, sounds.size() - 1)]); - } - + ai->PlayAttackEmote(1); return bot->Attack(target, !ai->IsRanged(bot) || (sServerFacade.GetDistance2d(bot, target) < 5.0f)); } else From 0321abf5705bc59cae67152acae80feb46f109fd Mon Sep 17 00:00:00 2001 From: ike3 Date: Tue, 22 Jun 2021 10:24:32 +0300 Subject: [PATCH 3/4] always/skip loot list: ll +[item] = always loot item ll ![item] = ignore item ll -[item] = remove from both lists --- playerbot/strategy/actions/LootAction.cpp | 4 + .../strategy/actions/LootStrategyAction.cpp | 87 +++++++++++++------ .../strategy/actions/LootStrategyAction.h | 3 + playerbot/strategy/values/ValueContext.h | 4 +- 4 files changed, 71 insertions(+), 27 deletions(-) diff --git a/playerbot/strategy/actions/LootAction.cpp b/playerbot/strategy/actions/LootAction.cpp index ac5e57759..d64b5c865 100644 --- a/playerbot/strategy/actions/LootAction.cpp +++ b/playerbot/strategy/actions/LootAction.cpp @@ -381,6 +381,10 @@ bool StoreLootAction::IsLootAllowed(ItemQualifier& itemQualifier, PlayerbotAI *a if (lootItems.find(itemQualifier.GetId()) != lootItems.end()) return true; + set& skipItems = AI_VALUE(set&, "skip loot list"); + if (skipItems.find(itemQualifier.GetId()) != skipItems.end()) + return false; + uint32 max = proto->MaxCount; if (max > 0 && ai->GetBot()->HasItemCount(itemQualifier.GetId(), max, true)) return false; diff --git a/playerbot/strategy/actions/LootStrategyAction.cpp b/playerbot/strategy/actions/LootStrategyAction.cpp index 2bcb926c8..d1ffddc02 100644 --- a/playerbot/strategy/actions/LootStrategyAction.cpp +++ b/playerbot/strategy/actions/LootStrategyAction.cpp @@ -15,6 +15,7 @@ bool LootStrategyAction::Execute(Event& event) LootObjectStack* lootItems = AI_VALUE(LootObjectStack*, "available loot"); set& alwaysLootItems = AI_VALUE(set&, "always loot list"); + set& skipLootItems = AI_VALUE(set&, "skip loot list"); if (strategy == "?") { @@ -25,23 +26,16 @@ bool LootStrategyAction::Execute(Event& event) ai->TellPlayer(requester, out); } - { - ostringstream out; - out << "Always loot items: "; - for (set::iterator i = alwaysLootItems.begin(); i != alwaysLootItems.end(); i++) - { - ItemPrototype const *proto = sItemStorage.LookupEntry(*i); - if (!proto) - { - continue; - } - - out << chat->formatItem(proto); - } - - ai->TellPlayer(requester, out); - } + TellLootList(requester, "always loot list"); + TellLootList(requester, "skip loot list"); } + else if (strategy == "clear") + { + alwaysLootItems.clear(); + skipLootItems.clear(); + ai->TellPlayer(requester, "My loot list is now empty"); + return true; + } else { set itemQualifiers = chat->parseItemQualifiers(strategy); @@ -58,11 +52,15 @@ bool LootStrategyAction::Execute(Event& event) return true; } + bool ignore = strategy.size() > 1 && strategy.substr(0, 1) == "!"; bool remove = strategy.size() > 1 && strategy.substr(0, 1) == "-"; bool query = strategy.size() > 1 && strategy.substr(0, 1) == "?"; + bool add = !ignore && !remove && !query; + bool changes = false; for (auto& qualifier : itemQualifiers) { ItemQualifier itemQualifier(qualifier); + auto itemid = itemQualifier.GetId(); if (query) { if (itemQualifier.GetProto()) @@ -72,20 +70,38 @@ bool LootStrategyAction::Execute(Event& event) ai->TellPlayer(requester, out.str()); } } - else if (remove) + + if (remove || add) { - set::iterator j = alwaysLootItems.find(itemQualifier.GetId()); - if (j != alwaysLootItems.end()) - { - alwaysLootItems.erase(j); - } + set::iterator j = skipLootItems.find(itemid); + if (j != skipLootItems.end()) skipLootItems.erase(j); + changes = true; + } + + if (remove || ignore) + { + set::iterator j = alwaysLootItems.find(itemid); + if (j != alwaysLootItems.end()) alwaysLootItems.erase(j); + changes = true; + } + + if (ignore) + { + skipLootItems.insert(itemid); + changes = true; + } - ai->TellPlayer(requester, "Item(s) removed from always loot list"); + if (add) + { + alwaysLootItems.insert(itemid); + changes = true; } - else + + if (changes) { - alwaysLootItems.insert(itemQualifier.GetId()); - ai->TellPlayer(requester, "Item(s) added to always loot list"); + TellLootList(requester, "always loot list"); + TellLootList(requester, "skip loot list"); + AI_VALUE(LootObjectStack*, "available loot")->Clear(); } } } @@ -93,3 +109,22 @@ bool LootStrategyAction::Execute(Event& event) return true; } +void LootStrategyAction::TellLootList(Player* requester, const string& name) +{ + set& alwaysLootItems = AI_VALUE(set&, name); + ostringstream out; + out << "My " << name << ":"; + + for (set::iterator i = alwaysLootItems.begin(); i != alwaysLootItems.end(); i++) + { + ItemPrototype const *proto = sItemStorage.LookupEntry(*i); + if (!proto) + { + continue; + } + + out << " " << chat->formatItem(proto); + } + + ai->TellPlayer(requester, out); +} \ No newline at end of file diff --git a/playerbot/strategy/actions/LootStrategyAction.h b/playerbot/strategy/actions/LootStrategyAction.h index 32500ae53..bf27bca9e 100644 --- a/playerbot/strategy/actions/LootStrategyAction.h +++ b/playerbot/strategy/actions/LootStrategyAction.h @@ -9,5 +9,8 @@ namespace ai public: LootStrategyAction(PlayerbotAI* ai) : ChatCommandAction(ai, "ll") {} virtual bool Execute(Event& event) override; + + private: + void TellLootList(Player* requester, const string& name); }; } diff --git a/playerbot/strategy/values/ValueContext.h b/playerbot/strategy/values/ValueContext.h index 29c5932fc..15b2c0a3c 100644 --- a/playerbot/strategy/values/ValueContext.h +++ b/playerbot/strategy/values/ValueContext.h @@ -183,6 +183,7 @@ namespace ai creators["stack space for item"] = &ValueContext::stack_space_for_item; creators["should loot object"] = &ValueContext::should_loot_object; creators["always loot list"] = &ValueContext::always_loot_list; + creators["skip loot list"] = &ValueContext::skip_loot_list; creators["loot strategy"] = &ValueContext::loot_strategy; creators["active rolls"] = &ValueContext::active_rolls; creators["last movement"] = &ValueContext::last_movement; @@ -456,7 +457,8 @@ namespace ai static UntypedValue* has_available_loot(PlayerbotAI* ai) { return new HasAvailableLootValue(ai); } static UntypedValue* stack_space_for_item(PlayerbotAI* ai) { return new StackSpaceForItem(ai); } static UntypedValue* should_loot_object(PlayerbotAI* ai) { return new ShouldLootObject(ai); } - static UntypedValue* always_loot_list(PlayerbotAI* ai) { return new AlwaysLootListValue(ai); } + static UntypedValue* always_loot_list(PlayerbotAI* ai) { return new AlwaysLootListValue(ai, "always loot list"); } + static UntypedValue* skip_loot_list(PlayerbotAI* ai) { return new AlwaysLootListValue(ai, "skip loot list"); } static UntypedValue* loot_strategy(PlayerbotAI* ai) { return new LootStrategyValue(ai); } static UntypedValue* active_rolls(PlayerbotAI* ai) { return new ActiveRolls(ai); } From b1a06c8812a180d4bd560e424dca5eca5f593db0 Mon Sep 17 00:00:00 2001 From: ike3 Date: Tue, 10 May 2022 18:00:30 +0300 Subject: [PATCH 4/4] ll ![gameobject] command to add GO to skip loot list, ll -[gameobject] to remove --- playerbot/LootObjectStack.cpp | 3 ++ .../strategy/actions/LootStrategyAction.cpp | 54 ++++++++++++++++--- .../strategy/actions/LootStrategyAction.h | 1 + playerbot/strategy/values/ValueContext.h | 2 + 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/playerbot/LootObjectStack.cpp b/playerbot/LootObjectStack.cpp index 5e0e05ba5..065dadeb8 100644 --- a/playerbot/LootObjectStack.cpp +++ b/playerbot/LootObjectStack.cpp @@ -119,6 +119,9 @@ void LootObject::Refresh(Player* bot, ObjectGuid guid) return; uint32 goId = go->GetGOInfo()->id; + set& skipGoLootList = ai->GetAiObjectContext()->GetValue& >("skip go loot list")->Get(); + if (skipGoLootList.find(goId) != skipGoLootList.end()) return; + uint32 lockId = go->GetGOInfo()->GetLockId(); LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); if (!lockInfo) diff --git a/playerbot/strategy/actions/LootStrategyAction.cpp b/playerbot/strategy/actions/LootStrategyAction.cpp index d1ffddc02..477111563 100644 --- a/playerbot/strategy/actions/LootStrategyAction.cpp +++ b/playerbot/strategy/actions/LootStrategyAction.cpp @@ -16,6 +16,7 @@ bool LootStrategyAction::Execute(Event& event) LootObjectStack* lootItems = AI_VALUE(LootObjectStack*, "available loot"); set& alwaysLootItems = AI_VALUE(set&, "always loot list"); set& skipLootItems = AI_VALUE(set&, "skip loot list"); + set& skipGoLootList = AI_VALUE(set&, "skip go loot list"); if (strategy == "?") { @@ -28,6 +29,7 @@ bool LootStrategyAction::Execute(Event& event) TellLootList(requester, "always loot list"); TellLootList(requester, "skip loot list"); + TellGoList(requester, "skip go loot list"); } else if (strategy == "clear") { @@ -39,8 +41,9 @@ bool LootStrategyAction::Execute(Event& event) else { set itemQualifiers = chat->parseItemQualifiers(strategy); + list gos = chat->parseGameobjects(strategy); - if (itemQualifiers.size() == 0) + if (itemQualifiers.size() == 0 && gos.size() == 0) { SET_AI_VALUE(string, "loot strategy", strategy); @@ -96,13 +99,34 @@ bool LootStrategyAction::Execute(Event& event) alwaysLootItems.insert(itemid); changes = true; } + } + + for (list::iterator i = gos.begin(); i != gos.end(); ++i) + { + GameObject *go = ai->GetGameObject(*i); + if (!go) continue; + uint32 goId = go->GetGOInfo()->id; - if (changes) + if (remove || add) { - TellLootList(requester, "always loot list"); - TellLootList(requester, "skip loot list"); - AI_VALUE(LootObjectStack*, "available loot")->Clear(); + set::iterator j = skipGoLootList.find(goId); + if (j != skipGoLootList.end()) skipGoLootList.erase(j); + changes = true; } + + if (ignore) + { + skipGoLootList.insert(goId); + changes = true; + } + } + + if (changes) + { + TellLootList(requester, "always loot list"); + TellLootList(requester, "skip loot list"); + TellGoList(requester, "skip go loot list"); + AI_VALUE(LootObjectStack*, "available loot")->Clear(); } } @@ -127,4 +151,22 @@ void LootStrategyAction::TellLootList(Player* requester, const string& name) } ai->TellPlayer(requester, out); -} \ No newline at end of file +} + +void LootStrategyAction::TellGoList(Player* requester, const string& name) +{ + set& skipGoItems = AI_VALUE(set&, name); + ostringstream out; + out << "My " << name << ":"; + + for (set::iterator i = skipGoItems.begin(); i != skipGoItems.end(); i++) + { + uint32 id = *i; + GameObjectInfo const *proto = sGOStorage.LookupEntry(id); + if (!proto) + continue; + + out << " |cFFFFFF00|Hfound:" << 0 << ":" << id << ":" << "|h[" << proto->name << "]|h|r"; + } + ai->TellPlayer(requester, out); +} diff --git a/playerbot/strategy/actions/LootStrategyAction.h b/playerbot/strategy/actions/LootStrategyAction.h index bf27bca9e..071c807fc 100644 --- a/playerbot/strategy/actions/LootStrategyAction.h +++ b/playerbot/strategy/actions/LootStrategyAction.h @@ -12,5 +12,6 @@ namespace ai private: void TellLootList(Player* requester, const string& name); + void TellGoList(Player* requester, const string& name); }; } diff --git a/playerbot/strategy/values/ValueContext.h b/playerbot/strategy/values/ValueContext.h index 15b2c0a3c..a0fdd6cee 100644 --- a/playerbot/strategy/values/ValueContext.h +++ b/playerbot/strategy/values/ValueContext.h @@ -184,6 +184,7 @@ namespace ai creators["should loot object"] = &ValueContext::should_loot_object; creators["always loot list"] = &ValueContext::always_loot_list; creators["skip loot list"] = &ValueContext::skip_loot_list; + creators["skip go loot list"] = &ValueContext::skip_go_loot_list; creators["loot strategy"] = &ValueContext::loot_strategy; creators["active rolls"] = &ValueContext::active_rolls; creators["last movement"] = &ValueContext::last_movement; @@ -459,6 +460,7 @@ namespace ai static UntypedValue* should_loot_object(PlayerbotAI* ai) { return new ShouldLootObject(ai); } static UntypedValue* always_loot_list(PlayerbotAI* ai) { return new AlwaysLootListValue(ai, "always loot list"); } static UntypedValue* skip_loot_list(PlayerbotAI* ai) { return new AlwaysLootListValue(ai, "skip loot list"); } + static UntypedValue* skip_go_loot_list(PlayerbotAI* ai) { return new AlwaysLootListValue(ai, "skip go loot list"); } static UntypedValue* loot_strategy(PlayerbotAI* ai) { return new LootStrategyValue(ai); } static UntypedValue* active_rolls(PlayerbotAI* ai) { return new ActiveRolls(ai); }