From cf6f2d85693df8b4b7ef640e2cd477c0c1706430 Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Tue, 22 Mar 2022 20:51:41 -0400 Subject: [PATCH 1/9] Initial attempt to merge playerbots from zero into two Most of the changes are pulled from https://github.com/mangoszero/server/commit/ee336830b59cfaad6d34354c32dc2001870d9292 or mangos zero HEAD. --- src/game/Object/Item.cpp | 7 + src/game/Object/Player.cpp | 40 + src/game/Object/Player.h | 22 + src/game/Server/WorldSession.cpp | 80 +- src/game/WorldHandlers/CharacterHandler.cpp | 121 ++ src/game/WorldHandlers/Chat.cpp | 5 + src/game/WorldHandlers/Chat.h | 6 + src/game/WorldHandlers/ChatHandler.cpp | 88 +- src/game/WorldHandlers/Group.h | 4 + src/game/WorldHandlers/Map.cpp | 3 + src/game/WorldHandlers/Spell.cpp | 7 + src/game/WorldHandlers/World.cpp | 36 + src/game/WorldHandlers/World.h | 22 + src/modules/Bots/CMakeLists.txt | 609 ++++++ src/modules/Bots/ahbot/AhBot.cpp | 1128 ++++++++++ src/modules/Bots/ahbot/AhBot.h | 87 + src/modules/Bots/ahbot/AhBotConfig.cpp | 64 + src/modules/Bots/ahbot/AhBotConfig.h | 88 + src/modules/Bots/ahbot/Category.cpp | 79 + src/modules/Bots/ahbot/Category.h | 323 +++ src/modules/Bots/ahbot/ConsumableCategory.cpp | 4 + src/modules/Bots/ahbot/ConsumableCategory.h | 87 + src/modules/Bots/ahbot/ItemBag.cpp | 197 ++ src/modules/Bots/ahbot/ItemBag.h | 82 + src/modules/Bots/ahbot/PricingStrategy.cpp | 244 +++ src/modules/Bots/ahbot/PricingStrategy.h | 58 + src/modules/Bots/ahbot/TradeCategory.cpp | 4 + src/modules/Bots/ahbot/TradeCategory.h | 42 + src/modules/Bots/ahbot/ahbot.conf.dist.in | 209 ++ src/modules/Bots/botpch.cpp | 1 + src/modules/Bots/botpch.h | 16 + src/modules/Bots/playerbot/AiFactory.cpp | 303 +++ src/modules/Bots/playerbot/AiFactory.h | 21 + src/modules/Bots/playerbot/ChatFilter.cpp | 311 +++ src/modules/Bots/playerbot/ChatFilter.h | 24 + src/modules/Bots/playerbot/ChatHelper.cpp | 468 +++++ src/modules/Bots/playerbot/ChatHelper.h | 50 + src/modules/Bots/playerbot/FleeManager.cpp | 175 ++ src/modules/Bots/playerbot/FleeManager.h | 87 + src/modules/Bots/playerbot/Helpers.cpp | 79 + .../Bots/playerbot/LazyCalculatedValue.h | 42 + .../Bots/playerbot/LootObjectStack.cpp | 273 +++ src/modules/Bots/playerbot/LootObjectStack.h | 76 + src/modules/Bots/playerbot/PlayerbotAI.cpp | 1299 ++++++++++++ src/modules/Bots/playerbot/PlayerbotAI.h | 183 ++ src/modules/Bots/playerbot/PlayerbotAIAware.h | 13 + .../Bots/playerbot/PlayerbotAIBase.cpp | 63 + src/modules/Bots/playerbot/PlayerbotAIBase.h | 24 + .../Bots/playerbot/PlayerbotAIConfig.cpp | 363 ++++ .../Bots/playerbot/PlayerbotAIConfig.h | 67 + .../Bots/playerbot/PlayerbotFactory.cpp | 1815 +++++++++++++++++ src/modules/Bots/playerbot/PlayerbotFactory.h | 67 + src/modules/Bots/playerbot/PlayerbotMgr.cpp | 490 +++++ src/modules/Bots/playerbot/PlayerbotMgr.h | 67 + .../Bots/playerbot/PlayerbotSecurity.cpp | 205 ++ .../Bots/playerbot/PlayerbotSecurity.h | 42 + .../Bots/playerbot/RandomPlayerbotFactory.cpp | 144 ++ .../Bots/playerbot/RandomPlayerbotFactory.h | 32 + .../Bots/playerbot/RandomPlayerbotMgr.cpp | 966 +++++++++ .../Bots/playerbot/RandomPlayerbotMgr.h | 66 + .../Bots/playerbot/aiplayerbot.conf.dist.in | 164 ++ src/modules/Bots/playerbot/playerbot.h | 28 + src/modules/Bots/playerbot/playerbotDefs.h | 2 + .../Bots/playerbot/strategy/Action.cpp | 111 + src/modules/Bots/playerbot/strategy/Action.h | 138 ++ .../Bots/playerbot/strategy/ActionBasket.cpp | 4 + .../Bots/playerbot/strategy/ActionBasket.h | 5 + .../Bots/playerbot/strategy/AiObject.cpp | 16 + .../Bots/playerbot/strategy/AiObject.h | 33 + .../playerbot/strategy/AiObjectContext.cpp | 48 + .../Bots/playerbot/strategy/AiObjectContext.h | 85 + .../Bots/playerbot/strategy/Engine.cpp | 578 ++++++ src/modules/Bots/playerbot/strategy/Engine.h | 123 ++ src/modules/Bots/playerbot/strategy/Event.cpp | 22 + src/modules/Bots/playerbot/strategy/Event.h | 36 + .../playerbot/strategy/ExternalEventHelper.h | 83 + .../Bots/playerbot/strategy/ItemVisitors.h | 282 +++ .../Bots/playerbot/strategy/Multiplier.cpp | 5 + .../Bots/playerbot/strategy/Multiplier.h | 16 + .../playerbot/strategy/NamedObjectContext.h | 281 +++ .../playerbot/strategy/PassiveMultiplier.cpp | 53 + .../playerbot/strategy/PassiveMultiplier.h | 20 + src/modules/Bots/playerbot/strategy/Queue.cpp | 83 + src/modules/Bots/playerbot/strategy/Queue.h | 21 + .../Bots/playerbot/strategy/Strategy.cpp | 117 ++ .../Bots/playerbot/strategy/Strategy.h | 55 + .../Bots/playerbot/strategy/StrategyContext.h | 161 ++ .../Bots/playerbot/strategy/Trigger.cpp | 27 + src/modules/Bots/playerbot/strategy/Trigger.h | 86 + src/modules/Bots/playerbot/strategy/Value.cpp | 5 + src/modules/Bots/playerbot/strategy/Value.h | 181 ++ .../strategy/actions/AcceptDuelAction.h | 31 + .../strategy/actions/AcceptInvitationAction.h | 52 + .../strategy/actions/AcceptQuestAction.cpp | 117 ++ .../strategy/actions/AcceptQuestAction.h | 27 + .../strategy/actions/AcceptResurrectAction.h | 33 + .../strategy/actions/ActionContext.h | 117 ++ .../strategy/actions/AddLootAction.cpp | 74 + .../strategy/actions/AddLootAction.h | 32 + .../strategy/actions/AreaTriggerAction.cpp | 93 + .../strategy/actions/AreaTriggerAction.h | 23 + .../strategy/actions/AttackAction.cpp | 118 ++ .../playerbot/strategy/actions/AttackAction.h | 38 + .../playerbot/strategy/actions/BankAction.cpp | 186 ++ .../playerbot/strategy/actions/BankAction.h | 21 + .../playerbot/strategy/actions/BuffAction.cpp | 132 ++ .../playerbot/strategy/actions/BuffAction.h | 17 + .../playerbot/strategy/actions/BuyAction.cpp | 60 + .../playerbot/strategy/actions/BuyAction.h | 19 + .../actions/CastCustomSpellAction.cpp | 56 + .../strategy/actions/CastCustomSpellAction.h | 14 + .../strategy/actions/ChangeChatAction.cpp | 26 + .../strategy/actions/ChangeChatAction.h | 14 + .../strategy/actions/ChangeStrategyAction.cpp | 38 + .../strategy/actions/ChangeStrategyAction.h | 30 + .../strategy/actions/ChangeTalentsAction.cpp | 10 + .../strategy/actions/ChangeTalentsAction.h | 16 + .../strategy/actions/ChatActionContext.h | 179 ++ .../strategy/actions/ChatShortcutActions.cpp | 124 ++ .../strategy/actions/ChatShortcutActions.h | 57 + .../actions/CheckMountStateAction.cpp | 81 + .../strategy/actions/CheckMountStateAction.h | 19 + .../strategy/actions/ChooseTargetActions.h | 79 + .../strategy/actions/DestroyItemAction.cpp | 35 + .../strategy/actions/DestroyItemAction.h | 17 + .../strategy/actions/DropQuestAction.cpp | 22 + .../strategy/actions/DropQuestAction.h | 13 + .../strategy/actions/EmoteAction.cpp | 100 + .../playerbot/strategy/actions/EmoteAction.h | 18 + .../strategy/actions/EquipAction.cpp | 51 + .../playerbot/strategy/actions/EquipAction.h | 18 + .../strategy/actions/FollowActions.cpp | 33 + .../strategy/actions/FollowActions.h | 37 + .../strategy/actions/GenericActions.cpp | 5 + .../strategy/actions/GenericActions.h | 19 + .../strategy/actions/GenericSpellActions.cpp | 62 + .../strategy/actions/GenericSpellActions.h | 277 +++ .../strategy/actions/GossipHelloAction.cpp | 77 + .../strategy/actions/GossipHelloAction.h | 13 + .../strategy/actions/GuildAcceptAction.cpp | 44 + .../strategy/actions/GuildAcceptAction.h | 14 + .../strategy/actions/GuildBankAction.cpp | 67 + .../strategy/actions/GuildBankAction.h | 18 + .../playerbot/strategy/actions/HelpAction.cpp | 56 + .../playerbot/strategy/actions/HelpAction.h | 22 + .../strategy/actions/InventoryAction.cpp | 308 +++ .../strategy/actions/InventoryAction.h | 24 + .../actions/InventoryChangeFailureAction.cpp | 54 + .../actions/InventoryChangeFailureAction.h | 12 + .../strategy/actions/InviteToGroupAction.h | 30 + .../strategy/actions/LeaveGroupAction.h | 87 + .../playerbot/strategy/actions/LfgActions.cpp | 10 + .../playerbot/strategy/actions/LfgActions.h | 9 + .../strategy/actions/ListQuestsActions.cpp | 81 + .../strategy/actions/ListQuestsActions.h | 25 + .../strategy/actions/ListSpellsAction.cpp | 76 + .../strategy/actions/ListSpellsAction.h | 16 + .../strategy/actions/LogLevelAction.cpp | 59 + .../strategy/actions/LogLevelAction.h | 17 + .../playerbot/strategy/actions/LootAction.cpp | 392 ++++ .../playerbot/strategy/actions/LootAction.h | 39 + .../strategy/actions/LootRollAction.cpp | 62 + .../strategy/actions/LootRollAction.h | 15 + .../strategy/actions/LootStrategyAction.cpp | 114 ++ .../strategy/actions/LootStrategyAction.h | 19 + .../strategy/actions/MovementActions.cpp | 419 ++++ .../strategy/actions/MovementActions.h | 92 + .../strategy/actions/NonCombatActions.cpp | 6 + .../strategy/actions/NonCombatActions.h | 51 + .../actions/PassLeadershipToMasterAction.h | 26 + .../strategy/actions/PositionAction.cpp | 42 + .../strategy/actions/PositionAction.h | 37 + .../strategy/actions/QueryItemUsageAction.cpp | 189 ++ .../strategy/actions/QueryItemUsageAction.h | 24 + .../strategy/actions/QueryQuestAction.cpp | 98 + .../strategy/actions/QueryQuestAction.h | 16 + .../strategy/actions/QuestAction.cpp | 161 ++ .../playerbot/strategy/actions/QuestAction.h | 33 + .../strategy/actions/ReachTargetActions.h | 57 + .../strategy/actions/ReadyCheckAction.cpp | 87 + .../strategy/actions/ReadyCheckAction.h | 26 + .../strategy/actions/ReleaseSpiritAction.h | 31 + .../strategy/actions/RememberTaxiAction.cpp | 46 + .../strategy/actions/RememberTaxiAction.h | 13 + .../strategy/actions/RepairAllAction.cpp | 37 + .../strategy/actions/RepairAllAction.h | 13 + .../strategy/actions/ResetAiAction.cpp | 12 + .../strategy/actions/ResetAiAction.h | 14 + .../actions/ReviveFromCorpseAction.cpp | 62 + .../strategy/actions/ReviveFromCorpseAction.h | 21 + .../strategy/actions/RewardAction.cpp | 81 + .../playerbot/strategy/actions/RewardAction.h | 17 + .../playerbot/strategy/actions/RtiAction.h | 46 + .../strategy/actions/SaveManaAction.cpp | 81 + .../strategy/actions/SaveManaAction.h | 20 + .../strategy/actions/SecurityCheckAction.cpp | 30 + .../strategy/actions/SecurityCheckAction.h | 14 + .../playerbot/strategy/actions/SellAction.cpp | 101 + .../playerbot/strategy/actions/SellAction.h | 18 + .../strategy/actions/SetHomeAction.cpp | 50 + .../strategy/actions/SetHomeAction.h | 12 + .../strategy/actions/StatsAction.cpp | 165 ++ .../playerbot/strategy/actions/StatsAction.h | 22 + .../strategy/actions/StayActions.cpp | 274 +++ .../playerbot/strategy/actions/StayActions.h | 42 + .../actions/SuggestWhatToDoAction.cpp | 287 +++ .../strategy/actions/SuggestWhatToDoAction.h | 33 + .../actions/TalkToQuestGiverAction.cpp | 99 + .../strategy/actions/TalkToQuestGiverAction.h | 22 + .../playerbot/strategy/actions/TaxiAction.cpp | 53 + .../playerbot/strategy/actions/TaxiAction.h | 13 + .../strategy/actions/TeleportAction.cpp | 60 + .../strategy/actions/TeleportAction.h | 16 + .../strategy/actions/TellCastFailedAction.cpp | 75 + .../strategy/actions/TellCastFailedAction.h | 22 + .../strategy/actions/TellItemCountAction.cpp | 18 + .../strategy/actions/TellItemCountAction.h | 14 + .../strategy/actions/TellLosAction.cpp | 65 + .../strategy/actions/TellLosAction.h | 17 + .../strategy/actions/TellMasterAction.h | 38 + .../strategy/actions/TellReputationAction.cpp | 79 + .../strategy/actions/TellReputationAction.h | 16 + .../strategy/actions/TellTargetAction.cpp | 58 + .../strategy/actions/TellTargetAction.h | 21 + .../strategy/actions/TradeAction.cpp | 95 + .../playerbot/strategy/actions/TradeAction.h | 19 + .../strategy/actions/TradeStatusAction.cpp | 224 ++ .../strategy/actions/TradeStatusAction.h | 20 + .../strategy/actions/TrainerAction.cpp | 140 ++ .../strategy/actions/TrainerAction.h | 22 + .../strategy/actions/UnequipAction.cpp | 45 + .../strategy/actions/UnequipAction.h | 18 + .../strategy/actions/UseItemAction.cpp | 327 +++ .../strategy/actions/UseItemAction.h | 47 + .../actions/UseMeetingStoneAction.cpp | 145 ++ .../strategy/actions/UseMeetingStoneAction.h | 26 + .../playerbot/strategy/actions/WhoAction.cpp | 173 ++ .../playerbot/strategy/actions/WhoAction.h | 23 + .../actions/WorldPacketActionContext.h | 98 + .../strategy/druid/BearTankDruidStrategy.cpp | 171 ++ .../strategy/druid/BearTankDruidStrategy.h | 18 + .../strategy/druid/CasterDruidStrategy.cpp | 177 ++ .../strategy/druid/CasterDruidStrategy.h | 39 + .../strategy/druid/CatDpsDruidStrategy.cpp | 139 ++ .../strategy/druid/CatDpsDruidStrategy.h | 29 + .../playerbot/strategy/druid/DruidActions.cpp | 31 + .../playerbot/strategy/druid/DruidActions.h | 184 ++ .../strategy/druid/DruidAiObjectContext.cpp | 252 +++ .../strategy/druid/DruidAiObjectContext.h | 12 + .../strategy/druid/DruidBearActions.h | 64 + .../strategy/druid/DruidCatActions.h | 69 + .../strategy/druid/DruidMultipliers.cpp | 6 + .../strategy/druid/DruidMultipliers.h | 6 + .../strategy/druid/DruidShapeshiftActions.h | 53 + .../strategy/druid/DruidTriggers.cpp | 7 + .../playerbot/strategy/druid/DruidTriggers.h | 127 ++ .../strategy/druid/FeralDruidStrategy.cpp | 90 + .../strategy/druid/FeralDruidStrategy.h | 75 + .../druid/GenericDruidNonCombatStrategy.cpp | 73 + .../druid/GenericDruidNonCombatStrategy.h | 16 + .../strategy/druid/GenericDruidStrategy.cpp | 132 ++ .../strategy/druid/GenericDruidStrategy.h | 18 + .../strategy/druid/HealDruidStrategy.cpp | 57 + .../strategy/druid/HealDruidStrategy.h | 18 + .../generic/AttackEnemyPlayersStrategy.cpp | 13 + .../generic/AttackEnemyPlayersStrategy.h | 16 + .../strategy/generic/AttackRtiStrategy.cpp | 14 + .../strategy/generic/AttackRtiStrategy.h | 16 + .../strategy/generic/AttackWeakStrategy.cpp | 13 + .../strategy/generic/AttackWeakStrategy.h | 16 + .../strategy/generic/CastTimeStrategy.cpp | 42 + .../strategy/generic/CastTimeStrategy.h | 26 + .../generic/ChatCommandHandlerStrategy.cpp | 176 ++ .../generic/ChatCommandHandlerStrategy.h | 15 + .../strategy/generic/CombatStrategy.cpp | 12 + .../strategy/generic/CombatStrategy.h | 13 + .../strategy/generic/ConserveManaStrategy.cpp | 116 ++ .../strategy/generic/ConserveManaStrategy.h | 32 + .../strategy/generic/DeadStrategy.cpp | 23 + .../playerbot/strategy/generic/DeadStrategy.h | 15 + .../strategy/generic/DpsAoeStrategy.cpp | 12 + .../strategy/generic/DpsAoeStrategy.h | 18 + .../strategy/generic/DpsAssistStrategy.cpp | 15 + .../strategy/generic/DpsAssistStrategy.h | 16 + .../strategy/generic/DuelStrategy.cpp | 24 + .../playerbot/strategy/generic/DuelStrategy.h | 15 + .../strategy/generic/EmoteStrategy.cpp | 17 + .../strategy/generic/EmoteStrategy.h | 16 + .../strategy/generic/FleeStrategy.cpp | 26 + .../playerbot/strategy/generic/FleeStrategy.h | 21 + .../strategy/generic/FollowLineStrategy.cpp | 10 + .../strategy/generic/FollowLineStrategy.h | 13 + .../generic/FollowMasterRandomStrategy.cpp | 20 + .../generic/FollowMasterRandomStrategy.h | 14 + .../strategy/generic/FollowMasterStrategy.cpp | 17 + .../strategy/generic/FollowMasterStrategy.h | 16 + .../strategy/generic/GrindingStrategy.cpp | 20 + .../strategy/generic/GrindingStrategy.h | 20 + .../strategy/generic/GuardStrategy.cpp | 16 + .../strategy/generic/GuardStrategy.h | 19 + .../strategy/generic/KiteStrategy.cpp | 16 + .../playerbot/strategy/generic/KiteStrategy.h | 15 + .../generic/LootNonCombatStrategy.cpp | 29 + .../strategy/generic/LootNonCombatStrategy.h | 24 + .../strategy/generic/MeleeCombatStrategy.cpp | 23 + .../strategy/generic/MeleeCombatStrategy.h | 16 + .../strategy/generic/MoveRandomStrategy.cpp | 13 + .../strategy/generic/MoveRandomStrategy.h | 16 + .../strategy/generic/NonCombatStrategy.cpp | 12 + .../strategy/generic/NonCombatStrategy.h | 12 + .../strategy/generic/PassTroughStrategy.h | 26 + .../strategy/generic/PassiveStrategy.cpp | 13 + .../strategy/generic/PassiveStrategy.h | 16 + .../strategy/generic/PullStrategy.cpp | 54 + .../playerbot/strategy/generic/PullStrategy.h | 24 + .../strategy/generic/QuestStrategies.cpp | 69 + .../strategy/generic/QuestStrategies.h | 34 + .../strategy/generic/RacialsStrategy.cpp | 39 + .../strategy/generic/RacialsStrategy.h | 15 + .../strategy/generic/RangedCombatStrategy.cpp | 15 + .../strategy/generic/RangedCombatStrategy.h | 15 + .../strategy/generic/RunawayStrategy.cpp | 18 + .../strategy/generic/RunawayStrategy.h | 16 + .../strategy/generic/StayCircleStrategy.cpp | 11 + .../strategy/generic/StayCircleStrategy.h | 14 + .../strategy/generic/StayCombatStrategy.cpp | 10 + .../strategy/generic/StayCombatStrategy.h | 13 + .../strategy/generic/StayLineStrategy.cpp | 10 + .../strategy/generic/StayLineStrategy.h | 14 + .../strategy/generic/StayStrategy.cpp | 11 + .../playerbot/strategy/generic/StayStrategy.h | 14 + .../strategy/generic/TankAoeStrategy.cpp | 12 + .../strategy/generic/TankAoeStrategy.h | 18 + .../strategy/generic/TankAssistStrategy.cpp | 13 + .../strategy/generic/TankAssistStrategy.h | 17 + .../strategy/generic/TellTargetStrategy.cpp | 13 + .../strategy/generic/TellTargetStrategy.h | 16 + .../strategy/generic/ThreatStrategy.cpp | 38 + .../strategy/generic/ThreatStrategy.h | 25 + .../strategy/generic/UseFoodStrategy.cpp | 18 + .../strategy/generic/UseFoodStrategy.h | 15 + .../strategy/generic/UsePotionsStrategy.cpp | 18 + .../strategy/generic/UsePotionsStrategy.h | 15 + .../generic/WorldPacketHandlerStrategy.cpp | 116 ++ .../generic/WorldPacketHandlerStrategy.h | 25 + .../strategy/hunter/DpsHunterStrategy.cpp | 118 ++ .../strategy/hunter/DpsHunterStrategy.h | 39 + .../hunter/GenericHunterNonCombatStrategy.cpp | 58 + .../hunter/GenericHunterNonCombatStrategy.h | 17 + .../strategy/hunter/GenericHunterStrategy.cpp | 66 + .../strategy/hunter/GenericHunterStrategy.h | 20 + .../strategy/hunter/HunterActions.cpp | 26 + .../playerbot/strategy/hunter/HunterActions.h | 132 ++ .../strategy/hunter/HunterAiObjectContext.cpp | 183 ++ .../strategy/hunter/HunterAiObjectContext.h | 12 + .../strategy/hunter/HunterBuffStrategies.cpp | 35 + .../strategy/hunter/HunterBuffStrategies.h | 47 + .../strategy/hunter/HunterMultipliers.cpp | 5 + .../strategy/hunter/HunterMultipliers.h | 6 + .../strategy/hunter/HunterTriggers.cpp | 29 + .../strategy/hunter/HunterTriggers.h | 86 + .../strategy/mage/ArcaneMageStrategy.cpp | 64 + .../strategy/mage/ArcaneMageStrategy.h | 18 + .../strategy/mage/FireMageStrategy.cpp | 44 + .../strategy/mage/FireMageStrategy.h | 28 + .../strategy/mage/FrostMageStrategy.cpp | 32 + .../strategy/mage/FrostMageStrategy.h | 28 + .../mage/GenericMageNonCombatStrategy.cpp | 87 + .../mage/GenericMageNonCombatStrategy.h | 37 + .../strategy/mage/GenericMageStrategy.cpp | 137 ++ .../strategy/mage/GenericMageStrategy.h | 17 + .../playerbot/strategy/mage/MageActions.cpp | 10 + .../playerbot/strategy/mage/MageActions.h | 157 ++ .../strategy/mage/MageAiObjectContext.cpp | 205 ++ .../strategy/mage/MageAiObjectContext.h | 12 + .../strategy/mage/MageMultipliers.cpp | 6 + .../playerbot/strategy/mage/MageMultipliers.h | 6 + .../playerbot/strategy/mage/MageTriggers.cpp | 15 + .../playerbot/strategy/mage/MageTriggers.h | 92 + .../strategy/paladin/DpsPaladinStrategy.cpp | 83 + .../strategy/paladin/DpsPaladinStrategy.h | 18 + .../GenericPaladinNonCombatStrategy.cpp | 65 + .../paladin/GenericPaladinNonCombatStrategy.h | 16 + .../paladin/GenericPaladinStrategy.cpp | 77 + .../strategy/paladin/GenericPaladinStrategy.h | 18 + .../GenericPaladinStrategyActionNodeFactory.h | 142 ++ .../strategy/paladin/PaladinActions.cpp | 6 + .../strategy/paladin/PaladinActions.h | 325 +++ .../paladin/PaladinAiObjectContext.cpp | 265 +++ .../strategy/paladin/PaladinAiObjectContext.h | 12 + .../paladin/PaladinBuffStrategies.cpp | 72 + .../strategy/paladin/PaladinBuffStrategies.h | 86 + .../strategy/paladin/PaladinMultipliers.cpp | 6 + .../strategy/paladin/PaladinMultipliers.h | 6 + .../strategy/paladin/PaladinTriggers.cpp | 23 + .../strategy/paladin/PaladinTriggers.h | 114 ++ .../strategy/paladin/TankPaladinStrategy.cpp | 70 + .../strategy/paladin/TankPaladinStrategy.h | 18 + .../strategy/priest/GenericPriestStrategy.cpp | 67 + .../strategy/priest/GenericPriestStrategy.h | 17 + .../GenericPriestStrategyActionNodeFactory.h | 173 ++ .../strategy/priest/HealPriestStrategy.cpp | 36 + .../strategy/priest/HealPriestStrategy.h | 18 + .../strategy/priest/HolyPriestStrategy.cpp | 46 + .../strategy/priest/HolyPriestStrategy.h | 18 + .../strategy/priest/PriestActions.cpp | 17 + .../playerbot/strategy/priest/PriestActions.h | 229 +++ .../strategy/priest/PriestAiObjectContext.cpp | 211 ++ .../strategy/priest/PriestAiObjectContext.h | 12 + .../strategy/priest/PriestMultipliers.cpp | 6 + .../strategy/priest/PriestMultipliers.h | 6 + .../priest/PriestNonCombatStrategy.cpp | 82 + .../strategy/priest/PriestNonCombatStrategy.h | 17 + ...PriestNonCombatStrategyActionNodeFactory.h | 126 ++ .../strategy/priest/PriestTriggers.cpp | 7 + .../strategy/priest/PriestTriggers.h | 54 + .../strategy/priest/ShadowPriestStrategy.cpp | 60 + .../strategy/priest/ShadowPriestStrategy.h | 38 + .../ShadowPriestStrategyActionNodeFactory.h | 37 + .../strategy/rogue/DpsRogueStrategy.cpp | 110 + .../strategy/rogue/DpsRogueStrategy.h | 18 + .../rogue/GenericRogueNonCombatStrategy.cpp | 14 + .../rogue/GenericRogueNonCombatStrategy.h | 16 + .../playerbot/strategy/rogue/RogueActions.cpp | 5 + .../playerbot/strategy/rogue/RogueActions.h | 63 + .../strategy/rogue/RogueAiObjectContext.cpp | 119 ++ .../strategy/rogue/RogueAiObjectContext.h | 12 + .../strategy/rogue/RogueComboActions.h | 45 + .../strategy/rogue/RogueFinishingActions.h | 35 + .../strategy/rogue/RogueMultipliers.cpp | 6 + .../strategy/rogue/RogueMultipliers.h | 6 + .../strategy/rogue/RogueOpeningActions.h | 24 + .../strategy/rogue/RogueTriggers.cpp | 7 + .../playerbot/strategy/rogue/RogueTriggers.h | 36 + .../strategy/shaman/CasterShamanStrategy.cpp | 75 + .../strategy/shaman/CasterShamanStrategy.h | 29 + .../strategy/shaman/GenericShamanStrategy.cpp | 159 ++ .../strategy/shaman/GenericShamanStrategy.h | 39 + .../strategy/shaman/HealShamanStrategy.cpp | 82 + .../strategy/shaman/HealShamanStrategy.h | 17 + .../strategy/shaman/MeleeShamanStrategy.cpp | 93 + .../strategy/shaman/MeleeShamanStrategy.h | 28 + .../strategy/shaman/ShamanActions.cpp | 6 + .../playerbot/strategy/shaman/ShamanActions.h | 210 ++ .../strategy/shaman/ShamanAiObjectContext.cpp | 236 +++ .../strategy/shaman/ShamanAiObjectContext.h | 12 + .../strategy/shaman/ShamanMultipliers.cpp | 6 + .../strategy/shaman/ShamanMultipliers.h | 6 + .../shaman/ShamanNonCombatStrategy.cpp | 49 + .../strategy/shaman/ShamanNonCombatStrategy.h | 19 + .../strategy/shaman/ShamanTriggers.cpp | 42 + .../strategy/shaman/ShamanTriggers.h | 197 ++ .../strategy/shaman/TotemsShamanStrategy.cpp | 31 + .../strategy/shaman/TotemsShamanStrategy.h | 17 + .../strategy/triggers/ChatCommandTrigger.h | 38 + .../strategy/triggers/ChatTriggerContext.h | 138 ++ .../strategy/triggers/CureTriggers.cpp | 17 + .../strategy/triggers/CureTriggers.h | 35 + .../strategy/triggers/GenericTriggers.cpp | 248 +++ .../strategy/triggers/GenericTriggers.h | 540 +++++ .../strategy/triggers/HealthTriggers.cpp | 26 + .../strategy/triggers/HealthTriggers.h | 139 ++ .../playerbot/strategy/triggers/LfgTriggers.h | 17 + .../strategy/triggers/LootTriggers.cpp | 20 + .../strategy/triggers/LootTriggers.h | 30 + .../strategy/triggers/RangeTriggers.h | 81 + .../strategy/triggers/TriggerContext.h | 158 ++ .../strategy/triggers/WithinAreaTrigger.h | 36 + .../strategy/triggers/WorldPacketTrigger.h | 38 + .../triggers/WorldPacketTriggerContext.h | 83 + .../strategy/values/AlwaysLootListValue.h | 14 + .../strategy/values/AoeHealValues.cpp | 49 + .../playerbot/strategy/values/AoeHealValues.h | 14 + .../strategy/values/AttackerCountValues.cpp | 123 ++ .../strategy/values/AttackerCountValues.h | 59 + .../values/AttackerWithoutAuraTargetValue.cpp | 32 + .../values/AttackerWithoutAuraTargetValue.h | 15 + .../strategy/values/AttackersValue.cpp | 99 + .../strategy/values/AttackersValue.h | 20 + .../strategy/values/AvailableLootValue.h | 42 + .../strategy/values/CcTargetValue.cpp | 102 + .../playerbot/strategy/values/CcTargetValue.h | 16 + .../playerbot/strategy/values/ChatValue.h | 11 + .../strategy/values/CurrentCcTargetValue.cpp | 33 + .../strategy/values/CurrentCcTargetValue.h | 16 + .../strategy/values/CurrentTargetValue.cpp | 28 + .../strategy/values/CurrentTargetValue.h | 17 + .../playerbot/strategy/values/DistanceValue.h | 41 + .../strategy/values/DpsTargetValue.cpp | 45 + .../strategy/values/DpsTargetValue.h | 16 + .../strategy/values/DuelTargetValue.cpp | 10 + .../strategy/values/DuelTargetValue.h | 15 + .../values/EnemyHealerTargetValue.cpp | 46 + .../strategy/values/EnemyHealerTargetValue.h | 15 + .../strategy/values/EnemyPlayerValue.cpp | 36 + .../strategy/values/EnemyPlayerValue.h | 15 + .../strategy/values/GrindTargetValue.cpp | 150 ++ .../strategy/values/GrindTargetValue.h | 20 + .../strategy/values/HasAvailableLootValue.h | 20 + .../playerbot/strategy/values/HasTotemValue.h | 40 + .../strategy/values/InvalidTargetValue.cpp | 26 + .../strategy/values/InvalidTargetValue.h | 14 + .../playerbot/strategy/values/IsBehindValue.h | 27 + .../playerbot/strategy/values/IsFacingValue.h | 22 + .../playerbot/strategy/values/IsMovingValue.h | 46 + .../strategy/values/ItemCountValue.cpp | 39 + .../strategy/values/ItemCountValue.h | 35 + .../strategy/values/ItemForSpellValue.cpp | 90 + .../strategy/values/ItemForSpellValue.h | 20 + .../strategy/values/ItemUsageValue.cpp | 134 ++ .../strategy/values/ItemUsageValue.h | 27 + .../strategy/values/LastMovementValue.h | 61 + .../strategy/values/LastSpellCastTimeValue.h | 11 + .../strategy/values/LastSpellCastValue.h | 39 + .../strategy/values/LeastHpTargetValue.cpp | 35 + .../strategy/values/LeastHpTargetValue.h | 15 + .../playerbot/strategy/values/LfgValues.h | 12 + .../strategy/values/LineTargetValue.cpp | 41 + .../strategy/values/LineTargetValue.h | 14 + .../playerbot/strategy/values/LogLevelValue.h | 12 + .../strategy/values/LootStrategyValue.h | 11 + .../strategy/values/ManaSaveLevelValue.h | 11 + .../strategy/values/MasterTargetValue.h | 13 + .../strategy/values/NearestAdsValue.cpp | 11 + .../strategy/values/NearestAdsValue.h | 18 + .../strategy/values/NearestCorpsesValue.cpp | 36 + .../strategy/values/NearestCorpsesValue.h | 19 + .../strategy/values/NearestGameObjects.cpp | 51 + .../strategy/values/NearestGameObjects.h | 19 + .../strategy/values/NearestNpcsValue.cpp | 22 + .../strategy/values/NearestNpcsValue.h | 18 + .../strategy/values/NearestUnitsValue.h | 38 + .../strategy/values/PartyMemberToDispel.cpp | 35 + .../strategy/values/PartyMemberToDispel.h | 16 + .../strategy/values/PartyMemberToHeal.cpp | 66 + .../strategy/values/PartyMemberToHeal.h | 17 + .../values/PartyMemberToResurrect.cpp | 44 + .../strategy/values/PartyMemberToResurrect.h | 16 + .../strategy/values/PartyMemberValue.cpp | 131 ++ .../strategy/values/PartyMemberValue.h | 31 + .../values/PartyMemberWithoutAuraValue.cpp | 33 + .../values/PartyMemberWithoutAuraValue.h | 17 + .../strategy/values/PetTargetValue.h | 13 + .../strategy/values/PositionValue.cpp | 10 + .../playerbot/strategy/values/PositionValue.h | 26 + .../strategy/values/PossibleTargetsValue.cpp | 23 + .../strategy/values/PossibleTargetsValue.h | 19 + .../strategy/values/RtiTargetValue.h | 82 + .../playerbot/strategy/values/RtiValue.cpp | 37 + .../Bots/playerbot/strategy/values/RtiValue.h | 11 + .../strategy/values/SelfTargetValue.h | 13 + .../strategy/values/SpellCastUsefulValue.cpp | 54 + .../strategy/values/SpellCastUsefulValue.h | 17 + .../strategy/values/SpellIdValue.cpp | 117 ++ .../playerbot/strategy/values/SpellIdValue.h | 17 + .../playerbot/strategy/values/StatsValues.cpp | 131 ++ .../playerbot/strategy/values/StatsValues.h | 133 ++ .../strategy/values/TankTargetValue.cpp | 47 + .../strategy/values/TankTargetValue.h | 16 + .../playerbot/strategy/values/TargetValue.cpp | 66 + .../playerbot/strategy/values/TargetValue.h | 39 + .../strategy/values/ThreatValues.cpp | 79 + .../playerbot/strategy/values/ThreatValues.h | 17 + .../playerbot/strategy/values/ValueContext.h | 222 ++ .../strategy/warlock/DpsWarlockStrategy.cpp | 76 + .../strategy/warlock/DpsWarlockStrategy.h | 39 + .../GenericWarlockNonCombatStrategy.cpp | 65 + .../warlock/GenericWarlockNonCombatStrategy.h | 16 + .../warlock/GenericWarlockStrategy.cpp | 74 + .../strategy/warlock/GenericWarlockStrategy.h | 18 + .../strategy/warlock/TankWarlockStrategy.cpp | 51 + .../strategy/warlock/TankWarlockStrategy.h | 17 + .../strategy/warlock/WarlockActions.cpp | 5 + .../strategy/warlock/WarlockActions.h | 146 ++ .../warlock/WarlockAiObjectContext.cpp | 173 ++ .../strategy/warlock/WarlockAiObjectContext.h | 12 + .../strategy/warlock/WarlockMultipliers.cpp | 6 + .../strategy/warlock/WarlockMultipliers.h | 6 + .../strategy/warlock/WarlockTriggers.cpp | 19 + .../strategy/warlock/WarlockTriggers.h | 81 + .../strategy/warrior/DpsWarriorStrategy.cpp | 130 ++ .../strategy/warrior/DpsWarriorStrategy.h | 28 + .../GenericWarriorNonCombatStrategy.cpp | 7 + .../warrior/GenericWarriorNonCombatStrategy.h | 13 + .../warrior/GenericWarriorStrategy.cpp | 73 + .../strategy/warrior/GenericWarriorStrategy.h | 19 + .../strategy/warrior/TankWarriorStrategy.cpp | 126 ++ .../strategy/warrior/TankWarriorStrategy.h | 18 + .../strategy/warrior/WarriorActions.cpp | 30 + .../strategy/warrior/WarriorActions.h | 195 ++ .../warrior/WarriorAiObjectContext.cpp | 186 ++ .../strategy/warrior/WarriorAiObjectContext.h | 12 + .../strategy/warrior/WarriorMultipliers.cpp | 6 + .../strategy/warrior/WarriorMultipliers.h | 6 + .../strategy/warrior/WarriorTriggers.cpp | 7 + .../strategy/warrior/WarriorTriggers.h | 78 + 596 files changed, 41175 insertions(+), 3 deletions(-) create mode 100644 src/modules/Bots/CMakeLists.txt create mode 100644 src/modules/Bots/ahbot/AhBot.cpp create mode 100644 src/modules/Bots/ahbot/AhBot.h create mode 100644 src/modules/Bots/ahbot/AhBotConfig.cpp create mode 100644 src/modules/Bots/ahbot/AhBotConfig.h create mode 100644 src/modules/Bots/ahbot/Category.cpp create mode 100644 src/modules/Bots/ahbot/Category.h create mode 100644 src/modules/Bots/ahbot/ConsumableCategory.cpp create mode 100644 src/modules/Bots/ahbot/ConsumableCategory.h create mode 100644 src/modules/Bots/ahbot/ItemBag.cpp create mode 100644 src/modules/Bots/ahbot/ItemBag.h create mode 100644 src/modules/Bots/ahbot/PricingStrategy.cpp create mode 100644 src/modules/Bots/ahbot/PricingStrategy.h create mode 100644 src/modules/Bots/ahbot/TradeCategory.cpp create mode 100644 src/modules/Bots/ahbot/TradeCategory.h create mode 100644 src/modules/Bots/ahbot/ahbot.conf.dist.in create mode 100644 src/modules/Bots/botpch.cpp create mode 100644 src/modules/Bots/botpch.h create mode 100644 src/modules/Bots/playerbot/AiFactory.cpp create mode 100644 src/modules/Bots/playerbot/AiFactory.h create mode 100644 src/modules/Bots/playerbot/ChatFilter.cpp create mode 100644 src/modules/Bots/playerbot/ChatFilter.h create mode 100644 src/modules/Bots/playerbot/ChatHelper.cpp create mode 100644 src/modules/Bots/playerbot/ChatHelper.h create mode 100644 src/modules/Bots/playerbot/FleeManager.cpp create mode 100644 src/modules/Bots/playerbot/FleeManager.h create mode 100644 src/modules/Bots/playerbot/Helpers.cpp create mode 100644 src/modules/Bots/playerbot/LazyCalculatedValue.h create mode 100644 src/modules/Bots/playerbot/LootObjectStack.cpp create mode 100644 src/modules/Bots/playerbot/LootObjectStack.h create mode 100644 src/modules/Bots/playerbot/PlayerbotAI.cpp create mode 100644 src/modules/Bots/playerbot/PlayerbotAI.h create mode 100644 src/modules/Bots/playerbot/PlayerbotAIAware.h create mode 100644 src/modules/Bots/playerbot/PlayerbotAIBase.cpp create mode 100644 src/modules/Bots/playerbot/PlayerbotAIBase.h create mode 100644 src/modules/Bots/playerbot/PlayerbotAIConfig.cpp create mode 100644 src/modules/Bots/playerbot/PlayerbotAIConfig.h create mode 100644 src/modules/Bots/playerbot/PlayerbotFactory.cpp create mode 100644 src/modules/Bots/playerbot/PlayerbotFactory.h create mode 100644 src/modules/Bots/playerbot/PlayerbotMgr.cpp create mode 100644 src/modules/Bots/playerbot/PlayerbotMgr.h create mode 100644 src/modules/Bots/playerbot/PlayerbotSecurity.cpp create mode 100644 src/modules/Bots/playerbot/PlayerbotSecurity.h create mode 100644 src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp create mode 100644 src/modules/Bots/playerbot/RandomPlayerbotFactory.h create mode 100644 src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp create mode 100644 src/modules/Bots/playerbot/RandomPlayerbotMgr.h create mode 100644 src/modules/Bots/playerbot/aiplayerbot.conf.dist.in create mode 100644 src/modules/Bots/playerbot/playerbot.h create mode 100644 src/modules/Bots/playerbot/playerbotDefs.h create mode 100644 src/modules/Bots/playerbot/strategy/Action.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Action.h create mode 100644 src/modules/Bots/playerbot/strategy/ActionBasket.cpp create mode 100644 src/modules/Bots/playerbot/strategy/ActionBasket.h create mode 100644 src/modules/Bots/playerbot/strategy/AiObject.cpp create mode 100644 src/modules/Bots/playerbot/strategy/AiObject.h create mode 100644 src/modules/Bots/playerbot/strategy/AiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/AiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/Engine.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Engine.h create mode 100644 src/modules/Bots/playerbot/strategy/Event.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Event.h create mode 100644 src/modules/Bots/playerbot/strategy/ExternalEventHelper.h create mode 100644 src/modules/Bots/playerbot/strategy/ItemVisitors.h create mode 100644 src/modules/Bots/playerbot/strategy/Multiplier.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Multiplier.h create mode 100644 src/modules/Bots/playerbot/strategy/NamedObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp create mode 100644 src/modules/Bots/playerbot/strategy/PassiveMultiplier.h create mode 100644 src/modules/Bots/playerbot/strategy/Queue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Queue.h create mode 100644 src/modules/Bots/playerbot/strategy/Strategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Strategy.h create mode 100644 src/modules/Bots/playerbot/strategy/StrategyContext.h create mode 100644 src/modules/Bots/playerbot/strategy/Trigger.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Trigger.h create mode 100644 src/modules/Bots/playerbot/strategy/Value.cpp create mode 100644 src/modules/Bots/playerbot/strategy/Value.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/AcceptDuelAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/AcceptInvitationAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/AcceptResurrectAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ActionContext.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/AddLootAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/AttackAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/AttackAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/BankAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/BankAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/BuffAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/BuyAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ChooseTargetActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/DropQuestAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/DropQuestAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/EmoteAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/EmoteAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/EquipAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/FollowActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/FollowActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/GenericActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/GenericActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/GuildBankAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/GuildBankAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/HelpAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/HelpAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/InventoryAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/InviteToGroupAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/LfgActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/LfgActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/LootAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/LootAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/LootRollAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/LootRollAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/MovementActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/NonCombatActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/NonCombatActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/PassLeadershipToMasterAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/PositionAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/PositionAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/QuestAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/QuestAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ReleaseSpiritAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/RepairAllAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ResetAiAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ResetAiAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/RewardAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/RtiAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/SaveManaAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/SaveManaAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/SellAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/SellAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/SetHomeAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/StatsAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/StatsAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/StayActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/StayActions.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TaxiAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TeleportAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellLosAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellReputationAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellReputationAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TellTargetAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TradeAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/TrainerAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/TrainerAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/UnequipAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/UseItemAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/UseItemAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp create mode 100644 src/modules/Bots/playerbot/strategy/actions/WhoAction.h create mode 100644 src/modules/Bots/playerbot/strategy/actions/WorldPacketActionContext.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidActions.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidBearActions.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidCatActions.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidShapeshiftActions.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/DruidTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/CombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/CombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/DeadStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/DeadStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/DuelStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/DuelStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/FleeStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/FleeStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/GuardStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/GuardStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/KiteStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/KiteStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/PullStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/QuestStrategies.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/QuestStrategies.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/StayStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterActions.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageActions.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/mage/MageTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinActions.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategyActionNodeFactory.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestActions.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/PriestTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategyActionNodeFactory.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueActions.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueFinishingActions.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/CureTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/LfgTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/LootTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/triggers/LootTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/TriggerContext.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/WithinAreaTrigger.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h create mode 100644 src/modules/Bots/playerbot/strategy/triggers/WorldPacketTriggerContext.h create mode 100644 src/modules/Bots/playerbot/strategy/values/AlwaysLootListValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/AoeHealValues.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/AoeHealValues.h create mode 100644 src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/AttackerCountValues.h create mode 100644 src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/AttackersValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/AvailableLootValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/CcTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/ChatValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/DistanceValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/DpsTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/DpsTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/DuelTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/DuelTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/GrindTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/HasAvailableLootValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/HasTotemValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/IsBehindValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/IsFacingValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/IsMovingValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/ItemCountValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/ItemUsageValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/ItemUsageValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LastMovementValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LastSpellCastTimeValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LastSpellCastValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LfgValues.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LineTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/LineTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LogLevelValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/LootStrategyValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/ManaSaveLevelValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/MasterTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestAdsValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestAdsValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestGameObjects.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestGameObjects.h create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/NearestUnitsValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PetTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PositionValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/PositionValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/RtiValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/RtiValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/SelfTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/SpellIdValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/SpellIdValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/StatsValues.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/StatsValues.h create mode 100644 src/modules/Bots/playerbot/strategy/values/TankTargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/TankTargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/TargetValue.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/TargetValue.h create mode 100644 src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp create mode 100644 src/modules/Bots/playerbot/strategy/values/ThreatValues.h create mode 100644 src/modules/Bots/playerbot/strategy/values/ValueContext.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockActions.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.h diff --git a/src/game/Object/Item.cpp b/src/game/Object/Item.cpp index 8eba93ae1e..05d861ecab 100644 --- a/src/game/Object/Item.cpp +++ b/src/game/Object/Item.cpp @@ -1263,6 +1263,13 @@ bool Item::IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) cons // time. void Item::SendTimeUpdate(Player* owner) { +#ifdef ENABLE_PLAYERBOTS + if (!owner || !owner->IsInWorld() || owner->GetPlayerbotAI()) + { + return; + } +#endif + uint32 duration = GetUInt32Value(ITEM_FIELD_DURATION); if (!duration) { diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index fc7eca0e17..f5e9efec4d 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -77,6 +77,9 @@ #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS +#include "playerbot.h" +#endif #include @@ -435,6 +438,11 @@ UpdateMask Player::updateVisualBits; Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_achievementMgr(this), m_reputationMgr(this) { +#ifdef ENABLE_PLAYERBOTS + m_playerbotAI = 0; + m_playerbotMgr = 0; +#endif + m_transport = 0; m_speakTime = 0; @@ -628,6 +636,11 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_ m_lastFallZ = 0; m_cachedGS = 0; +#ifdef ENABLE_PLAYERBOTS + m_playerbotAI = NULL; + m_playerbotMgr = NULL; +#endif + } Player::~Player() @@ -667,6 +680,21 @@ Player::~Player() delete ItemSetEff[x]; } +#ifdef ENABLE_PLAYERBOTS + if (m_playerbotAI) { + { + delete m_playerbotAI; + } + m_playerbotAI = 0; + } + if (m_playerbotMgr) { + { + delete m_playerbotMgr; + } + m_playerbotMgr = 0; + } +#endif + // clean up player-instance binds, may unload some instance saves for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) @@ -1624,6 +1652,18 @@ void Player::Update(uint32 update_diff, uint32 p_time) { TeleportTo(m_teleport_dest, m_teleport_options); } + +#ifdef ENABLE_PLAYERBOTS + if (m_playerbotAI) + { + m_playerbotAI->UpdateAI(p_time); + } + if (m_playerbotMgr) + { + m_playerbotMgr->UpdateAI(p_time); + } +#endif + } void Player::SetDeathState(DeathState s) diff --git a/src/game/Object/Player.h b/src/game/Object/Player.h index 6b91149f2c..de4e6ef6ff 100644 --- a/src/game/Object/Player.h +++ b/src/game/Object/Player.h @@ -63,6 +63,11 @@ class Item; struct AreaTrigger; +#ifdef ENABLE_PLAYERBOTS +class PlayerbotAI; +class PlayerbotMgr; +#endif + typedef std::deque PlayerMails; #define PLAYER_MAX_SKILLS 127 @@ -1595,6 +1600,9 @@ class Player : public Unit /*********************************************************/ bool LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder); +#ifdef ENABLE_PLAYERBOTS + bool MinimalLoadFromDB(QueryResult *result, uint32 guid); +#endif static uint32 GetZoneIdFromDB(ObjectGuid guid); static uint32 GetLevelFromDB(ObjectGuid guid); @@ -2567,6 +2575,16 @@ class Player : public Unit MapReference& GetMapRef() { return m_mapRef; } bool isAllowedToLoot(Creature* creature); + +#ifdef ENABLE_PLAYERBOTS + //EquipmentSets& GetEquipmentSets() { return m_EquipmentSets; } + void SetPlayerbotAI(PlayerbotAI* ai) { assert(!m_playerbotAI && !m_playerbotMgr); m_playerbotAI = ai; } + PlayerbotAI* GetPlayerbotAI() { return m_playerbotAI; } + void SetPlayerbotMgr(PlayerbotMgr* mgr) { assert(!m_playerbotAI && !m_playerbotMgr); m_playerbotMgr = mgr; } + PlayerbotMgr* GetPlayerbotMgr() { return m_playerbotMgr; } + void SetBotDeathTimer() { m_deathTimer = 0; } + //PlayerTalentMap& GetTalentMap(uint8 spec) { return m_talents[spec]; } +#endif DeclinedName const* GetDeclinedNames() const { return m_declinedname; } @@ -2875,6 +2893,10 @@ class Player : public Unit GridReference m_gridRef; MapReference m_mapRef; +#ifdef ENABLE_PLAYERBOTS + PlayerbotAI* m_playerbotAI; + PlayerbotMgr* m_playerbotMgr; +#endif // Homebind coordinates uint32 m_homebindMapId; uint16 m_homebindAreaId; diff --git a/src/game/Server/WorldSession.cpp b/src/game/Server/WorldSession.cpp index 80de67188a..acb4761b40 100644 --- a/src/game/Server/WorldSession.cpp +++ b/src/game/Server/WorldSession.cpp @@ -49,6 +49,9 @@ #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /*ENABLE_ELUNA*/ +#ifdef ENABLE_PLAYERBOTS +#include "playerbot.h" +#endif // Warden #include "WardenWin.h" @@ -162,6 +165,19 @@ char const* WorldSession::GetPlayerName() const /// Send a packet to the client void WorldSession::SendPacket(WorldPacket const* packet) { +#ifdef ENABLE_PLAYERBOTS + if (GetPlayer()) { + if (GetPlayer()->GetPlayerbotAI()) + { + GetPlayer()->GetPlayerbotAI()->HandleBotOutgoingPacket(*packet); + } + else if (GetPlayer()->GetPlayerbotMgr()) + { + GetPlayer()->GetPlayerbotMgr()->HandleMasterOutgoingPacket(*packet); + } + } +#endif + if (!m_Socket) { return; @@ -267,6 +283,12 @@ bool WorldSession::Update(PacketFilter& updater) } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer +#ifdef ENABLE_PLAYERBOTS + if(_player && _player->GetPlayerbotMgr()) + { + _player->GetPlayerbotMgr()->HandleMasterIncomingPacket(*packet); + } +#endif break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT: if (!_player && !m_playerRecentlyLogout) @@ -348,6 +370,12 @@ bool WorldSession::Update(PacketFilter& updater) delete packet; } +#ifdef ENABLE_PLAYERBOTS + if (GetPlayer() && GetPlayer()->GetPlayerbotMgr()) + { + GetPlayer()->GetPlayerbotMgr()->UpdateSessions(0); + } +#endif ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed()) @@ -387,6 +415,18 @@ bool WorldSession::Update(PacketFilter& updater) return true; } +#ifdef ENABLE_PLAYERBOTS +void WorldSession::HandleBotPackets() +{ + WorldPacket* packet; + while (_recvQueue.next(packet)) + { + OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; + (this->*opHandle.handler)(*packet); + delete packet; + } +} +#endif /// %Log the player out void WorldSession::LogoutPlayer(bool Save) @@ -402,6 +442,13 @@ void WorldSession::LogoutPlayer(bool Save) if (_player) { +#ifdef ENABLE_PLAYERBOTS + if (GetPlayer()->GetPlayerbotMgr()) + { + GetPlayer()->GetPlayerbotMgr()->LogoutAllBots(); + } +#endif + sLog.outChar("Account: %d (IP: %s) Logout Character:[%s] (guid: %u)", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName() , _player->GetGUIDLow()); if (ObjectGuid lootGuid = GetPlayer()->GetLootGuid()) @@ -409,6 +456,14 @@ void WorldSession::LogoutPlayer(bool Save) DoLootRelease(lootGuid); } +#ifdef ENABLE_PLAYERBOTS + if (_player->GetPlayerbotMgr()) + { + _player->GetPlayerbotMgr()->LogoutAllBots(); + } + sRandomPlayerbotMgr.OnPlayerLogout(_player); +#endif + ///- If the player just died before logging out, make him appear as a ghost // FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) @@ -502,10 +557,23 @@ void WorldSession::LogoutPlayer(bool Save) ///- Reset the online field in the account table // no point resetting online in character table here as Player::SaveToDB() will set it to 1 since player has not been removed from world at this stage // No SQL injection as AccountID is uint32 +#ifdef ENABLE_PLAYERBOTS + if(!GetPlayer()->GetPlayerbotAI()) + { + static SqlStatementID id; + // playerbot mod + if (!_player->GetPlayerbotAI()) + { + SqlStatement stmt = LoginDatabase.CreateStatement(id, "UPDATE `account` SET `active_realm_id` = ? WHERE `id` = ?"); + stmt.PExecute(uint32(0), GetAccountId()); + } + } +#else static SqlStatementID id; SqlStatement stmt = LoginDatabase.CreateStatement(id, "UPDATE `account` SET `active_realm_id` = ? WHERE `id` = ?"); stmt.PExecute(uint32(0), GetAccountId()); +#endif ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr.GetGuildById(_player->GetGuildId())) @@ -531,7 +599,7 @@ void WorldSession::LogoutPlayer(bool Save) ///- Leave all channels before player delete... _player->CleanupChannels(); - +#ifndef ENABLE_PLAYERBOTS ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); @@ -541,6 +609,7 @@ void WorldSession::LogoutPlayer(bool Save) { _player->RemoveFromGroup(); } +#endif ///- Send update to group if (_player->GetGroup()) @@ -552,6 +621,10 @@ void WorldSession::LogoutPlayer(bool Save) sSocialMgr.SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetObjectGuid(), true); sSocialMgr.RemovePlayerSocial(_player->GetGUIDLow()); +#ifdef ENABLE_PLAYERBOTS + uint32 guid = GetPlayer()->GetGUIDLow(); +#endif + #ifdef ENABLE_ELUNA sEluna->OnLogout(_player); #endif @@ -581,8 +654,11 @@ void WorldSession::LogoutPlayer(bool Save) // No SQL injection as AccountId is uint32 static SqlStatementID updChars; - +#ifdef ENABLE_PLAYERBOTS + SqlStatement stmt = CharacterDatabase.CreateStatement(updChars, "UPDATE `characters` SET `online` = 0 WHERE `account` = ?"); +#else stmt = CharacterDatabase.CreateStatement(updChars, "UPDATE `characters` SET `online` = 0 WHERE `account` = ?"); +#endif stmt.PExecute(GetAccountId()); DEBUG_LOG("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); diff --git a/src/game/WorldHandlers/CharacterHandler.cpp b/src/game/WorldHandlers/CharacterHandler.cpp index 7a8846fbae..e999aa4a4f 100644 --- a/src/game/WorldHandlers/CharacterHandler.cpp +++ b/src/game/WorldHandlers/CharacterHandler.cpp @@ -51,6 +51,10 @@ #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS +#include "playerbot.h" +#include "PlayerbotAIConfig.h" +#endif // config option SkipCinematics supported values enum CinematicsSkipMode @@ -73,6 +77,23 @@ class LoginQueryHolder : public SqlQueryHolder bool Initialize(); }; +#ifdef ENABLE_PLAYERBOTS +class PlayerbotLoginQueryHolder : public LoginQueryHolder +{ +private: + uint32 masterAccountId; + PlayerbotHolder* playerbotHolder; + +public: + PlayerbotLoginQueryHolder(PlayerbotHolder* playerbotHolder, uint32 masterAccount, uint32 accountId, ObjectGuid guid) + : LoginQueryHolder(accountId, guid), masterAccountId(masterAccount), playerbotHolder(playerbotHolder) { } + +public: + uint32 GetMasterAccountId() const { return masterAccountId; } + PlayerbotHolder* GetPlayerbotHolder() { return playerbotHolder; } +}; +#endif + bool LoginQueryHolder::Initialize() { SetSize(MAX_PLAYER_LOGIN_QUERY); @@ -151,10 +172,103 @@ class CharacterHandler delete holder; return; } +#ifdef ENABLE_PLAYERBOTS + ObjectGuid guid = ((LoginQueryHolder*)holder)->GetGuid(); +#endif session->HandlePlayerLogin((LoginQueryHolder*)holder); +#ifdef ENABLE_PLAYERBOTS + Player* player = sObjectMgr.GetPlayer(guid, true); + if (player && !player->GetPlayerbotAI()) + { + player->SetPlayerbotMgr(new PlayerbotMgr(player)); + sRandomPlayerbotMgr.OnPlayerLogin(player); + } +#endif } +#ifdef ENABLE_PLAYERBOTS + void HandlePlayerBotLoginCallback(QueryResult * dummy, SqlQueryHolder * holder) + { + if(!holder) + { + return; + } + + PlayerbotLoginQueryHolder* lqh = (PlayerbotLoginQueryHolder*)holder; + if (sObjectMgr.GetPlayer(lqh->GetGuid())) + { + delete holder; + return; + } + + PlayerbotHolder* playerbotHolder = lqh->GetPlayerbotHolder(); + uint32 masterAccount = lqh->GetMasterAccountId(); + WorldSession* masterSession = masterAccount ? sWorld.FindSession(masterAccount) : NULL; + + // The bot's WorldSession is owned by the bot's Player object + // The bot's WorldSession is deleted by PlayerbotMgr::LogoutPlayerBot + uint32 botAccountId = lqh->GetAccountId(); + WorldSession *botSession = new WorldSession(botAccountId, NULL, SEC_PLAYER, masterSession->Expansion(), 0, LOCALE_enUS); + botSession->m_Address = "bot"; + botSession->HandlePlayerLogin(lqh); // will delete lqh + Player* bot = botSession->GetPlayer(); + if (!bot) + { + return; + } + + bool allowed = false; + if (botAccountId == masterAccount) + { + allowed = true; + } + else if (masterSession && sPlayerbotAIConfig.allowGuildBots && bot->GetGuildId() == masterSession->GetPlayer()->GetGuildId()) + { + allowed = true; + } + else if (sPlayerbotAIConfig.IsInRandomAccountList(botAccountId)) + { + allowed = true; + } + + if (allowed) + { + playerbotHolder->OnBotLogin(bot); + } + else if (masterSession) + { + ChatHandler ch(masterSession); + ch.PSendSysMessage("You are not allowed to control bot %s...", bot->GetName()); + playerbotHolder->LogoutPlayerBot(bot->GetObjectGuid().GetRawValue()); + } + } +#endif } chrHandler; +#ifdef ENABLE_PLAYERBOTS +void PlayerbotHolder::AddPlayerBot(uint64 playerGuid, uint32 masterAccountId) +{ + //has bot already been added? + if (sObjectMgr.GetPlayer(ObjectGuid(playerGuid))) + { + return; + } + + uint32 accountId = sObjectMgr.GetPlayerAccountIdByGUID(ObjectGuid(playerGuid)); + if (accountId == 0) + { + return; + } + + PlayerbotLoginQueryHolder *holder = new PlayerbotLoginQueryHolder(this, masterAccountId, accountId, ObjectGuid(playerGuid)); + if(!holder->Initialize()) + { + delete holder; // delete all unprocessed queries + return; + } + CharacterDatabase.DelayQueryHolder(&chrHandler, &CharacterHandler::HandlePlayerBotLoginCallback, holder); +} +#endif + void WorldSession::HandleCharEnum(QueryResult* result) { WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size @@ -846,7 +960,14 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) stmt.PExecute(pCurrChar->GetGUIDLow()); stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE `account` SET `active_realm_id` = ? WHERE `id` = ?"); +#ifdef ENABLE_PLAYERBOTS + if(pCurrChar->GetSession()->GetRemoteAddress() != "bot") + { + stmt.PExecute(realmID, GetAccountId()); + } +#else stmt.PExecute(realmID, GetAccountId()); +#endif /* Sync player's in-game time with server time */ pCurrChar->SetInGameTime(GameTime::GetGameTimeMS()); diff --git a/src/game/WorldHandlers/Chat.cpp b/src/game/WorldHandlers/Chat.cpp index bd28f1e999..cc1a8ad018 100644 --- a/src/game/WorldHandlers/Chat.cpp +++ b/src/game/WorldHandlers/Chat.cpp @@ -842,6 +842,11 @@ ChatCommand* ChatHandler::getCommandTable() { "quit", SEC_CONSOLE, true, &ChatHandler::HandleQuitCommand, "", NULL }, { "gearscore", SEC_ADMINISTRATOR, false, &ChatHandler::HandleShowGearScoreCommand, "", NULL }, { "mmap", SEC_GAMEMASTER, false, NULL, "", mmapCommandTable }, +#ifdef ENABLE_PLAYERBOTS + { "bot", SEC_PLAYER, false, &ChatHandler::HandlePlayerbotCommand, "", NULL }, + { "rndbot", SEC_CONSOLE, true, &ChatHandler::HandlePlayerbotConsoleCommand, "", NULL }, + { "ahbot", SEC_GAMEMASTER, true, &ChatHandler::HandleAhBotCommand, "", NULL }, +#endif { NULL, 0, false, NULL, "", NULL } }; diff --git a/src/game/WorldHandlers/Chat.h b/src/game/WorldHandlers/Chat.h index 636e11e880..1441a9f885 100644 --- a/src/game/WorldHandlers/Chat.h +++ b/src/game/WorldHandlers/Chat.h @@ -665,6 +665,12 @@ class ChatHandler bool HandleMmapTestArea(char* args); bool HandleMmapTestHeight(char* args); +#ifdef ENABLE_PLAYERBOTS + bool HandlePlayerbotCommand(char* args); + bool HandlePlayerbotConsoleCommand(char* args); + bool HandleAhBotCommand(char* args); +#endif + //! Development Commands bool HandleSaveAllCommand(char* args); diff --git a/src/game/WorldHandlers/ChatHandler.cpp b/src/game/WorldHandlers/ChatHandler.cpp index 3255536415..4ec5f0982d 100644 --- a/src/game/WorldHandlers/ChatHandler.cpp +++ b/src/game/WorldHandlers/ChatHandler.cpp @@ -44,6 +44,10 @@ #ifdef ENABLE_ELUNA #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS +#include "playerbot.h" +#include "RandomPlayerbotMgr.h" +#endif bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang) { @@ -298,6 +302,15 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) return; } #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS + if (player->GetPlayerbotAI()) + { + player->GetPlayerbotAI()->HandleCommand(type, msg, *GetPlayer()); + GetPlayer()->m_speakTime = 0; + GetPlayer()->m_speakCount = 0; + } + else +#endif GetPlayer()->Whisper(msg, lang, player->GetObjectGuid()); } break; @@ -351,6 +364,19 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) } #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* player = itr->getSource(); + if (player && player->GetPlayerbotAI()) + { + player->GetPlayerbotAI()->HandleCommand(type, msg, *GetPlayer()); + GetPlayer()->m_speakTime = 0; + GetPlayer()->m_speakCount = 0; + } + } +#endif + WorldPacket data; ChatHandler::BuildChatPacket(data, ChatMsg(type), msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false, group->GetMemberGroup(GetPlayer()->GetObjectGuid())); @@ -396,6 +422,21 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } +#ifdef ENABLE_PLAYERBOTS + PlayerbotMgr *mgr = GetPlayer()->GetPlayerbotMgr(); + if (mgr) + { + for (PlayerBotMap::const_iterator it = mgr->GetPlayerBotsBegin(); it != mgr->GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + if (bot->GetGuildId() == GetPlayer()->GetGuildId()) + { + bot->GetPlayerbotAI()->HandleCommand(type, msg, *GetPlayer()); + } + } + } +#endif + break; } case CHAT_MSG_OFFICER: @@ -483,6 +524,19 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) } #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* player = itr->getSource(); + if (player && player->GetPlayerbotAI()) + { + player->GetPlayerbotAI()->HandleCommand(type, msg, *GetPlayer()); + GetPlayer()->m_speakTime = 0; + GetPlayer()->m_speakCount = 0; + } + } +#endif + WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false); @@ -531,6 +585,19 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) } #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* player = itr->getSource(); + if (player && player->GetPlayerbotAI()) + { + player->GetPlayerbotAI()->HandleCommand(type, msg, *GetPlayer()); + GetPlayer()->m_speakTime = 0; + GetPlayer()->m_speakCount = 0; + } + } +#endif + WorldPacket data; ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_LEADER, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); group->BroadcastPacket(&data, false); @@ -566,6 +633,19 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) } #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* player = itr->getSource(); + if (player && player->GetPlayerbotAI()) + { + player->GetPlayerbotAI()->HandleCommand(type, msg, *GetPlayer()); + GetPlayer()->m_speakTime = 0; + GetPlayer()->m_speakCount = 0; + } + } +#endif + WorldPacket data; // in battleground, raid warning is sent only to players in battleground - code is ok ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_WARNING, msg.c_str(), Language(lang), _player->GetChatTag(), _player->GetObjectGuid(), _player->GetName()); @@ -669,7 +749,13 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recv_data) return; } #endif /* ENABLE_ELUNA */ - +#ifdef ENABLE_PLAYERBOTS + if (_player->GetPlayerbotMgr() && chn->GetFlags() & 0x18) + { + _player->GetPlayerbotMgr()->HandleCommand(type, msg); + } + sRandomPlayerbotMgr.HandleCommand(type, msg, *_player); +#endif /* ENABLE_PLAYERBOTS */ chn->Say(_player, msg.c_str(), lang); } } diff --git a/src/game/WorldHandlers/Group.h b/src/game/WorldHandlers/Group.h index b36e67408a..d21e0d7dd9 100644 --- a/src/game/WorldHandlers/Group.h +++ b/src/game/WorldHandlers/Group.h @@ -462,6 +462,10 @@ class Group InstanceGroupBind* GetBoundInstance(Map* aMap, Difficulty difficulty); BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } +#ifdef ENABLE_PLAYERBOTS + ObjectGuid GetTargetIcon(int index) { return m_targetIcons[index]; } +#endif + protected: bool _addMember(ObjectGuid guid, const char* name, bool isAssistant = false); bool _addMember(ObjectGuid guid, const char* name, bool isAssistant, uint8 group); diff --git a/src/game/WorldHandlers/Map.cpp b/src/game/WorldHandlers/Map.cpp index 1caec20198..5ea952b844 100644 --- a/src/game/WorldHandlers/Map.cpp +++ b/src/game/WorldHandlers/Map.cpp @@ -711,6 +711,9 @@ void Map::Remove(Player* player, bool remove) SendRemoveTransports(player); UpdateObjectVisibility(player, cell, p); +#ifdef ENABLE_PLAYERBOTS + if (!player->GetPlayerbotAI()) +#endif player->ResetMap(); if (remove) { diff --git a/src/game/WorldHandlers/Spell.cpp b/src/game/WorldHandlers/Spell.cpp index 6be019cb7f..83e14d0a5f 100644 --- a/src/game/WorldHandlers/Spell.cpp +++ b/src/game/WorldHandlers/Spell.cpp @@ -4392,6 +4392,13 @@ void Spell::finish(bool ok) { ((DungeonMap*)map)->GetPersistanceState()->UpdateEncounterState(ENCOUNTER_CREDIT_CAST_SPELL, m_spellInfo->Id); } +#ifdef ENABLE_PLAYERBOTS + + if(!m_caster->GetMapId()) + { + return; + } +#endif } void Spell::SendCastResult(SpellCastResult result) diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 82c8f906e5..7a291cb5f5 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -86,6 +86,12 @@ #include "LuaEngine.h" #endif /* ENABLE_ELUNA */ +#ifdef ENABLE_PLAYERBOTS + +#include "PlayerbotAIConfig.h" +#include "RandomPlayerbotMgr.h" +#endif + // WARDEN #include "WardenCheckMgr.h" @@ -843,6 +849,27 @@ void World::LoadConfigSettings(bool reload) setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT, "PetUnsummonAtMount", true); +#ifdef ENABLE_PLAYERBOTS + setConfig(CONFIG_BOOL_PLAYERBOT_DISABLE, "PlayerbotAI.DisableBots", true); + setConfig(CONFIG_BOOL_PLAYERBOT_DEBUGWHISPER, "PlayerbotAI.DebugWhisper", false); + setConfigMinMax(CONFIG_UINT32_PLAYERBOT_MAXBOTS, "PlayerbotAI.MaxNumBots", 3, 1, 9); + setConfigMinMax(CONFIG_UINT32_PLAYERBOT_RESTRICTLEVEL, "PlayerbotAI.RestrictBotLevel", getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL), 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)); + setConfigMinMax(CONFIG_UINT32_PLAYERBOT_MINBOTLEVEL, "PlayerbotAI.MinBotLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)); + setConfig(CONFIG_FLOAT_PLAYERBOT_MINDISTANCE, "PlayerbotAI.FollowDistanceMin", 0.5f); + setConfig(CONFIG_FLOAT_PLAYERBOT_MAXDISTANCE, "PlayerbotAI.FollowDistanceMax", 1.0f); + + setConfig(CONFIG_BOOL_PLAYERBOT_ALLOW_SUMMON_OPPOSITE_FACTION, "PlayerbotAI.AllowSummonOppositeFaction", false); + setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_COMBAT, "PlayerbotAI.Collect.Combat", true); + setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_QUESTS, "PlayerbotAI.Collect.Quest", true); + setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_PROFESSION, "PlayerbotAI.Collect.Profession", true); + setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_LOOT, "PlayerbotAI.Collect.Loot", true); + setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_SKIN, "PlayerbotAI.Collect.Skin", true); + setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_OBJECTS, "PlayerbotAI.Collect.Objects", true); + setConfig(CONFIG_BOOL_PLAYERBOT_SELL_TRASH, "PlayerbotAI.SellGarbage", true); + + setConfig(CONFIG_BOOL_PLAYERBOT_SHAREDBOTS, "PlayerbotAI.SharedBots", true); +#endif + // WARDEN setConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED, "Warden.WinEnabled", true); @@ -1817,6 +1844,11 @@ void World::Update(uint32 diff) m_timers[WUPDATE_LFGMGR].Reset(); } +#ifdef ENABLE_PLAYERBOTS + sRandomPlayerbotMgr.UpdateAI(diff); + sRandomPlayerbotMgr.UpdateSessions(diff); +#endif + ///
  • Handle session updates UpdateSessions(diff); @@ -2221,6 +2253,10 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode) ShutdownMsg(true); } +#ifdef ENABLE_PLAYERBOTS + sRandomPlayerbotMgr.LogoutAllBots(); +#endif + ///- Used by Eluna #ifdef ENABLE_ELUNA sEluna->OnShutdownInitiate(ShutdownExitCode(exitcode), ShutdownMask(options)); diff --git a/src/game/WorldHandlers/World.h b/src/game/WorldHandlers/World.h index b4bdd2961f..14539521bc 100644 --- a/src/game/WorldHandlers/World.h +++ b/src/game/WorldHandlers/World.h @@ -211,6 +211,11 @@ enum eConfigUInt32Values CONFIG_UINT32_WARDEN_NUM_MEM_CHECKS, CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS, CONFIG_UINT32_WARDEN_DB_LOGLEVEL, +#ifdef ENABLE_PLAYERBOTS + CONFIG_UINT32_PLAYERBOT_MAXBOTS, + CONFIG_UINT32_PLAYERBOT_RESTRICTLEVEL, + CONFIG_UINT32_PLAYERBOT_MINBOTLEVEL, +#endif CONFIG_UINT32_AUTOBROADCAST_INTERVAL, CONFIG_UINT32_VALUE_COUNT @@ -299,6 +304,10 @@ enum eConfigFloatValues CONFIG_FLOAT_THREAT_RADIUS, CONFIG_FLOAT_GHOST_RUN_SPEED_WORLD, CONFIG_FLOAT_GHOST_RUN_SPEED_BG, +#ifdef ENABLE_PLAYERBOTS + CONFIG_FLOAT_PLAYERBOT_MINDISTANCE, + CONFIG_FLOAT_PLAYERBOT_MAXDISTANCE, +#endif CONFIG_FLOAT_VALUE_COUNT }; @@ -369,6 +378,19 @@ enum eConfigBoolValues CONFIG_BOOL_MMAP_ENABLED, CONFIG_BOOL_ELUNA_ENABLED, CONFIG_BOOL_PLAYER_COMMANDS, +#ifdef ENABLE_PLAYERBOTS + CONFIG_BOOL_PLAYERBOT_DISABLE, + CONFIG_BOOL_PLAYERBOT_DEBUGWHISPER, + CONFIG_BOOL_PLAYERBOT_SHAREDBOTS, + CONFIG_BOOL_PLAYERBOT_ALLOW_SUMMON_OPPOSITE_FACTION, + CONFIG_BOOL_PLAYERBOT_COLLECT_COMBAT, + CONFIG_BOOL_PLAYERBOT_COLLECT_QUESTS, + CONFIG_BOOL_PLAYERBOT_COLLECT_PROFESSION, + CONFIG_BOOL_PLAYERBOT_COLLECT_LOOT, + CONFIG_BOOL_PLAYERBOT_COLLECT_SKIN, + CONFIG_BOOL_PLAYERBOT_COLLECT_OBJECTS, + CONFIG_BOOL_PLAYERBOT_SELL_TRASH, +#endif // Warden CONFIG_BOOL_WARDEN_WIN_ENABLED, CONFIG_BOOL_WARDEN_OSX_ENABLED, diff --git a/src/modules/Bots/CMakeLists.txt b/src/modules/Bots/CMakeLists.txt new file mode 100644 index 0000000000..cf9330ab0c --- /dev/null +++ b/src/modules/Bots/CMakeLists.txt @@ -0,0 +1,609 @@ +# +# Copyright (C) 2005-2022 MaNGOS +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +set(BOT_SRCS + playerbot/AiFactory.cpp + playerbot/AiFactory.h + playerbot/ChatFilter.cpp + playerbot/ChatFilter.h + playerbot/ChatHelper.cpp + playerbot/ChatHelper.h + playerbot/FleeManager.cpp + playerbot/FleeManager.h + playerbot/Helpers.cpp + playerbot/LazyCalculatedValue.h + playerbot/LootObjectStack.cpp + playerbot/LootObjectStack.h + playerbot/playerbot.h + playerbot/PlayerbotAI.cpp + playerbot/PlayerbotAI.h + playerbot/PlayerbotAIAware.h + playerbot/PlayerbotAIBase.cpp + playerbot/PlayerbotAIBase.h + playerbot/PlayerbotAIConfig.cpp + playerbot/PlayerbotAIConfig.h + playerbot/playerbotDefs.h + playerbot/PlayerbotFactory.cpp + playerbot/PlayerbotFactory.h + playerbot/PlayerbotMgr.cpp + playerbot/PlayerbotMgr.h + playerbot/PlayerbotSecurity.cpp + playerbot/PlayerbotSecurity.h + playerbot/RandomPlayerbotFactory.cpp + playerbot/RandomPlayerbotFactory.h + playerbot/RandomPlayerbotMgr.cpp + playerbot/RandomPlayerbotMgr.h + playerbot/strategy/Action.cpp + playerbot/strategy/Action.h + playerbot/strategy/ActionBasket.cpp + playerbot/strategy/ActionBasket.h + playerbot/strategy/actions/AcceptDuelAction.h + playerbot/strategy/actions/AcceptInvitationAction.h + playerbot/strategy/actions/AcceptQuestAction.cpp + playerbot/strategy/actions/AcceptQuestAction.h + playerbot/strategy/actions/AcceptResurrectAction.h + playerbot/strategy/actions/ActionContext.h + playerbot/strategy/actions/AddLootAction.cpp + playerbot/strategy/actions/AddLootAction.h + playerbot/strategy/actions/AreaTriggerAction.cpp + playerbot/strategy/actions/AreaTriggerAction.h + playerbot/strategy/actions/AttackAction.cpp + playerbot/strategy/actions/AttackAction.h + playerbot/strategy/actions/BankAction.cpp + playerbot/strategy/actions/BankAction.h + playerbot/strategy/actions/BuffAction.cpp + playerbot/strategy/actions/BuffAction.h + playerbot/strategy/actions/BuyAction.cpp + playerbot/strategy/actions/BuyAction.h + playerbot/strategy/actions/CastCustomSpellAction.cpp + playerbot/strategy/actions/CastCustomSpellAction.h + playerbot/strategy/actions/ChangeChatAction.cpp + playerbot/strategy/actions/ChangeChatAction.h + playerbot/strategy/actions/ChangeStrategyAction.cpp + playerbot/strategy/actions/ChangeStrategyAction.h + playerbot/strategy/actions/ChangeTalentsAction.cpp + playerbot/strategy/actions/ChangeTalentsAction.h + playerbot/strategy/actions/ChatActionContext.h + playerbot/strategy/actions/ChatShortcutActions.cpp + playerbot/strategy/actions/ChatShortcutActions.h + playerbot/strategy/actions/CheckMountStateAction.cpp + playerbot/strategy/actions/CheckMountStateAction.h + playerbot/strategy/actions/ChooseTargetActions.h + playerbot/strategy/actions/DestroyItemAction.cpp + playerbot/strategy/actions/DestroyItemAction.h + playerbot/strategy/actions/DropQuestAction.cpp + playerbot/strategy/actions/DropQuestAction.h + playerbot/strategy/actions/EmoteAction.cpp + playerbot/strategy/actions/EmoteAction.h + playerbot/strategy/actions/EquipAction.cpp + playerbot/strategy/actions/EquipAction.h + playerbot/strategy/actions/FollowActions.cpp + playerbot/strategy/actions/FollowActions.h + playerbot/strategy/actions/GenericActions.cpp + playerbot/strategy/actions/GenericActions.h + playerbot/strategy/actions/GenericSpellActions.cpp + playerbot/strategy/actions/GenericSpellActions.h + playerbot/strategy/actions/GossipHelloAction.cpp + playerbot/strategy/actions/GossipHelloAction.h + playerbot/strategy/actions/GuildAcceptAction.cpp + playerbot/strategy/actions/GuildAcceptAction.h + playerbot/strategy/actions/GuildBankAction.cpp + playerbot/strategy/actions/GuildBankAction.h + playerbot/strategy/actions/HelpAction.cpp + playerbot/strategy/actions/HelpAction.h + playerbot/strategy/actions/InventoryAction.cpp + playerbot/strategy/actions/InventoryAction.h + playerbot/strategy/actions/InventoryChangeFailureAction.cpp + playerbot/strategy/actions/InventoryChangeFailureAction.h + playerbot/strategy/actions/InviteToGroupAction.h + playerbot/strategy/actions/LeaveGroupAction.h + playerbot/strategy/actions/LfgActions.cpp + playerbot/strategy/actions/LfgActions.h + playerbot/strategy/actions/ListQuestsActions.cpp + playerbot/strategy/actions/ListQuestsActions.h + playerbot/strategy/actions/ListSpellsAction.cpp + playerbot/strategy/actions/ListSpellsAction.h + playerbot/strategy/actions/LogLevelAction.cpp + playerbot/strategy/actions/LogLevelAction.h + playerbot/strategy/actions/LootAction.cpp + playerbot/strategy/actions/LootAction.h + playerbot/strategy/actions/LootRollAction.cpp + playerbot/strategy/actions/LootRollAction.h + playerbot/strategy/actions/LootStrategyAction.cpp + playerbot/strategy/actions/LootStrategyAction.h + playerbot/strategy/actions/MovementActions.cpp + playerbot/strategy/actions/MovementActions.h + playerbot/strategy/actions/NonCombatActions.cpp + playerbot/strategy/actions/NonCombatActions.h + playerbot/strategy/actions/PassLeadershipToMasterAction.h + playerbot/strategy/actions/PositionAction.cpp + playerbot/strategy/actions/PositionAction.h + playerbot/strategy/actions/QueryItemUsageAction.cpp + playerbot/strategy/actions/QueryItemUsageAction.h + playerbot/strategy/actions/QueryQuestAction.cpp + playerbot/strategy/actions/QueryQuestAction.h + playerbot/strategy/actions/QuestAction.cpp + playerbot/strategy/actions/QuestAction.h + playerbot/strategy/actions/ReachTargetActions.h + playerbot/strategy/actions/ReadyCheckAction.cpp + playerbot/strategy/actions/ReadyCheckAction.h + playerbot/strategy/actions/ReleaseSpiritAction.h + playerbot/strategy/actions/RememberTaxiAction.cpp + playerbot/strategy/actions/RememberTaxiAction.h + playerbot/strategy/actions/RepairAllAction.cpp + playerbot/strategy/actions/RepairAllAction.h + playerbot/strategy/actions/ResetAiAction.cpp + playerbot/strategy/actions/ResetAiAction.h + playerbot/strategy/actions/ReviveFromCorpseAction.cpp + playerbot/strategy/actions/ReviveFromCorpseAction.h + playerbot/strategy/actions/RewardAction.cpp + playerbot/strategy/actions/RewardAction.h + playerbot/strategy/actions/RtiAction.h + playerbot/strategy/actions/SaveManaAction.cpp + playerbot/strategy/actions/SaveManaAction.h + playerbot/strategy/actions/SecurityCheckAction.cpp + playerbot/strategy/actions/SecurityCheckAction.h + playerbot/strategy/actions/SellAction.cpp + playerbot/strategy/actions/SellAction.h + playerbot/strategy/actions/SetHomeAction.cpp + playerbot/strategy/actions/SetHomeAction.h + playerbot/strategy/actions/StatsAction.cpp + playerbot/strategy/actions/StatsAction.h + playerbot/strategy/actions/StayActions.cpp + playerbot/strategy/actions/StayActions.h + playerbot/strategy/actions/SuggestWhatToDoAction.cpp + playerbot/strategy/actions/SuggestWhatToDoAction.h + playerbot/strategy/actions/TalkToQuestGiverAction.cpp + playerbot/strategy/actions/TalkToQuestGiverAction.h + playerbot/strategy/actions/TaxiAction.cpp + playerbot/strategy/actions/TaxiAction.h + playerbot/strategy/actions/TeleportAction.cpp + playerbot/strategy/actions/TeleportAction.h + playerbot/strategy/actions/TellCastFailedAction.cpp + playerbot/strategy/actions/TellCastFailedAction.h + playerbot/strategy/actions/TellItemCountAction.cpp + playerbot/strategy/actions/TellItemCountAction.h + playerbot/strategy/actions/TellLosAction.cpp + playerbot/strategy/actions/TellLosAction.h + playerbot/strategy/actions/TellMasterAction.h + playerbot/strategy/actions/TellReputationAction.cpp + playerbot/strategy/actions/TellReputationAction.h + playerbot/strategy/actions/TellTargetAction.cpp + playerbot/strategy/actions/TellTargetAction.h + playerbot/strategy/actions/TradeAction.cpp + playerbot/strategy/actions/TradeAction.h + playerbot/strategy/actions/TradeStatusAction.cpp + playerbot/strategy/actions/TradeStatusAction.h + playerbot/strategy/actions/TrainerAction.cpp + playerbot/strategy/actions/TrainerAction.h + playerbot/strategy/actions/UnequipAction.cpp + playerbot/strategy/actions/UnequipAction.h + playerbot/strategy/actions/UseItemAction.cpp + playerbot/strategy/actions/UseItemAction.h + playerbot/strategy/actions/UseMeetingStoneAction.cpp + playerbot/strategy/actions/UseMeetingStoneAction.h + playerbot/strategy/actions/WhoAction.cpp + playerbot/strategy/actions/WhoAction.h + playerbot/strategy/actions/WorldPacketActionContext.h + playerbot/strategy/AiObject.cpp + playerbot/strategy/AiObject.h + playerbot/strategy/AiObjectContext.cpp + playerbot/strategy/AiObjectContext.h + playerbot/strategy/druid/BearTankDruidStrategy.cpp + playerbot/strategy/druid/BearTankDruidStrategy.h + playerbot/strategy/druid/CasterDruidStrategy.cpp + playerbot/strategy/druid/CasterDruidStrategy.h + playerbot/strategy/druid/CatDpsDruidStrategy.cpp + playerbot/strategy/druid/CatDpsDruidStrategy.h + playerbot/strategy/druid/DruidActions.cpp + playerbot/strategy/druid/DruidActions.h + playerbot/strategy/druid/DruidAiObjectContext.cpp + playerbot/strategy/druid/DruidAiObjectContext.h + playerbot/strategy/druid/DruidBearActions.h + playerbot/strategy/druid/DruidCatActions.h + playerbot/strategy/druid/DruidMultipliers.cpp + playerbot/strategy/druid/DruidMultipliers.h + playerbot/strategy/druid/DruidShapeshiftActions.h + playerbot/strategy/druid/DruidTriggers.cpp + playerbot/strategy/druid/DruidTriggers.h + playerbot/strategy/druid/FeralDruidStrategy.cpp + playerbot/strategy/druid/FeralDruidStrategy.h + playerbot/strategy/druid/GenericDruidNonCombatStrategy.cpp + playerbot/strategy/druid/GenericDruidNonCombatStrategy.h + playerbot/strategy/druid/GenericDruidStrategy.cpp + playerbot/strategy/druid/GenericDruidStrategy.h + playerbot/strategy/druid/HealDruidStrategy.cpp + playerbot/strategy/druid/HealDruidStrategy.h + playerbot/strategy/Engine.cpp + playerbot/strategy/Engine.h + playerbot/strategy/Event.cpp + playerbot/strategy/Event.h + playerbot/strategy/ExternalEventHelper.h + playerbot/strategy/generic/AttackEnemyPlayersStrategy.cpp + playerbot/strategy/generic/AttackEnemyPlayersStrategy.h + playerbot/strategy/generic/AttackRtiStrategy.cpp + playerbot/strategy/generic/AttackRtiStrategy.h + playerbot/strategy/generic/AttackWeakStrategy.cpp + playerbot/strategy/generic/AttackWeakStrategy.h + playerbot/strategy/generic/CastTimeStrategy.cpp + playerbot/strategy/generic/CastTimeStrategy.h + playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp + playerbot/strategy/generic/ChatCommandHandlerStrategy.h + playerbot/strategy/generic/CombatStrategy.cpp + playerbot/strategy/generic/CombatStrategy.h + playerbot/strategy/generic/ConserveManaStrategy.cpp + playerbot/strategy/generic/ConserveManaStrategy.h + playerbot/strategy/generic/DeadStrategy.cpp + playerbot/strategy/generic/DeadStrategy.h + playerbot/strategy/generic/DpsAoeStrategy.cpp + playerbot/strategy/generic/DpsAoeStrategy.h + playerbot/strategy/generic/DpsAssistStrategy.cpp + playerbot/strategy/generic/DpsAssistStrategy.h + playerbot/strategy/generic/DuelStrategy.cpp + playerbot/strategy/generic/DuelStrategy.h + playerbot/strategy/generic/EmoteStrategy.cpp + playerbot/strategy/generic/EmoteStrategy.h + playerbot/strategy/generic/FleeStrategy.cpp + playerbot/strategy/generic/FleeStrategy.h + playerbot/strategy/generic/FollowLineStrategy.cpp + playerbot/strategy/generic/FollowLineStrategy.h + playerbot/strategy/generic/FollowMasterRandomStrategy.cpp + playerbot/strategy/generic/FollowMasterRandomStrategy.h + playerbot/strategy/generic/FollowMasterStrategy.cpp + playerbot/strategy/generic/FollowMasterStrategy.h + playerbot/strategy/generic/GrindingStrategy.cpp + playerbot/strategy/generic/GrindingStrategy.h + playerbot/strategy/generic/GuardStrategy.cpp + playerbot/strategy/generic/GuardStrategy.h + playerbot/strategy/generic/KiteStrategy.cpp + playerbot/strategy/generic/KiteStrategy.h + playerbot/strategy/generic/LootNonCombatStrategy.cpp + playerbot/strategy/generic/LootNonCombatStrategy.h + playerbot/strategy/generic/MeleeCombatStrategy.cpp + playerbot/strategy/generic/MeleeCombatStrategy.h + playerbot/strategy/generic/MoveRandomStrategy.cpp + playerbot/strategy/generic/MoveRandomStrategy.h + playerbot/strategy/generic/NonCombatStrategy.cpp + playerbot/strategy/generic/NonCombatStrategy.h + playerbot/strategy/generic/PassiveStrategy.cpp + playerbot/strategy/generic/PassiveStrategy.h + playerbot/strategy/generic/PassTroughStrategy.h + playerbot/strategy/generic/PullStrategy.cpp + playerbot/strategy/generic/PullStrategy.h + playerbot/strategy/generic/QuestStrategies.cpp + playerbot/strategy/generic/QuestStrategies.h + playerbot/strategy/generic/RacialsStrategy.cpp + playerbot/strategy/generic/RacialsStrategy.h + playerbot/strategy/generic/RangedCombatStrategy.cpp + playerbot/strategy/generic/RangedCombatStrategy.h + playerbot/strategy/generic/RunawayStrategy.cpp + playerbot/strategy/generic/RunawayStrategy.h + playerbot/strategy/generic/StayCircleStrategy.cpp + playerbot/strategy/generic/StayCircleStrategy.h + playerbot/strategy/generic/StayCombatStrategy.cpp + playerbot/strategy/generic/StayCombatStrategy.h + playerbot/strategy/generic/StayLineStrategy.cpp + playerbot/strategy/generic/StayLineStrategy.h + playerbot/strategy/generic/StayStrategy.cpp + playerbot/strategy/generic/StayStrategy.h + playerbot/strategy/generic/TankAoeStrategy.cpp + playerbot/strategy/generic/TankAoeStrategy.h + playerbot/strategy/generic/TankAssistStrategy.cpp + playerbot/strategy/generic/TankAssistStrategy.h + playerbot/strategy/generic/TellTargetStrategy.cpp + playerbot/strategy/generic/TellTargetStrategy.h + playerbot/strategy/generic/ThreatStrategy.cpp + playerbot/strategy/generic/ThreatStrategy.h + playerbot/strategy/generic/UseFoodStrategy.cpp + playerbot/strategy/generic/UseFoodStrategy.h + playerbot/strategy/generic/UsePotionsStrategy.cpp + playerbot/strategy/generic/UsePotionsStrategy.h + playerbot/strategy/generic/WorldPacketHandlerStrategy.cpp + playerbot/strategy/generic/WorldPacketHandlerStrategy.h + playerbot/strategy/hunter/DpsHunterStrategy.cpp + playerbot/strategy/hunter/DpsHunterStrategy.h + playerbot/strategy/hunter/GenericHunterNonCombatStrategy.cpp + playerbot/strategy/hunter/GenericHunterNonCombatStrategy.h + playerbot/strategy/hunter/GenericHunterStrategy.cpp + playerbot/strategy/hunter/GenericHunterStrategy.h + playerbot/strategy/hunter/HunterActions.cpp + playerbot/strategy/hunter/HunterActions.h + playerbot/strategy/hunter/HunterAiObjectContext.cpp + playerbot/strategy/hunter/HunterAiObjectContext.h + playerbot/strategy/hunter/HunterBuffStrategies.cpp + playerbot/strategy/hunter/HunterBuffStrategies.h + playerbot/strategy/hunter/HunterMultipliers.cpp + playerbot/strategy/hunter/HunterMultipliers.h + playerbot/strategy/hunter/HunterTriggers.cpp + playerbot/strategy/hunter/HunterTriggers.h + playerbot/strategy/ItemVisitors.h + playerbot/strategy/mage/ArcaneMageStrategy.cpp + playerbot/strategy/mage/ArcaneMageStrategy.h + playerbot/strategy/mage/FireMageStrategy.cpp + playerbot/strategy/mage/FireMageStrategy.h + playerbot/strategy/mage/FrostMageStrategy.cpp + playerbot/strategy/mage/FrostMageStrategy.h + playerbot/strategy/mage/GenericMageNonCombatStrategy.cpp + playerbot/strategy/mage/GenericMageNonCombatStrategy.h + playerbot/strategy/mage/GenericMageStrategy.cpp + playerbot/strategy/mage/GenericMageStrategy.h + playerbot/strategy/mage/MageActions.cpp + playerbot/strategy/mage/MageActions.h + playerbot/strategy/mage/MageAiObjectContext.cpp + playerbot/strategy/mage/MageAiObjectContext.h + playerbot/strategy/mage/MageMultipliers.cpp + playerbot/strategy/mage/MageMultipliers.h + playerbot/strategy/mage/MageTriggers.cpp + playerbot/strategy/mage/MageTriggers.h + playerbot/strategy/Multiplier.cpp + playerbot/strategy/Multiplier.h + playerbot/strategy/NamedObjectContext.h + playerbot/strategy/paladin/DpsPaladinStrategy.cpp + playerbot/strategy/paladin/DpsPaladinStrategy.h + playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.cpp + playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.h + playerbot/strategy/paladin/GenericPaladinStrategy.cpp + playerbot/strategy/paladin/GenericPaladinStrategy.h + playerbot/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h + playerbot/strategy/paladin/PaladinActions.cpp + playerbot/strategy/paladin/PaladinActions.h + playerbot/strategy/paladin/PaladinAiObjectContext.cpp + playerbot/strategy/paladin/PaladinAiObjectContext.h + playerbot/strategy/paladin/PaladinBuffStrategies.cpp + playerbot/strategy/paladin/PaladinBuffStrategies.h + playerbot/strategy/paladin/PaladinMultipliers.cpp + playerbot/strategy/paladin/PaladinMultipliers.h + playerbot/strategy/paladin/PaladinTriggers.cpp + playerbot/strategy/paladin/PaladinTriggers.h + playerbot/strategy/paladin/TankPaladinStrategy.cpp + playerbot/strategy/paladin/TankPaladinStrategy.h + playerbot/strategy/PassiveMultiplier.cpp + playerbot/strategy/PassiveMultiplier.h + playerbot/strategy/priest/GenericPriestStrategy.cpp + playerbot/strategy/priest/GenericPriestStrategy.h + playerbot/strategy/priest/GenericPriestStrategyActionNodeFactory.h + playerbot/strategy/priest/HealPriestStrategy.cpp + playerbot/strategy/priest/HealPriestStrategy.h + playerbot/strategy/priest/HolyPriestStrategy.cpp + playerbot/strategy/priest/HolyPriestStrategy.h + playerbot/strategy/priest/PriestActions.cpp + playerbot/strategy/priest/PriestActions.h + playerbot/strategy/priest/PriestAiObjectContext.cpp + playerbot/strategy/priest/PriestAiObjectContext.h + playerbot/strategy/priest/PriestMultipliers.cpp + playerbot/strategy/priest/PriestMultipliers.h + playerbot/strategy/priest/PriestNonCombatStrategy.cpp + playerbot/strategy/priest/PriestNonCombatStrategy.h + playerbot/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h + playerbot/strategy/priest/PriestTriggers.cpp + playerbot/strategy/priest/PriestTriggers.h + playerbot/strategy/priest/ShadowPriestStrategy.cpp + playerbot/strategy/priest/ShadowPriestStrategy.h + playerbot/strategy/priest/ShadowPriestStrategyActionNodeFactory.h + playerbot/strategy/Queue.cpp + playerbot/strategy/Queue.h + playerbot/strategy/rogue/DpsRogueStrategy.cpp + playerbot/strategy/rogue/DpsRogueStrategy.h + playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp + playerbot/strategy/rogue/GenericRogueNonCombatStrategy.h + playerbot/strategy/rogue/RogueActions.cpp + playerbot/strategy/rogue/RogueActions.h + playerbot/strategy/rogue/RogueAiObjectContext.cpp + playerbot/strategy/rogue/RogueAiObjectContext.h + playerbot/strategy/rogue/RogueComboActions.h + playerbot/strategy/rogue/RogueFinishingActions.h + playerbot/strategy/rogue/RogueMultipliers.cpp + playerbot/strategy/rogue/RogueMultipliers.h + playerbot/strategy/rogue/RogueOpeningActions.h + playerbot/strategy/rogue/RogueTriggers.cpp + playerbot/strategy/rogue/RogueTriggers.h + playerbot/strategy/shaman/CasterShamanStrategy.cpp + playerbot/strategy/shaman/CasterShamanStrategy.h + playerbot/strategy/shaman/GenericShamanStrategy.cpp + playerbot/strategy/shaman/GenericShamanStrategy.h + playerbot/strategy/shaman/HealShamanStrategy.cpp + playerbot/strategy/shaman/HealShamanStrategy.h + playerbot/strategy/shaman/MeleeShamanStrategy.cpp + playerbot/strategy/shaman/MeleeShamanStrategy.h + playerbot/strategy/shaman/ShamanActions.cpp + playerbot/strategy/shaman/ShamanActions.h + playerbot/strategy/shaman/ShamanAiObjectContext.cpp + playerbot/strategy/shaman/ShamanAiObjectContext.h + playerbot/strategy/shaman/ShamanMultipliers.cpp + playerbot/strategy/shaman/ShamanMultipliers.h + playerbot/strategy/shaman/ShamanNonCombatStrategy.cpp + playerbot/strategy/shaman/ShamanNonCombatStrategy.h + playerbot/strategy/shaman/ShamanTriggers.cpp + playerbot/strategy/shaman/ShamanTriggers.h + playerbot/strategy/shaman/TotemsShamanStrategy.cpp + playerbot/strategy/shaman/TotemsShamanStrategy.h + playerbot/strategy/Strategy.cpp + playerbot/strategy/Strategy.h + playerbot/strategy/StrategyContext.h + playerbot/strategy/Trigger.cpp + playerbot/strategy/Trigger.h + playerbot/strategy/triggers/ChatCommandTrigger.h + playerbot/strategy/triggers/ChatTriggerContext.h + playerbot/strategy/triggers/CureTriggers.cpp + playerbot/strategy/triggers/CureTriggers.h + playerbot/strategy/triggers/GenericTriggers.cpp + playerbot/strategy/triggers/GenericTriggers.h + playerbot/strategy/triggers/HealthTriggers.cpp + playerbot/strategy/triggers/HealthTriggers.h + playerbot/strategy/triggers/LfgTriggers.h + playerbot/strategy/triggers/LootTriggers.cpp + playerbot/strategy/triggers/LootTriggers.h + playerbot/strategy/triggers/RangeTriggers.h + playerbot/strategy/triggers/TriggerContext.h + playerbot/strategy/triggers/WithinAreaTrigger.h + playerbot/strategy/triggers/WorldPacketTrigger.h + playerbot/strategy/triggers/WorldPacketTriggerContext.h + playerbot/strategy/Value.cpp + playerbot/strategy/Value.h + playerbot/strategy/values/AlwaysLootListValue.h + playerbot/strategy/values/AoeHealValues.cpp + playerbot/strategy/values/AoeHealValues.h + playerbot/strategy/values/AttackerCountValues.cpp + playerbot/strategy/values/AttackerCountValues.h + playerbot/strategy/values/AttackersValue.cpp + playerbot/strategy/values/AttackersValue.h + playerbot/strategy/values/AttackerWithoutAuraTargetValue.cpp + playerbot/strategy/values/AttackerWithoutAuraTargetValue.h + playerbot/strategy/values/AvailableLootValue.h + playerbot/strategy/values/CcTargetValue.cpp + playerbot/strategy/values/CcTargetValue.h + playerbot/strategy/values/ChatValue.h + playerbot/strategy/values/CurrentCcTargetValue.cpp + playerbot/strategy/values/CurrentCcTargetValue.h + playerbot/strategy/values/CurrentTargetValue.cpp + playerbot/strategy/values/CurrentTargetValue.h + playerbot/strategy/values/DistanceValue.h + playerbot/strategy/values/DpsTargetValue.cpp + playerbot/strategy/values/DpsTargetValue.h + playerbot/strategy/values/DuelTargetValue.cpp + playerbot/strategy/values/DuelTargetValue.h + playerbot/strategy/values/EnemyHealerTargetValue.cpp + playerbot/strategy/values/EnemyHealerTargetValue.h + playerbot/strategy/values/EnemyPlayerValue.cpp + playerbot/strategy/values/EnemyPlayerValue.h + playerbot/strategy/values/GrindTargetValue.cpp + playerbot/strategy/values/GrindTargetValue.h + playerbot/strategy/values/HasAvailableLootValue.h + playerbot/strategy/values/HasTotemValue.h + playerbot/strategy/values/InvalidTargetValue.cpp + playerbot/strategy/values/InvalidTargetValue.h + playerbot/strategy/values/IsBehindValue.h + playerbot/strategy/values/IsFacingValue.h + playerbot/strategy/values/IsMovingValue.h + playerbot/strategy/values/ItemCountValue.cpp + playerbot/strategy/values/ItemCountValue.h + playerbot/strategy/values/ItemForSpellValue.cpp + playerbot/strategy/values/ItemForSpellValue.h + playerbot/strategy/values/ItemUsageValue.cpp + playerbot/strategy/values/ItemUsageValue.h + playerbot/strategy/values/LastMovementValue.h + playerbot/strategy/values/LastSpellCastTimeValue.h + playerbot/strategy/values/LastSpellCastValue.h + playerbot/strategy/values/LeastHpTargetValue.cpp + playerbot/strategy/values/LeastHpTargetValue.h + playerbot/strategy/values/LfgValues.h + playerbot/strategy/values/LineTargetValue.cpp + playerbot/strategy/values/LineTargetValue.h + playerbot/strategy/values/LogLevelValue.h + playerbot/strategy/values/LootStrategyValue.h + playerbot/strategy/values/ManaSaveLevelValue.h + playerbot/strategy/values/MasterTargetValue.h + playerbot/strategy/values/NearestAdsValue.cpp + playerbot/strategy/values/NearestAdsValue.h + playerbot/strategy/values/NearestCorpsesValue.cpp + playerbot/strategy/values/NearestCorpsesValue.h + playerbot/strategy/values/NearestGameObjects.cpp + playerbot/strategy/values/NearestGameObjects.h + playerbot/strategy/values/NearestNpcsValue.cpp + playerbot/strategy/values/NearestNpcsValue.h + playerbot/strategy/values/NearestUnitsValue.h + playerbot/strategy/values/PartyMemberToDispel.cpp + playerbot/strategy/values/PartyMemberToDispel.h + playerbot/strategy/values/PartyMemberToHeal.cpp + playerbot/strategy/values/PartyMemberToHeal.h + playerbot/strategy/values/PartyMemberToResurrect.cpp + playerbot/strategy/values/PartyMemberToResurrect.h + playerbot/strategy/values/PartyMemberValue.cpp + playerbot/strategy/values/PartyMemberValue.h + playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp + playerbot/strategy/values/PartyMemberWithoutAuraValue.h + playerbot/strategy/values/PetTargetValue.h + playerbot/strategy/values/PositionValue.cpp + playerbot/strategy/values/PositionValue.h + playerbot/strategy/values/PossibleTargetsValue.cpp + playerbot/strategy/values/PossibleTargetsValue.h + playerbot/strategy/values/RtiTargetValue.h + playerbot/strategy/values/RtiValue.cpp + playerbot/strategy/values/RtiValue.h + playerbot/strategy/values/SelfTargetValue.h + playerbot/strategy/values/SpellCastUsefulValue.cpp + playerbot/strategy/values/SpellCastUsefulValue.h + playerbot/strategy/values/SpellIdValue.cpp + playerbot/strategy/values/SpellIdValue.h + playerbot/strategy/values/StatsValues.cpp + playerbot/strategy/values/StatsValues.h + playerbot/strategy/values/TankTargetValue.cpp + playerbot/strategy/values/TankTargetValue.h + playerbot/strategy/values/TargetValue.cpp + playerbot/strategy/values/TargetValue.h + playerbot/strategy/values/ThreatValues.cpp + playerbot/strategy/values/ThreatValues.h + playerbot/strategy/values/ValueContext.h + playerbot/strategy/warlock/DpsWarlockStrategy.cpp + playerbot/strategy/warlock/DpsWarlockStrategy.h + playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.cpp + playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.h + playerbot/strategy/warlock/GenericWarlockStrategy.cpp + playerbot/strategy/warlock/GenericWarlockStrategy.h + playerbot/strategy/warlock/TankWarlockStrategy.cpp + playerbot/strategy/warlock/TankWarlockStrategy.h + playerbot/strategy/warlock/WarlockActions.cpp + playerbot/strategy/warlock/WarlockActions.h + playerbot/strategy/warlock/WarlockAiObjectContext.cpp + playerbot/strategy/warlock/WarlockAiObjectContext.h + playerbot/strategy/warlock/WarlockMultipliers.cpp + playerbot/strategy/warlock/WarlockMultipliers.h + playerbot/strategy/warlock/WarlockTriggers.cpp + playerbot/strategy/warlock/WarlockTriggers.h + playerbot/strategy/warrior/DpsWarriorStrategy.cpp + playerbot/strategy/warrior/DpsWarriorStrategy.h + playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.cpp + playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.h + playerbot/strategy/warrior/GenericWarriorStrategy.cpp + playerbot/strategy/warrior/GenericWarriorStrategy.h + playerbot/strategy/warrior/TankWarriorStrategy.cpp + playerbot/strategy/warrior/TankWarriorStrategy.h + playerbot/strategy/warrior/WarriorActions.cpp + playerbot/strategy/warrior/WarriorActions.h + playerbot/strategy/warrior/WarriorAiObjectContext.cpp + playerbot/strategy/warrior/WarriorAiObjectContext.h + playerbot/strategy/warrior/WarriorMultipliers.cpp + playerbot/strategy/warrior/WarriorMultipliers.h + playerbot/strategy/warrior/WarriorTriggers.cpp + playerbot/strategy/warrior/WarriorTriggers.h +) + +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/playerbot FILES ${BOT_SRCS}) + +add_library(BotsIntf INTERFACE) +add_library(Bots STATIC ${BOT_SRCS}) + +target_include_directories(BotsIntf + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/playerbot +) + +target_link_libraries(Bots + PUBLIC + game +) + +# Install config files +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/playerbot/aiplayerbot.conf.dist.in ${CMAKE_CURRENT_BINARY_DIR}/aiplayerbot.conf.dist) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/aiplayerbot.conf.dist DESTINATION ${CONF_INSTALL_DIR}) + +# Generate PCH +if(PCH) + ADD_CXX_PCH(Bots ${bots_PCH}) +endif() diff --git a/src/modules/Bots/ahbot/AhBot.cpp b/src/modules/Bots/ahbot/AhBot.cpp new file mode 100644 index 0000000000..593ed0451c --- /dev/null +++ b/src/modules/Bots/ahbot/AhBot.cpp @@ -0,0 +1,1128 @@ +#include "ace/Task.h" +#include "Category.h" +#include "ItemBag.h" +#include "AhBot.h" +#include "World.h" +#include "Config.h" +#include "Chat.h" +#include "AhBotConfig.h" +#include "AuctionHouseMgr.h" +#include "WorldSession.h" +#include "Player.h" +#include "ObjectAccessor.h" +#include "ObjectGuid.h" +#include "ObjectMgr.h" +#include "playerbot/PlayerbotAIConfig.h" +#include "AccountMgr.h" +#include "playerbot/playerbot.h" + + +using namespace ahbot; + +bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid ) +{ + bool delete_result = true; + if (!result) + { + // 0 1 2 3 4 5 6 7 + result = CharacterDatabase.PQuery("SELECT `name`, `position_x`, `position_y`, `position_z`, `map`, `totaltime`, `leveltime`, `at_login` FROM `characters` WHERE `guid` = '%u'",guid); + if (!result) + { + return false; + } + } + else + { + delete_result = false; + } + + Field *fields = result->Fetch(); + + // overwrite possible wrong/corrupted guid + Object::_Create( guid, 0, HIGHGUID_PLAYER ); + + m_name = fields[0].GetCppString(); + + Relocate(fields[1].GetFloat(),fields[2].GetFloat(),fields[3].GetFloat()); + SetLocationMapId(fields[4].GetUInt32()); + + m_Played_time[PLAYED_TIME_TOTAL] = fields[5].GetUInt32(); + m_Played_time[PLAYED_TIME_LEVEL] = fields[6].GetUInt32(); + + m_atLoginFlags = fields[7].GetUInt32(); + + if (delete_result) + { + delete result; + } + + for (int i = 0; i < PLAYER_SLOTS_COUNT; ++i) + { + m_items[i] = NULL; + } + + if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + { + m_deathState = DEAD; + } + + return true; +} + +bool ChatHandler::HandleAhBotCommand(char* args) +{ + auctionbot.HandleCommand(args); + return true; +} + +INSTANTIATE_SINGLETON_1( ahbot::AhBot ); + +uint32 AhBot::auctionIds[MAX_AUCTIONS] = {1,6,7}; +uint32 AhBot::auctioneers[MAX_AUCTIONS] = {79707,4656,23442}; +map AhBot::factions; + +void AhBot::Init() +{ + sLog.outString("Initializing AhBot by ike3"); + + if (!sAhBotConfig.Initialize()) + { + return; + } + + factions[1] = 1; + factions[2] = 1; + factions[3] = 1; + factions[4] = 2; + factions[5] = 2; + factions[6] = 2; + factions[7] = 3; + + availableItems.Init(); + + sLog.outString("AhBot configuration loaded"); +} + +AhBot::~AhBot() +{ +} + +ObjectGuid AhBot::GetAHBplayerGUID() +{ + return ObjectGuid(sAhBotConfig.guid); +} + +class AhbotThread: public ACE_Task +{ +private: + AhBot* bot; +public: + AhbotThread(AhBot* bot) : bot(bot) {} + int svc(void) { bot->ForceUpdate(); return 0; } +}; + +void AhBot::Update() +{ + time_t now = time(0); + + if (now < nextAICheckTime) + { + return; + } + + if (updating) + { + return; + } + + nextAICheckTime = time(0) + sAhBotConfig.updateInterval; + + AhbotThread *thread = new AhbotThread(this); + thread->activate(); +} + +void AhBot::ForceUpdate() +{ + if (!sAhBotConfig.enabled) + { + return; + } + + if (updating) + { + return; + } + + sLog.outString("AhBot is now checking auctions"); + updating = true; + + if (!allBidders.size()) + { + LoadRandomBots(); + } + + if (!allBidders.size()) + { + sLog.outError("Ahbot is disabled but there is no bidders available"); + return; + } + + CheckCategoryMultipliers(); + + int answered = 0, added = 0; + for (int i = 0; i < MAX_AUCTIONS; i++) + { + InAuctionItemsBag inAuctionItems(auctionIds[i]); + inAuctionItems.Init(true); + + for (int j = 0; j < CategoryList::instance.size(); j++) + { + Category* category = CategoryList::instance[j]; + answered += Answer(i, category, &inAuctionItems); + added += AddAuctions(i, category, &inAuctionItems); + } + } + + CleanupHistory(); + + sLog.outString("AhBot auction check finished. %d auctions answered, %d new auctions added. Next check in %d seconds", + answered, added, sAhBotConfig.updateInterval); + updating = false; +} + +struct SortByPricePredicate +{ + bool operator()(AuctionEntry* const & a, AuctionEntry* const & b) const + { + if (a->startbid == b->startbid) + { + return a->buyout < b->buyout; + } + + return a->startbid < b->startbid; + } +}; + +vector AhBot::LoadAuctions(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, + Category*& category, int& auction) +{ + vector entries; + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + { + AuctionEntry *entry = itr->second; + if (IsBotAuction(entry->owner) || IsBotAuction(entry->bidder)) + { + continue; + } + + Item *item = sAuctionMgr.GetAItem(entry->itemGuidLow); + if (!item) + { + continue; + } + + if (!category->Contains(item->GetProto())) + { + continue; + } + + uint32 price = category->GetPricingStrategy()->GetBuyPrice(item->GetProto(), auctionIds[auction]); + if (!price || !item->GetCount()) + { + sLog.outDetail("%s (x%d) in auction %d: price cannot be determined", + item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); + continue; + } + + entries.push_back(entry); + } + sort(entries.begin(), entries.end(), SortByPricePredicate()); + return entries; +} + +void AhBot::FindMinPrice(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, AuctionEntry*& entry, Item*& item, uint32* minBid, + uint32* minBuyout) +{ + *minBid = 0; + *minBuyout = 0; + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + { + AuctionEntry *other = itr->second; + if (other->owner == entry->owner) + { + continue; + } + + Item *otherItem = sAuctionMgr.GetAItem(other->itemGuidLow); + if (!otherItem || !otherItem->GetCount() || otherItem->GetProto()->ItemId != item->GetProto()->ItemId) + { + continue; + } + + uint32 startbid = other->startbid / otherItem->GetCount() * item->GetCount(); + uint32 bid = other->bid / otherItem->GetCount() * item->GetCount(); + uint32 buyout = other->buyout / otherItem->GetCount() * item->GetCount(); + + if (!bid && startbid && (!*minBid || *minBid > startbid)) + { + *minBid = startbid; + } + + if (bid && (*minBid || *minBid > bid)) + { + *minBid = bid; + } + + if (buyout && (!*minBuyout || *minBuyout > buyout)) + { + *minBuyout = buyout; + } + } +} + +int AhBot::Answer(int auction, Category* category, ItemBag* inAuctionItems) +{ + const AuctionHouseEntry* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + if (!ahEntry) + { + return 0; + } + + int answered = 0; + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); + const AuctionHouseObject::AuctionEntryMap& auctionEntryMap = auctionHouse->GetAuctions(); + int64 availableMoney = GetAvailableMoney(auctionIds[auction]); + + vector entries = LoadAuctions(auctionEntryMap, category, auction); + for (vector::iterator itr = entries.begin(); itr != entries.end(); ++itr) + { + AuctionEntry *entry = *itr; + + Item *item = sAuctionMgr.GetAItem(entry->itemGuidLow); + if (!item || !item->GetCount()) + { + continue; + } + + const ItemPrototype* proto = item->GetProto(); + vector items = availableItems.Get(category); + if (find(items.begin(), items.end(), proto->ItemId) == items.end()) + { + sLog.outDetail("%s (x%d) in auction %d: unavailable item", + item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); + continue; + } + + uint32 answerCount = GetAnswerCount(proto->ItemId, auctionIds[auction], sAhBotConfig.itemBuyMaxInterval); + uint32 maxAnswerCount = category->GetMaxAllowedItemAuctionCount(proto); + if (maxAnswerCount && answerCount > maxAnswerCount) + { + sLog.outDetail("%s (x%d) in auction %d: answer count %d > %d (max)", + item->GetProto()->Name1, item->GetCount(), auctionIds[auction], answerCount, maxAnswerCount); + continue; + } + + if (proto->RequiredLevel > sAhBotConfig.maxRequiredLevel || proto->ItemLevel > sAhBotConfig.maxItemLevel) + { + sLog.outDetail("%s (x%d) in auction %d: above max required or item level", + item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); + continue; + } + + uint32 price = category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); + if (!price) + { + sLog.outDetail("%s (x%d) in auction %d: cannot determine price", + item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); + continue; + } + + uint32 bidPrice = item->GetCount() * price; + uint32 buyoutPrice = item->GetCount() * urand(price, 4 * price / 3); + + uint32 curPrice = entry->bid; + if (!curPrice) curPrice = entry->startbid; + { + if (!curPrice) curPrice = entry->buyout; + } + + if (curPrice > buyoutPrice) + { + sLog.outDetail("%s (x%d) in auction %d: price %d > %d (buyout price)", + proto->Name1, item->GetCount(), auctionIds[auction], curPrice, buyoutPrice); + continue; + } + + if (availableMoney < curPrice) + { + sLog.outDetail("%s (x%d) in auction %d: price %d > %d (available money)", + proto->Name1, item->GetCount(), auctionIds[auction], curPrice, availableMoney); + continue; + } + + uint32 minBid = 0, minBuyout = 0; + FindMinPrice(auctionEntryMap, entry, item, &minBid, &minBuyout); + + if (minBid && entry->bid && minBid < entry->bid) + { + sLog.outDetail("%s (x%d) in auction %d: %d (bid) > %d (minBid)", + proto->Name1, item->GetCount(), auctionIds[auction], entry->bid, minBid); + continue; + } + + if (minBid && entry->startbid && minBid < entry->startbid) + { + sLog.outDetail("%s (x%d) in auction %d: %d (startbid) > %d (minBid)", + proto->Name1, item->GetCount(), auctionIds[auction], entry->startbid, minBid); + continue; + } + + double priceLevel = (double)curPrice / (double)buyoutPrice; + uint32 buytime = GetBuyTime(entry->Id, proto->ItemId, auctionIds[auction], category, priceLevel); + if (time(0) < buytime) + { + sLog.outDetail("%s (x%d) in auction %d: will buy/bid in %d seconds", + proto->Name1, item->GetCount(), auctionIds[auction], buytime - time(0)); + continue; + } + + uint32 bidder = GetRandomBidder(auctionIds[auction]); + if (!bidder) + { + sLog.outError("No bidders for auction %d", auctionIds[auction]); + break; + } + + entry->bidder = bidder; + entry->bid = curPrice + urand(1, 1 + bidPrice / 10); + availableMoney -= curPrice; + + updateMarketPrice(item->GetProto()->ItemId, entry->buyout / item->GetCount(), auctionIds[auction]); + + if ((entry->buyout && (entry->bid >= entry->buyout || 100 * (entry->buyout - entry->bid) / price < 25)) && + !(minBuyout && entry->buyout && minBuyout < entry->buyout)) + { + sLog.outDetail("AhBot %d won %s (x%d) in auction %d for %d", + bidder, item->GetProto()->Name1, item->GetCount(), auctionIds[auction], entry->buyout); + + entry->bid = entry->buyout; + entry->AuctionBidWinning(NULL); + } + else + { + sLog.outDetail("AhBot %d placed bid %d for %s (x%d) in auction %d", + bidder, entry->bid, item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); + + CharacterDatabase.PExecute("UPDATE `auction` SET `buyguid` = '%u',`lastbid` = '%u' WHERE `id` = '%u'", + entry->bidder, entry->bid, entry->Id); + AddToHistory(entry, AHBOT_WON_BID); + } + + CharacterDatabase.PExecute("DELETE FROM `ahbot_history` WHERE `item` = '%u' AND `won` = 4 AND `auction_house` = '%u' ", + proto->ItemId, factions[auctionIds[auction]]); + + answered++; + } + + return answered; +} + +uint32 AhBot::GetTime(string category, uint32 id, uint32 auctionHouse, uint32 type) +{ + QueryResult* results = CharacterDatabase.PQuery("SELECT MAX(`buytime`) FROM `ahbot_history` WHERE `item` = '%u' AND `won` = '%u' AND `auction_house` = '%u' AND `category` = '%s'", + id, type, factions[auctionHouse], category.c_str()); + + if (!results) + { + return 0; + } + + Field* fields = results->Fetch(); + uint32 result = fields[0].GetUInt32(); + delete results; + + return result; +} + +void AhBot::SetTime(string category, uint32 id, uint32 auctionHouse, uint32 type, uint32 value) +{ + CharacterDatabase.PExecute("DELETE FROM `ahbot_history` WHERE `item` = '%u' AND `won` = '%u' AND `auction_house` = '%u' AND `category` = '%s'", + id, type, factions[auctionHouse], category.c_str()); + + CharacterDatabase.PExecute("INSERT INTO `ahbot_history` (`buytime`, `item`, `bid`, `buyout`, `category`, `won`, `auction_house`) " + "VALUES ('%u', '%u', '%u', '%u', '%s', '%u', '%u')", + value, id, 0, 0, + category.c_str(), type, factions[auctionHouse]); +} + +uint32 AhBot::GetBuyTime(uint32 entry, uint32 itemId, uint32 auctionHouse, Category*& category, double priceLevel) +{ + uint32 entryTime = GetTime("entry", entry, auctionHouse, AHBOT_WON_DELAY); + if (entryTime > time(0)) + { + return entryTime; + } + + uint32 result = entryTime; + + string categoryName = category->GetName(); + uint32 categoryTime = GetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY); + uint32 itemTime = GetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY); + + if (categoryTime < time(0)) categoryTime = time(0); + { + if (itemTime < time(0)) itemTime = time(0); + } + + double rarity = category->GetPricingStrategy()->GetRarityPriceMultiplier(itemId); + categoryTime += urand(sAhBotConfig.itemBuyMinInterval, sAhBotConfig.itemBuyMaxInterval) * priceLevel; + itemTime += urand(sAhBotConfig.itemBuyMinInterval, sAhBotConfig.itemBuyMaxInterval) * priceLevel / rarity; + entryTime = max(categoryTime, itemTime); + + SetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY, categoryTime); + SetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY, itemTime); + SetTime("entry", entry, auctionHouse, AHBOT_WON_DELAY, entryTime); + + return result ? result : entryTime; +} + +uint32 AhBot::GetSellTime(uint32 itemId, uint32 auctionHouse, Category*& category) +{ + uint32 itemSellTime = GetTime("item", itemId, auctionHouse, AHBOT_SELL_DELAY); + uint32 itemBuyTime = GetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY); + uint32 itemTime = max(itemSellTime, itemBuyTime); + + if (itemTime > time(0)) + { + return itemTime; + } + + uint32 result = itemTime; + + string categoryName = category->GetName(); + uint32 categorySellTime = GetTime(categoryName, 0, auctionHouse, AHBOT_SELL_DELAY); + uint32 categoryBuyTime = GetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY); + uint32 categoryTime = max(categorySellTime, categoryBuyTime); + + if (categoryTime < time(0)) categoryTime = time(0); + { + if (itemTime < time(0)) itemTime = time(0); + } + + double rarity = category->GetPricingStrategy()->GetRarityPriceMultiplier(itemId); + categoryTime += urand(sAhBotConfig.itemSellMinInterval, sAhBotConfig.itemSellMaxInterval); + itemTime += urand(sAhBotConfig.itemSellMinInterval, sAhBotConfig.itemSellMaxInterval) * rarity; + itemTime = max(itemTime, categoryTime); + + SetTime(categoryName, 0, auctionHouse, AHBOT_SELL_DELAY, categoryTime); + SetTime("item", itemId, auctionHouse, AHBOT_SELL_DELAY, itemTime); + + return result ? result : itemTime; +} + +int AhBot::AddAuctions(int auction, Category* category, ItemBag* inAuctionItems) +{ + vector& inAuction = inAuctionItems->Get(category); + + int32 maxAllowedAuctionCount = categoryMaxAuctionCount[category->GetName()]; + if (inAuctionItems->GetCount(category) >= maxAllowedAuctionCount) + { + return 0; + } + + int added = 0; + vector available = availableItems.Get(category); + for (int32 i = 0; i <= maxAllowedAuctionCount && available.size() > 0 && inAuctionItems->GetCount(category) < maxAllowedAuctionCount; ++i) + { + uint32 index = urand(0, available.size() - 1); + uint32 itemId = available[index]; + + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } + + int32 maxAllowedItems = category->GetMaxAllowedItemAuctionCount(proto); + if (maxAllowedItems && inAuctionItems->GetCount(category, proto->ItemId) >= maxAllowedItems) + { + continue; + } + + uint32 sellTime = GetSellTime(proto->ItemId, auctionIds[auction], category); + if (time(0) < sellTime) + { + sLog.outDetail("%s in auction %d: will add in %d seconds", + proto->Name1, auctionIds[auction], sellTime - time(0)); + continue; + } + else if (time(0) - sellTime > sAhBotConfig.maxSellInterval) + { + sLog.outDetail("%s in auction %d: too old (%d secs)", + proto->Name1, auctionIds[auction], time(0) - sellTime); + continue; + } + + inAuctionItems->Add(proto); + added += AddAuction(auction, category, proto); + } + + return added; +} + +int AhBot::AddAuction(int auction, Category* category, ItemPrototype const* proto) +{ + uint32 price = category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]); + + sLog.outDebug("AddAuction: market price adjust"); + updateMarketPrice(proto->ItemId, price, auctionIds[auction]); + + price = category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); + + uint32 stackCount = category->GetStackCount(proto); + if (!price || !stackCount) + { + return 0; + } + + if (urand(0, 100) <= sAhBotConfig.underPriceProbability * 100) + { + price = price * 100 / urand(100, 200); + } + + uint32 bidPrice = stackCount * price; + uint32 buyoutPrice = stackCount * urand(price, 4 * price / 3); + + Item* item = Item::CreateItem(proto->ItemId, stackCount); + if (!item) + { + return 0; + } + + uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(proto->ItemId); + if (randomPropertyId) + { + item->SetItemRandomProperties(randomPropertyId); + } + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + if(!ahEntry) + { + return 0; + } + + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); + + uint32 owner = GetRandomBidder(auctionIds[auction]); + if (!owner) + { + sLog.outError("No bidders for auction %d", auctionIds[auction]); + return 0; + } + + AuctionEntry* auctionEntry = new AuctionEntry; + auctionEntry->Id = sObjectMgr.GenerateAuctionID(); + auctionEntry->itemGuidLow = item->GetGUIDLow(); + auctionEntry->itemTemplate = item->GetEntry(); + auctionEntry->owner = owner; + auctionEntry->startbid = bidPrice; + auctionEntry->buyout = buyoutPrice; + auctionEntry->bidder = 0; + auctionEntry->bid = 0; + auctionEntry->deposit = 0; + auctionEntry->expireTime = (time_t) (urand(8, 24) * 60 * 60 + time(NULL)); + auctionEntry->auctionHouseEntry = ahEntry; + item->SaveToDB(); + + sAuctionMgr.AddAItem(item); + + + auctionHouse->AddAuction(auctionEntry); + + auctionHouse->AddAuction(auctionEntry); + auctionEntry->SaveToDB(); + + sLog.outDetail("AhBot %d added %d of %s to auction %d for %d..%d", owner, stackCount, proto->Name1, auctionIds[auction], bidPrice, buyoutPrice); + return 1; +} + +void AhBot::HandleCommand(string command) +{ + if (!sAhBotConfig.enabled) + { + return; + } + + if (command == "expire") + { + for (int i = 0; i < MAX_AUCTIONS; i++) + { + Expire(i); + } + + return; + } + + if (command == "stats") + { + for (int i = 0; i < MAX_AUCTIONS; i++) + { + PrintStats(i); + } + + return; + } + + if (command == "update") + { + AhbotThread *thread = new AhbotThread(this); + thread->activate(); + return; + } + + uint32 itemId = atoi(command.c_str()); + if (!itemId) + { + sLog.outString("ahbot stats - show short summary"); + sLog.outString("ahbot expire - expire all auctions"); + sLog.outString("ahbot update - update all auctions"); + sLog.outString("ahbot - show item price"); + return; + } + + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + return; + } + + for (int i=0; iContains(proto)) + { + vector items = availableItems.Get(category); + if (find(items.begin(), items.end(), proto->ItemId) == items.end()) + { + continue; + } + + ostringstream out; + out << proto->Name1 << " (" << category->GetDisplayName() << "), " + << category->GetMaxAllowedAuctionCount() << "x" << category->GetMaxAllowedItemAuctionCount(proto) + << "x" << category->GetStackCount(proto) << " max" + << "\n"; + for (int auction = 0; auction < MAX_AUCTIONS; auction++) + { + const AuctionHouseEntry* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + out << "--- auction house " << auctionIds[auction] << "(faction: " << factions[auctionIds[auction]] << ", money: " + << GetAvailableMoney(auctionIds[auction]) + << ") ---\n"; + + out << "sell: " << category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]) + << " (" << category->GetPricingStrategy()->ExplainSellPrice(proto, auctionIds[auction]) << ")" + << "\n"; + + out << "buy: " << category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]) + << " (" << category->GetPricingStrategy()->ExplainBuyPrice(proto, auctionIds[auction]) << ")" + << "\n"; + } + sLog.outString(out.str().c_str()); + break; + } + } +} + +void AhBot::Expire(int auction) +{ + if (!sAhBotConfig.enabled) + { + return; + } + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + if(!ahEntry) + { + return; + } + + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); + + AuctionHouseObject::AuctionEntryMap const& auctions = auctionHouse->GetAuctions(); + AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctions.begin(); + + int count = 0; + while (itr != auctions.end()) + { + if (IsBotAuction(itr->second->owner)) + { + itr->second->expireTime = sWorld.GetGameTime(); + count++; + } + + ++itr; + } + + CharacterDatabase.PExecute("DELETE FROM `ahbot_category`"); + sLog.outString("%d auctions marked as expired in auction %d", count, auctionIds[auction]); +} + +void AhBot::PrintStats(int auction) +{ + if (!sAhBotConfig.enabled) + { + return; + } + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + if(!ahEntry) + { + return; + } + + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); + AuctionHouseObject::AuctionEntryMap const& auctions = auctionHouse->GetAuctions(); + + sLog.outString("%d auctions available on auction house %d", auctions.size(), auctionIds[auction]); +} + +void AhBot::AddToHistory(AuctionEntry* entry, uint32 won) +{ + if (!sAhBotConfig.enabled || !entry) + { + return; + } + + if (!IsBotAuction(entry->owner) && !IsBotAuction(entry->bidder)) + { + return; + } + + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(entry->itemTemplate); + if (!proto) + { + return; + } + + string category = ""; + for (int i = 0; i < CategoryList::instance.size(); i++) + { + if (CategoryList::instance[i]->Contains(proto)) + { + category = CategoryList::instance[i]->GetName(); + break; + } + } + + if (!won) + { + won = AHBOT_WON_PLAYER; + if (IsBotAuction(entry->bidder)) + { + won = AHBOT_WON_SELF; + } + } + + sLog.outDebug("AddToHistory: market price adjust"); + int count = entry->itemCount ? entry->itemCount : 1; + updateMarketPrice(proto->ItemId, entry->buyout / count, entry->auctionHouseEntry->houseId); + + uint32 now = time(0); + CharacterDatabase.PExecute("INSERT INTO `ahbot_history` (`buytime`, `item`, `bid`, `buyout`, `category`, `won`, `auction_house`) " + "VALUES ('%u', '%u', '%u', '%u', '%s', '%u', '%u')", + now, entry->itemTemplate, entry->bid ? entry->bid : entry->startbid, entry->buyout, + category.c_str(), won, factions[entry->auctionHouseEntry->houseId]); +} + +uint32 AhBot::GetAnswerCount(uint32 itemId, uint32 auctionHouse, uint32 withinTime) +{ + uint32 count = 0; + + QueryResult* results = CharacterDatabase.PQuery("SELECT COUNT(*) FROM `ahbot_history` WHERE " + "`item` = '%u' AND `won` in (2, 3) AND `auction_house` = '%u' AND `buytime` > '%u'", + itemId, factions[auctionHouse], time(0) - withinTime); + if (results) + { + do + { + Field* fields = results->Fetch(); + count = fields[0].GetUInt32(); + } while (results->NextRow()); + + delete results; + } + + return count; +} + +void AhBot::CleanupHistory() +{ + uint32 when = time(0) - 3600 * 24 * sAhBotConfig.historyDays; + CharacterDatabase.PExecute("DELETE FROM `ahbot_history` WHERE `buytime` < '%u'", when); +} + +uint32 AhBot::GetAvailableMoney(uint32 auctionHouse) +{ + int64 result = sAhBotConfig.alwaysAvailableMoney; + + map data; + data[AHBOT_WON_PLAYER] = 0; + data[AHBOT_WON_SELF] = 0; + + const AuctionHouseEntry* ahEntry = sAuctionHouseStore.LookupEntry(auctionHouse); + QueryResult* results = CharacterDatabase.PQuery( + "SELECT `won`, SUM(`bid`) FROM `ahbot_history` WHERE `auction_house` = '%u' GROUP BY `won` HAVING `won` > 0 ORDER BY `won`", + factions[auctionHouse]); + if (results) + { + do + { + Field* fields = results->Fetch(); + data[fields[0].GetUInt32()] = fields[1].GetUInt32(); + + } while (results->NextRow()); + + delete results; + } + + results = CharacterDatabase.PQuery( + "SELECT max(`buytime`) FROM `ahbot_history` WHERE `auction_house` = '%u' AND `won` = '2'", + factions[auctionHouse]); + if (results) + { + Field* fields = results->Fetch(); + uint32 lastBuyTime = fields[0].GetUInt32(); + uint32 now = time(0); + if (lastBuyTime && now > lastBuyTime) + { + result += (now - lastBuyTime) / 3600 / 24 * sAhBotConfig.alwaysAvailableMoney; + } + + delete results; + } + + AuctionHouseObject::AuctionEntryMap const& auctionEntryMap = sAuctionMgr.GetAuctionsMap(ahEntry)->GetAuctions(); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + { + AuctionEntry *entry = itr->second; + if (!IsBotAuction(entry->bidder)) + { + continue; + } + + result -= entry->bid; + } + + result += (data[AHBOT_WON_PLAYER] - data[AHBOT_WON_SELF]); + return result < 0 ? 0 : (uint32)result; +} + +void AhBot::CheckCategoryMultipliers() +{ + QueryResult* results = CharacterDatabase.PQuery("SELECT `category`, `multiplier`, `max_auction_count`, `expire_time` FROM `ahbot_category`"); + if (results) + { + do + { + Field* fields = results->Fetch(); + categoryMultipliers[fields[0].GetCppString()] = fields[1].GetFloat(); + categoryMaxAuctionCount[fields[0].GetCppString()] = fields[2].GetInt32(); + categoryMultiplierExpireTimes[fields[0].GetCppString()] = fields[3].GetUInt64(); + + } while (results->NextRow()); + + delete results; + } + + CharacterDatabase.PExecute("DELETE FROM `ahbot_category`"); + + for (int i = 0; i < CategoryList::instance.size(); i++) + { + string name = CategoryList::instance[i]->GetName(); + if (categoryMultiplierExpireTimes[name] <= time(0) || categoryMultipliers[name] <= 0) + { + categoryMultipliers[name] = (double)urand(20, 100) / 20.0; + uint32 maxAllowedAuctionCount = CategoryList::instance[i]->GetMaxAllowedAuctionCount(); + categoryMaxAuctionCount[name] = urand(maxAllowedAuctionCount / 2, maxAllowedAuctionCount); + categoryMultiplierExpireTimes[name] = time(0) + urand(4, 7) * 3600 * 24; + } + + CharacterDatabase.PExecute("INSERT INTO `ahbot_category` (`category`, `multiplier`, `max_auction_count`, `expire_time`) " + "VALUES ('%s', '%f', '%u', '%u')", + name.c_str(), categoryMultipliers[name], categoryMaxAuctionCount[name], categoryMultiplierExpireTimes[name]); + } +} + + +void AhBot::updateMarketPrice(uint32 itemId, double price, uint32 auctionHouse) +{ + double marketPrice = 0; + + QueryResult* results = CharacterDatabase.PQuery("SELECT `price` FROM `ahbot_price` WHERE `item` = '%u' AND `auction_house` = '%u'", itemId, auctionHouse); + if (results) + { + marketPrice = results->Fetch()[0].GetFloat(); + delete results; + } + + if (marketPrice > 0) + { + marketPrice = (marketPrice + price) / 2; + } + else + { + marketPrice = price; + } + + CharacterDatabase.PExecute("DELETE FROM `ahbot_price` WHERE `item` = '%u' AND `auction_house` = '%u'", itemId, auctionHouse); + CharacterDatabase.PExecute("INSERT INTO `ahbot_price` (`item`, `price`, `auction_house`) VALUES ('%u', '%lf', '%u')", itemId, marketPrice, auctionHouse); +} + +bool AhBot::IsBotAuction(uint32 bidder) +{ + return allBidders.find(bidder) != allBidders.end(); +} + +uint32 AhBot::GetRandomBidder(uint32 auctionHouse) +{ + vector guids = bidders[factions[auctionHouse]]; + if (guids.empty()) + { + return 0; + } + + int index = urand(0, guids.size() - 1); + return guids[index]; +} + +void AhBot::LoadRandomBots() +{ + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); i++) + { + uint32 accountId = *i; + if (!sAccountMgr.GetCharactersCount(accountId)) + { + continue; + } + + QueryResult *result = CharacterDatabase.PQuery("SELECT `guid`, `race` FROM `characters` WHERE `account` = '%u'", accountId); + if (!result) + { + continue; + } + + do + { + Field* fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + uint32 race = fields[1].GetUInt32(); + uint32 auctionHouse = PlayerbotAI::IsOpposing(race, RACE_HUMAN) ? 2 : 1; + bidders[auctionHouse].push_back(guid); + bidders[3].push_back(guid); + allBidders.insert(guid); + } while (result->NextRow()); + delete result; + } + + if (allBidders.empty() && sAhBotConfig.guid) + { + uint32 guid = sAhBotConfig.guid; + allBidders.insert(guid); + for (int i = 1; i <= 3; i++) + { + bidders[i].push_back(guid); + } + } + + sLog.outDetail("{A=%d,H=%d,N=%d} bidders loaded", bidders[1].size(), bidders[2].size(), bidders[3].size()); +} + +int32 AhBot::GetSellPrice(ItemPrototype const* proto) +{ + if (!sAhBotConfig.enabled) + { + return 0; + } + + int32 maxPrice = 0; + for (int i=0; iContains(proto)) + { + continue; + } + + for (int auction = 0; auction < MAX_AUCTIONS; auction++) + { + int32 price = (int32)category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]); + if (!price) + { + price = (int32)category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); + } + + if (price > maxPrice) + { + maxPrice = price; + } + } + } + + return maxPrice; +} + +int32 AhBot::GetBuyPrice(ItemPrototype const* proto) +{ + if (!sAhBotConfig.enabled) + { + return 0; + } + + int32 maxPrice = 0; + for (int i=0; iContains(proto)) + { + continue; + } + + for (int auction = 0; auction < MAX_AUCTIONS; auction++) + { + int32 price = (int32)category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); + if (!price) + { + continue; + } + + if (price > maxPrice) + { + maxPrice = price; + } + } + } + + return maxPrice; +} + +double AhBot::GetRarityPriceMultiplier(const ItemPrototype* proto) +{ + if (!sAhBotConfig.enabled) + { + return 1.0; + } + + for (int i=0; iContains(proto)) + { + continue; + } + + return category->GetPricingStrategy()->GetRarityPriceMultiplier(proto->ItemId); + } + + return 1.0; + +} diff --git a/src/modules/Bots/ahbot/AhBot.h b/src/modules/Bots/ahbot/AhBot.h new file mode 100644 index 0000000000..ac063b3d0c --- /dev/null +++ b/src/modules/Bots/ahbot/AhBot.h @@ -0,0 +1,87 @@ +#pragma once + +#include "Category.h" +#include "ItemBag.h" +#include "PlayerbotAIBase.h" +#include "AuctionHouseMgr.h" +#include "ObjectGuid.h" +#include "WorldSession.h" + +#define MAX_AUCTIONS 3 +#define AHBOT_WON_EXPIRE 0 +#define AHBOT_WON_PLAYER 1 +#define AHBOT_WON_SELF 2 +#define AHBOT_WON_BID 3 +#define AHBOT_WON_DELAY 4 +#define AHBOT_SELL_DELAY 5 + +namespace ahbot +{ + using namespace std; + + class AhBot + { + public: + AhBot() : nextAICheckTime(0), updating(false) {} + virtual ~AhBot(); + + public: + ObjectGuid GetAHBplayerGUID(); + void Init(); + void Update(); + void ForceUpdate(); + void HandleCommand(string command); + void Won(AuctionEntry* entry) { AddToHistory(entry); } + void Expired(AuctionEntry* entry) {} + + double GetCategoryMultiplier(string category) + { + return categoryMultipliers[category]; + } + + int32 GetSellPrice(const ItemPrototype* proto); + int32 GetBuyPrice(const ItemPrototype* proto); + double GetRarityPriceMultiplier(const ItemPrototype* proto); + + private: + int Answer(int auction, Category* category, ItemBag* inAuctionItems); + int AddAuctions(int auction, Category* category, ItemBag* inAuctionItems); + int AddAuction(int auction, Category* category, const ItemPrototype* proto); + void Expire(int auction); + void PrintStats(int auction); + void AddToHistory(AuctionEntry* entry, uint32 won = 0); + void CleanupHistory(); + uint32 GetAvailableMoney(uint32 auctionHouse); + void CheckCategoryMultipliers(); + void updateMarketPrice(uint32 itemId, double price, uint32 auctionHouse); + bool IsBotAuction(uint32 bidder); + uint32 GetRandomBidder(uint32 auctionHouse); + void LoadRandomBots(); + uint32 GetAnswerCount(uint32 itemId, uint32 auctionHouse, uint32 withinTime); + vector LoadAuctions(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, Category*& category, + int& auction); + void FindMinPrice(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, AuctionEntry*& entry, Item*& item, uint32* minBid, + uint32* minBuyout); + uint32 GetBuyTime(uint32 entry, uint32 itemId, uint32 auctionHouse, Category*& category, double priceLevel); + uint32 GetTime(string category, uint32 id, uint32 auctionHouse, uint32 type); + void SetTime(string category, uint32 id, uint32 auctionHouse, uint32 type, uint32 value); + uint32 GetSellTime(uint32 itemId, uint32 auctionHouse, Category*& category); + + public: + static uint32 auctionIds[MAX_AUCTIONS]; + static uint32 auctioneers[MAX_AUCTIONS]; + static map factions; + + private: + AvailableItemsBag availableItems; + time_t nextAICheckTime; + map categoryMultipliers; + map categoryMaxAuctionCount; + map categoryMultiplierExpireTimes; + map > bidders; + set allBidders; + bool updating; + }; +}; + +#define auctionbot MaNGOS::Singleton::Instance() diff --git a/src/modules/Bots/ahbot/AhBotConfig.cpp b/src/modules/Bots/ahbot/AhBotConfig.cpp new file mode 100644 index 0000000000..5ad07a36b4 --- /dev/null +++ b/src/modules/Bots/ahbot/AhBotConfig.cpp @@ -0,0 +1,64 @@ +#include "../botpch.h" +#include "AhBotConfig.h" +#include "SystemConfig.h" +std::vector split(const std::string &s, char delim); + +using namespace std; + +INSTANTIATE_SINGLETON_1(AhBotConfig); + +AhBotConfig::AhBotConfig() +{ +} + +template +void LoadSet(string value, T &res) +{ + vector ids = split(value, ','); + for (vector::iterator i = ids.begin(); i != ids.end(); i++) + { + uint32 id = atoi((*i).c_str()); + if (!id) + { + continue; + } + + res.insert(id); + } +} + +bool AhBotConfig::Initialize() +{ + if (!config.SetSource(AUCTIONHOUSEBOT_CONFIG_NAME)) + { + sLog.outString("AhBot is Disabled. Unable to open configuration file ahbot.conf"); + return false; + } + + enabled = config.GetBoolDefault("AhBot.Enabled", false); + + if (enabled) + { + guid = (uint64)config.GetIntDefault("AhBot.GUID", 0); + updateInterval = config.GetIntDefault("AhBot.UpdateIntervalInSeconds", 300); + historyDays = config.GetIntDefault("AhBot.History.Days", 30); + itemBuyMinInterval = config.GetIntDefault("AhBot.ItemBuyMinInterval", 7200); + itemBuyMaxInterval = config.GetIntDefault("AhBot.ItemBuyMaxInterval", 28800); + itemSellMinInterval = config.GetIntDefault("AhBot.ItemSellMinInterval", 7200); + itemSellMaxInterval = config.GetIntDefault("AhBot.ItemSellMaxInterval", 28800); + maxSellInterval = config.GetIntDefault("AhBot.MaxSellInterval", 3600 * 8); + alwaysAvailableMoney = config.GetIntDefault("AhBot.AlwaysAvailableMoney", 200000); + priceMultiplier = config.GetFloatDefault("AhBot.PriceMultiplier", 1.0f); + defaultMinPrice = config.GetIntDefault("AhBot.DefaultMinPrice", 20); + maxItemLevel = config.GetIntDefault("AhBot.MaxItemLevel", 199); + maxRequiredLevel = config.GetIntDefault("AhBot.MaxRequiredLevel", 80); + priceQualityMultiplier = config.GetFloatDefault("AhBot.PriceQualityMultiplier", 1.0f); + underPriceProbability = config.GetFloatDefault("AhBot.UnderPriceProbability", 0.05f); + LoadSet >(config.GetStringDefault("AhBot.IgnoreItemIds", "49283,52200,8494,6345,6891,2460,37164,34835"), ignoreItemIds); + } + else + { + sLog.outString("AhBot is Disabled in ahbot.conf"); + } + return enabled; +} diff --git a/src/modules/Bots/ahbot/AhBotConfig.h b/src/modules/Bots/ahbot/AhBotConfig.h new file mode 100644 index 0000000000..f81a2bbd2b --- /dev/null +++ b/src/modules/Bots/ahbot/AhBotConfig.h @@ -0,0 +1,88 @@ +#pragma once + +#include "../../shared/Config/Config.h" + +using namespace std; + +class AhBotConfig +{ +public: + AhBotConfig(); + +public: + bool Initialize(); + + bool enabled; + uint64 guid; + uint32 updateInterval; + uint32 historyDays, maxSellInterval; + uint32 itemBuyMinInterval, itemBuyMaxInterval; + uint32 itemSellMinInterval, itemSellMaxInterval; + uint32 alwaysAvailableMoney; + float priceMultiplier, priceQualityMultiplier; + uint32 defaultMinPrice; + uint32 maxItemLevel, maxRequiredLevel; + float underPriceProbability; + std::set ignoreItemIds; + + float GetSellPriceMultiplier(string category) + { + return GetCategoryParameter(sellPriceMultipliers, "PriceMultiplier.Sell", category, 1.0f); + } + + float GetBuyPriceMultiplier(string category) + { + return GetCategoryParameter(buyPriceMultipliers, "PriceMultiplier.Buy", category, 1.0f); + } + + float GetItemPriceMultiplier(string name) + { + return GetCategoryParameter(itemPriceMultipliers, "PriceMultiplier.Item", name, 1.0f); + } + + int32 GetMaxAllowedAuctionCount(string category) + { + return (int32)GetCategoryParameter(maxAuctionCount, "MaxAuctionCount", category, 5); + } + + std::string GetStringDefault(const char* name, const char* def) + { + return config.GetStringDefault(name, def); + } + + bool GetBoolDefault(const char* name, const bool def = false) + { + return config.GetBoolDefault(name, def); + } + + int32 GetIntDefault(const char* name, const int32 def) + { + return config.GetIntDefault(name, def); + } + + float GetFloatDefault(const char* name, const float def) + { + return config.GetFloatDefault(name, def); + } + +private: + float GetCategoryParameter(map& cache, string type, string category, float defaultValue) + { + if (cache.find(category) == cache.end()) + { + ostringstream out; out << "AhBot."<< type << "." << category; + cache[category] = config.GetFloatDefault(out.str().c_str(), defaultValue); + } + + return cache[category]; + } + +private: + Config config; + map sellPriceMultipliers; + map buyPriceMultipliers; + map itemPriceMultipliers; + map maxAuctionCount; +}; + +#define sAhBotConfig MaNGOS::Singleton::Instance() diff --git a/src/modules/Bots/ahbot/Category.cpp b/src/modules/Bots/ahbot/Category.cpp new file mode 100644 index 0000000000..bb700f02de --- /dev/null +++ b/src/modules/Bots/ahbot/Category.cpp @@ -0,0 +1,79 @@ +#include "Category.h" +#include "ItemBag.h" +#include "AhBotConfig.h" +#include "PricingStrategy.h" + +using namespace ahbot; + +uint32 Category::GetStackCount(ItemPrototype const* proto) +{ + if (proto->Quality > ITEM_QUALITY_UNCOMMON) + { + return 1; + } + + return urand(1, proto->GetMaxStackSize()); +} + +uint32 Category::GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) +{ + return 0; +} + +uint32 Category::GetMaxAllowedAuctionCount() +{ + return sAhBotConfig.GetMaxAllowedAuctionCount(GetName()); +} + +PricingStrategy* Category::GetPricingStrategy() +{ + if (pricingStrategy) + { + return pricingStrategy; + } + + ostringstream out; out << "AhBot.PricingStrategy." << GetName(); + string name = sAhBotConfig.GetStringDefault(out.str().c_str(), "default"); + return pricingStrategy = PricingStrategyFactory::Create(name, this); +} + +QualityCategoryWrapper::QualityCategoryWrapper(Category* category, uint32 quality) : Category(), quality(quality), category(category) +{ + ostringstream out; out << category->GetName() << "."; + switch (quality) + { + case ITEM_QUALITY_POOR: + out << "gray"; + break; + case ITEM_QUALITY_NORMAL: + out << "white"; + break; + case ITEM_QUALITY_UNCOMMON: + out << "green"; + break; + case ITEM_QUALITY_RARE: + out << "blue"; + break; + default: + out << "epic"; + break; + } + + combinedName = out.str(); +} + +bool QualityCategoryWrapper::Contains(ItemPrototype const* proto) +{ + return proto->Quality == quality && category->Contains(proto); +} + +uint32 QualityCategoryWrapper::GetMaxAllowedAuctionCount() +{ + uint32 count = sAhBotConfig.GetMaxAllowedAuctionCount(combinedName); + return count > 0 ? count : category->GetMaxAllowedAuctionCount(); +} + +uint32 QualityCategoryWrapper::GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) +{ + return category->GetMaxAllowedItemAuctionCount(proto); +} diff --git a/src/modules/Bots/ahbot/Category.h b/src/modules/Bots/ahbot/Category.h new file mode 100644 index 0000000000..70c3385bb8 --- /dev/null +++ b/src/modules/Bots/ahbot/Category.h @@ -0,0 +1,323 @@ +#pragma once +#include "Config.h" +#include "PricingStrategy.h" +#include "ItemPrototype.h" +#include "SharedDefines.h" +#include "Util.h" + +using namespace std; + +namespace ahbot +{ + class Category + { + public: + Category() : pricingStrategy(NULL) {} + virtual ~Category() { if (pricingStrategy) delete pricingStrategy; } + + public: + virtual bool Contains(ItemPrototype const* proto) { return false; } + virtual string GetName() { return "default"; } + virtual string GetDisplayName() { return GetName(); } + + virtual uint32 GetMaxAllowedAuctionCount(); + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto); + virtual uint32 GetStackCount(ItemPrototype const* proto); + + virtual PricingStrategy* GetPricingStrategy(); + + private: + PricingStrategy *pricingStrategy; + }; + + class Consumable : public Category + { + public: + Consumable() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_CONSUMABLE; + } + + virtual string GetName() { return "consumable"; } + + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 10; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + if (proto->Quality > ITEM_QUALITY_UNCOMMON) + { + return 1; + } + + uint32 maxStackSize = proto->GetMaxStackSize(); + if (maxStackSize == 1) + { + return 1; + } + + if (maxStackSize <= 10) + { + return urand(1, 10); + } + + return urand(1, 4) * maxStackSize / 5; + } + }; + + class Quest : public Category + { + public: + Quest() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_QUEST; + } + virtual string GetName() { return "quest"; } + + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 5; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + if (proto->Quality > ITEM_QUALITY_UNCOMMON) + { + return 1; + } + + uint32 maxStackSize = proto->GetMaxStackSize(); + if (proto->Quality == ITEM_QUALITY_UNCOMMON && maxStackSize > 10) + { + maxStackSize = urand(1, 10); + } + + if (maxStackSize > 20) + { + maxStackSize = urand(1, 20); + } + + return maxStackSize; + } + }; + + class Trade : public Category + { + public: + Trade() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_TRADE_GOODS; + } + virtual string GetName() { return "trade"; } + + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 5; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + uint32 maxStack = proto->GetMaxStackSize(); + if (maxStack < 2) + { + return maxStack; + } + + switch (proto->Quality) + { + case ITEM_QUALITY_NORMAL: + return maxStack; + case ITEM_QUALITY_UNCOMMON: + return urand(1, maxStack); + } + + return 1; + } + }; + + class Reagent : public Category + { + public: + Reagent() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_REAGENT && proto->ItemLevel > 1; + } + virtual string GetName() { return "reagent"; } + }; + + class Recipe : public Category + { + public: + Recipe() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_RECIPE && proto->ItemLevel > 1; + } + virtual string GetName() { return "recipe"; } + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 1; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + return 1; + } + }; + + class Equip : public Category + { + public: + Equip() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return (proto->Class == ITEM_CLASS_WEAPON || + proto->Class == ITEM_CLASS_ARMOR) && proto->ItemLevel > 1; + } + virtual string GetName() { return "equip"; } + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 1; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + return 1; + } + }; + + class Other : public Category + { + public: + Other() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Quality > ITEM_QUALITY_POOR && ( + proto->Class == ITEM_CLASS_MISC) && proto->ItemLevel > 1; + } + virtual string GetName() { return "other"; } + + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 1; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + return 1; + } + }; + + class Quiver : public Category + { + public: + Quiver() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_QUIVER && proto->ItemLevel > 1; + } + + virtual string GetName() { return "quiver"; } + + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 1; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + return 1; + } + }; + + class Projectile : public Category + { + public: + Projectile() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_PROJECTILE; + } + + virtual string GetName() { return "projectile"; } + + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 5; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + return proto->GetMaxStackSize(); + } + }; + + class Container : public Category + { + public: + Container() : Category() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return proto->Class == ITEM_CLASS_CONTAINER && proto->ItemLevel > 1; + } + + virtual string GetName() { return "container"; } + + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto) + { + return 1; + } + + virtual uint32 GetStackCount(ItemPrototype const* proto) + { + return 1; + } + }; + + + class QualityCategoryWrapper : public Category + { + public: + QualityCategoryWrapper(Category* category, uint32 quality); + + public: + virtual bool Contains(ItemPrototype const* proto); + virtual uint32 GetMaxAllowedAuctionCount(); + virtual string GetName() { return category->GetName(); } + virtual string GetDisplayName() { return combinedName; } + virtual uint32 GetMaxAllowedItemAuctionCount(ItemPrototype const* proto); + virtual uint32 GetStackCount(ItemPrototype const* proto) { return category->GetStackCount(proto); } + virtual PricingStrategy* GetPricingStrategy() { return category->GetPricingStrategy(); } + + private: + uint32 quality; + Category* category; + string combinedName; + }; +}; diff --git a/src/modules/Bots/ahbot/ConsumableCategory.cpp b/src/modules/Bots/ahbot/ConsumableCategory.cpp new file mode 100644 index 0000000000..855c6742dc --- /dev/null +++ b/src/modules/Bots/ahbot/ConsumableCategory.cpp @@ -0,0 +1,4 @@ +#include "ConsumableCategory.h" +//#include "ItemBag.h" + +using namespace ahbot; diff --git a/src/modules/Bots/ahbot/ConsumableCategory.h b/src/modules/Bots/ahbot/ConsumableCategory.h new file mode 100644 index 0000000000..362095120e --- /dev/null +++ b/src/modules/Bots/ahbot/ConsumableCategory.h @@ -0,0 +1,87 @@ +#pragma once +#include "Config/Config.h" +#include "Category.h" + +using namespace std; + +namespace ahbot +{ + class Alchemy : public Consumable + { + public: + Alchemy() : Consumable() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return Consumable::Contains(proto) && + (proto->SubClass == ITEM_SUBCLASS_POTION || + proto->SubClass == ITEM_SUBCLASS_ELIXIR || + proto->SubClass == ITEM_SUBCLASS_FLASK); + } + + virtual string GetName() { return "Alchemy"; } + }; + + class Scroll : public Consumable + { + public: + Scroll() : Consumable() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return Consumable::Contains(proto) && + (proto->SubClass == ITEM_SUBCLASS_SCROLL || + proto->SubClass == ITEM_SUBCLASS_ITEM_ENHANCEMENT); + } + + virtual string GetName() { return "Scroll"; } + }; + + class Food : public Consumable + { + public: + Food() : Consumable() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return Consumable::Contains(proto) && + proto->SubClass == ITEM_SUBCLASS_FOOD; + } + + virtual string GetName() { return "Food"; } + }; + + class Bandage : public Consumable + { + public: + Bandage() : Consumable() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return Consumable::Contains(proto) && + proto->SubClass == ITEM_SUBCLASS_BANDAGE; + } + + virtual string GetName() { return "Bandage"; } + }; + + class OtherConsumable : public Consumable + { + public: + OtherConsumable() : Consumable() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return Consumable::Contains(proto) && + (proto->SubClass == ITEM_SUBCLASS_CONSUMABLE || + proto->SubClass == ITEM_SUBCLASS_CONSUMABLE_OTHER) && (proto->RequiredSkill); + } + + virtual string GetName() { return "OtherConsumable"; } + }; +}; diff --git a/src/modules/Bots/ahbot/ItemBag.cpp b/src/modules/Bots/ahbot/ItemBag.cpp new file mode 100644 index 0000000000..bb3bc20ac2 --- /dev/null +++ b/src/modules/Bots/ahbot/ItemBag.cpp @@ -0,0 +1,197 @@ +#include "Category.h" +#include "ItemBag.h" +#include "ConsumableCategory.h" +#include "TradeCategory.h" +#include "AhBotConfig.h" +#include "DBCStructure.h" +#include "Log.h" +#include "QueryResult.h" +#include "DatabaseEnv.h" +#include "SQLStorage.h" +#include "DBCStore.h" +#include "SQLStorages.h" +#include "AuctionHouseMgr.h" +#include "ObjectMgr.h" + +using namespace ahbot; +char * strstri (const char* str1, const char* str2); + +CategoryList CategoryList::instance; + +CategoryList::CategoryList() +{ + Add(new Equip()); + Add(new ahbot::Quest()); + Add(new Quiver()); + Add(new Projectile()); + + Add(new Recipe()); + Add(new Container()); + + Add(new Reagent()); + Add(new Alchemy()); + Add(new Scroll()); + Add(new Food()); + Add(new Bandage()); + + Add(new Engineering()); + + Add(new OtherConsumable()); + Add(new OtherTrade()); + Add(new Other()); +} + +void CategoryList::Add(Category* category) +{ + for (uint32 quality = ITEM_QUALITY_NORMAL; quality <= ITEM_QUALITY_EPIC; ++quality) + { + categories.push_back(new QualityCategoryWrapper(category, quality)); + } +} + +CategoryList::~CategoryList() +{ + for (vector::const_iterator i = categories.begin(); i != categories.end(); ++i) + { + delete *i; + } +} + +ItemBag::ItemBag() +{ + for (int i = 0; i < CategoryList::instance.size(); i++) + { + content[CategoryList::instance[i]] = vector(); + } +} + +void ItemBag::Init(bool silent) +{ + if (silent) + { + Load(); + return; + } + + sLog.outString("Loading/Scanning %s...", GetName().c_str()); + + Load(); + + for (int i = 0; i < CategoryList::instance.size(); i++) + { + Category* category = CategoryList::instance[i]; + Shuffle(content[category]); + sLog.outString("loaded %d %s items", content[category].size(), category->GetDisplayName().c_str()); + } +} + +int32 ItemBag::GetCount(Category* category, uint32 item) +{ + uint32 count = 0; + + vector& items = content[category]; + for (vector::iterator i = items.begin(); i != items.end(); ++i) + { + if (*i == item) + { + count++; + } + } + + return count; +} + +bool ItemBag::Add(ItemPrototype const* proto) +{ + if (!proto || + proto->Bonding == BIND_WHEN_PICKED_UP || + proto->Bonding == BIND_QUEST_ITEM) + return false; + + if (proto->RequiredLevel > sAhBotConfig.maxRequiredLevel || proto->ItemLevel > sAhBotConfig.maxItemLevel) + { + return false; + } + + if (proto->Duration & 0x80000000) + { + return false; + } + + if (sAhBotConfig.ignoreItemIds.find(proto->ItemId) != sAhBotConfig.ignoreItemIds.end()) + { + return false; + } + + if (strstri(proto->Name1, "qa") || strstri(proto->Name1, "test") || strstri(proto->Name1, "deprecated")) + { + return false; + } + + for (int i = 0; i < CategoryList::instance.size(); i++) + { + if (CategoryList::instance[i]->Contains(proto)) + { + content[CategoryList::instance[i]].push_back(proto->ItemId); + return true; + } + } + + return false; +} + +void AvailableItemsBag::Load() +{ + set vendorItems; + + QueryResult* results = WorldDatabase.PQuery("SELECT `item` FROM `npc_vendor` WHERE `maxcount` = 0"); + if (results != NULL) + { + do + { + Field* fields = results->Fetch(); + vendorItems.insert(fields[0].GetUInt32()); + } while (results->NextRow()); + + delete results; + } + + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + if (vendorItems.find(itemId) != vendorItems.end()) + { + continue; + } + + Add(sObjectMgr.GetItemPrototype(itemId)); + } + +} + +void InAuctionItemsBag::Load() +{ + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionId); + if(!ahEntry) + { + return; + } + + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); + AuctionHouseObject::AuctionEntryMap const& auctionEntryMap = auctionHouse->GetAuctions(); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itr->second->itemTemplate); + if (!proto) + { + continue; + } + + Add(proto); + } +} + +string InAuctionItemsBag::GetName() +{ + ostringstream out; out << "auction house " << auctionId; + return out.str(); +} diff --git a/src/modules/Bots/ahbot/ItemBag.h b/src/modules/Bots/ahbot/ItemBag.h new file mode 100644 index 0000000000..fd422c8102 --- /dev/null +++ b/src/modules/Bots/ahbot/ItemBag.h @@ -0,0 +1,82 @@ +#pragma once +#include "Category.h" + +namespace ahbot +{ + using namespace std; + + class CategoryList + { + public: + CategoryList(); + virtual ~CategoryList(); + + Category* operator[](int index) { return categories[index]; } + int32 size() { return categories.size(); } + static CategoryList instance; + + private: + void Add(Category* category); + + private: + vector categories; + }; + + template + void Shuffle(vector& items) + { + uint32 count = items.size(); + for (uint32 i = 0; i < count * 5; i++) + { + int i1 = urand(0, count - 1); + int i2 = urand(0, count - 1); + + T item = items[i1]; + items[i1] = items[i2]; + items[i2] = item; + } + } + + class ItemBag + { + public: + ItemBag(); + + public: + void Init(bool silent = false); + vector& Get(Category* category) { return content[category]; } + int32 GetCount(Category* category) { return content[category].size(); } + int32 GetCount(Category* category, uint32 item); + bool Add(ItemPrototype const* proto); + + protected: + virtual void Load() = 0; + virtual string GetName() = 0; + + protected: + map > content; + }; + + class AvailableItemsBag : public ItemBag + { + public: + AvailableItemsBag() {} + + protected: + virtual void Load(); + virtual string GetName() { return "available"; } + }; + + class InAuctionItemsBag : public ItemBag + { + public: + InAuctionItemsBag(uint32 auctionId) : auctionId(auctionId) {} + + protected: + virtual void Load(); + virtual string GetName(); + + private: + uint32 auctionId; + }; +}; diff --git a/src/modules/Bots/ahbot/PricingStrategy.cpp b/src/modules/Bots/ahbot/PricingStrategy.cpp new file mode 100644 index 0000000000..765a609a58 --- /dev/null +++ b/src/modules/Bots/ahbot/PricingStrategy.cpp @@ -0,0 +1,244 @@ +#include "PricingStrategy.h" +#include "Category.h" +#include "ItemBag.h" +#include "AhBotConfig.h" +#include "../../shared/Database/DatabaseEnv.h" +#include "AhBot.h" + +using namespace ahbot; + +uint32 PricingStrategy::GetSellPrice(ItemPrototype const* proto, uint32 auctionHouse) +{ + uint32 now = time(0); + double price = sAhBotConfig.GetItemPriceMultiplier(proto->Name1) * + auctionbot.GetCategoryMultiplier(category->GetName()) * + GetRarityPriceMultiplier(proto->ItemId) * + GetCategoryPriceMultiplier(now, auctionHouse) * + GetItemPriceMultiplier(proto, now, auctionHouse) * + sAhBotConfig.GetSellPriceMultiplier(category->GetName()) * + GetDefaultSellPrice(proto); + return (uint32)price; +} + +double PricingStrategy::GetMarketPrice(uint32 itemId, uint32 auctionHouse) +{ + double marketPrice = 0; + + QueryResult* results = CharacterDatabase.PQuery("SELECT `price` FROM `ahbot_price` WHERE `item` = '%u' AND `auction_house` = '%u'", itemId, auctionHouse); + if (results) + { + marketPrice = results->Fetch()[0].GetFloat(); + delete results; + } + + return marketPrice; +} + +uint32 PricingStrategy::GetBuyPrice(ItemPrototype const* proto, uint32 auctionHouse) +{ + double marketPrice = GetMarketPrice(proto->ItemId, auctionHouse); + + if (marketPrice > 0) + { + return marketPrice; + } + + uint32 untilTime = time(0) - 3600 * 12; + double price = sAhBotConfig.GetItemPriceMultiplier(proto->Name1) * + auctionbot.GetCategoryMultiplier(category->GetName()) * + GetRarityPriceMultiplier(proto->ItemId) * + GetCategoryPriceMultiplier(untilTime, auctionHouse) * + GetItemPriceMultiplier(proto, untilTime, auctionHouse) * + sAhBotConfig.GetBuyPriceMultiplier(category->GetName()) * + GetDefaultBuyPrice(proto); + return (uint32)price; +} + +string PricingStrategy::ExplainSellPrice(ItemPrototype const* proto, uint32 auctionHouse) +{ + ostringstream out; + + uint32 untilTime = time(0); + out << sAhBotConfig.GetItemPriceMultiplier(proto->Name1) << " (item const) * " << + auctionbot.GetCategoryMultiplier(category->GetName()) << " (random) * " << + GetRarityPriceMultiplier(proto->ItemId) << " (rariry) * " << + GetCategoryPriceMultiplier(untilTime, auctionHouse) << " (category) * " << + GetItemPriceMultiplier(proto, untilTime, auctionHouse) << " (item) * " << + sAhBotConfig.GetSellPriceMultiplier(category->GetName()) << " (sell) * " << + GetDefaultSellPrice(proto) << " (price)"; + return out.str(); +} + +string PricingStrategy::ExplainBuyPrice(ItemPrototype const* proto, uint32 auctionHouse) +{ + ostringstream out; + + double marketPrice = GetMarketPrice(proto->ItemId, auctionHouse); + if (marketPrice > 0) + { + out << marketPrice << " (market)"; + return out.str(); + } + + uint32 untilTime = time(0) - 3600 * 12; + out << sAhBotConfig.GetItemPriceMultiplier(proto->Name1) << " (item const) * " << + auctionbot.GetCategoryMultiplier(category->GetName()) << " (random) * " << + GetRarityPriceMultiplier(proto->ItemId) << " (rarity) * " << + GetCategoryPriceMultiplier(untilTime, auctionHouse) << " (category) * " << + GetItemPriceMultiplier(proto, untilTime, auctionHouse) << " (item) * " << + sAhBotConfig.GetBuyPriceMultiplier(category->GetName()) << " (buy) * " << + GetDefaultBuyPrice(proto) << " (price)"; + return out.str(); +} + +double PricingStrategy::GetRarityPriceMultiplier(uint32 itemId) +{ + double result = 1.0; + + QueryResult* results = WorldDatabase.PQuery( + "SELECT MAX(`ChanceOrQuestChance`) FROM ( " + "SELECT `ChanceOrQuestChance` FROM `gameobject_loot_template` WHERE `item` = '%u' " + //"union select ChanceOrQuestChance from spell_loot_template where item = '%u' " + "UNION SELECT `ChanceOrQuestChance` FROM `disenchant_loot_template` WHERE `item` = '%u' " + "UNION SELECT `ChanceOrQuestChance` FROM `fishing_loot_template` WHERE `item` = '%u' " + "UNION SELECT `ChanceOrQuestChance` FROM `item_loot_template` WHERE `item` = '%u' " + //"union select ChanceOrQuestChance from milling_loot_template where `item` = '%u' " + "UNION SELECT `ChanceOrQuestChance` FROM `pickpocketing_loot_template` WHERE `item` = '%u' " + //"union select ChanceOrQuestChance from prospecting_loot_template where `item` = '%u' " + "UNION SELECT `ChanceOrQuestChance` FROM `reference_loot_template` WHERE `item` = '%u' " + "UNION SELECT `ChanceOrQuestChance` FROM `skinning_loot_template` WHERE `item` = '%u' " + "UNION SELECT `ChanceOrQuestChance` FROM `creature_loot_template` WHERE `item` = '%u' " + "UNION SELECT 0 " + ") a", + itemId,itemId,itemId,itemId,itemId,itemId,itemId,itemId,itemId,itemId,itemId); + + if (results) + { + Field* fields = results->Fetch(); + float chance = fields[0].GetFloat(); + + if (chance > 0 && chance <= 90.0) + { + result = sqrt((100.0 - chance) / 10.0); + } + + delete results; + } + + return result >= 1.0 ? result : 1.0; +} + + +double PricingStrategy::GetCategoryPriceMultiplier(uint32 untilTime, uint32 auctionHouse) +{ + double result = 1.0; + + QueryResult* results = CharacterDatabase.PQuery( + "SELECT COUNT(*) FROM (SELECT ROUND(`buytime`/3600/24/5) AS days FROM `ahbot_history` WHERE `category` = '%s' AND `won` = '1' AND `buytime` <= '%u' AND `auction_house` = '%u' GROUP BY `days`) q", + category->GetName().c_str(), untilTime, AhBot::factions[auctionHouse]); + if (results) + { + Field* fields = results->Fetch(); + uint32 count = fields[0].GetUInt32(); + + if (count) + { + result += count; + } + + delete results; + } + + return result; +} + +double PricingStrategy::GetMultiplier(double count, double firstBuyTime, double lastBuyTime) +{ + double k1 = (double)count / (double)((time(0) - firstBuyTime) / 3600 / 24 + 1); + double k2 = (double)count / (double)((time(0) - lastBuyTime) / 3600 / 24 + 1); + return max(1.0, k1 + k2) * sAhBotConfig.priceMultiplier; +} + +double PricingStrategy::GetItemPriceMultiplier(ItemPrototype const* proto, uint32 untilTime, uint32 auctionHouse) +{ + double result = 1.0; + + QueryResult* results = CharacterDatabase.PQuery( + "SELECT count(*) FROM (SELECT ROUND(`buytime`/3600/24/5) AS `days` FROM `ahbot_history` WHERE `won` = '1' AND `item` = '%u' AND `buytime` <= '%u' AND `auction_house` = '%u' GROUP BY `days`) q", + proto->ItemId, untilTime, AhBot::factions[auctionHouse]); + if (results) + { + Field* fields = results->Fetch(); + uint32 count = fields[0].GetUInt32(); + + if (count) + { + result += count; + } + + delete results; + } + + return result; +} + +uint32 PricingStrategy::ApplyQualityMultiplier(ItemPrototype const* proto, uint32 price) +{ + if (proto->Quality == ITEM_QUALITY_POOR) + { + return price; + } + + return (uint32)(price * sqrt((double)proto->Quality) * sAhBotConfig.priceQualityMultiplier); +} + +uint32 PricingStrategy::GetDefaultBuyPrice(ItemPrototype const* proto) +{ + uint32 price = 0; + + if (proto->SellPrice) + { + price = proto->SellPrice; + } + if (proto->BuyPrice) + { + price = max(price, proto->BuyPrice / 4); + } + + uint32 level = max(proto->ItemLevel, proto->RequiredLevel); + if (proto->Class == ITEM_CLASS_QUEST) + { + double result = 1.0; + + QueryResult* results = WorldDatabase.PQuery( + "SELECT MAX(`QuestLevel`), MAX(`MinLevel`) FROM `quest_template` WHERE `ReqItemId1` = %u OR `ReqItemId2` = %u OR `ReqItemId3` = %u OR `ReqItemId4` = %u", + proto->ItemId, proto->ItemId, proto->ItemId, proto->ItemId); + if (results) + { + Field* fields = results->Fetch(); + level = max(fields[0].GetUInt32(), fields[1].GetUInt32()); + delete results; + } + } + price = max(price, sAhBotConfig.defaultMinPrice * level * level / 10); + price = max(price, (uint32)100); + + return ApplyQualityMultiplier(proto, price) * sAhBotConfig.priceMultiplier; +} + +uint32 PricingStrategy::GetDefaultSellPrice(ItemPrototype const* proto) +{ + return GetDefaultBuyPrice(proto); +} + + +uint32 BuyOnlyRarePricingStrategy::GetBuyPrice(ItemPrototype const* proto, uint32 auctionHouse) +{ + if (proto->Quality < ITEM_QUALITY_RARE) + { + return 0; + } + + return PricingStrategy::GetBuyPrice(proto, auctionHouse); +} + diff --git a/src/modules/Bots/ahbot/PricingStrategy.h b/src/modules/Bots/ahbot/PricingStrategy.h new file mode 100644 index 0000000000..80f9530fd4 --- /dev/null +++ b/src/modules/Bots/ahbot/PricingStrategy.h @@ -0,0 +1,58 @@ +#pragma once +#include "Config.h" +#include "ItemPrototype.h" + +using namespace std; + +namespace ahbot +{ + class Category; + + class PricingStrategy + { + public: + PricingStrategy(Category* category) : category(category) {} + + public: + virtual uint32 GetSellPrice(ItemPrototype const* proto, uint32 auctionHouse); + virtual uint32 GetBuyPrice(ItemPrototype const* proto, uint32 auctionHouse); + string ExplainSellPrice(ItemPrototype const* proto, uint32 auctionHouse); + string ExplainBuyPrice(ItemPrototype const* proto, uint32 auctionHouse); + virtual double GetRarityPriceMultiplier(uint32 itemId); + + protected: + virtual uint32 GetDefaultBuyPrice(ItemPrototype const* proto); + virtual uint32 GetDefaultSellPrice(ItemPrototype const* proto); + virtual uint32 ApplyQualityMultiplier(ItemPrototype const* proto, uint32 price); + virtual double GetCategoryPriceMultiplier(uint32 untilTime, uint32 auctionHouse); + virtual double GetItemPriceMultiplier(ItemPrototype const* proto, uint32 untilTime, uint32 auctionHouse); + double GetMultiplier(double count, double firstBuyTime, double lastBuyTime); + double GetMarketPrice(uint32 itemId, uint32 auctionHouse); + + protected: + Category* category; + }; + + class BuyOnlyRarePricingStrategy : public PricingStrategy + { + public: + BuyOnlyRarePricingStrategy(Category* category) : PricingStrategy(category) {} + + public: + virtual uint32 GetBuyPrice(ItemPrototype const* proto, uint32 auctionHouse); + }; + + class PricingStrategyFactory + { + public: + static PricingStrategy* Create(string name, Category* category) + { + if (name == "buyOnlyRare") + { + return new BuyOnlyRarePricingStrategy(category); + } + + return new PricingStrategy(category); + } + }; +}; diff --git a/src/modules/Bots/ahbot/TradeCategory.cpp b/src/modules/Bots/ahbot/TradeCategory.cpp new file mode 100644 index 0000000000..15fafa72c5 --- /dev/null +++ b/src/modules/Bots/ahbot/TradeCategory.cpp @@ -0,0 +1,4 @@ +#include "TradeCategory.h" +//#include "ItemBag.h" + +using namespace ahbot; diff --git a/src/modules/Bots/ahbot/TradeCategory.h b/src/modules/Bots/ahbot/TradeCategory.h new file mode 100644 index 0000000000..a32ddf4961 --- /dev/null +++ b/src/modules/Bots/ahbot/TradeCategory.h @@ -0,0 +1,42 @@ +#pragma once +#include "Config/Config.h" +#include "Category.h" + +using namespace std; + +namespace ahbot +{ + class Engineering : public Trade + { + public: + Engineering() : Trade() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return Trade::Contains(proto) && + (proto->SubClass == ITEM_SUBCLASS_PARTS || + proto->SubClass == ITEM_SUBCLASS_DEVICES || + proto->SubClass == ITEM_SUBCLASS_EXPLOSIVES); + } + + virtual string GetName() { return "Engineering"; } + }; + + class OtherTrade : public Trade + { + public: + OtherTrade() : Trade() {} + + public: + virtual bool Contains(ItemPrototype const* proto) + { + return Trade::Contains(proto) && + proto->SubClass != ITEM_SUBCLASS_PARTS && + proto->SubClass != ITEM_SUBCLASS_DEVICES && + proto->SubClass != ITEM_SUBCLASS_EXPLOSIVES; + } + + virtual string GetName() { return "OtherTrade"; } + }; +}; diff --git a/src/modules/Bots/ahbot/ahbot.conf.dist.in b/src/modules/Bots/ahbot/ahbot.conf.dist.in new file mode 100644 index 0000000000..f50ffc269c --- /dev/null +++ b/src/modules/Bots/ahbot/ahbot.conf.dist.in @@ -0,0 +1,209 @@ +################################################ +# MANGOS Auction House Bot Configuration file # +################################################ + +[AhbotConf] +ConfVersion=2010102201 + +################################################################################################################### +# AUCTION HOUSE BOT SETTINGS +# +################################################################################################################### + +# Disable original AuctionHouseBot +AuctionHouseBot.Seller.Enabled = 0 +AuctionHouseBot.Buyer.Enabled = 0 + +# Replace with the new AhBot +AhBot.Enabled = 1 + +# Should be used only if random bots are disabled +# AhBot.GUID = 0 + +# 199 for 80, 80 for 70, 70 for 60, ..., 25 for 20 +AhBot.MaxItemLevel = 199 +# Same as level cap +AhBot.MaxRequiredLevel = 80 + +# Ignore items by ID +AhBot.IgnoreItemIds = 49283,52200,8494,6345,6891,2460 + +AhBot.PriceMultiplier = 1.0 +AhBot.DefaultMinPrice = 20 +AhBot.PriceQualityMultiplier = 1.0 +AhBot.AlwaysAvailableMoney = 2000000 + +# Buy/sell delays +AhBot.ItemBuyMinInterval = 7200 +AhBot.ItemBuyMaxInterval = 28800 +AhBot.ItemSellMinInterval = 7200 +AhBot.ItemSellMaxInterval = 28800 + +# +# Items +# + +AhBot.MaxAuctionCount.equip.green = 0 +AhBot.MaxAuctionCount.equip.blue = 40 +AhBot.MaxAuctionCount.equip.epic = 20 +AhBot.PriceMultiplier.Sell.equip = 1.0 +AhBot.PriceMultiplier.Buy.equip = 1.0 +AhBot.PricingStrategy.equip = buyOnlyRare + +AhBot.MaxAuctionCount.reagent.white = 6 +AhBot.MaxAuctionCount.reagent.green = 2 +AhBot.PriceMultiplier.Sell.reagent = 1.0 +AhBot.PriceMultiplier.Buy.reagent = 1.0 +AhBot.PricingStrategy.reagent = buyOnlyRare + +AhBot.MaxAuctionCount.other.white = 20 +AhBot.MaxAuctionCount.other.green = 10 +AhBot.MaxAuctionCount.other.blue = 6 +AhBot.PriceMultiplier.Sell.other = 1.0 +AhBot.PriceMultiplier.Buy.other = 1.0 +AhBot.PricingStrategy.other = buyOnlyRare + +# +# Container +# + +AhBot.MaxAuctionCount.quiver.white = 2 +AhBot.PriceMultiplier.Sell.quiver = 1.0 +AhBot.PriceMultiplier.Buy.quiver = 1.0 +AhBot.PricingStrategy.quiver = buyOnlyRare + +AhBot.MaxAuctionCount.container.white = 6 +AhBot.MaxAuctionCount.container.green = 2 +AhBot.MaxAuctionCount.container.blue = 2 +AhBot.PriceMultiplier.Sell.container = 1.0 +AhBot.PriceMultiplier.Buy.container = 1.0 + +# +# Glyph +# + +AhBot.MaxAuctionCount.glyph.white = 50 +AhBot.MaxAuctionCount.glyph.green = 20 +AhBot.MaxAuctionCount.glyph.blue = 10 +AhBot.PriceMultiplier.Sell.glyph = 1.0 +AhBot.PriceMultiplier.Buy.glyph = 1.0 + +# +# Quest +# + +AhBot.MaxAuctionCount.quest.white = 14 +AhBot.MaxAuctionCount.quest.green = 2 +AhBot.MaxAuctionCount.quest.blue = 2 +AhBot.PriceMultiplier.Sell.quest = 1.0 +AhBot.PriceMultiplier.Buy.quest = 1.0 + +# +# Consumables +# + +AhBot.MaxAuctionCount.alchemy.white = 50 +AhBot.MaxAuctionCount.alchemy.green = 20 +AhBot.MaxAuctionCount.alchemy.blue = 10 +AhBot.PriceMultiplier.Sell.alchemy = 1.0 +AhBot.PriceMultiplier.Buy.alchemy = 1.0 + +AhBot.MaxAuctionCount.scroll.white = 40 +AhBot.MaxAuctionCount.scroll.green = 6 +AhBot.MaxAuctionCount.scroll.blue = 4 +AhBot.PriceMultiplier.Sell.scroll = 1.0 +AhBot.PriceMultiplier.Buy.scroll = 1.0 + +AhBot.MaxAuctionCount.Food.white = 40 +AhBot.PriceMultiplier.Sell.Food = 1.0 +AhBot.PriceMultiplier.Buy.Food = 1.0 + +AhBot.MaxAuctionCount.bandage.white = 10 +AhBot.PriceMultiplier.Sell.bandage = 1.0 +AhBot.PriceMultiplier.Buy.bandage = 1.0 + +AhBot.MaxAuctionCount.OtherConsumable.white = 20 +AhBot.MaxAuctionCount.OtherConsumable.green = 10 +AhBot.MaxAuctionCount.OtherConsumable.blue = 5 +AhBot.PriceMultiplier.Sell.OtherConsumable = 1.0 +AhBot.PriceMultiplier.Buy.OtherConsumable = 1.0 + +# +# Recipe +# + +AhBot.MaxAuctionCount.recipe.white = 8 +AhBot.MaxAuctionCount.recipe.green = 4 +AhBot.MaxAuctionCount.recipe.blue = 2 +AhBot.MaxAuctionCount.recipe.epic = 2 +AhBot.PriceMultiplier.Sell.recipe = 1.0 +AhBot.PriceMultiplier.Buy.recipe = 1.0 + +# +# Trade +# + +AhBot.MaxAuctionCount.Elemental.white = 30 +AhBot.MaxAuctionCount.Elemental.green = 20 +AhBot.MaxAuctionCount.Elemental.blue = 6 +AhBot.PriceMultiplier.Sell.Elemental = 1.0 +AhBot.PriceMultiplier.Buy.Elemental = 1.0 + +AhBot.MaxAuctionCount.Cloth.white = 50 +AhBot.MaxAuctionCount.Cloth.green = 14 +AhBot.MaxAuctionCount.Cloth.blue = 6 +AhBot.PriceMultiplier.Sell.Cloth = 1.0 +AhBot.PriceMultiplier.Buy.Cloth = 1.0 + +AhBot.MaxAuctionCount.Leather.white = 50 +AhBot.MaxAuctionCount.Leather.green = 14 +AhBot.MaxAuctionCount.Leather.blue = 6 +AhBot.PriceMultiplier.Sell.Leather = 1.0 +AhBot.PriceMultiplier.Buy.Leather = 1.0 + +AhBot.MaxAuctionCount.Herb.white = 50 +AhBot.MaxAuctionCount.Herb.green = 14 +AhBot.PriceMultiplier.Sell.Herb = 1.0 +AhBot.PriceMultiplier.Buy.Herb = 1.0 + +AhBot.MaxAuctionCount.Meat.white = 50 +AhBot.PriceMultiplier.Sell.Meat = 1.0 +AhBot.PriceMultiplier.Buy.Meat = 1.0 + +AhBot.MaxAuctionCount.Metal.white = 50 +AhBot.MaxAuctionCount.Metal.green = 14 +AhBot.MaxAuctionCount.Metal.blue = 6 +AhBot.PriceMultiplier.Sell.Metal = 1.0 +AhBot.PriceMultiplier.Buy.Metal = 1.0 + +AhBot.MaxAuctionCount.Engineering.white = 20 +AhBot.MaxAuctionCount.Engineering.green = 10 +AhBot.MaxAuctionCount.Engineering.blue = 4 +AhBot.PriceMultiplier.Sell.Engineering = 1.0 +AhBot.PriceMultiplier.Buy.Engineering = 1.0 + +AhBot.MaxAuctionCount.Disenchants.white = 40 +AhBot.MaxAuctionCount.Disenchants.green = 20 +AhBot.MaxAuctionCount.Disenchants.blue = 20 +AhBot.PriceMultiplier.Sell.Disenchants = 1.0 +AhBot.PriceMultiplier.Buy.Disenchants = 1.0 + +AhBot.MaxAuctionCount.SimpleGems.green = 30 +AhBot.MaxAuctionCount.SimpleGems.blue = 20 +AhBot.MaxAuctionCount.SimpleGems.epic = 4 +AhBot.PriceMultiplier.Sell.SimpleGems = 1.0 +AhBot.PriceMultiplier.Buy.SimpleGems = 1.0 + +AhBot.MaxAuctionCount.SocketGems.green = 50 +AhBot.MaxAuctionCount.SocketGems.blue = 20 +AhBot.MaxAuctionCount.SocketGems.epic = 4 +AhBot.PriceMultiplier.Sell.SocketGems = 1.0 +AhBot.PriceMultiplier.Buy.SocketGems = 1.0 + +AhBot.MaxAuctionCount.OtherTrade.white = 10 +AhBot.PriceMultiplier.Sell.OtherTrade = 1.0 +AhBot.PriceMultiplier.Buy.OtherTrade = 1.0 + +AhBot.PriceMultiplier.Sell.projectile = 1.0 +AhBot.PriceMultiplier.Buy.projectile = 1.0 +AhBot.PricingStrategy.projectile = buyOnlyRare diff --git a/src/modules/Bots/botpch.cpp b/src/modules/Bots/botpch.cpp new file mode 100644 index 0000000000..5417c3eb76 --- /dev/null +++ b/src/modules/Bots/botpch.cpp @@ -0,0 +1 @@ +#include "botpch.h" diff --git a/src/modules/Bots/botpch.h b/src/modules/Bots/botpch.h new file mode 100644 index 0000000000..329246e677 --- /dev/null +++ b/src/modules/Bots/botpch.h @@ -0,0 +1,16 @@ +//add here most rarely modified headers to speed up debug build compilation +#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it +#include "Common.h" + +#include "MapManager.h" +#include "Log.h" +#include "ObjectAccessor.h" +#include "ObjectGuid.h" +#include "SQLStorages.h" +#include "Opcodes.h" +#include "SharedDefines.h" +#include "GuildMgr.h" +#include "ObjectMgr.h" +#include "ScriptMgr.h" + +#include "playerbot.h" \ No newline at end of file diff --git a/src/modules/Bots/playerbot/AiFactory.cpp b/src/modules/Bots/playerbot/AiFactory.cpp new file mode 100644 index 0000000000..8c36faa14b --- /dev/null +++ b/src/modules/Bots/playerbot/AiFactory.cpp @@ -0,0 +1,303 @@ +#include "../botpch.h" +#include "playerbot.h" +#include "AiFactory.h" +#include "strategy/Engine.h" + +#include "strategy/priest/PriestAiObjectContext.h" +#include "strategy/mage/MageAiObjectContext.h" +#include "strategy/warlock/WarlockAiObjectContext.h" +#include "strategy/warrior/WarriorAiObjectContext.h" +#include "strategy/shaman/ShamanAiObjectContext.h" +#include "strategy/paladin/PaladinAiObjectContext.h" +#include "strategy/druid/DruidAiObjectContext.h" +#include "strategy/hunter/HunterAiObjectContext.h" +#include "strategy/rogue/RogueAiObjectContext.h" +#include "Player.h" +#include "PlayerbotAIConfig.h" +#include "RandomPlayerbotMgr.h" + + +AiObjectContext* AiFactory::createAiObjectContext(Player* player, PlayerbotAI* ai) +{ + switch (player->getClass()) + { + case CLASS_PRIEST: + return new PriestAiObjectContext(ai); + break; + case CLASS_MAGE: + return new MageAiObjectContext(ai); + break; + case CLASS_WARLOCK: + return new WarlockAiObjectContext(ai); + break; + case CLASS_WARRIOR: + return new WarriorAiObjectContext(ai); + break; + case CLASS_SHAMAN: + return new ShamanAiObjectContext(ai); + break; + case CLASS_PALADIN: + return new PaladinAiObjectContext(ai); + break; + case CLASS_DRUID: + return new DruidAiObjectContext(ai); + break; + case CLASS_HUNTER: + return new HunterAiObjectContext(ai); + break; + case CLASS_ROGUE: + return new RogueAiObjectContext(ai); + break; + } + return new AiObjectContext(ai); +} + +int AiFactory::GetPlayerSpecTab(Player* bot) +{ + map tabs = GetPlayerSpecTabs(bot); + + int tab = -1, max = 0; + for (uint32 i = 0; i < uint32(3); i++) + { + if (tab == -1 || max < tabs[i]) + { + tab = i; + max = tabs[i]; + } + } + + return tab; +} + +map AiFactory::GetPlayerSpecTabs(Player* bot) +{ + map tabs; + for (uint32 i = 0; i < uint32(3); i++) + { + tabs[i] = 0; + } + + uint32 classMask = bot->getClassMask(); + for (uint32 i = 0; i < sTalentStore.GetNumRows() && bot->GetFreeTalentPoints(); ++i) + { + TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); + if (!talentInfo) + { + continue; + } + + TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab); + if (!talentTabInfo) + { + continue; + } + + if ((classMask & talentTabInfo->ClassMask) == 0) + { + continue; + } + + for (int rank = MAX_TALENT_RANK - 1; rank >= 0; --rank) + { + if (!talentInfo->RankID[rank]) + { + continue; + } + + uint32 spellid = talentInfo->RankID[rank]; + if (spellid && bot->HasSpell(spellid)) + { + tabs[talentTabInfo->tabpage]++; + } + + } + } + + return tabs; +} + +void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* engine) +{ + int tab = GetPlayerSpecTab(player); + + engine->addStrategies("attack weak", "racials", "chat", "default", "aoe", "potions", "cast time", "conserve mana", "duel", "pvp", NULL); + + switch (player->getClass()) + { + case CLASS_PRIEST: + if (tab == 2) + { + engine->addStrategies("dps", "threat", NULL); + if (player->getLevel() > 19) + { + engine->addStrategy("dps debuff"); + } + } + else + { + engine->addStrategy("heal"); + } + + engine->addStrategy("flee"); + break; + case CLASS_MAGE: + if (tab == 0) + { + engine->addStrategies("arcane", "threat", NULL); + } + else if (tab == 1) + { + engine->addStrategies("fire", "fire aoe", "threat", NULL); + } + else + { + engine->addStrategies("frost", "frost aoe", "threat", NULL); + } + + engine->addStrategy("flee"); + break; + case CLASS_WARRIOR: + if (tab == 2) + { + engine->addStrategies("tank", "tank aoe", NULL); + } + else + { + engine->addStrategies("dps", "threat", NULL); + } + break; + case CLASS_SHAMAN: + if (tab == 0) + { + engine->addStrategies("caster", "caster aoe", "bmana", "threat", "flee", NULL); + } + else if (tab == 2) + { + engine->addStrategies("heal", "bmana", "flee", NULL); + } + else + { + engine->addStrategies("dps", "melee aoe", "bdps", "threat", NULL); + } + break; + case CLASS_PALADIN: + if (tab == 1) + { + engine->addStrategies("tank", "tank aoe", "barmor", NULL); + } + else + { + engine->addStrategies("dps", "bdps", "threat", NULL); + } + break; + case CLASS_DRUID: + if (tab == 0) + { + engine->addStrategies("caster", "caster aoe", "threat", "flee", NULL); + if (player->getLevel() > 19) + { + engine->addStrategy("caster debuff"); + } + } + else if (tab == 2) + { + engine->addStrategies("heal", "flee", NULL); + } + else + { + engine->addStrategies("bear", "tank aoe", "threat", "flee", NULL); + } + break; + case CLASS_HUNTER: + engine->addStrategies("dps", "bdps", "threat", NULL); + if (player->getLevel() > 19) + { + engine->addStrategy("dps debuff"); + } + break; + case CLASS_ROGUE: + engine->addStrategies("dps", "threat", NULL); + break; + case CLASS_WARLOCK: + if (tab == 1) + { + engine->addStrategies("tank", "threat", NULL); + } + else + { + engine->addStrategies("dps", "threat", NULL); + } + + if (player->getLevel() > 19) + { + engine->addStrategy("dps debuff"); + } + + engine->addStrategy("flee"); + break; + } + + if (sRandomPlayerbotMgr.IsRandomBot(player) && !player->GetGroup()) + { + engine->ChangeStrategy(sPlayerbotAIConfig.randomBotCombatStrategies); + } +} + +Engine* AiFactory::createCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext) { + Engine* engine = new Engine(facade, AiObjectContext); + AddDefaultCombatStrategies(player, facade, engine); + return engine; +} + +void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* nonCombatEngine) +{ + int tab = GetPlayerSpecTab(player); + + switch (player->getClass()){ + case CLASS_PALADIN: + case CLASS_HUNTER: + case CLASS_SHAMAN: + nonCombatEngine->addStrategy("bmana"); + break; + case CLASS_MAGE: + if (tab == 1) + { + nonCombatEngine->addStrategy("bdps"); + } + else + { + nonCombatEngine->addStrategy("bmana"); + } + break; + } + nonCombatEngine->addStrategies("nc", "attack weak", "food", "stay", "chat", + "default", "quest", "loot", "gather", "duel", "emote", NULL); + + if (sRandomPlayerbotMgr.IsRandomBot(player) && !player->GetGroup()) + { + nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig.randomBotNonCombatStrategies); + } + +} + +Engine* AiFactory::createNonCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext) { + Engine* nonCombatEngine = new Engine(facade, AiObjectContext); + + AddDefaultNonCombatStrategies(player, facade, nonCombatEngine); + return nonCombatEngine; +} + +void AiFactory::AddDefaultDeadStrategies(Player* player, PlayerbotAI* const facade, Engine* deadEngine) +{ + deadEngine->addStrategies("dead", "stay", "chat", "default", "follow master", NULL); + if (sRandomPlayerbotMgr.IsRandomBot(player) && !player->GetGroup()) + { + deadEngine->removeStrategy("follow master"); + } +} + +Engine* AiFactory::createDeadEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext) { + Engine* deadEngine = new Engine(facade, AiObjectContext); + AddDefaultDeadStrategies(player, facade, deadEngine); + return deadEngine; +} diff --git a/src/modules/Bots/playerbot/AiFactory.h b/src/modules/Bots/playerbot/AiFactory.h new file mode 100644 index 0000000000..736ffb63d7 --- /dev/null +++ b/src/modules/Bots/playerbot/AiFactory.h @@ -0,0 +1,21 @@ +#pragma once + +class Player; + +using namespace ai; + +class AiFactory +{ +public: + static AiObjectContext* createAiObjectContext(Player* player, PlayerbotAI* ai); + static Engine* createCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext); + static Engine* createNonCombatEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext); + static Engine* createDeadEngine(Player* player, PlayerbotAI* const facade, AiObjectContext* AiObjectContext); + static void AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* nonCombatEngine); + static void AddDefaultDeadStrategies(Player* player, PlayerbotAI* const facade, Engine* deadEngine); + static void AddDefaultCombatStrategies(Player* player, PlayerbotAI* const facade, Engine* engine); + +public: + static int GetPlayerSpecTab(Player* player); + static map GetPlayerSpecTabs(Player* player); +}; diff --git a/src/modules/Bots/playerbot/ChatFilter.cpp b/src/modules/Bots/playerbot/ChatFilter.cpp new file mode 100644 index 0000000000..24547890e9 --- /dev/null +++ b/src/modules/Bots/playerbot/ChatFilter.cpp @@ -0,0 +1,311 @@ +#include "../botpch.h" +#include "playerbot.h" +#include "ChatFilter.h" +#include "strategy/values/RtiTargetValue.h" + +using namespace ai; +using namespace std; + +string ChatFilter::Filter(string message) +{ + if (message.find("@") == string::npos) + { + return message; + } + + return message.substr(message.find(" ") + 1); +} + +class StrategyChatFilter : public ChatFilter +{ +public: + StrategyChatFilter(PlayerbotAI* ai) : ChatFilter(ai) {} + + virtual string Filter(string message) + { + Player* bot = ai->GetBot(); + + bool tank = message.find("@tank") == 0; + if (tank && !ai->IsTank(bot)) + { + return ""; + } + + bool dps = message.find("@dps") == 0; + if (dps && ai->IsTank(bot)) + { + return ""; + } + + bool heal = message.find("@heal") == 0; + if (heal && !ai->IsHeal(bot)) + { + return ""; + } + + if (tank || dps) + { + return ChatFilter::Filter(message); + } + + return message; + } +}; + +class LevelChatFilter : public ChatFilter +{ +public: + LevelChatFilter(PlayerbotAI* ai) : ChatFilter(ai) {} + + virtual string Filter(string message) + { + Player* bot = ai->GetBot(); + + if (message[0] != '@') + { + return message; + } + + if (message.find("-") != string::npos) + { + int fromLevel = atoi(message.substr(message.find("@") + 1, message.find("-")).c_str()); + int toLevel = atoi(message.substr(message.find("-") + 1, message.find(" ")).c_str()); + + if (bot->getLevel() >= fromLevel && bot->getLevel() <= toLevel) + { + return ChatFilter::Filter(message); + } + + return message; + } + + int level = atoi(message.substr(message.find("@") + 1, message.find(" ")).c_str()); + if (bot->getLevel() == level) + { + return ChatFilter::Filter(message); + } + + return message; + } +}; + +class CombatTypeChatFilter : public ChatFilter +{ +public: + CombatTypeChatFilter(PlayerbotAI* ai) : ChatFilter(ai) {} + + virtual string Filter(string message) + { + Player* bot = ai->GetBot(); + + bool melee = message.find("@melee") == 0; + bool ranged = message.find("@ranged") == 0; + + if (!melee && !ranged) + { + return message; + } + + switch (bot->getClass()) + { + case CLASS_WARRIOR: + case CLASS_PALADIN: + case CLASS_ROGUE: + /*case CLASS_DEATH_KNIGHT: + if (ranged) + { + return ""; + } + break;*/ + + case CLASS_HUNTER: + case CLASS_PRIEST: + case CLASS_MAGE: + case CLASS_WARLOCK: + if (melee) + { + return ""; + } + break; + + case CLASS_DRUID: + if (ranged && ai->IsTank(bot)) + { + return ""; + } + if (melee && !ai->IsTank(bot)) + { + return ""; + } + break; + + case CLASS_SHAMAN: + if (melee && ai->IsHeal(bot)) + { + return ""; + } + if (ranged && !ai->IsHeal(bot)) + { + return ""; + } + break; + } + + return ChatFilter::Filter(message); + } +}; + +class RtiChatFilter : public ChatFilter +{ +public: + RtiChatFilter(PlayerbotAI* ai) : ChatFilter(ai) + { + rtis.push_back("@star"); + rtis.push_back("@circle"); + rtis.push_back("@diamond"); + rtis.push_back("@triangle"); + rtis.push_back("@moon"); + rtis.push_back("@square"); + rtis.push_back("@cross"); + rtis.push_back("@skull"); + } + + virtual string Filter(string message) + { + Player* bot = ai->GetBot(); + Group *group = bot->GetGroup(); + if(!group) + { + return message; + } + + bool found = false; + for (list::iterator i = rtis.begin(); i != rtis.end(); i++) + { + string rti = *i; + + bool isRti = message.find(rti) == 0; + if (!isRti) + { + continue; + } + + ObjectGuid rtiTarget = group->GetTargetIcon(RtiTargetValue::GetRtiIndex(rti.substr(1))); + if (bot->GetObjectGuid() == rtiTarget) + { + return ChatFilter::Filter(message); + } + + Unit* target = *ai->GetAiObjectContext()->GetValue("current target"); + if (!target) + { + return ""; + } + + if (target->GetObjectGuid() != rtiTarget) + { + return ""; + } + + if (found |= isRti) + { + break; + } + } + + if (found) + { + return ChatFilter::Filter(message); + } + + return message; + } + +private: + list rtis; +}; + +class ClassChatFilter : public ChatFilter +{ +public: + ClassChatFilter(PlayerbotAI* ai) : ChatFilter(ai) + { + //classNames["@death_knight"] = CLASS_DEATH_KNIGHT; + classNames["@druid"] = CLASS_DRUID; + classNames["@hunter"] = CLASS_HUNTER; + classNames["@mage"] = CLASS_MAGE; + classNames["@paladin"] = CLASS_PALADIN; + classNames["@priest"] = CLASS_PRIEST; + classNames["@rogue"] = CLASS_ROGUE; + classNames["@shaman"] = CLASS_SHAMAN; + classNames["@warlock"] = CLASS_WARLOCK; + classNames["@warrior"] = CLASS_WARRIOR; + } + + virtual string Filter(string message) + { + Player* bot = ai->GetBot(); + + bool found = false; + for (map::iterator i = classNames.begin(); i != classNames.end(); i++) + { + bool isClass = message.find(i->first) == 0; + if (isClass && bot->getClass() != i->second) + { + return ""; + } + + if (found |= isClass) + { + break; + } + } + + if (found) + { + return ChatFilter::Filter(message); + } + + return message; + } + +private: + map classNames; +}; + + + +CompositeChatFilter::CompositeChatFilter(PlayerbotAI* ai) : ChatFilter(ai) +{ + filters.push_back(new StrategyChatFilter(ai)); + filters.push_back(new ClassChatFilter(ai)); + filters.push_back(new RtiChatFilter(ai)); + filters.push_back(new CombatTypeChatFilter(ai)); + filters.push_back(new LevelChatFilter(ai)); +} + +CompositeChatFilter::~CompositeChatFilter() +{ + for (list::iterator i = filters.begin(); i != filters.end(); i++) + { + delete (*i); + } +} + +string CompositeChatFilter::Filter(string message) +{ + for (int j = 0; j < filters.size(); ++j) + { + for (list::iterator i = filters.begin(); i != filters.end(); i++) + { + message = (*i)->Filter(message); + if (message.empty()) + { + break; + } + } + } + + return message; +} + diff --git a/src/modules/Bots/playerbot/ChatFilter.h b/src/modules/Bots/playerbot/ChatFilter.h new file mode 100644 index 0000000000..16dde4dfee --- /dev/null +++ b/src/modules/Bots/playerbot/ChatFilter.h @@ -0,0 +1,24 @@ +#pragma once + +using namespace std; + +namespace ai +{ + class ChatFilter : public PlayerbotAIAware + { + public: + ChatFilter(PlayerbotAI* ai) : PlayerbotAIAware(ai) {} + virtual string Filter(string message); + }; + + class CompositeChatFilter : public ChatFilter + { + public: + CompositeChatFilter(PlayerbotAI* ai); + virtual ~CompositeChatFilter(); + string Filter(string message); + + private: + list filters; + }; +}; diff --git a/src/modules/Bots/playerbot/ChatHelper.cpp b/src/modules/Bots/playerbot/ChatHelper.cpp new file mode 100644 index 0000000000..37da50c6aa --- /dev/null +++ b/src/modules/Bots/playerbot/ChatHelper.cpp @@ -0,0 +1,468 @@ +#include "../botpch.h" +#include "playerbot.h" +#include "ChatHelper.h" +#include "AiFactory.h" + +using namespace ai; +using namespace std; + +map ChatHelper::consumableSubClasses; +map ChatHelper::tradeSubClasses; +map ChatHelper::itemQualities; +map ChatHelper::slots; +map ChatHelper::chats; +map ChatHelper::classes; +map ChatHelper::races; +map > ChatHelper::specs; + +template +static bool substrContainsInMap(string searchTerm, map searchIn) +{ + for (typename map::iterator i = searchIn.begin(); i != searchIn.end(); ++i) + { + string term = i->first; + if (term.size() > 1 && searchTerm.find(term) != string::npos) + { + return true; + } + } + + return false; +} + +ChatHelper::ChatHelper(PlayerbotAI* ai) : PlayerbotAIAware(ai) +{ + itemQualities["poor"] = ITEM_QUALITY_POOR; + itemQualities["gray"] = ITEM_QUALITY_POOR; + itemQualities["normal"] = ITEM_QUALITY_NORMAL; + itemQualities["white"] = ITEM_QUALITY_NORMAL; + itemQualities["uncommon"] = ITEM_QUALITY_UNCOMMON; + itemQualities["green"] = ITEM_QUALITY_UNCOMMON; + itemQualities["rare"] = ITEM_QUALITY_RARE; + itemQualities["blue"] = ITEM_QUALITY_RARE; + itemQualities["epic"] = ITEM_QUALITY_EPIC; + itemQualities["violet"] = ITEM_QUALITY_EPIC; + + consumableSubClasses["potion"] = ITEM_SUBCLASS_POTION; + consumableSubClasses["elixir"] = ITEM_SUBCLASS_ELIXIR; + consumableSubClasses["flask"] = ITEM_SUBCLASS_FLASK; + consumableSubClasses["scroll"] = ITEM_SUBCLASS_SCROLL; + consumableSubClasses["food"] = ITEM_SUBCLASS_FOOD; + consumableSubClasses["bandage"] = ITEM_SUBCLASS_BANDAGE; + consumableSubClasses["enchant"] = ITEM_SUBCLASS_CONSUMABLE_OTHER; + + //tradeSubClasses["cloth"] = ITEM_SUBCLASS_CLOTH; + //tradeSubClasses["leather"] = ITEM_SUBCLASS_LEATHER; + //tradeSubClasses["metal"] = ITEM_SUBCLASS_METAL_STONE; + //tradeSubClasses["stone"] = ITEM_SUBCLASS_METAL_STONE; + //tradeSubClasses["ore"] = ITEM_SUBCLASS_METAL_STONE; + //tradeSubClasses["meat"] = ITEM_SUBCLASS_MEAT; + //tradeSubClasses["herb"] = ITEM_SUBCLASS_HERB; + //tradeSubClasses["elemental"] = ITEM_SUBCLASS_ELEMENTAL; + //tradeSubClasses["disenchants"] = ITEM_SUBCLASS_ENCHANTING; + //tradeSubClasses["enchanting"] = ITEM_SUBCLASS_ENCHANTING; + //tradeSubClasses["gems"] = ITEM_SUBCLASS_JEWELCRAFTING; + //tradeSubClasses["jewels"] = ITEM_SUBCLASS_JEWELCRAFTING; + //tradeSubClasses["jewelcrafting"] = ITEM_SUBCLASS_JEWELCRAFTING; + + slots["head"] = EQUIPMENT_SLOT_HEAD; + slots["neck"] = EQUIPMENT_SLOT_NECK; + slots["shoulder"] = EQUIPMENT_SLOT_SHOULDERS; + slots["shirt"] = EQUIPMENT_SLOT_BODY; + slots["chest"] = EQUIPMENT_SLOT_CHEST; + slots["waist"] = EQUIPMENT_SLOT_WAIST; + slots["legs"] = EQUIPMENT_SLOT_LEGS; + slots["feet"] = EQUIPMENT_SLOT_FEET; + slots["wrist"] = EQUIPMENT_SLOT_WRISTS; + slots["hands"] = EQUIPMENT_SLOT_HANDS; + slots["finger 1"] = EQUIPMENT_SLOT_FINGER1; + slots["finger 2"] = EQUIPMENT_SLOT_FINGER2; + slots["trinket 1"] = EQUIPMENT_SLOT_TRINKET1; + slots["trinket 2"] = EQUIPMENT_SLOT_TRINKET2; + slots["back"] = EQUIPMENT_SLOT_BACK; + slots["main hand"] = EQUIPMENT_SLOT_MAINHAND; + slots["off hand"] = EQUIPMENT_SLOT_OFFHAND; + slots["ranged"] = EQUIPMENT_SLOT_RANGED; + slots["tabard"] = EQUIPMENT_SLOT_TABARD; + + chats["party"] = CHAT_MSG_PARTY; + chats["p"] = CHAT_MSG_PARTY; + chats["guild"] = CHAT_MSG_GUILD; + chats["g"] = CHAT_MSG_GUILD; + chats["raid"] = CHAT_MSG_RAID; + chats["r"] = CHAT_MSG_RAID; + chats["whisper"] = CHAT_MSG_WHISPER; + chats["w"] = CHAT_MSG_WHISPER; + + classes[CLASS_DRUID] = "druid"; + specs[CLASS_DRUID][0] = "balance"; + specs[CLASS_DRUID][1] = "feral combat"; + specs[CLASS_DRUID][2] = "restoration"; + + classes[CLASS_HUNTER] = "hunter"; + specs[CLASS_HUNTER][0] = "beast mastery"; + specs[CLASS_HUNTER][1] = "marksmanship"; + specs[CLASS_HUNTER][2] = "survival"; + + classes[CLASS_MAGE] = "mage"; + specs[CLASS_MAGE][0] = "arcane"; + specs[CLASS_MAGE][1] = "fire"; + specs[CLASS_MAGE][2] = "frost"; + + classes[CLASS_PALADIN] = "paladin"; + specs[CLASS_PALADIN][0] = "holy"; + specs[CLASS_PALADIN][1] = "protection"; + specs[CLASS_PALADIN][2] = "retribution"; + + classes[CLASS_PRIEST] = "priest"; + specs[CLASS_PRIEST][0] = "discipline"; + specs[CLASS_PRIEST][1] = "holy"; + specs[CLASS_PRIEST][2] = "shadow"; + + classes[CLASS_ROGUE] = "rogue"; + specs[CLASS_ROGUE][0] = "assasination"; + specs[CLASS_ROGUE][1] = "combat"; + specs[CLASS_ROGUE][2] = "subtlety"; + + classes[CLASS_SHAMAN] = "shaman"; + specs[CLASS_SHAMAN][0] = "elemental"; + specs[CLASS_SHAMAN][1] = "enhancement"; + specs[CLASS_SHAMAN][2] = "restoration"; + + classes[CLASS_WARLOCK] = "warlock"; + specs[CLASS_WARLOCK][0] = "affliction"; + specs[CLASS_WARLOCK][1] = "demonology"; + specs[CLASS_WARLOCK][2] = "destruction"; + + classes[CLASS_WARRIOR] = "warrior"; + specs[CLASS_WARRIOR][0] = "arms"; + specs[CLASS_WARRIOR][1] = "fury"; + specs[CLASS_WARRIOR][2] = "protection"; + + races[RACE_DWARF] = "Dwarf"; + races[RACE_GNOME] = "Gnome"; + races[RACE_HUMAN] = "Human"; + races[RACE_NIGHTELF] = "Night Elf"; + races[RACE_ORC] = "Orc"; + races[RACE_TAUREN] = "Tauren"; + races[RACE_TROLL] = "Troll"; + races[RACE_UNDEAD] = "Undead"; +} + +string ChatHelper::formatMoney(uint32 copper) +{ + ostringstream out; + if (!copper) + { + out << "0|TInterface\\AddOns\\AtlasLoot\\Images\\bronze:0|t"; + return out.str(); + } + + uint32 gold = uint32(copper / 10000); + copper -= (gold * 10000); + uint32 silver = uint32(copper / 100); + copper -= (silver * 100); + out << " "; + if (gold > 0) + { + out << gold << "|TInterface\\AddOns\\AtlasLoot\\Images\\gold:0|t "; + } + if (silver > 0 && gold < 50) + { + out << silver << "|TInterface\\AddOns\\AtlasLoot\\Images\\silver:0|t "; + } + if (copper > 0 && gold < 10) + { + out << copper << "|TInterface\\AddOns\\AtlasLoot\\Images\\bronze:0|t"; + } + + return out.str(); +} + +uint32 ChatHelper::parseMoney(string& text) +{ + // if user specified money in ##g##s##c format + string acum = ""; + uint32 copper = 0; + for (uint8 i = 0; i < text.length(); i++) + { + if (text[i] == 'g') + { + copper += (atol(acum.c_str()) * 100 * 100); + acum = ""; + } + else if (text[i] == 'c') + { + copper += atol(acum.c_str()); + acum = ""; + } + else if (text[i] == 's') + { + copper += (atol(acum.c_str()) * 100); + acum = ""; + } + else if (text[i] == ' ') + { + break; + } + else if (text[i] >= 48 && text[i] <= 57) + { + acum += text[i]; + } + else + { + copper = 0; + break; + } + } + return copper; +} + +ItemIds ChatHelper::parseItems(string& text) +{ + ItemIds itemIds; + + uint8 pos = 0; + while (true) + { + int i = text.find("Hitem:", pos); + if (i == -1) + { + break; + } + pos = i + 6; + int endPos = text.find(':', pos); + if (endPos == -1) + { + break; + } + string idC = text.substr(pos, endPos - pos); + uint32 id = atol(idC.c_str()); + pos = endPos; + if (id) + { + itemIds.insert(id); + } + } + + return itemIds; +} + +string ChatHelper::formatQuest(Quest const* quest) +{ + ostringstream out; + out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle() << "]|h|r"; + return out.str(); +} + +string ChatHelper::formatGameobject(GameObject* go) +{ + ostringstream out; + out << "|cFFFFFF00|Hfound:" << go->GetObjectGuid().GetRawValue() << ":" << go->GetEntry() << ":" << "|h[" << go->GetGOInfo()->name << "]|h|r"; + return out.str(); +} + +string ChatHelper::formatSpell(SpellEntry const *sInfo) +{ + ostringstream out; + out << "|cffffffff|Hspell:" << sInfo->Id << "|h[" << sInfo->SpellName[LOCALE_enUS] << "]|h|r"; + return out.str(); +} + +string ChatHelper::formatItem(ItemPrototype const * proto, int count) +{ + char color[32]; + sprintf(color, "%x", ItemQualityColors[proto->Quality]); + + ostringstream out; + out << "|c" << color << "|Hitem:" << proto->ItemId + << ":0:0:0:0:0:0:0" << "|h[" << proto->Name1 + << "]|h|r"; + + if (count > 1) + { + out << "x" << count; + } + + return out.str(); +} + +ChatMsg ChatHelper::parseChat(string& text) +{ + if (chats.find(text) != chats.end()) + { + return chats[text]; + } + + return CHAT_MSG_SYSTEM; +} + +string ChatHelper::formatChat(ChatMsg chat) +{ + switch (chat) + { + case CHAT_MSG_GUILD: + return "guild"; + case CHAT_MSG_PARTY: + return "party"; + case CHAT_MSG_WHISPER: + return "whisper"; + case CHAT_MSG_RAID: + return "raid"; + } + + return "unknown"; +} + + +uint32 ChatHelper::parseSpell(string& text) +{ + PlayerbotChatHandler handler(ai->GetBot()); + return handler.extractSpellId(text); +} + +list ChatHelper::parseGameobjects(string& text) +{ + list gos; + // Link format + // |cFFFFFF00|Hfound:" << guid << ':' << entry << ':' << "|h[" << gInfo->name << "]|h|r"; + // |cFFFFFF00|Hfound:9582:1731|h[Copper Vein]|h|r + + uint8 pos = 0; + while (true) + { + // extract GO guid + int i = text.find("Hfound:", pos); // base H = 11 + if (i == -1) // break if error + { + break; + } + + pos = i + 7; //start of window in text 11 + 7 = 18 + int endPos = text.find(':', pos); // end of window in text 22 + if (endPos == -1) //break if error + { + break; + } + istringstream stream(text.substr(pos, endPos - pos)); + uint64 guid; stream >> guid; + + // extract GO entry + pos = endPos + 1; + endPos = text.find(':', pos); // end of window in text + if (endPos == -1) //break if error + { + break; + } + + std::string entryC = text.substr(pos, endPos - pos); // get string within window i.e entry + uint32 entry = atol(entryC.c_str()); // convert ascii to float + + ObjectGuid lootCurrent = ObjectGuid(guid); + + if (guid) + { + gos.push_back(lootCurrent); + } + } + + return gos; +} + +string ChatHelper::formatQuestObjective(string name, int available, int required) +{ + ostringstream out; + out << "|cFFFFFFFF" << name << (available >= required ? "|c0000FF00: " : "|c00FF0000: ") + << available << "/" << required << "|r"; + + return out.str(); +} + + +uint32 ChatHelper::parseItemQuality(string text) +{ + if (itemQualities.find(text) == itemQualities.end()) + { + return MAX_ITEM_QUALITY; + } + + return itemQualities[text]; +} + +bool ChatHelper::parseItemClass(string text, uint32 *itemClass, uint32 *itemSubClass) +{ + if (text == "questitem") + { + *itemClass = ITEM_CLASS_QUEST; + *itemSubClass = ITEM_SUBCLASS_QUEST; + return true; + } + + if (consumableSubClasses.find(text) != consumableSubClasses.end()) + { + *itemClass = ITEM_CLASS_CONSUMABLE; + *itemSubClass = consumableSubClasses[text]; + return true; + } + + if (tradeSubClasses.find(text) != tradeSubClasses.end()) + { + *itemClass = ITEM_CLASS_TRADE_GOODS; + *itemSubClass = tradeSubClasses[text]; + return true; + } + + return false; +} + +uint32 ChatHelper::parseSlot(string text) +{ + if (slots.find(text) != slots.end()) + { + return slots[text]; + } + + return EQUIPMENT_SLOT_END; +} + +bool ChatHelper::parseable(string text) +{ + return text.find("|H") != string::npos || + text == "questitem" || + substrContainsInMap(text, consumableSubClasses) || + substrContainsInMap(text, tradeSubClasses) || + substrContainsInMap(text, itemQualities) || + substrContainsInMap(text, slots) || + substrContainsInMap(text, chats) || + parseMoney(text) > 0; +} + +string ChatHelper::formatClass(Player* player, int spec) +{ + uint8 cls = player->getClass(); + + ostringstream out; + out << specs[cls][spec] << " ("; + + map tabs = AiFactory::GetPlayerSpecTabs(player); + int c0 = (int)tabs[0]; + int c1 = (int)tabs[1]; + int c2 = (int)tabs[2]; + + out << (c0 ? "|h|cff00ff00" : "") << c0 << "|h|cffffffff/"; + out << (c1 ? "|h|cff00ff00" : "") << c1 << "|h|cffffffff/"; + out << (c2 ? "|h|cff00ff00" : "") << c2 << "|h|cffffffff"; + + out << ") " << classes[cls]; + return out.str(); +} + +string ChatHelper::formatClass(uint8 cls) +{ + return classes[cls]; +} + +string ChatHelper::formatRace(uint8 race) +{ + return races[race]; +} diff --git a/src/modules/Bots/playerbot/ChatHelper.h b/src/modules/Bots/playerbot/ChatHelper.h new file mode 100644 index 0000000000..d1a4d5d020 --- /dev/null +++ b/src/modules/Bots/playerbot/ChatHelper.h @@ -0,0 +1,50 @@ +#pragma once + +using namespace std; + +typedef set ItemIds; +typedef set SpellIds; + +namespace ai +{ + class ChatHelper : public PlayerbotAIAware + { + public: + ChatHelper(PlayerbotAI* ai); + + public: + static string formatMoney(uint32 copper); + static uint32 parseMoney(string& text); + static ItemIds parseItems(string& text); + uint32 parseSpell(string& text); + static string formatQuest(Quest const* quest); + static string formatItem(ItemPrototype const * proto, int count = 0); + static string formatSpell(SpellEntry const *sInfo); + static string formatGameobject(GameObject* go); + static string formatQuestObjective(string name, int available, int required); + static list parseGameobjects(string& text); + + static ChatMsg parseChat(string& text); + static string formatChat(ChatMsg chat); + + static string formatClass(Player* player, int spec); + static string formatClass(uint8 cls); + static string formatRace(uint8 race); + + static uint32 parseItemQuality(string text); + static bool parseItemClass(string text, uint32 *itemClass, uint32 *itemSubClass); + static uint32 parseSlot(string text); + + static bool parseable(string text); + + private: + static map consumableSubClasses; + static map tradeSubClasses; + static map itemQualities; + static map slots; + static map chats; + static map classes; + static map races; + static map > specs; + }; +}; diff --git a/src/modules/Bots/playerbot/FleeManager.cpp b/src/modules/Bots/playerbot/FleeManager.cpp new file mode 100644 index 0000000000..85d0c71e31 --- /dev/null +++ b/src/modules/Bots/playerbot/FleeManager.cpp @@ -0,0 +1,175 @@ +#include "../botpch.h" +#include "playerbot.h" +#include "FleeManager.h" +#include "PlayerbotAIConfig.h" + +using namespace ai; +using namespace std; + +void FleeManager::calculateDistanceToPlayers(FleePoint *point) +{ + Group* group = bot->GetGroup(); + if (!group) + { + return; + } + + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->getSource(); + if(player == bot) + { + continue; + } + + float d = player->GetDistance(point->x, point->y, point->z); + point->toAllPlayers.probe(d); + switch (player->getClass()) { + case CLASS_HUNTER: + case CLASS_MAGE: + case CLASS_PRIEST: + case CLASS_WARLOCK: + point->toRangedPlayers.probe(d); + break; + case CLASS_PALADIN: + case CLASS_ROGUE: + case CLASS_WARRIOR: + point->toMeleePlayers.probe(d); + break; + } + } +} + +void FleeManager::calculateDistanceToCreatures(FleePoint *point) +{ + RangePair &distance = point->toCreatures; + + list units = *bot->GetPlayerbotAI()->GetAiObjectContext()->GetValue >("possible targets"); + for (list::iterator i = units.begin(); i != units.end(); ++i) + { + Unit* unit = bot->GetPlayerbotAI()->GetUnit(*i); + if (!unit) + { + continue; + } + + float d = unit->GetDistance(point->x, point->y, point->z); + if (d <= sPlayerbotAIConfig.tooCloseDistance) + { + continue; + } + + distance.probe(d); + } +} + +void FleeManager::calculatePossibleDestinations(list &points) +{ + float botPosX = bot->GetPositionX(); + float botPosY = bot->GetPositionY(); + float botPosZ = bot->GetPositionZ(); + + for (float distance = maxAllowedDistance; distance > sPlayerbotAIConfig.tooCloseDistance + 5.0f; distance -= 5.0f) + { + for (float angle = -M_PI + followAngle; angle < M_PI + followAngle; angle += M_PI / 16) + { + float x = botPosX + cos(angle) * distance; + float y = botPosY + sin(angle) * distance; + + if (!bot->IsWithinLOS(x, y, botPosZ)) + { + continue; + } + + FleePoint *point = new FleePoint(x, y, botPosZ); + calculateDistanceToPlayers(point); + calculateDistanceToCreatures(point); + points.push_back(point); + } + } +} + +void FleeManager::cleanup(list &points) +{ + for (list::iterator i = points.begin(); i != points.end(); i++) + { + FleePoint* point = *i; + delete point; + } + points.clear(); +} + +bool FleePoint::isReasonable() +{ + return toAllPlayers.max <= sPlayerbotAIConfig.sightDistance && toCreatures.min >= sPlayerbotAIConfig.tooCloseDistance; +} + +bool FleePoint::isBetterByCreatures(FleePoint* other) +{ + return toCreatures.min > 0 && other->toCreatures.min > 0 && + (toCreatures.min - other->toCreatures.min) >= 0.0f; +} + +bool FleePoint::isBetterByAll(FleePoint* other) +{ + bool isFartherFromCreatures = isBetterByCreatures(other); + bool isNearerToRangedPlayers = toRangedPlayers.max > 0 && other->toRangedPlayers.max > 0 && + (toRangedPlayers.max - other->toRangedPlayers.max) <= 0.0f; + bool isFartherFromMeleePlayers = toMeleePlayers.min > 0 && other->toMeleePlayers.min > 0 && + (toMeleePlayers.min - other->toMeleePlayers.min) >= 0.0f; + + return isFartherFromCreatures && (isNearerToRangedPlayers || isFartherFromMeleePlayers); +} + +FleePoint* FleeManager::selectOptimalDestination(list &points) +{ + FleePoint* byCreatures = NULL; + for (list::iterator i = points.begin(); i != points.end(); i++) + { + FleePoint* point = *i; + if (point->isReasonable() && (!byCreatures || point->isBetterByCreatures(byCreatures))) + { + byCreatures = point; + } + } + + FleePoint* byAll = NULL; + for (list::iterator i = points.begin(); i != points.end(); i++) + { + FleePoint* point = *i; + if (point->isReasonable() && (!byAll || point->isBetterByAll(byAll))) + { + byAll = point; + } + } + + if (byAll && byCreatures) + { + if (byAll->isBetterByCreatures(byCreatures)) + { + return byAll; + } + } + + return byCreatures; +} + +bool FleeManager::CalculateDestination(float* rx, float* ry, float* rz) +{ + list points; + calculatePossibleDestinations(points); + + FleePoint* point = selectOptimalDestination(points); + if (!point) + { + cleanup(points); + return false; + } + + *rx = point->x; + *ry = point->y; + *rz = bot->GetPositionZ(); + + cleanup(points); + return true; +} diff --git a/src/modules/Bots/playerbot/FleeManager.h b/src/modules/Bots/playerbot/FleeManager.h new file mode 100644 index 0000000000..3f37896b87 --- /dev/null +++ b/src/modules/Bots/playerbot/FleeManager.h @@ -0,0 +1,87 @@ +#pragma once + +using namespace std; + +class Player; + +namespace ai +{ + class Engine; + + class RangePair { + public: + RangePair() { + min = -1.0f; + max = -1.0f; + } + + public: + float min; + float max; + + public: + void probe(float d) { + if (min < 0 || min > d) + { + min = d; + } + + if (max < 0 || max < d) + { + max = d; + } + } + }; + + class FleePoint { + public: + FleePoint(float x, float y, float z) { + this->x = x; + this->y = y; + this->z = z; + } + + public: + bool isReasonable(); + bool isBetterByCreatures(FleePoint* other); + bool isBetterByAll(FleePoint* other); + + public: + float x; + float y; + float z; + + RangePair toCreatures; + RangePair toAllPlayers; + RangePair toMeleePlayers; + RangePair toRangedPlayers; + }; + + class FleeManager + { + public: + FleeManager(Player* bot, float maxAllowedDistance, float followAngle) { + this->bot = bot; + this->maxAllowedDistance = maxAllowedDistance; + this->followAngle = followAngle; + } + + public: + bool CalculateDestination(float* rx, float* ry, float* rz); + + private: + void calculatePossibleDestinations(list &points); + void calculateDistanceToPlayers(FleePoint *point); + void calculateDistanceToCreatures(FleePoint *point); + void cleanup(list &points); + FleePoint* selectOptimalDestination(list &points); + bool isReasonable(FleePoint* point); + bool isBetterThan(FleePoint* point, FleePoint* other); + + private: + Player* bot; + float maxAllowedDistance; + float followAngle; + }; + +}; diff --git a/src/modules/Bots/playerbot/Helpers.cpp b/src/modules/Bots/playerbot/Helpers.cpp new file mode 100644 index 0000000000..e75fbc52f7 --- /dev/null +++ b/src/modules/Bots/playerbot/Helpers.cpp @@ -0,0 +1,79 @@ +#include "../botpch.h" +#include "playerbot.h" +#include "Util.h" +#include +#include +#include + +vector& split(const string &s, char delim, vector &elems) +{ + stringstream ss(s); + string item; + while(getline(ss, item, delim)) + { + elems.push_back(item); + } + return elems; +} + + +vector split(const string &s, char delim) +{ + vector elems; + return split(s, delim, elems); +} + +char *strstri(const char *haystack, const char *needle) +{ + if ( !*needle ) + { + return (char*)haystack; + } + for ( ; *haystack; ++haystack ) + { + if ( tolower(*haystack) == tolower(*needle) ) + { + const char *h = haystack, *n = needle; + for ( ; *h && *n; ++h, ++n ) + { + if ( tolower(*h) != tolower(*n) ) + { + break; + } + } + if ( !*n ) + { + return (char*)haystack; + } + } + } + return 0; +} + + + +uint64 extractGuid(WorldPacket& packet) +{ + uint8 mask; + packet >> mask; + uint64 guid = 0; + uint8 bit = 0; + uint8 testMask = 1; + while (true) + { + if (mask & testMask) + { + uint8 word; + packet >> word; + guid += (word << bit); + } + if (bit == 7) + { + break; + } + ++bit; + testMask <<= 1; + } + return guid; +} + diff --git a/src/modules/Bots/playerbot/LazyCalculatedValue.h b/src/modules/Bots/playerbot/LazyCalculatedValue.h new file mode 100644 index 0000000000..e7839c6db2 --- /dev/null +++ b/src/modules/Bots/playerbot/LazyCalculatedValue.h @@ -0,0 +1,42 @@ +#pragma once + +using namespace std; + +namespace ai +{ + template + class LazyCalculatedValue + { + public: + typedef TValue (TOwner::*Calculator)(); + + public: + LazyCalculatedValue(TOwner* owner, Calculator calculator) + { + this->calculator = calculator; + this->owner = owner; + Reset(); + } + + public: + TValue GetValue() + { + if (!calculated) + { + value = (owner->*calculator)(); + calculated = true; + } + return value; + } + void Reset() + { + calculated = false; + } + + protected: + Calculator calculator; + TOwner* owner; + bool calculated; + TValue value; + }; +}; diff --git a/src/modules/Bots/playerbot/LootObjectStack.cpp b/src/modules/Bots/playerbot/LootObjectStack.cpp new file mode 100644 index 0000000000..a684b0628a --- /dev/null +++ b/src/modules/Bots/playerbot/LootObjectStack.cpp @@ -0,0 +1,273 @@ +#include "../botpch.h" +#include "LootObjectStack.h" +#include "playerbot.h" + +using namespace ai; +using namespace std; + +#define MAX_LOOT_OBJECT_COUNT 10 + +LootTarget::LootTarget(ObjectGuid guid) : guid(guid), asOfTime(time(0)) +{ +} + +LootTarget::LootTarget(LootTarget const& other) +{ + guid = other.guid; + asOfTime = other.asOfTime; +} + +LootTarget& LootTarget::operator=(LootTarget const& other) +{ + if((void*)this == (void*)&other) + { + return *this; + } + + guid = other.guid; + asOfTime = other.asOfTime; + + return *this; +} + +bool LootTarget::operator< (const LootTarget& other) const +{ + return guid < other.guid; +} + +void LootTargetList::shrink(time_t fromTime) +{ + for (set::iterator i = begin(); i != end(); ) + { + if (i->asOfTime <= fromTime) + { + erase(i++); + } + else + { + ++i; + } + } +} + +LootObject::LootObject(Player* bot, ObjectGuid guid) + : guid(), skillId(SKILL_NONE), reqSkillValue(0), reqItem(0) +{ + Refresh(bot, guid); +} + +void LootObject::Refresh(Player* bot, ObjectGuid guid) +{ + skillId = SKILL_NONE; + reqSkillValue = 0; + reqItem = 0; + this->guid = ObjectGuid(); + + PlayerbotAI* ai = bot->GetPlayerbotAI(); + Creature *creature = ai->GetCreature(guid); + if (creature && creature->GetDeathState() == CORPSE) + { + if (creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) + { + this->guid = guid; + } + + if (creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) + { + skillId = creature->GetCreatureInfo()->GetRequiredLootSkill(); + uint32 targetLevel = creature->getLevel(); + reqSkillValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel - 10) * 10 : targetLevel * 5; + if (bot->HasSkill(skillId) && bot->GetSkillValue(skillId) >= reqSkillValue) + { + this->guid = guid; + } + } + + return; + } + + GameObject* go = ai->GetGameObject(guid); + if (go && go->isSpawned()) + { + uint32 lockId = go->GetGOInfo()->GetLockId(); + LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); + if (!lockInfo) + { + return; + } + + for (int i = 0; i < 8; ++i) + { + switch (lockInfo->Type[i]) + { + case LOCK_KEY_ITEM: + if (lockInfo->Index[i] > 0) + { + reqItem = lockInfo->Index[i]; + this->guid = guid; + } + break; + case LOCK_KEY_SKILL: + if (SkillByLockType(LockType(lockInfo->Index[i])) > 0) + { + skillId = SkillByLockType(LockType(lockInfo->Index[i])); + reqSkillValue = lockInfo->Skill[i]; + this->guid = guid; + } + break; + default: + break; + } + } + } +} + +WorldObject* LootObject::GetWorldObject(Player* bot) +{ + Refresh(bot, guid); + + PlayerbotAI* ai = bot->GetPlayerbotAI(); + + Creature *creature = ai->GetCreature(guid); + if (creature && creature->GetDeathState() == CORPSE) + { + return creature; + } + + GameObject* go = ai->GetGameObject(guid); + if (go && go->isSpawned()) + { + return go; + } + + return NULL; +} + +LootObject::LootObject(const LootObject& other) +{ + guid = other.guid; + skillId = other.skillId; + reqSkillValue = other.reqSkillValue; + reqItem = other.reqItem; +} + +bool LootObject::IsLootPossible(Player* bot) +{ + if (IsEmpty() || !GetWorldObject(bot)) + { + return false; + } + + PlayerbotAI* ai = bot->GetPlayerbotAI(); + + if (reqItem && !bot->HasItemCount(reqItem, 1)) + { + return false; + } + + if (skillId == SKILL_NONE) + { + return true; + } + + if (skillId == SKILL_FISHING) + { + return false; + } + + if (!bot->HasSkill(skillId)) + { + return false; + } + + if (!reqSkillValue) + { + return true; + } + + uint32 skillValue = uint32(bot->GetPureSkillValue(skillId)); + if (reqSkillValue > skillValue) + { + return false; + } + + return true; +} + +bool LootObjectStack::Add(ObjectGuid guid) +{ + if (!availableLoot.insert(guid).second) + { + return false; + } + + if (availableLoot.size() < MAX_LOOT_OBJECT_COUNT) + { + return true; + } + + vector ordered = OrderByDistance(); + for (size_t i = MAX_LOOT_OBJECT_COUNT; i < ordered.size(); i++) + { + Remove(ordered[i].guid); + } + + return true; +} + +void LootObjectStack::Remove(ObjectGuid guid) +{ + LootTargetList::iterator i = availableLoot.find(guid); + if (i != availableLoot.end()) + { + availableLoot.erase(i); + } +} + +void LootObjectStack::Clear() +{ + availableLoot.clear(); +} + +bool LootObjectStack::CanLoot(float maxDistance) +{ + vector ordered = OrderByDistance(maxDistance); + return !ordered.empty(); +} + +LootObject LootObjectStack::GetLoot(float maxDistance) +{ + vector ordered = OrderByDistance(maxDistance); + return ordered.empty() ? LootObject() : *ordered.begin(); +} + +vector LootObjectStack::OrderByDistance(float maxDistance) +{ + availableLoot.shrink(time(0) - 30); + + map sortedMap; + LootTargetList safeCopy(availableLoot); + for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); i++) + { + ObjectGuid guid = i->guid; + LootObject lootObject(bot, guid); + if (!lootObject.IsLootPossible(bot)) + { + continue; + } + + float distance = bot->GetDistance(lootObject.GetWorldObject(bot)); + if (!maxDistance || distance <= maxDistance) + { + sortedMap[distance] = lootObject; + } + } + + vector result; + for (map::iterator i = sortedMap.begin(); i != sortedMap.end(); i++) + { + result.push_back(i->second); + } + return result; +} + diff --git a/src/modules/Bots/playerbot/LootObjectStack.h b/src/modules/Bots/playerbot/LootObjectStack.h new file mode 100644 index 0000000000..a35bdd224a --- /dev/null +++ b/src/modules/Bots/playerbot/LootObjectStack.h @@ -0,0 +1,76 @@ +#pragma once + +using namespace std; + +namespace ai +{ + enum LootStrategy + { + LOOTSTRATEGY_QUEST = 1, + LOOTSTRATEGY_SKILL = 2, + LOOTSTRATEGY_GRAY = 3, + LOOTSTRATEGY_NORMAL = 4, + LOOTSTRATEGY_ALL = 5 + }; + + class LootObject + { + public: + LootObject() {} + LootObject(Player* bot, ObjectGuid guid); + LootObject(const LootObject& other); + + public: + bool IsEmpty() { return !guid; } + bool IsLootPossible(Player* bot); + void Refresh(Player* bot, ObjectGuid guid); + WorldObject* GetWorldObject(Player* bot); + ObjectGuid guid; + + uint32 skillId; + uint32 reqSkillValue; + uint32 reqItem; + }; + + class LootTarget + { + public: + LootTarget(ObjectGuid guid); + LootTarget(LootTarget const& other); + + public: + LootTarget& operator=(LootTarget const& other); + bool operator< (const LootTarget& other) const; + + public: + ObjectGuid guid; + time_t asOfTime; + }; + + class LootTargetList : public set + { + public: + void shrink(time_t fromTime); + }; + + class LootObjectStack + { + public: + LootObjectStack(Player* bot) : bot(bot) {} + + public: + bool Add(ObjectGuid guid); + void Remove(ObjectGuid guid); + void Clear(); + bool CanLoot(float maxDistance); + LootObject GetLoot(float maxDistance = 0); + + private: + vector OrderByDistance(float maxDistance = 0); + + private: + Player* bot; + LootTargetList availableLoot; + }; + +}; diff --git a/src/modules/Bots/playerbot/PlayerbotAI.cpp b/src/modules/Bots/playerbot/PlayerbotAI.cpp new file mode 100644 index 0000000000..47e23f2399 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotAI.cpp @@ -0,0 +1,1299 @@ +#include "../botpch.h" +#include "PlayerbotMgr.h" +#include "playerbot.h" + +#include "AiFactory.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "strategy/values/LastMovementValue.h" +#include "strategy/actions/LogLevelAction.h" +#include "strategy/values/LastSpellCastValue.h" +#include "LootObjectStack.h" +#include "PlayerbotAIConfig.h" +#include "PlayerbotAI.h" +#include "PlayerbotFactory.h" +#include "PlayerbotSecurity.h" +#include "Util.h" + +using namespace ai; +using namespace std; + +vector& split(const string &s, char delim, vector &elems); +vector split(const string &s, char delim); +char * strstri (string str1, string str2); +uint64 extractGuid(WorldPacket& packet); + +uint32 PlayerbotChatHandler::extractQuestId(string str) +{ + char* source = (char*)str.c_str(); + char* cId = ExtractKeyFromLink(&source,"Hquest"); + return cId ? atol(cId) : 0; +} + +void PacketHandlingHelper::AddHandler(uint16 opcode, string handler) +{ + handlers[opcode] = handler; +} + +void PacketHandlingHelper::Handle(ExternalEventHelper &helper) +{ + while (!queue.empty()) + { + helper.HandlePacket(handlers, queue.top()); + queue.pop(); + } +} + +void PacketHandlingHelper::AddPacket(const WorldPacket& packet) +{ + if (handlers.find(packet.GetOpcode()) != handlers.end()) + { + queue.push(WorldPacket(packet)); + } +} + + +PlayerbotAI::PlayerbotAI() : PlayerbotAIBase(), bot(NULL), aiObjectContext(NULL), + currentEngine(NULL), chatHelper(this), chatFilter(this), accountId(0), security(NULL), master(NULL) +{ + for (int i = 0 ; i < BOT_STATE_MAX; i++) + { + engines[i] = NULL; + } +} + +PlayerbotAI::PlayerbotAI(Player* bot) : + PlayerbotAIBase(), chatHelper(this), chatFilter(this), security(bot), master(NULL) +{ + this->bot = bot; + + accountId = sObjectMgr.GetPlayerAccountIdByGUID(bot->GetObjectGuid()); + + aiObjectContext = AiFactory::createAiObjectContext(bot, this); + + engines[BOT_STATE_COMBAT] = AiFactory::createCombatEngine(bot, this, aiObjectContext); + engines[BOT_STATE_NON_COMBAT] = AiFactory::createNonCombatEngine(bot, this, aiObjectContext); + engines[BOT_STATE_DEAD] = AiFactory::createDeadEngine(bot, this, aiObjectContext); + currentEngine = engines[BOT_STATE_NON_COMBAT]; + currentState = BOT_STATE_NON_COMBAT; + + //masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_REPORT_USE, "use game object"); + masterIncomingPacketHandlers.AddHandler(CMSG_AREATRIGGER, "area trigger"); + masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object"); + 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_MOVE_SPLINE_DONE, "taxi done"); + masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE_GUID, "uninvite"); + masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share"); + masterIncomingPacketHandlers.AddHandler(CMSG_GUILD_INVITE, "guild invite"); + + botOutgoingPacketHandlers.AddHandler(SMSG_GROUP_INVITE, "group invite"); + botOutgoingPacketHandlers.AddHandler(BUY_ERR_NOT_ENOUGHT_MONEY, "not enough money"); + botOutgoingPacketHandlers.AddHandler(BUY_ERR_REPUTATION_REQUIRE, "not enough reputation"); + botOutgoingPacketHandlers.AddHandler(SMSG_GROUP_SET_LEADER, "group set leader"); + botOutgoingPacketHandlers.AddHandler(SMSG_FORCE_RUN_SPEED_CHANGE, "check mount state"); + botOutgoingPacketHandlers.AddHandler(SMSG_RESURRECT_REQUEST, "resurrect request"); + 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_CAST_FAILED, "cast failed"); + botOutgoingPacketHandlers.AddHandler(SMSG_DUEL_REQUESTED, "duel requested"); + //botOutgoingPacketHandlers.AddHandler(SMSG_LFG_ROLE_CHECK_UPDATE, "lfg role check"); + //botOutgoingPacketHandlers.AddHandler(SMSG_LFG_PROPOSAL_UPDATE, "lfg proposal"); + + 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"); +} + +PlayerbotAI::~PlayerbotAI() +{ + for (int i = 0 ; i < BOT_STATE_MAX; i++) + { + if (engines[i]) + { + delete engines[i]; + } + } + + if (aiObjectContext) + { + delete aiObjectContext; + } +} + +void PlayerbotAI::UpdateAI(uint32 elapsed) +{ + if (bot->IsBeingTeleported()) + { + return; + } + + if (nextAICheckDelay > sPlayerbotAIConfig.globalCoolDown && + bot->IsNonMeleeSpellCasted(true, true, false) && + *GetAiObjectContext()->GetValue("invalid target", "current target")) + { + Spell* spell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (spell && !IsPositiveSpell(spell->m_spellInfo)) + { + InterruptSpell(); + SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); + } + } + + if (nextAICheckDelay > sPlayerbotAIConfig.maxWaitForMove && bot->IsInCombat() && !bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + { + nextAICheckDelay = sPlayerbotAIConfig.maxWaitForMove; + } + + PlayerbotAIBase::UpdateAI(elapsed); +} + +void PlayerbotAI::UpdateAIInternal(uint32 elapsed) +{ + ExternalEventHelper helper(aiObjectContext); + while (!chatCommands.empty()) + { + ChatCommandHolder holder = chatCommands.top(); + string command = holder.GetCommand(); + Player* owner = holder.GetOwner(); + if (!helper.ParseChatCommand(command, owner) && holder.GetType() == CHAT_MSG_WHISPER) + { + ostringstream out; out << "Unknown command " << command; + TellMaster(out); + helper.ParseChatCommand("help"); + } + chatCommands.pop(); + } + + botOutgoingPacketHandlers.Handle(helper); + masterIncomingPacketHandlers.Handle(helper); + masterOutgoingPacketHandlers.Handle(helper); + + DoNextAction(); +} + +void PlayerbotAI::HandleTeleportAck() +{ + bot->GetMotionMaster()->Clear(true); + if (bot->IsBeingTeleportedNear()) + { + WorldPacket p = WorldPacket(MSG_MOVE_TELEPORT_ACK, 8 + 4 + 4); + p << bot->GetObjectGuid(); + p << (uint32)0; // supposed to be flags? not used currently + p << (uint32)time(0); // time - not currently used + bot->GetSession()->HandleMoveTeleportAckOpcode(p); + } + else if (bot->IsBeingTeleportedFar()) + { + bot->GetSession()->HandleMoveWorldportAckOpcode(); + } +} + +void PlayerbotAI::Reset() +{ + if (bot->IsTaxiFlying()) + { + return; + } + + currentEngine = engines[BOT_STATE_NON_COMBAT]; + nextAICheckDelay = 0; + + aiObjectContext->GetValue("old target")->Set(NULL); + aiObjectContext->GetValue("current target")->Set(NULL); + aiObjectContext->GetValue("loot target")->Set(LootObject()); + aiObjectContext->GetValue("lfg proposal")->Set(0); + + LastSpellCast & lastSpell = aiObjectContext->GetValue("last spell cast")->Get(); + lastSpell.Reset(); + + LastMovement & lastMovement = aiObjectContext->GetValue("last movement")->Get(); + lastMovement.Set(NULL); + + bot->GetMotionMaster()->Clear(); + bot->m_taxi.ClearTaxiDestinations(); + InterruptSpell(); + + for (int i = 0 ; i < BOT_STATE_MAX; i++) + { + engines[i]->Init(); + } +} + +void PlayerbotAI::HandleCommand(uint32 type, const string& text, Player& fromPlayer) +{ + if (!GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, type != CHAT_MSG_WHISPER, &fromPlayer)) + { + return; + } + + if (type == CHAT_MSG_ADDON) + { + return; + } + + string filtered = text; + if (!sPlayerbotAIConfig.commandPrefix.empty()) + { + if (filtered.find(sPlayerbotAIConfig.commandPrefix) != 0) + { + return; + } + + filtered = filtered.substr(sPlayerbotAIConfig.commandPrefix.size()); + } + + filtered = chatFilter.Filter(trim((string&)filtered)); + if (filtered.empty()) + { + return; + } + + if (filtered.find("who") != 0 && !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, &fromPlayer)) + { + return; + } + + if (type == CHAT_MSG_RAID_WARNING && filtered.find(bot->GetName()) != string::npos && filtered.find("award") == string::npos) + { + ChatCommandHolder cmd("warning", &fromPlayer, type); + chatCommands.push(cmd); + return; + } + + if (filtered.size() > 2 && filtered.substr(0, 2) == "d " || filtered.size() > 3 && filtered.substr(0, 3) == "do ") + { + std::string action = filtered.substr(filtered.find(" ") + 1); + DoSpecificAction(action); + } + else if (filtered == "reset") + { + Reset(); + } + else + { + ChatCommandHolder cmd(filtered, &fromPlayer, type); + chatCommands.push(cmd); + } +} + +void PlayerbotAI::HandleBotOutgoingPacket(const WorldPacket& packet) +{ + switch (packet.GetOpcode()) + { + case SMSG_CAST_FAILED: + { + WorldPacket p(packet); + p.rpos(0); + uint8 status, result; + p >> status >> result; + if (result != SPELL_CAST_OK) + { + LastSpellCast& lastSpell = aiObjectContext->GetValue("last spell cast")->Get(); + SpellInterrupted(lastSpell.id); + botOutgoingPacketHandlers.AddPacket(packet); + } + return; + } + case SMSG_SPELL_FAILURE: + { + WorldPacket p(packet); + p.rpos(0); + ObjectGuid casterGuid; + p >> casterGuid.ReadAsPacked(); + if (casterGuid != bot->GetObjectGuid()) + { + return; + } + + uint32 spellId; + p >> spellId; + SpellInterrupted(spellId); + return; + } + case SMSG_SPELL_DELAYED: + { + WorldPacket p(packet); + p.rpos(0); + ObjectGuid casterGuid; + p >> casterGuid.ReadAsPacked(); + + if (casterGuid != bot->GetObjectGuid()) + { + return; + } + + uint32 delaytime; + p >> delaytime; + if (delaytime <= 1000) + { + IncreaseNextCheckDelay(delaytime); + } + return; + } + default: + botOutgoingPacketHandlers.AddPacket(packet); + } +} + +void PlayerbotAI::SpellInterrupted(uint32 spellid) +{ + LastSpellCast& lastSpell = aiObjectContext->GetValue("last spell cast")->Get(); + if (lastSpell.id != spellid) + { + return; + } + + lastSpell.Reset(); + + time_t now = time(0); + if (now <= lastSpell.time) + { + return; + } + + uint32 castTimeSpent = 1000 * (now - lastSpell.time); + + uint32 globalCooldown = CalculateGlobalCooldown(lastSpell.id); + if (castTimeSpent < globalCooldown) + { + SetNextCheckDelay(globalCooldown - castTimeSpent); + } + else + { + SetNextCheckDelay(0); + } + + lastSpell.id = 0; +} + +uint32 PlayerbotAI::CalculateGlobalCooldown(uint32 spellid) +{ + if (!spellid) + { + return 0; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid ); + + if (bot->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + { + return sPlayerbotAIConfig.globalCoolDown; + } + + return sPlayerbotAIConfig.reactDelay; +} + +void PlayerbotAI::HandleMasterIncomingPacket(const WorldPacket& packet) +{ + masterIncomingPacketHandlers.AddPacket(packet); +} + +void PlayerbotAI::HandleMasterOutgoingPacket(const WorldPacket& packet) +{ + masterOutgoingPacketHandlers.AddPacket(packet); +} + +void PlayerbotAI::ChangeEngine(BotState type) +{ + Engine* engine = engines[type]; + + if (currentEngine != engine) + { + currentEngine = engine; + currentState = type; + ReInitCurrentEngine(); + + switch (type) + { + case BOT_STATE_COMBAT: + sLog.outDebug("=== %s COMBAT ===", bot->GetName()); + break; + case BOT_STATE_NON_COMBAT: + sLog.outDebug("=== %s NON-COMBAT ===", bot->GetName()); + break; + case BOT_STATE_DEAD: + sLog.outDebug("=== %s DEAD ===", bot->GetName()); + break; + } + } +} + +void PlayerbotAI::DoNextAction() +{ + if (bot->IsBeingTeleported() /*|| bot->IsBeingTeleportedDelayEvent()*/|| (GetMaster() && GetMaster()->IsBeingTeleported())) + { + return; + } + + currentEngine->DoNextAction(NULL); + + /*if (!bot->GetAurasByType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED).empty()) + { + bot->m_movementInfo.SetMovementFlags((MovementFlags)(MOVEFLAG_FLYING|MOVEFLAG_CAN_FLY)); + + WorldPacket packet(CMSG_MOVE_SET_FLY); + packet << bot->GetObjectGuid().WriteAsPacked(); + packet << bot->m_movementInfo; + bot->SetMover(bot); + bot->GetSession()->HandleMovementOpcodes(packet); + }*/ + + Player* master = GetMaster(); + if (bot->IsMounted() && bot->IsFlying()) + { + bot->m_movementInfo.SetMovementFlags((MovementFlags)(MOVEFLAG_FLYING|MOVEFLAG_CAN_FLY)); + + //bot->SetSpeedRate(MOVE_FLIGHT, 1.0f, true); + bot->SetSpeedRate(MOVE_RUN, 1.0f, true); + + if (master) + { + //bot->SetSpeedRate(MOVE_FLIGHT, master->GetSpeedRate(MOVE_FLIGHT), true); + //bot->SetSpeedRate(MOVE_RUN, master->GetSpeedRate(MOVE_FLIGHT), true); + } + + } + + if (currentEngine != engines[BOT_STATE_DEAD] && !bot->IsAlive()) + { + ChangeEngine(BOT_STATE_DEAD); + } + + if (currentEngine == engines[BOT_STATE_DEAD] && bot->IsAlive()) + { + ChangeEngine(BOT_STATE_NON_COMBAT); + } + + Group *group = bot->GetGroup(); + if (!master && group) + { + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->getSource(); + PlayerbotAI* ai = bot->GetPlayerbotAI(); + if (member && member->IsInWorld() && !member->GetPlayerbotAI() && (!master || master->GetPlayerbotAI())) + { + ai->SetMaster(member); + ai->ResetStrategies(); + ai->TellMaster("Hello"); + break; + } + } + } +} + +void PlayerbotAI::ReInitCurrentEngine() +{ + InterruptSpell(); + currentEngine->Init(); +} + +void PlayerbotAI::ChangeStrategy(string names, BotState type) +{ + Engine* e = engines[type]; + if (!e) + { + return; + } + + e->ChangeStrategy(names); +} + +void PlayerbotAI::DoSpecificAction(string name) +{ + for (int i = 0 ; i < BOT_STATE_MAX; i++) + { + ostringstream out; + ActionResult res = engines[i]->ExecuteAction(name); + switch (res) + { + case ACTION_RESULT_UNKNOWN: + continue; + case ACTION_RESULT_OK: + out << name << ": done"; + TellMaster(out); + return; + case ACTION_RESULT_IMPOSSIBLE: + out << name << ": impossible"; + TellMaster(out); + return; + case ACTION_RESULT_USELESS: + out << name << ": useless"; + TellMaster(out); + return; + case ACTION_RESULT_FAILED: + out << name << ": failed"; + TellMaster(out); + return; + } + } + ostringstream out; + out << name << ": unknown action"; + TellMaster(out); +} + +bool PlayerbotAI::ContainsStrategy(StrategyType type) +{ + for (int i = 0 ; i < BOT_STATE_MAX; i++) + { + if (engines[i]->ContainsStrategy(type)) + { + return true; + } + } + return false; +} + +bool PlayerbotAI::HasStrategy(string name, BotState type) +{ + return engines[type]->HasStrategy(name); +} + +void PlayerbotAI::ResetStrategies() +{ + for (int i = 0 ; i < BOT_STATE_MAX; i++) + { + engines[i]->removeAllStrategies(); + } + + AiFactory::AddDefaultCombatStrategies(bot, this, engines[BOT_STATE_COMBAT]); + AiFactory::AddDefaultNonCombatStrategies(bot, this, engines[BOT_STATE_NON_COMBAT]); + AiFactory::AddDefaultDeadStrategies(bot, this, engines[BOT_STATE_DEAD]); +} + +bool PlayerbotAI::IsRanged(Player* player) +{ + PlayerbotAI* botAi = player->GetPlayerbotAI(); + if (botAi) + { + return botAi->ContainsStrategy(STRATEGY_TYPE_RANGED); + } + + switch (player->getClass()) + { + //case CLASS_DEATH_KNIGHT: + case CLASS_PALADIN: + case CLASS_WARRIOR: + case CLASS_ROGUE: + return false; + case CLASS_DRUID: + return !HasAnyAuraOf(player, "cat form", "bear form", "dire bear form", NULL); + } + return true; +} + +bool PlayerbotAI::IsTank(Player* player) +{ + PlayerbotAI* botAi = player->GetPlayerbotAI(); + if (botAi) + { + return botAi->ContainsStrategy(STRATEGY_TYPE_TANK); + } + + switch (player->getClass()) + { + //case CLASS_DEATH_KNIGHT: + case CLASS_PALADIN: + case CLASS_WARRIOR: + return true; + case CLASS_DRUID: + return HasAnyAuraOf(player, "bear form", "dire bear form", NULL); + } + return false; +} + +bool PlayerbotAI::IsHeal(Player* player) +{ + PlayerbotAI* botAi = player->GetPlayerbotAI(); + if (botAi) + { + return botAi->ContainsStrategy(STRATEGY_TYPE_HEAL); + } + + switch (player->getClass()) + { + case CLASS_PRIEST: + return true; + case CLASS_DRUID: + return HasAnyAuraOf(player, "tree of life form", NULL); + } + return false; +} + + + +namespace MaNGOS +{ + + class UnitByGuidInRangeCheck + { + public: + UnitByGuidInRangeCheck(WorldObject const* obj, ObjectGuid guid, float range) : i_obj(obj), i_range(range), i_guid(guid) {} + WorldObject const& GetFocusObject() const { return *i_obj; } + bool operator()(Unit* u) + { + return u->GetObjectGuid() == i_guid && i_obj->IsWithinDistInMap(u, i_range); + } + private: + WorldObject const* i_obj; + float i_range; + ObjectGuid i_guid; + }; + + class GameObjectByGuidInRangeCheck + { + public: + GameObjectByGuidInRangeCheck(WorldObject const* obj, ObjectGuid guid, float range) : i_obj(obj), i_range(range), i_guid(guid) {} + WorldObject const& GetFocusObject() const { return *i_obj; } + bool operator()(GameObject* u) + { + if (u && i_obj->IsWithinDistInMap(u, i_range) && u->isSpawned() && u->GetGOInfo() && u->GetObjectGuid() == i_guid) + { + return true; + } + + return false; + } + private: + WorldObject const* i_obj; + float i_range; + ObjectGuid i_guid; + }; + +}; + + +Unit* PlayerbotAI::GetUnit(ObjectGuid guid) +{ + if (!guid) + { + return NULL; + } + + list targets; + + MaNGOS::UnitByGuidInRangeCheck u_check(bot, guid, sPlayerbotAIConfig.sightDistance); + MaNGOS::UnitListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(bot, searcher, sPlayerbotAIConfig.sightDistance); + + if (targets.empty()) + { + return NULL; + } + + return *targets.begin(); +} + + +Creature* PlayerbotAI::GetCreature(ObjectGuid guid) +{ + if (!guid) + { + return NULL; + } + + list targets; + + MaNGOS::UnitByGuidInRangeCheck u_check(bot, guid, sPlayerbotAIConfig.sightDistance); + MaNGOS::UnitListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(bot, searcher, sPlayerbotAIConfig.sightDistance); + + for(list::iterator i = targets.begin(); i != targets.end(); i++) + { + Creature* creature = dynamic_cast(*i); + if (creature) + { + return creature; + } + } + + return NULL; +} + +GameObject* PlayerbotAI::GetGameObject(ObjectGuid guid) +{ + if (!guid) + { + return NULL; + } + + list targets; + + MaNGOS::GameObjectByGuidInRangeCheck u_check(bot, guid, sPlayerbotAIConfig.sightDistance); + MaNGOS::GameObjectListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(bot, searcher, sPlayerbotAIConfig.sightDistance); + + for(list::iterator i = targets.begin(); i != targets.end(); i++) + { + GameObject* go = *i; + if (go && go->isSpawned()) + { + return go; + } + } + + return NULL; +} + +bool PlayerbotAI::TellMasterNoFacing(string text, PlayerbotSecurityLevel securityLevel) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + if (!GetSecurity()->CheckLevelFor(securityLevel, true, master)) + { + return false; + } + + if (sPlayerbotAIConfig.whisperDistance && !bot->GetGroup() && sRandomPlayerbotMgr.IsRandomBot(bot) && + master->GetSession()->GetSecurity() < SEC_GAMEMASTER && + (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig.whisperDistance)) + return false; + + bot->Whisper(text, LANG_UNIVERSAL, master->GetObjectGuid()); + return true; +} + +bool PlayerbotAI::TellMaster(string text, PlayerbotSecurityLevel securityLevel) +{ + if (!TellMasterNoFacing(text, securityLevel)) + { + return false; + } + + if (!bot->isMoving() && !bot->IsInCombat() && bot->GetMapId() == master->GetMapId()) + { + if (!bot->IsInFront(master, sPlayerbotAIConfig.sightDistance, M_PI / 2)) + { + bot->SetFacingTo(bot->GetAngle(master)); + } + + bot->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + } + + return true; +} + +bool IsRealAura(Player* bot, Aura* aura, Unit* unit) +{ + if (!aura) + { + return false; + } + + if (!unit->IsHostileTo(bot)) + { + return true; + } + + uint32 stacks = aura->GetHolder()->GetStackAmount(); + if (stacks >= aura->GetHolder()->GetSpellProto()->StackAmount) + { + return true; + } + + if (aura->GetHolder()->GetCaster() == bot || aura->GetHolder()->IsPositive() || aura->GetHolder()->IsAreaAura()) + { + return true; + } + + return false; +} + +bool PlayerbotAI::HasAura(string name, Unit* unit) +{ + if (!unit) + { + return false; + } + + uint32 spellId = aiObjectContext->GetValue("spell id", name)->Get(); + if (spellId) + { + return HasAura(spellId, unit); + } + + wstring wnamepart; + if (!Utf8toWStr(name, wnamepart)) + { + return 0; + } + + wstrToLower(wnamepart); + + for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++) + { + Unit::AuraList const& auras = unit->GetAurasByType((AuraType)auraType); + for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); i++) + { + Aura* aura = *i; + if (!aura) + { + continue; + } + + const string auraName = aura->GetSpellProto()->SpellName[0]; + if (auraName.empty() || auraName.length() != wnamepart.length() || !Utf8FitTo(auraName, wnamepart)) + { + continue; + } + + if (IsRealAura(bot, aura, unit)) + { + return true; + } + } + } + + return false; +} + +bool PlayerbotAI::HasAura(uint32 spellId, const Unit* unit) +{ + if (!spellId || !unit) + { + return false; + } + + for (uint32 effect = EFFECT_INDEX_0; effect <= EFFECT_INDEX_2; effect++) + { + Aura* aura = ((Unit*)unit)->GetAura(spellId, (SpellEffectIndex)effect); + + if (IsRealAura(bot, aura, (Unit*)unit)) + { + return true; + } + } + + return false; +} + +bool PlayerbotAI::HasAnyAuraOf(Unit* player, ...) +{ + if (!player) + { + return false; + } + + va_list vl; + va_start(vl, player); + + const char* cur; + do { + cur = va_arg(vl, const char*); + if (cur && HasAura(cur, player)) { + { + va_end(vl); + } + return true; + } + } + while (cur); + + va_end(vl); + return false; +} + +bool PlayerbotAI::CanCastSpell(string name, Unit* target) +{ + return CanCastSpell(aiObjectContext->GetValue("spell id", name)->Get(), target); +} + +bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell) +{ + if (!spellid) + { + return false; + } + + if (!target) + { + target = bot; + } + + if (checkHasSpell && !bot->HasSpell(spellid)) + { + return false; + } + + if (bot->HasSpellCooldown(spellid)) + { + return false; + } + + bool positiveSpell = IsPositiveSpell(spellid); + if (positiveSpell && bot->IsHostileTo(target)) + { + return false; + } + + if (!positiveSpell && bot->IsFriendlyTo(target)) + { + return false; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid ); + if (!spellInfo) + { + return false; + } + + if (target->IsImmuneToSpell(spellInfo, false)) + { + return false; + } + + if (bot != target && bot->GetDistance(target) > sPlayerbotAIConfig.sightDistance) + { + return false; + } + + ObjectGuid oldSel = bot->GetSelectionGuid(); + bot->SetSelectionGuid(target->GetObjectGuid()); + Spell *spell = new Spell(bot, spellInfo, false ); + + spell->m_targets.setUnitTarget(target); + spell->m_CastItem = aiObjectContext->GetValue("item for spell", spellid)->Get(); + spell->m_targets.setItemTarget(spell->m_CastItem); + SpellCastResult result = spell->CheckCast(false); + delete spell; + bot->SetSelectionGuid(oldSel); + + switch (result) + { + case SPELL_FAILED_NOT_INFRONT: + case SPELL_FAILED_NOT_STANDING: + case SPELL_FAILED_UNIT_NOT_INFRONT: + case SPELL_FAILED_MOVING: + case SPELL_FAILED_TRY_AGAIN: + case SPELL_FAILED_BAD_IMPLICIT_TARGETS: + case SPELL_FAILED_BAD_TARGETS: + case SPELL_CAST_OK: + return true; + default: + return false; + } +} + + +bool PlayerbotAI::CastSpell(string name, Unit* target) +{ + bool result = CastSpell(aiObjectContext->GetValue("spell id", name)->Get(), target); + if (result) + { + aiObjectContext->GetValue("last spell cast time", name)->Set(time(0)); + } + + return result; +} + +bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target) +{ + if (!spellId) + { + return false; + } + + if (!target) + { + target = bot; + } + + Pet* pet = bot->GetPet(); + if (pet && pet->HasSpell(spellId)) + { + pet->ToggleAutocast(spellId, true); + TellMaster("My pet will auto-cast this spell"); + return true; + } + + aiObjectContext->GetValue("last spell cast")->Get().Set(spellId, target->GetObjectGuid(), time(0)); + aiObjectContext->GetValue("last movement")->Get().Set(NULL); + + const SpellEntry* const pSpellInfo = sSpellStore.LookupEntry(spellId); + + MotionMaster &mm = *bot->GetMotionMaster(); + if (bot->isMoving() && GetSpellCastTime(pSpellInfo, NULL)) + { + return false; + } + + if (bot->IsTaxiFlying()) + { + return false; + } + + bot->clearUnitState( UNIT_STAT_CHASE ); + bot->clearUnitState( UNIT_STAT_FOLLOW ); + + ObjectGuid oldSel = bot->GetSelectionGuid(); + bot->SetSelectionGuid(target->GetObjectGuid()); + + Spell *spell = new Spell(bot, pSpellInfo, false); + + SpellCastTargets targets; + targets.setUnitTarget(target); + WorldObject* faceTo = target; + + if (pSpellInfo->Targets & TARGET_FLAG_ITEM) + { + spell->m_CastItem = aiObjectContext->GetValue("item for spell", spellId)->Get(); + targets.setItemTarget(spell->m_CastItem); + } + + if (pSpellInfo->Effect[0] == SPELL_EFFECT_OPEN_LOCK || + pSpellInfo->Effect[0] == SPELL_EFFECT_SKINNING) + { + LootObject loot = *aiObjectContext->GetValue("loot target"); + if (!loot.IsLootPossible(bot)) + { + return false; + } + + GameObject* go = GetGameObject(loot.guid); + if (go && go->isSpawned()) + { + WorldPacket* const packetgouse = new WorldPacket(CMSG_GAMEOBJ_USE, 8); + *packetgouse << loot.guid; + bot->GetSession()->QueuePacket(packetgouse); + targets.setGOTarget(go); + faceTo = go; + } + else + { + Unit* creature = GetUnit(loot.guid); + if (creature) + { + targets.setUnitTarget(creature); + faceTo = creature; + } + } + } + + + if (!bot->IsInFront(faceTo, sPlayerbotAIConfig.sightDistance)) + { + bot->SetFacingTo(bot->GetAngle(faceTo)); + SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); + return false; + } + + WaitForSpellCast(spellId); + + spell->prepare(&targets); + bot->SetSelectionGuid(oldSel); + + LastSpellCast& lastSpell = aiObjectContext->GetValue("last spell cast")->Get(); + return lastSpell.id == spellId; +} + +void PlayerbotAI::WaitForSpellCast(uint32 spellId) +{ + const SpellEntry* const pSpellInfo = sSpellStore.LookupEntry(spellId); + + float castTime = GetSpellCastTime(pSpellInfo) + sPlayerbotAIConfig.reactDelay; + if (IsChanneledSpell(pSpellInfo)) + { + int32 duration = GetSpellDuration(pSpellInfo); + if (duration > 0) + { + castTime += duration; + } + } + + castTime = ceil(castTime); + + uint32 globalCooldown = CalculateGlobalCooldown(spellId); + if (castTime < globalCooldown) + { + castTime = globalCooldown; + } + + SetNextCheckDelay(castTime); +} + +void PlayerbotAI::InterruptSpell() +{ + if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + { + return; + } + + LastSpellCast& lastSpell = aiObjectContext->GetValue("last spell cast")->Get(); + + for (int type = CURRENT_MELEE_SPELL; type < CURRENT_CHANNELED_SPELL; type++) + { + Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type); + if (!spell) + { + continue; + } + + bot->InterruptSpell((CurrentSpellTypes)type); + + WorldPacket data(SMSG_SPELL_FAILURE, 8 + 1 + 4 + 1); + data << bot->GetPackGUID(); + data << uint8(1); + data << uint32(spell->m_spellInfo->Id); + data << uint8(0); + bot->SendMessageToSet(&data, true); + + data.Initialize(SMSG_SPELL_FAILED_OTHER, 8 + 1 + 4 + 1); + data << bot->GetObjectGuid(); + data << uint8(1); + data << uint32(spell->m_spellInfo->Id); + data << uint8(0); + bot->SendMessageToSet(&data, true); + + SpellInterrupted(spell->m_spellInfo->Id); + } + + SpellInterrupted(lastSpell.id); +} + + +void PlayerbotAI::RemoveAura(string name) +{ + uint32 spellid = aiObjectContext->GetValue("spell id", name)->Get(); + if (spellid && HasAura(spellid, bot)) + { + bot->RemoveAurasDueToSpell(spellid); + } +} + +bool PlayerbotAI::IsInterruptableSpellCasting(Unit* target, string spell) +{ + uint32 spellid = aiObjectContext->GetValue("spell id", spell)->Get(); + if (!spellid || !target->IsNonMeleeSpellCasted(true)) + { + return false; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid ); + if (!spellInfo) + { + return false; + } + + if (target->IsImmuneToSpell(spellInfo, false)) + { + return false; + } + + for (int32 i = EFFECT_INDEX_0; i <= EFFECT_INDEX_2; i++) + { + if ((spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT) && spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + { + return true; + } + + if ((spellInfo->Effect[i] == SPELL_EFFECT_INTERRUPT_CAST) && + !target->IsImmuneToSpellEffect(spellInfo, (SpellEffectIndex)i, true)) + return true; + } + + return false; +} + +bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType) +{ + for (uint32 type = SPELL_AURA_NONE; type < TOTAL_AURAS; ++type) + { + Unit::AuraList const& auras = target->GetAurasByType((AuraType)type); + for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) + { + const Aura* aura = *itr; + const SpellEntry* entry = aura->GetSpellProto(); + uint32 spellId = entry->Id; + + bool isPositiveSpell = IsPositiveSpell(spellId); + if (isPositiveSpell && bot->IsFriendlyTo(target)) + { + continue; + } + + if (!isPositiveSpell && bot->IsHostileTo(target)) + { + continue; + } + + if (canDispel(entry, dispelType)) + { + return true; + } + } + } + return false; +} + + +#ifndef WIN32 +inline int strcmpi(const char* s1, const char* s2) +{ + for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2); + { + return *s1 - *s2; + } +} +#endif + +bool PlayerbotAI::canDispel(const SpellEntry* entry, uint32 dispelType) +{ + if (entry->Dispel != dispelType) + { + return false; + } + + return !entry->SpellName[0] || + (strcmpi((const char*)entry->SpellName[0], "demon skin") && + strcmpi((const char*)entry->SpellName[0], "mage armor") && + strcmpi((const char*)entry->SpellName[0], "frost armor") && + strcmpi((const char*)entry->SpellName[0], "wavering will") && + strcmpi((const char*)entry->SpellName[0], "chilled") && + strcmpi((const char*)entry->SpellName[0], "ice armor")); +} + +bool IsAlliance(uint8 race) +{ + return race == RACE_HUMAN || race == RACE_DWARF || race == RACE_NIGHTELF || + race == RACE_GNOME; +} + +bool PlayerbotAI::IsOpposing(Player* player) +{ + return IsOpposing(player->getRace(), bot->getRace()); +} + +bool PlayerbotAI::IsOpposing(uint8 race1, uint8 race2) +{ + return (IsAlliance(race1) && !IsAlliance(race2)) || (!IsAlliance(race1) && IsAlliance(race2)); +} + +void PlayerbotAI::RemoveShapeshift() +{ + RemoveAura("bear form"); + RemoveAura("dire bear form"); + RemoveAura("moonkin form"); + RemoveAura("travel form"); + RemoveAura("cat form"); + RemoveAura("flight form"); + RemoveAura("swift flight form"); + RemoveAura("aquatic form"); + RemoveAura("ghost wolf"); + RemoveAura("tree of life"); +} diff --git a/src/modules/Bots/playerbot/PlayerbotAI.h b/src/modules/Bots/playerbot/PlayerbotAI.h new file mode 100644 index 0000000000..b36d188dca --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotAI.h @@ -0,0 +1,183 @@ +#pragma once + +#include "PlayerbotMgr.h" +#include "PlayerbotAIBase.h" +#include "strategy/AiObjectContext.h" +#include "strategy/Engine.h" +#include "strategy/ExternalEventHelper.h" +#include "ChatFilter.h" +#include "PlayerbotSecurity.h" + +class Player; +class PlayerbotMgr; +class ChatHandler; + +using namespace std; +using namespace ai; + +bool IsAlliance(uint8 race); + +class PlayerbotChatHandler: protected ChatHandler +{ +public: + explicit PlayerbotChatHandler(Player* pMasterPlayer) : ChatHandler(pMasterPlayer) {} + bool revive(const Player& botPlayer) { return HandleReviveCommand((char*)botPlayer.GetName()); } + bool teleport(const Player& botPlayer) { return HandleSummonCommand((char*)botPlayer.GetName()); } + void sysmessage(string str) { SendSysMessage(str.c_str()); } + bool dropQuest(string str) { return HandleQuestRemoveCommand((char*)str.c_str()); } + uint32 extractQuestId(string str); + uint32 extractSpellId(string str) + { + char* source = (char*)str.c_str(); + return ExtractSpellIdFromLink(&source); + } +}; + +namespace ai +{ + class MinValueCalculator { + public: + MinValueCalculator(float def = 0.0f) { + param = NULL; + minValue = def; + } + + public: + void probe(float value, void* p) { + if (!param || minValue >= value) { + { + minValue = value; + } + param = p; + } + } + + public: + void* param; + float minValue; + }; +}; + +enum BotState +{ + BOT_STATE_COMBAT = 0, + BOT_STATE_NON_COMBAT = 1, + BOT_STATE_DEAD = 2 +}; + +#define BOT_STATE_MAX 3 + +class PacketHandlingHelper +{ +public: + void AddHandler(uint16 opcode, string handler); + void Handle(ExternalEventHelper &helper); + void AddPacket(const WorldPacket& packet); + +private: + map handlers; + stack queue; +}; + +class ChatCommandHolder +{ +public: + ChatCommandHolder(string command, Player* owner = NULL, uint32 type = CHAT_MSG_WHISPER) : command(command), owner(owner), type(type) {} + ChatCommandHolder(ChatCommandHolder const& other) + { + this->command = other.command; + this->owner = other.owner; + this->type = other.type; + } + +public: + string GetCommand() { return command; } + Player* GetOwner() { return owner; } + uint32 GetType() { return type; } + +private: + string command; + Player* owner; + uint32 type; +}; + +class PlayerbotAI : public PlayerbotAIBase +{ +public: + PlayerbotAI(); + PlayerbotAI(Player* bot); + virtual ~PlayerbotAI(); + +public: + virtual void UpdateAI(uint32 elapsed); + virtual void UpdateAIInternal(uint32 elapsed); + void HandleCommand(uint32 type, const string& text, Player& fromPlayer); + void HandleBotOutgoingPacket(const WorldPacket& packet); + void HandleMasterIncomingPacket(const WorldPacket& packet); + void HandleMasterOutgoingPacket(const WorldPacket& packet); + void HandleTeleportAck(); + void ChangeEngine(BotState type); + void DoNextAction(); + void DoSpecificAction(string name); + void ChangeStrategy(string name, BotState type); + bool ContainsStrategy(StrategyType type); + bool HasStrategy(string name, BotState type); + void ResetStrategies(); + void ReInitCurrentEngine(); + void Reset(); + bool IsTank(Player* player); + bool IsHeal(Player* player); + bool IsRanged(Player* player); + Creature* GetCreature(ObjectGuid guid); + Unit* GetUnit(ObjectGuid guid); + GameObject* GetGameObject(ObjectGuid guid); + bool TellMaster(ostringstream &stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL) { return TellMaster(stream.str(), securityLevel); } + bool TellMaster(string text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + bool TellMasterNoFacing(string text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + void SpellInterrupted(uint32 spellid); + uint32 CalculateGlobalCooldown(uint32 spellid); + void InterruptSpell(); + void RemoveAura(string name); + void RemoveShapeshift(); + void WaitForSpellCast(uint32 spellId); + + virtual bool CanCastSpell(string name, Unit* target); + virtual bool CastSpell(string name, Unit* target); + virtual bool HasAura(string spellName, Unit* player); + virtual bool HasAnyAuraOf(Unit* player, ...); + + virtual bool IsInterruptableSpellCasting(Unit* player, string spell); + virtual bool HasAuraToDispel(Unit* player, uint32 dispelType); + bool CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell = true); + + bool HasAura(uint32 spellId, const Unit* player); + bool CastSpell(uint32 spellId, Unit* target); + bool canDispel(const SpellEntry* entry, uint32 dispelType); + +public: + Player* GetBot() { return bot; } + Player* GetMaster() { return master; } + void SetMaster(Player* master) { this->master = master; } + AiObjectContext* GetAiObjectContext() { return aiObjectContext; } + ChatHelper* GetChatHelper() { return &chatHelper; } + bool IsOpposing(Player* player); + static bool IsOpposing(uint8 race1, uint8 race2); + PlayerbotSecurity* GetSecurity() { return &security; } + +protected: + Player* bot; + Player* master; + uint32 accountId; + AiObjectContext* aiObjectContext; + Engine* currentEngine; + Engine* engines[BOT_STATE_MAX]; + BotState currentState; + ChatHelper chatHelper; + stack chatCommands; + PacketHandlingHelper botOutgoingPacketHandlers; + PacketHandlingHelper masterIncomingPacketHandlers; + PacketHandlingHelper masterOutgoingPacketHandlers; + CompositeChatFilter chatFilter; + PlayerbotSecurity security; +}; + diff --git a/src/modules/Bots/playerbot/PlayerbotAIAware.h b/src/modules/Bots/playerbot/PlayerbotAIAware.h new file mode 100644 index 0000000000..1679edde17 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotAIAware.h @@ -0,0 +1,13 @@ +#pragma once + +namespace ai +{ + class PlayerbotAIAware + { + public: + PlayerbotAIAware(PlayerbotAI* const ai) : ai(ai) { } + + protected: + PlayerbotAI* ai; + }; +} diff --git a/src/modules/Bots/playerbot/PlayerbotAIBase.cpp b/src/modules/Bots/playerbot/PlayerbotAIBase.cpp new file mode 100644 index 0000000000..185220ffd1 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotAIBase.cpp @@ -0,0 +1,63 @@ +#include "../botpch.h" +#include "playerbot.h" +#include "PlayerbotAIConfig.h" + +using namespace ai; +using namespace std; + +PlayerbotAIBase::PlayerbotAIBase() : nextAICheckDelay(0) +{ +} + +void PlayerbotAIBase::UpdateAI(uint32 elapsed) +{ + if (nextAICheckDelay > elapsed) + { + nextAICheckDelay -= elapsed; + } + else + { + nextAICheckDelay = 0; + } + + if (!CanUpdateAI()) + { + return; + } + + UpdateAIInternal(elapsed); + YieldThread(); +} + +void PlayerbotAIBase::SetNextCheckDelay(const uint32 delay) +{ + nextAICheckDelay = delay; + + if (nextAICheckDelay > sPlayerbotAIConfig.globalCoolDown) + { + sLog.outDebug("set next check delay: %d", nextAICheckDelay); + } +} + +void PlayerbotAIBase::IncreaseNextCheckDelay(uint32 delay) +{ + nextAICheckDelay += delay; + + if (nextAICheckDelay > sPlayerbotAIConfig.globalCoolDown) + { + sLog.outDebug("increase next check delay: %d", nextAICheckDelay); + } +} + +bool PlayerbotAIBase::CanUpdateAI() +{ + return nextAICheckDelay < 100; +} + +void PlayerbotAIBase::YieldThread() +{ + if (nextAICheckDelay < sPlayerbotAIConfig.reactDelay) + { + nextAICheckDelay = sPlayerbotAIConfig.reactDelay; + } +} diff --git a/src/modules/Bots/playerbot/PlayerbotAIBase.h b/src/modules/Bots/playerbot/PlayerbotAIBase.h new file mode 100644 index 0000000000..eae6385a83 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotAIBase.h @@ -0,0 +1,24 @@ +#pragma once + +class Player; +class PlayerbotMgr; +class ChatHandler; + +using namespace std; + +class PlayerbotAIBase +{ +public: + PlayerbotAIBase(); + +public: + bool CanUpdateAI(); + void SetNextCheckDelay(const uint32 delay); + void IncreaseNextCheckDelay(uint32 delay); + void YieldThread(); + virtual void UpdateAI(uint32 elapsed); + virtual void UpdateAIInternal(uint32 elapsed) = 0; + +protected: + uint32 nextAICheckDelay; +}; diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp new file mode 100644 index 0000000000..a7744047a4 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp @@ -0,0 +1,363 @@ +#include "../botpch.h" +#include "PlayerbotAIConfig.h" +#include "playerbot.h" +#include "RandomPlayerbotFactory.h" +#include "AccountMgr.h" +#include "SystemConfig.h" + +using namespace std; + +INSTANTIATE_SINGLETON_1(PlayerbotAIConfig); + +PlayerbotAIConfig::PlayerbotAIConfig() +{ +} + +template +void LoadList(string value, T &list) +{ + vector ids = split(value, ','); + for (vector::iterator i = ids.begin(); i != ids.end(); i++) + { + uint32 id = atoi((*i).c_str()); + if (!id) + { + continue; + } + + list.push_back(id); + } +} + +bool PlayerbotAIConfig::Initialize() +{ + sLog.outString("Initializing AI Playerbot by ike3, based on the original Playerbot by blueboy"); + + if (!config.SetSource(SYSCONFDIR"aiplayerbot.conf")) + { + sLog.outString("AI Playerbot is Disabled. Unable to open configuration file aiplayerbot.conf"); + return false; + } + + enabled = config.GetBoolDefault("AiPlayerbot.Enabled", true); + if (!enabled) + { + sLog.outString("AI Playerbot is Disabled in aiplayerbot.conf"); + return false; + } + + globalCoolDown = (uint32) config.GetIntDefault("AiPlayerbot.GlobalCooldown", 500); + maxWaitForMove = config.GetIntDefault("AiPlayerbot.MaxWaitForMove", 3000); + reactDelay = (uint32) config.GetIntDefault("AiPlayerbot.ReactDelay", 100); + + sightDistance = config.GetFloatDefault("AiPlayerbot.SightDistance", 50.0f); + spellDistance = config.GetFloatDefault("AiPlayerbot.SpellDistance", 30.0f); + reactDistance = config.GetFloatDefault("AiPlayerbot.ReactDistance", 150.0f); + grindDistance = config.GetFloatDefault("AiPlayerbot.GrindDistance", 100.0f); + lootDistance = config.GetFloatDefault("AiPlayerbot.LootDistance", 20.0f); + fleeDistance = config.GetFloatDefault("AiPlayerbot.FleeDistance", 20.0f); + tooCloseDistance = config.GetFloatDefault("AiPlayerbot.TooCloseDistance", 7.0f); + meleeDistance = config.GetFloatDefault("AiPlayerbot.MeleeDistance", 1.5f); + followDistance = config.GetFloatDefault("AiPlayerbot.FollowDistance", 1.5f); + whisperDistance = config.GetFloatDefault("AiPlayerbot.WhisperDistance", 6000.0f); + contactDistance = config.GetFloatDefault("AiPlayerbot.ContactDistance", 0.5f); + + criticalHealth = config.GetIntDefault("AiPlayerbot.CriticalHealth", 20); + lowHealth = config.GetIntDefault("AiPlayerbot.LowHealth", 50); + mediumHealth = config.GetIntDefault("AiPlayerbot.MediumHealth", 70); + almostFullHealth = config.GetIntDefault("AiPlayerbot.AlmostFullHealth", 85); + lowMana = config.GetIntDefault("AiPlayerbot.LowMana", 15); + mediumMana = config.GetIntDefault("AiPlayerbot.MediumMana", 40); + + randomGearLoweringChance = config.GetFloatDefault("AiPlayerbot.RandomGearLoweringChance", 0.15f); + randomBotMaxLevelChance = config.GetFloatDefault("AiPlayerbot.RandomBotMaxLevelChance", 0.4f); + + iterationsPerTick = config.GetIntDefault("AiPlayerbot.IterationsPerTick", 4); + + allowGuildBots = config.GetBoolDefault("AiPlayerbot.AllowGuildBots", true); + + randomBotMapsAsString = config.GetStringDefault("AiPlayerbot.RandomBotMaps", "0,1,530,571"); + LoadList >(randomBotMapsAsString, randomBotMaps); + LoadList >(config.GetStringDefault("AiPlayerbot.RandomBotQuestItems", "6948,5175,5176,5177,5178"), randomBotQuestItems); + LoadList >(config.GetStringDefault("AiPlayerbot.RandomBotSpellIds", "54197"), randomBotSpellIds); + + randomBotAutologin = config.GetBoolDefault("AiPlayerbot.RandomBotAutologin", true); + minRandomBots = config.GetIntDefault("AiPlayerbot.MinRandomBots", 50); + maxRandomBots = config.GetIntDefault("AiPlayerbot.MaxRandomBots", 200); + randomBotUpdateInterval = config.GetIntDefault("AiPlayerbot.RandomBotUpdateInterval", 60); + randomBotCountChangeMinInterval = config.GetIntDefault("AiPlayerbot.RandomBotCountChangeMinInterval", 24 * 3600); + randomBotCountChangeMaxInterval = config.GetIntDefault("AiPlayerbot.RandomBotCountChangeMaxInterval", 3 * 24 * 3600); + minRandomBotInWorldTime = config.GetIntDefault("AiPlayerbot.MinRandomBotInWorldTime", 2 * 3600); + maxRandomBotInWorldTime = config.GetIntDefault("AiPlayerbot.MaxRandomBotInWorldTime", 14 * 24 * 3600); + minRandomBotRandomizeTime = config.GetIntDefault("AiPlayerbot.MinRandomBotRandomizeTime", 2 * 3600); + maxRandomBotRandomizeTime = config.GetIntDefault("AiPlayerbot.MaxRandomRandomizeTime", 14 * 24 * 3600); + minRandomBotReviveTime = config.GetIntDefault("AiPlayerbot.MinRandomBotReviveTime", 60); + maxRandomBotReviveTime = config.GetIntDefault("AiPlayerbot.MaxRandomReviveTime", 300); + randomBotTeleportDistance = config.GetIntDefault("AiPlayerbot.RandomBotTeleportDistance", 1000); + minRandomBotsPerInterval = config.GetIntDefault("AiPlayerbot.MinRandomBotsPerInterval", 50); + maxRandomBotsPerInterval = config.GetIntDefault("AiPlayerbot.MaxRandomBotsPerInterval", 100); + minRandomBotsPriceChangeInterval = config.GetIntDefault("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * 3600); + maxRandomBotsPriceChangeInterval = config.GetIntDefault("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * 3600); + randomBotJoinLfg = config.GetBoolDefault("AiPlayerbot.RandomBotJoinLfg", true); + logInGroupOnly = config.GetBoolDefault("AiPlayerbot.LogInGroupOnly", true); + logValuesPerTick = config.GetBoolDefault("AiPlayerbot.LogValuesPerTick", false); + fleeingEnabled = config.GetBoolDefault("AiPlayerbot.FleeingEnabled", true); + randomBotMinLevel = config.GetIntDefault("AiPlayerbot.RandomBotMinLevel", 1); + randomBotMaxLevel = config.GetIntDefault("AiPlayerbot.RandomBotMaxLevel", 255); + randomBotLoginAtStartup = config.GetBoolDefault("AiPlayerbot.RandomBotLoginAtStartup", true); + randomBotTeleLevel = config.GetIntDefault("AiPlayerbot.RandomBotTeleLevel", 3); + + randomChangeMultiplier = config.GetFloatDefault("AiPlayerbot.RandomChangeMultiplier", 1.0); + + randomBotCombatStrategies = config.GetStringDefault("AiPlayerbot.RandomBotCombatStrategies", "+dps,+attack weak"); + randomBotNonCombatStrategies = config.GetStringDefault("AiPlayerbot.RandomBotNonCombatStrategies", "+grind,+move random,+loot"); + + commandPrefix = config.GetStringDefault("AiPlayerbot.CommandPrefix", ""); + + commandServerPort = config.GetIntDefault("AiPlayerbot.CommandServerPort", 0); + + for (uint32 cls = 0; cls < MAX_CLASSES; ++cls) + { + for (uint32 spec = 0; spec < 3; ++spec) + { + ostringstream os; os << "AiPlayerbot.RandomClassSpecProbability." << cls << "." << spec; + specProbability[cls][spec] = config.GetIntDefault(os.str().c_str(), 33); + } + } + + CreateRandomBots(); + sLog.outString("AI Playerbot configuration loaded"); + + return true; +} + + +bool PlayerbotAIConfig::IsInRandomAccountList(uint32 id) +{ + return find(randomBotAccounts.begin(), randomBotAccounts.end(), id) != randomBotAccounts.end(); +} + +bool PlayerbotAIConfig::IsInRandomQuestItemList(uint32 id) +{ + return find(randomBotQuestItems.begin(), randomBotQuestItems.end(), id) != randomBotQuestItems.end(); +} + +string PlayerbotAIConfig::GetValue(string name) +{ + ostringstream out; + + if (name == "GlobalCooldown") + { + out << globalCoolDown; + } + else if (name == "ReactDelay") + { + out << reactDelay; + } + + else if (name == "SightDistance") + { + out << sightDistance; + } + else if (name == "SpellDistance") + { + out << spellDistance; + } + else if (name == "ReactDistance") + { + out << reactDistance; + } + else if (name == "GrindDistance") + { + out << grindDistance; + } + else if (name == "LootDistance") + { + out << lootDistance; + } + else if (name == "FleeDistance") + { + out << fleeDistance; + } + + else if (name == "CriticalHealth") + { + out << criticalHealth; + } + else if (name == "LowHealth") + { + out << lowHealth; + } + else if (name == "MediumHealth") + { + out << mediumHealth; + } + else if (name == "AlmostFullHealth") + { + out << almostFullHealth; + } + else if (name == "LowMana") + { + out << lowMana; + } + + else if (name == "IterationsPerTick") + { + out << iterationsPerTick; + } + + return out.str(); +} + +void PlayerbotAIConfig::SetValue(string name, string value) +{ + istringstream out(value, istringstream::in); + + if (name == "GlobalCooldown") + { + out >> globalCoolDown; + } + else if (name == "ReactDelay") + { + out >> reactDelay; + } + + else if (name == "SightDistance") + { + out >> sightDistance; + } + else if (name == "SpellDistance") + { + out >> spellDistance; + } + else if (name == "ReactDistance") + { + out >> reactDistance; + } + else if (name == "GrindDistance") + { + out >> grindDistance; + } + else if (name == "LootDistance") + { + out >> lootDistance; + } + else if (name == "FleeDistance") + { + out >> fleeDistance; + } + + else if (name == "CriticalHealth") + { + out >> criticalHealth; + } + else if (name == "LowHealth") + { + out >> lowHealth; + } + else if (name == "MediumHealth") + { + out >> mediumHealth; + } + else if (name == "AlmostFullHealth") + { + out >> almostFullHealth; + } + else if (name == "LowMana") + { + out >> lowMana; + } + + else if (name == "IterationsPerTick") + { + out >> iterationsPerTick; + } +} + + +void PlayerbotAIConfig::CreateRandomBots() +{ + string randomBotAccountPrefix = config.GetStringDefault("AiPlayerbot.RandomBotAccountPrefix", "rndbot"); + int32 randomBotAccountCount = config.GetIntDefault("AiPlayerbot.RandomBotAccountCount", 50); + + if (config.GetBoolDefault("AiPlayerbot.DeleteRandomBotAccounts", false)) + { + sLog.outBasic("Deleting random bot accounts..."); + QueryResult *results = LoginDatabase.PQuery("SELECT `id` FROM `account` WHERE `username` LIKE '%s%%'", randomBotAccountPrefix.c_str()); + if (results) + { + do + { + Field* fields = results->Fetch(); + sAccountMgr.DeleteAccount(fields[0].GetUInt32()); + } while (results->NextRow()); + + delete results; + } + + CharacterDatabase.Execute("DELETE FROM `ai_playerbot_random_bots`"); + sLog.outBasic("Random bot accounts deleted"); + } + + for (int accountNumber = 0; accountNumber < randomBotAccountCount; ++accountNumber) + { + ostringstream out; out << randomBotAccountPrefix << accountNumber; + string accountName = out.str(); + QueryResult *results = LoginDatabase.PQuery("SELECT `id` FROM `account` WHERE `username` = '%s'", accountName.c_str()); + if (results) + { + delete results; + continue; + } + + string password = ""; + for (int i = 0; i < 10; i++) + { + password += (char)urand('!', 'z'); + } + sAccountMgr.CreateAccount(accountName, password); + + sLog.outDetail("Account %s created for random bots", accountName.c_str()); + } + + LoginDatabase.PExecute("UPDATE `account` SET `expansion` = '%u', `playerbot` = %u WHERE `username` LIKE '%s%%'", 0,true, randomBotAccountPrefix.c_str()); + + int totalRandomBotChars = 0; + for (int accountNumber = 0; accountNumber < randomBotAccountCount; ++accountNumber) + { + ostringstream out; out << randomBotAccountPrefix << accountNumber; + string accountName = out.str(); + + QueryResult *results = LoginDatabase.PQuery("SELECT `id` FROM `account` WHERE `username` = '%s'", accountName.c_str()); + if (!results) + { + continue; + } + + Field* fields = results->Fetch(); + uint32 accountId = fields[0].GetUInt32(); + delete results; + + randomBotAccounts.push_back(accountId); + + int count = sAccountMgr.GetCharactersCount(accountId); + if (count >= 10) + { + totalRandomBotChars += count; + continue; + } + + RandomPlayerbotFactory factory(accountId); + for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES; ++cls) + { + if (cls != 10 && cls != 6) + { + factory.CreateRandomBot(cls); + } + } + + totalRandomBotChars += sAccountMgr.GetCharactersCount(accountId); + } + + sLog.outBasic("%d random bot accounts with %d characters available", randomBotAccounts.size(), totalRandomBotChars); +} diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.h b/src/modules/Bots/playerbot/PlayerbotAIConfig.h new file mode 100644 index 0000000000..2c2aa9a4ee --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.h @@ -0,0 +1,67 @@ +#pragma once + +#include "Config/Config.h" + +class Player; +class PlayerbotMgr; +class ChatHandler; + +class PlayerbotAIConfig +{ +public: + PlayerbotAIConfig(); + +public: + bool Initialize(); + bool IsInRandomAccountList(uint32 id); + bool IsInRandomQuestItemList(uint32 id); + + bool enabled; + bool allowGuildBots; + uint32 globalCoolDown, reactDelay, maxWaitForMove; + float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, + fleeDistance, tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance; + uint32 criticalHealth, lowHealth, mediumHealth, almostFullHealth; + uint32 lowMana, mediumMana; + + bool randomBotAutologin; + std::string randomBotMapsAsString; + std::vector randomBotMaps; + std::list randomBotQuestItems; + std::list randomBotAccounts; + std::list randomBotSpellIds; + uint32 randomBotTeleportDistance; + float randomGearLoweringChance; + float randomBotMaxLevelChance; + uint32 minRandomBots, maxRandomBots; + uint32 randomBotUpdateInterval, randomBotCountChangeMinInterval, randomBotCountChangeMaxInterval; + uint32 minRandomBotInWorldTime, maxRandomBotInWorldTime; + uint32 minRandomBotRandomizeTime, maxRandomBotRandomizeTime; + uint32 minRandomBotReviveTime, maxRandomBotReviveTime; + uint32 minRandomBotPvpTime, maxRandomBotPvpTime; + uint32 minRandomBotsPerInterval, maxRandomBotsPerInterval; + uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval; + bool randomBotJoinLfg; + bool randomBotLoginAtStartup; + uint32 randomBotTeleLevel; + bool logInGroupOnly, logValuesPerTick; + bool fleeingEnabled; + std::string randomBotCombatStrategies, randomBotNonCombatStrategies; + uint32 randomBotMinLevel, randomBotMaxLevel; + float randomChangeMultiplier; + uint32 specProbability[MAX_CLASSES][3]; + std::string commandPrefix; + + uint32 iterationsPerTick; + + int commandServerPort; + + std::string GetValue(std::string name); + void SetValue(std::string name, std::string value); + +private: + void CreateRandomBots(); + Config config; +}; + +#define sPlayerbotAIConfig MaNGOS::Singleton::Instance() diff --git a/src/modules/Bots/playerbot/PlayerbotFactory.cpp b/src/modules/Bots/playerbot/PlayerbotFactory.cpp new file mode 100644 index 0000000000..646483ad94 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotFactory.cpp @@ -0,0 +1,1815 @@ +#include "botpch.h" +#include "playerbot.h" +#include "ahbot/AhBot.h" +#include "PlayerbotFactory.h" +#include "SQLStorages.h" +#include "ItemPrototype.h" +#include "PlayerbotAIConfig.h" +#include "AccountMgr.h" +#include "DBCStore.h" +#include "SharedDefines.h" + + +using namespace ai; +using namespace std; + +uint32 PlayerbotFactory::tradeSkills[] = +{ + SKILL_ALCHEMY, + SKILL_ENCHANTING, + SKILL_SKINNING, + SKILL_TAILORING, + SKILL_LEATHERWORKING, + SKILL_ENGINEERING, + SKILL_HERBALISM, + SKILL_MINING, + SKILL_BLACKSMITHING, + SKILL_COOKING, + SKILL_FIRST_AID, + SKILL_FISHING +}; + +void PlayerbotFactory::Randomize() +{ + Randomize(true); +} + +void PlayerbotFactory::Refresh() +{ + Prepare(); + InitEquipment(true); + InitAmmo(); + InitFood(); + InitPotions(); + + uint32 money = urand(level * 1000, level * 5 * 1000); + if (bot->GetMoney() < money) + { + bot->SetMoney(money); + } + bot->SaveToDB(); +} + +void PlayerbotFactory::CleanRandomize() +{ + Randomize(false); +} + +void PlayerbotFactory::Prepare() +{ + if (!itemQuality) + { + if (level <= 10) + { + itemQuality = urand(ITEM_QUALITY_NORMAL, ITEM_QUALITY_UNCOMMON); + } + else if (level <= 20) + { + itemQuality = urand(ITEM_QUALITY_UNCOMMON, ITEM_QUALITY_RARE); + } + else if (level <= 40) + { + itemQuality = urand(ITEM_QUALITY_UNCOMMON, ITEM_QUALITY_EPIC); + } + else if (level < 60) + { + itemQuality = urand(ITEM_QUALITY_UNCOMMON, ITEM_QUALITY_EPIC); + } + else + { + itemQuality = urand(ITEM_QUALITY_RARE, ITEM_QUALITY_EPIC); + } + } + + if (bot->IsDead()) + { + bot->ResurrectPlayer(1.0f, false); + } + + bot->CombatStop(true); + bot->SetLevel(level); + bot->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); + bot->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); +} + +void PlayerbotFactory::Randomize(bool incremental) +{ + Prepare(); + + bot->resetTalents(true); + ClearSpells(); + ClearInventory(); + bot->SaveToDB(); + + InitQuests(); + // quest rewards boost bot level, so reduce back + bot->SetLevel(level); + ClearInventory(); + bot->SetUInt32Value(PLAYER_XP, 0); + CancelAuras(); + bot->SaveToDB(); + + InitAvailableSpells(); + InitSkills(); + InitTradeSkills(); + InitTalents(); + InitAvailableSpells(); + InitSpecialSpells(); + InitMounts(); + UpdateTradeSkills(); + bot->SaveToDB(); + + InitEquipment(incremental); + InitBags(); + InitAmmo(); + InitFood(); + InitPotions(); + InitSecondEquipmentSet(); + InitInventory(); + bot->SetMoney(urand(level * 1000, level * 5 * 1000)); + bot->SaveToDB(); + + InitPet(); + bot->SaveToDB(); +} + +void PlayerbotFactory::InitPet() +{ + Pet* pet = bot->GetPet(); + if (!pet) + { + if (bot->getClass() != CLASS_HUNTER) + { + return; + } + + Map* map = bot->GetMap(); + if (!map) + { + return; + } + + vector ids; + for (uint32 id = 0; id < sCreatureStorage.GetMaxEntry(); ++id) + { + CreatureInfo const* co = sCreatureStorage.LookupEntry(id); + if (!co || !co->isTameable(bot->CanTameExoticPets())) + { + continue; + } + + if (co->MinLevel > bot->getLevel()) + { + continue; + } + + PetLevelInfo const* petInfo = sObjectMgr.GetPetLevelInfo(co->Entry, bot->getLevel()); + if (!petInfo) + { + continue; + } + + ids.push_back(id); + } + + if (ids.empty()) + { + sLog.outError("No pets available for bot %s (%d level)", bot->GetName(), bot->getLevel()); + return; + } + + for (int i = 0; i < 100; i++) + { + int index = urand(0, ids.size() - 1); + CreatureInfo const* co = sCreatureStorage.LookupEntry(ids[index]); + + PetLevelInfo const* petInfo = sObjectMgr.GetPetLevelInfo(co->Entry, bot->getLevel()); + if (!petInfo) + { + continue; + } + + uint32 guid = map->GenerateLocalLowGuid(HIGHGUID_PET); + CreatureCreatePos pos(map, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(), bot->GetPhaseMask()); + pet = new Pet(HUNTER_PET); + if (!pet->Create(guid, pos, co, 0)) + { + delete pet; + pet = NULL; + continue; + } + + pet->SetOwnerGuid(bot->GetObjectGuid()); + pet->SetCreatorGuid(bot->GetObjectGuid()); + pet->setFaction(bot->getFaction()); + pet->SetLevel(bot->getLevel()); + bot->SetPet(pet); + + sLog.outDetail("Bot %s: assign pet %d (%d level)", bot->GetName(), co->Entry, bot->getLevel()); + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + break; + } + } + + if (!pet) + { + sLog.outError("Cannot create pet for bot %s", bot->GetName()); + return; + } + + for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr) + { + if(itr->second.state == PETSPELL_REMOVED) + { + continue; + } + + uint32 spellId = itr->first; + if(IsPassiveSpell(spellId)) + { + continue; + } + + pet->ToggleAutocast(spellId, true); + } +} + +void PlayerbotFactory::ClearSpells() +{ + list spells; + for(PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) + { + uint32 spellId = itr->first; + if(itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled || IsPassiveSpell(spellId)) + { + continue; + } + + spells.push_back(spellId); + } + + for (list::iterator i = spells.begin(); i != spells.end(); ++i) + { + bot->removeSpell(*i); + } +} + +void PlayerbotFactory::InitSpells() +{ + for (int i = 0; i < 15; i++) + { + InitAvailableSpells(); + } +} + +void PlayerbotFactory::InitTalents() +{ + uint32 point = urand(0, 100); + uint8 cls = bot->getClass(); + uint32 p1 = sPlayerbotAIConfig.specProbability[cls][0]; + uint32 p2 = p1 + sPlayerbotAIConfig.specProbability[cls][1]; + + uint32 specNo = (point < p1 ? 0 : (point < p2 ? 1 : 2)); + InitTalents(specNo); + + if (bot->GetFreeTalentPoints()) + { + InitTalents(2 - specNo); + } +} + + +class DestroyItemsVisitor : public IterateItemsVisitor +{ +public: + DestroyItemsVisitor(Player* bot) : IterateItemsVisitor(), bot(bot) {} + + virtual bool Visit(Item* item) + { + uint32 id = item->GetProto()->ItemId; + if (CanKeep(id)) + { + keep.insert(id); + return true; + } + + bot->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); + return true; + } + +private: + bool CanKeep(uint32 id) + { + if (keep.find(id) != keep.end()) + { + return false; + } + + if (sPlayerbotAIConfig.IsInRandomQuestItemList(id)) + { + return true; + } + + ItemPrototype const* proto = sItemStorage.LookupEntry(id); + if (proto->Class == ITEM_CLASS_MISC && proto->SubClass == ITEM_SUBCLASS_JUNK) + { + return true; + } + + return false; + } + +private: + Player* bot; + set keep; + +}; + +bool PlayerbotFactory::CanEquipArmor(ItemPrototype const* proto) +{ + if (bot->HasSkill(SKILL_SHIELD) && proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD) + { + return true; + } + + if (bot->HasSkill(SKILL_PLATE_MAIL)) + { + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_PLATE) + { + return false; + } + } + else if (bot->HasSkill(SKILL_MAIL)) + { + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_MAIL) + { + return false; + } + } + else if (bot->HasSkill(SKILL_LEATHER)) + { + if (proto->SubClass != ITEM_SUBCLASS_ARMOR_LEATHER) + { + return false; + } + } + + if (proto->Quality <= ITEM_QUALITY_NORMAL) + { + return true; + } + + uint8 sp = 0, ap = 0, tank = 0; + for (int j = 0; j < MAX_ITEM_PROTO_STATS; ++j) + { + // for ItemStatValue != 0 + if(!proto->ItemStat[j].ItemStatValue) + { + continue; + } + + AddItemStats(proto->ItemStat[j].ItemStatType, sp, ap, tank); + } + + return CheckItemStats(sp, ap, tank); +} + +bool PlayerbotFactory::CheckItemStats(uint8 sp, uint8 ap, uint8 tank) +{ + switch (bot->getClass()) + { + case CLASS_PRIEST: + case CLASS_MAGE: + case CLASS_WARLOCK: + if (!sp || ap > sp || tank > sp) + { + return false; + } + break; + case CLASS_PALADIN: + case CLASS_WARRIOR: + if ((!ap && !tank) || sp > ap || sp > tank) + { + return false; + } + break; + case CLASS_HUNTER: + case CLASS_ROGUE: + if (!ap || sp > ap || sp > tank) + { + return false; + } + break; + } + + return sp || ap || tank; +} + +void PlayerbotFactory::AddItemStats(uint32 mod, uint8 &sp, uint8 &ap, uint8 &tank) +{ + switch (mod) + { + //FOEREAPER + //case ITEM_MOD_HIT_RATING: + //case ITEM_MOD_CRIT_RATING: + //case ITEM_MOD_HASTE_RATING: + case ITEM_MOD_HEALTH: + case ITEM_MOD_STAMINA: + //case ITEM_MOD_HEALTH_REGEN: + case ITEM_MOD_MANA: + case ITEM_MOD_INTELLECT: + case ITEM_MOD_SPIRIT: + //case ITEM_MOD_MANA_REGENERATION: + //case ITEM_MOD_SPELL_POWER: + //case ITEM_MOD_SPELL_PENETRATION: + //case ITEM_MOD_HIT_SPELL_RATING: + //case ITEM_MOD_CRIT_SPELL_RATING: + //case ITEM_MOD_HASTE_SPELL_RATING: + sp++; + break; + } + + switch (mod) + { + //case ITEM_MOD_HIT_RATING: + //case ITEM_MOD_CRIT_RATING: + //case ITEM_MOD_HASTE_RATING: + case ITEM_MOD_AGILITY: + case ITEM_MOD_STRENGTH: + case ITEM_MOD_HEALTH: + case ITEM_MOD_STAMINA: + //case ITEM_MOD_HEALTH_REGEN: + //case ITEM_MOD_DEFENSE_SKILL_RATING: + //case ITEM_MOD_DODGE_RATING: + //case ITEM_MOD_PARRY_RATING: + //case ITEM_MOD_BLOCK_RATING: + //case ITEM_MOD_HIT_TAKEN_MELEE_RATING: + //case ITEM_MOD_HIT_TAKEN_RANGED_RATING: + //case ITEM_MOD_HIT_TAKEN_SPELL_RATING: + //case ITEM_MOD_CRIT_TAKEN_MELEE_RATING: + //case ITEM_MOD_CRIT_TAKEN_RANGED_RATING: + //case ITEM_MOD_CRIT_TAKEN_SPELL_RATING: + //case ITEM_MOD_HIT_TAKEN_RATING: + //case ITEM_MOD_CRIT_TAKEN_RATING: + //case ITEM_MOD_RESILIENCE_RATING: + //case ITEM_MOD_BLOCK_VALUE: + tank++; + break; + } + + switch (mod) + { + case ITEM_MOD_HEALTH: + case ITEM_MOD_STAMINA: + //case ITEM_MOD_HEALTH_REGEN: + case ITEM_MOD_AGILITY: + case ITEM_MOD_STRENGTH: + //case ITEM_MOD_HIT_MELEE_RATING: + //case ITEM_MOD_HIT_RANGED_RATING: + //case ITEM_MOD_CRIT_MELEE_RATING: + //case ITEM_MOD_CRIT_RANGED_RATING: + //case ITEM_MOD_HASTE_MELEE_RATING: + //case ITEM_MOD_HASTE_RANGED_RATING: + //case ITEM_MOD_HIT_RATING: + //case ITEM_MOD_CRIT_RATING: + //case ITEM_MOD_HASTE_RATING: + //case ITEM_MOD_EXPERTISE_RATING: + //case ITEM_MOD_ATTACK_POWER: + //case ITEM_MOD_RANGED_ATTACK_POWER: + //case ITEM_MOD_ARMOR_PENETRATION_RATING: + ap++; + break; + } +} + +bool PlayerbotFactory::CanEquipWeapon(ItemPrototype const* proto) +{ + switch (bot->getClass()) + { + case CLASS_PRIEST: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_STAFF && + proto->SubClass != ITEM_SUBCLASS_WEAPON_WAND && + proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE) + return false; + break; + case CLASS_MAGE: + case CLASS_WARLOCK: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_STAFF && + proto->SubClass != ITEM_SUBCLASS_WEAPON_WAND && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD) + return false; + break; + case CLASS_WARRIOR: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD && + proto->SubClass != ITEM_SUBCLASS_WEAPON_GUN && + proto->SubClass != ITEM_SUBCLASS_WEAPON_CROSSBOW && + proto->SubClass != ITEM_SUBCLASS_WEAPON_BOW && + proto->SubClass != ITEM_SUBCLASS_WEAPON_THROWN) + return false; + break; + case CLASS_PALADIN: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD) + return false; + break; + case CLASS_SHAMAN: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE && + proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_STAFF) + return false; + break; + case CLASS_DRUID: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE && + proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER && + proto->SubClass != ITEM_SUBCLASS_WEAPON_STAFF) + return false; + break; + case CLASS_HUNTER: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_AXE2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_GUN && + proto->SubClass != ITEM_SUBCLASS_WEAPON_CROSSBOW && + proto->SubClass != ITEM_SUBCLASS_WEAPON_BOW) + return false; + break; + case CLASS_ROGUE: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD && + proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE && + proto->SubClass != ITEM_SUBCLASS_WEAPON_GUN && + proto->SubClass != ITEM_SUBCLASS_WEAPON_CROSSBOW && + proto->SubClass != ITEM_SUBCLASS_WEAPON_BOW && + proto->SubClass != ITEM_SUBCLASS_WEAPON_THROWN) + return false; + break; + } + + return true; +} + +bool PlayerbotFactory::CanEquipItem(ItemPrototype const* proto, uint32 desiredQuality) +{ + if (proto->Duration & 0x80000000) + { + return false; + } + + if (proto->Quality != desiredQuality) + { + return false; + } + + if (proto->Bonding == BIND_QUEST_ITEM || proto->Bonding == BIND_WHEN_USE) + { + return false; + } + + if (proto->Class == ITEM_CLASS_CONTAINER) + { + return true; + } + + uint32 requiredLevel = proto->RequiredLevel; + if (!requiredLevel) + { + return false; + } + + uint32 level = bot->getLevel(); + uint32 delta = 2; + if (level < 15) + { + delta = urand(7, 15); + } + else if (proto->Class == ITEM_CLASS_WEAPON || proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD) + { + delta = urand(2, 3); + } + else if (!(level % 10) || (level % 10) == 9) + { + delta = 2; + } + else if (level < 40) + { + delta = urand(5, 10); + } + else if (level < 60) + { + delta = urand(3, 7); + } + else if (level < 70) + { + delta = urand(2, 5); + } + else if (level < 80) + { + delta = urand(2, 4); + } + + if (desiredQuality > ITEM_QUALITY_NORMAL && + (requiredLevel > level || requiredLevel < level - delta)) + return false; + + for (uint32 gap = 60; gap <= 80; gap += 10) + { + if (level > gap && requiredLevel <= gap) + { + return false; + } + } + + return true; +} + +void PlayerbotFactory::InitEquipment(bool incremental) +{ + DestroyItemsVisitor visitor(bot); + IterateItems(&visitor, ITERATE_ALL_ITEMS); + + map > items; + for(uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot) + { + if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY) + { + continue; + } + + uint32 desiredQuality = itemQuality; + if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) { + { + desiredQuality--; + } + } + + do + { + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } + + if (proto->Class != ITEM_CLASS_WEAPON && + proto->Class != ITEM_CLASS_ARMOR && + proto->Class != ITEM_CLASS_CONTAINER && + proto->Class != ITEM_CLASS_PROJECTILE) + continue; + + if (!CanEquipItem(proto, desiredQuality)) + { + continue; + } + + if (proto->Class == ITEM_CLASS_ARMOR && ( + slot == EQUIPMENT_SLOT_HEAD || + slot == EQUIPMENT_SLOT_SHOULDERS || + slot == EQUIPMENT_SLOT_CHEST || + slot == EQUIPMENT_SLOT_WAIST || + slot == EQUIPMENT_SLOT_LEGS || + slot == EQUIPMENT_SLOT_FEET || + slot == EQUIPMENT_SLOT_WRISTS || + slot == EQUIPMENT_SLOT_HANDS) && !CanEquipArmor(proto)) + continue; + + if (proto->Class == ITEM_CLASS_WEAPON && !CanEquipWeapon(proto)) + { + continue; + } + + if (slot == EQUIPMENT_SLOT_OFFHAND && bot->getClass() == CLASS_ROGUE && proto->Class != ITEM_CLASS_WEAPON) + { + continue; + } + + uint16 dest = 0; + if (CanEquipUnseenItem(slot, dest, itemId)) + { + items[slot].push_back(itemId); + } + } + } while (items[slot].empty() && desiredQuality-- > ITEM_QUALITY_NORMAL); + } + + for(uint8 slot = 0; slot < EQUIPMENT_SLOT_END; ++slot) + { + if (slot == EQUIPMENT_SLOT_TABARD || slot == EQUIPMENT_SLOT_BODY) + { + continue; + } + + vector& ids = items[slot]; + if (ids.empty()) + { + sLog.outDetail("%s: no items to equip for slot %d", bot->GetName(), slot); + continue; + } + + for (int attempts = 0; attempts < 15; attempts++) + { + uint32 index = urand(0, ids.size() - 1); + uint32 newItemId = ids[index]; + Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + + if (incremental && !IsDesiredReplacement(oldItem)) { + { + continue; + } + } + + uint16 dest; + if (!CanEquipUnseenItem(slot, dest, newItemId)) + { + continue; + } + + if (oldItem) + { + bot->RemoveItem(INVENTORY_SLOT_BAG_0, slot, true); + oldItem->DestroyForPlayer(bot); + } + + Item* newItem = bot->EquipNewItem(dest, newItemId, true); + if (newItem) + { + newItem->AddToWorld(); + newItem->AddToUpdateQueueOf(bot); + bot->AutoUnequipOffhandIfNeed(); + EnchantItem(newItem); + break; + } + } + } +} + +bool PlayerbotFactory::IsDesiredReplacement(Item* item) +{ + if (!item) + { + return true; + } + + ItemPrototype const* proto = item->GetProto(); + int delta = 1 + (80 - bot->getLevel()) / 10; + return (int)bot->getLevel() - (int)proto->RequiredLevel > delta; +} + +void PlayerbotFactory::InitSecondEquipmentSet() +{ + if (bot->getClass() == CLASS_MAGE || bot->getClass() == CLASS_WARLOCK || bot->getClass() == CLASS_PRIEST) + { + return; + } + + map > items; + + uint32 desiredQuality = itemQuality; + while (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) { + desiredQuality--; + } + + do + { + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } + + if (!CanEquipItem(proto, desiredQuality)) + { + continue; + } + + if (proto->Class == ITEM_CLASS_WEAPON) + { + if (!CanEquipWeapon(proto)) + { + continue; + } + + Item* existingItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + if (existingItem) + { + switch (existingItem->GetProto()->SubClass) + { + case ITEM_SUBCLASS_WEAPON_AXE: + case ITEM_SUBCLASS_WEAPON_DAGGER: + case ITEM_SUBCLASS_WEAPON_FIST: + case ITEM_SUBCLASS_WEAPON_MACE: + case ITEM_SUBCLASS_WEAPON_SWORD: + if (proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE || proto->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER || + proto->SubClass == ITEM_SUBCLASS_WEAPON_FIST || proto->SubClass == ITEM_SUBCLASS_WEAPON_MACE || + proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD) + continue; + break; + default: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_AXE && proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER && + proto->SubClass != ITEM_SUBCLASS_WEAPON_FIST && proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD) + continue; + break; + } + } + } + else if (proto->Class == ITEM_CLASS_ARMOR && proto->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD) + { + if (!CanEquipArmor(proto)) + { + continue; + } + + Item* existingItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + if (existingItem && existingItem->GetProto()->SubClass == ITEM_SUBCLASS_ARMOR_SHIELD) + { + continue; + } + } + else + { + continue; + } + + items[proto->Class].push_back(itemId); + } + } while (items[ITEM_CLASS_ARMOR].empty() && items[ITEM_CLASS_WEAPON].empty() && desiredQuality-- > ITEM_QUALITY_NORMAL); + + for (map >::iterator i = items.begin(); i != items.end(); ++i) + { + vector& ids = i->second; + if (ids.empty()) + { + sLog.outDetail("%s: no items to make second equipment set for slot %d", bot->GetName(), i->first); + continue; + } + + for (int attempts = 0; attempts < 15; attempts++) + { + uint32 index = urand(0, ids.size() - 1); + uint32 newItemId = ids[index]; + + Item* newItem = bot->StoreNewItemInInventorySlot(newItemId, 1); + if (newItem) + { + EnchantItem(newItem); + newItem->AddToWorld(); + newItem->AddToUpdateQueueOf(bot); + break; + } + } + } +} + +void PlayerbotFactory::InitBags() +{ + vector ids; + + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto || proto->Class != ITEM_CLASS_CONTAINER) + { + continue; + } + + if (!CanEquipItem(proto, ITEM_QUALITY_NORMAL)) + { + continue; + } + + ids.push_back(itemId); + } + + if (ids.empty()) + { + sLog.outError("%s: no bags found", bot->GetName()); + return; + } + + for (uint8 slot = INVENTORY_SLOT_BAG_START; slot < INVENTORY_SLOT_BAG_END; ++slot) + { + for (int attempts = 0; attempts < 15; attempts++) + { + uint32 index = urand(0, ids.size() - 1); + uint32 newItemId = ids[index]; + + uint16 dest; + if (!CanEquipUnseenItem(slot, dest, newItemId)) + { + continue; + } + + Item* newItem = bot->EquipNewItem(dest, newItemId, true); + if (newItem) + { + newItem->AddToWorld(); + newItem->AddToUpdateQueueOf(bot); + break; + } + } + } +} + +void PlayerbotFactory::EnchantItem(Item* item) +{ + if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance) + { + return; + } + + if (bot->getLevel() < urand(40, 50)) + { + return; + } + + ItemPrototype const* proto = item->GetProto(); + int32 itemLevel = proto->ItemLevel; + + vector ids; + for (uint32 id = 0; id < sSpellStore.GetNumRows(); ++id) + { + SpellEntry const *entry = sSpellStore.LookupEntry(id); + if (!entry) + { + continue; + } + + int32 requiredLevel = (int32)entry->baseLevel; + if (requiredLevel && (requiredLevel > itemLevel || requiredLevel < itemLevel - 35)) + { + continue; + } + + if (entry->maxLevel && level > entry->maxLevel) + { + continue; + } + + uint32 spellLevel = entry->spellLevel; + if (spellLevel && (spellLevel > level || spellLevel < level - 10)) + { + continue; + } + + for (int j = 0; j < 3; ++j) + { + if (entry->Effect[j] != SPELL_EFFECT_ENCHANT_ITEM) + { + continue; + } + + uint32 enchant_id = entry->EffectMiscValue[j]; + if (!enchant_id) + { + continue; + } + + SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if (!enchant || enchant->slot != PERM_ENCHANTMENT_SLOT) + { + continue; + } + + uint8 sp = 0, ap = 0, tank = 0; + for (int i = 0; i < 3; ++i) + { + if (enchant->type[i] != ITEM_ENCHANTMENT_TYPE_STAT) + { + continue; + } + + AddItemStats(enchant->spellid[i], sp, ap, tank); + } + + if (!CheckItemStats(sp, ap, tank)) + { + continue; + } + + if (!item->IsFitToSpellRequirements(entry)) + { + continue; + } + + ids.push_back(enchant_id); + } + } + + if (ids.empty()) + { + sLog.outDetail("%s: no enchantments found for item %d", bot->GetName(), item->GetProto()->ItemId); + return; + } + + int index = urand(0, ids.size() - 1); + uint32 id = ids[index]; + + SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(id); + if (!enchant) + { + return; + } + + bot->ApplyEnchantment(item, PERM_ENCHANTMENT_SLOT, false); + item->SetEnchantment(PERM_ENCHANTMENT_SLOT, id, 0, 0); + bot->ApplyEnchantment(item, PERM_ENCHANTMENT_SLOT, true); +} + +bool PlayerbotFactory::CanEquipUnseenItem(uint8 slot, uint16 &dest, uint32 item) +{ + dest = 0; + Item *pItem = Item::CreateItem(item, 1, bot); + if (pItem) + { + InventoryResult result = bot->CanEquipItem(slot, dest, pItem, true, false); + pItem->RemoveFromUpdateQueueOf(bot); + delete pItem; + return result == EQUIP_ERR_OK; + } + + return false; +} + +void PlayerbotFactory::InitTradeSkills() +{ + for (int i = 0; i < sizeof(tradeSkills) / sizeof(uint32); ++i) + { + bot->SetSkill(tradeSkills[i], 0, 0); + } + + vector firstSkills; + vector secondSkills; + switch (bot->getClass()) + { + case CLASS_WARRIOR: + case CLASS_PALADIN: + firstSkills.push_back(SKILL_MINING); + secondSkills.push_back(SKILL_BLACKSMITHING); + secondSkills.push_back(SKILL_ENGINEERING); + break; + case CLASS_SHAMAN: + case CLASS_DRUID: + case CLASS_HUNTER: + case CLASS_ROGUE: + firstSkills.push_back(SKILL_SKINNING); + secondSkills.push_back(SKILL_LEATHERWORKING); + break; + default: + firstSkills.push_back(SKILL_TAILORING); + secondSkills.push_back(SKILL_ENCHANTING); + } + + SetRandomSkill(SKILL_FIRST_AID); + SetRandomSkill(SKILL_FISHING); + SetRandomSkill(SKILL_COOKING); + + switch (urand(0, 1)) + { + case 0: + SetRandomSkill(SKILL_HERBALISM); + SetRandomSkill(SKILL_ALCHEMY); + break; + /*case 1: + SetRandomSkill(SKILL_HERBALISM); + SetRandomSkill(SKILL_INSCRIPTION); + break; + case 2: + SetRandomSkill(SKILL_MINING); + SetRandomSkill(SKILL_JEWELCRAFTING); + break;*/ + case 1://3: + SetRandomSkill(firstSkills[urand(0, firstSkills.size() - 1)]); + SetRandomSkill(secondSkills[urand(0, secondSkills.size() - 1)]); + break; + } +} + +void PlayerbotFactory::UpdateTradeSkills() +{ + for (int i = 0; i < sizeof(tradeSkills) / sizeof(uint32); ++i) + { + if (bot->GetSkillValue(tradeSkills[i]) == 1) + { + bot->SetSkill(tradeSkills[i], 0, 0); + } + } +} + +void PlayerbotFactory::InitSkills() +{ + uint32 maxValue = level * 5; + SetRandomSkill(SKILL_DEFENSE); + SetRandomSkill(SKILL_SWORDS); + SetRandomSkill(SKILL_AXES); + SetRandomSkill(SKILL_BOWS); + SetRandomSkill(SKILL_GUNS); + SetRandomSkill(SKILL_MACES); + SetRandomSkill(SKILL_2H_SWORDS); + SetRandomSkill(SKILL_STAVES); + SetRandomSkill(SKILL_2H_MACES); + SetRandomSkill(SKILL_2H_AXES); + SetRandomSkill(SKILL_DAGGERS); + SetRandomSkill(SKILL_THROWN); + SetRandomSkill(SKILL_CROSSBOWS); + SetRandomSkill(SKILL_WANDS); + SetRandomSkill(SKILL_POLEARMS); + SetRandomSkill(SKILL_FIST_WEAPONS); + + if (bot->getLevel() >= 70) + { + bot->SetSkill(SKILL_RIDING, 300, 300); + } + else if (bot->getLevel() >= 60) + { + bot->SetSkill(SKILL_RIDING, 225, 225); + } + else if (bot->getLevel() >= 40) + { + bot->SetSkill(SKILL_RIDING, 150, 150); + } + else if (bot->getLevel() >= 20) + { + bot->SetSkill(SKILL_RIDING, 75, 75); + } + else + { + bot->SetSkill(SKILL_RIDING, 0, 0); + } + + uint32 skillLevel = bot->getLevel() < 40 ? 0 : 1; + switch (bot->getClass()) + { + //case CLASS_DEATH_KNIGHT: + case CLASS_WARRIOR: + case CLASS_PALADIN: + bot->SetSkill(SKILL_PLATE_MAIL, skillLevel, skillLevel); + break; + case CLASS_SHAMAN: + case CLASS_HUNTER: + bot->SetSkill(SKILL_MAIL, skillLevel, skillLevel); + } +} + +void PlayerbotFactory::SetRandomSkill(uint16 id) +{ + uint32 maxValue = level * 5; + uint32 curValue = urand(maxValue - level, maxValue); + bot->SetSkill(id, curValue, maxValue); + +} + +void PlayerbotFactory::InitAvailableSpells() +{ + bot->learnDefaultSpells(); + + for (uint32 id = 0; id < sCreatureStorage.GetMaxEntry(); ++id) + { + CreatureInfo const* co = sCreatureStorage.LookupEntry(id); + if (!co) + { + continue; + } + + if (co->TrainerType != TRAINER_TYPE_TRADESKILLS && co->TrainerType != TRAINER_TYPE_CLASS) + { + continue; + } + + if (co->TrainerType == TRAINER_TYPE_CLASS && co->TrainerClass != bot->getClass()) + { + continue; + } + + uint32 trainerId = co->TrainerTemplateId; + if (!trainerId) + { + trainerId = co->Entry; + } + + TrainerSpellData const* trainer_spells = sObjectMgr.GetNpcTrainerTemplateSpells(trainerId); + if (!trainer_spells) + { + trainer_spells = sObjectMgr.GetNpcTrainerSpells(trainerId); + } + + if (!trainer_spells) + { + continue; + } + + for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) + { + TrainerSpell const* tSpell = &itr->second; + + if (!tSpell) + { + continue; + } + + uint32 reqLevel = 0; + + reqLevel = tSpell->isProvidedReqLevel ? tSpell->reqLevel : std::max(reqLevel, tSpell->reqLevel); + TrainerSpellState state = bot->GetTrainerSpellState(tSpell, reqLevel); + if (state != TRAINER_SPELL_GREEN) + { + continue; + } + + ai->CastSpell(tSpell->spell, bot); + } + } +} + +void PlayerbotFactory::InitSpecialSpells() +{ + for (list::iterator i = sPlayerbotAIConfig.randomBotSpellIds.begin(); i != sPlayerbotAIConfig.randomBotSpellIds.end(); ++i) + { + uint32 spellId = *i; + bot->learnSpell(spellId, false); + } +} + +void PlayerbotFactory::InitTalents(uint32 specNo) +{ + uint32 classMask = bot->getClassMask(); + + map > spells; + for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) + { + TalentEntry const *talentInfo = sTalentStore.LookupEntry(i); + if(!talentInfo) + { + continue; + } + + TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab ); + if(!talentTabInfo || talentTabInfo->tabpage != specNo) + { + continue; + } + + if( (classMask & talentTabInfo->ClassMask) == 0 ) + { + continue; + } + + spells[talentInfo->Row].push_back(talentInfo); + } + + uint32 freePoints = bot->GetFreeTalentPoints(); + for (map >::iterator i = spells.begin(); i != spells.end(); ++i) + { + vector &spells = i->second; + if (spells.empty()) + { + sLog.outError("%s: No spells for talent row %d", bot->GetName(), i->first); + continue; + } + + int attemptCount = 0; + while (!spells.empty() && (int)freePoints - (int)bot->GetFreeTalentPoints() < 5 && attemptCount++ < 3 && bot->GetFreeTalentPoints()) + { + int index = urand(0, spells.size() - 1); + TalentEntry const *talentInfo = spells[index]; + for (int rank = 0; rank < MAX_TALENT_RANK && bot->GetFreeTalentPoints(); ++rank) + { + uint32 spellId = talentInfo->RankID[rank]; + if (!spellId) + { + continue; + } + bot->learnSpell(spellId, false); + bot->UpdateFreeTalentPoints(false); + } + spells.erase(spells.begin() + index); + } + + freePoints = bot->GetFreeTalentPoints(); + } +} + +ObjectGuid PlayerbotFactory::GetRandomBot() +{ + vector guids; + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); i++) + { + uint32 accountId = *i; + if (!sAccountMgr.GetCharactersCount(accountId)) + { + continue; + } + + QueryResult *result = CharacterDatabase.PQuery("SELECT `guid` FROM `characters` WHERE `account` = '%u'", accountId); + if (!result) + { + continue; + } + + do + { + Field* fields = result->Fetch(); + ObjectGuid guid = ObjectGuid(fields[0].GetUInt64()); + if (!sObjectMgr.GetPlayer(guid)) + { + guids.push_back(guid); + } + } while (result->NextRow()); + + delete result; + } + + if (guids.empty()) + { + return ObjectGuid(); + } + + int index = urand(0, guids.size() - 1); + return guids[index]; +} + +void PlayerbotFactory::InitQuests() +{ + QueryResult *results = WorldDatabase.PQuery("SELECT `entry`, `RequiredClasses`, `RequiredRaces` FROM `quest_template` WHERE `QuestLevel` = -1 and `MinLevel` <= '%u'", + bot->getLevel()); + if (!results) + { + return; + } + + list ids; + do + { + Field* fields = results->Fetch(); + uint32 questId = fields[0].GetUInt32(); + uint32 requiredClasses = fields[1].GetUInt32(); + uint32 requiredRaces = fields[2].GetUInt32(); + if ((requiredClasses & bot->getClassMask()) && (requiredRaces & bot->getRaceMask())) + { + ids.push_back(questId); + } + } while (results->NextRow()); + + delete results; + + for (int i = 0; i < 15; i++) + { + for (list::iterator i = ids.begin(); i != ids.end(); ++i) + { + uint32 questId = *i; + Quest const *quest = sObjectMgr.GetQuestTemplate(questId); + + bot->SetQuestStatus(questId, QUEST_STATUS_NONE); + + if (!bot->SatisfyQuestClass(quest, false) || + !bot->SatisfyQuestRace(quest, false) || + !bot->SatisfyQuestStatus(quest, false)) + continue; + + if (quest->IsRepeatable()) + { + continue; + } + + bot->SetQuestStatus(questId, QUEST_STATUS_COMPLETE); + bot->RewardQuest(quest, 0, bot, false); + ClearInventory(); + } + } +} + +void PlayerbotFactory::ClearInventory() +{ + DestroyItemsVisitor visitor(bot); + IterateItems(&visitor); +} + +void PlayerbotFactory::InitAmmo() +{ + if (bot->getClass() != CLASS_HUNTER && bot->getClass() != CLASS_ROGUE && bot->getClass() != CLASS_WARRIOR) + { + return; + } + + Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED); + if (!pItem) + { + return; + } + + uint32 subClass = 0; + switch (pItem->GetProto()->SubClass) + { + case ITEM_SUBCLASS_WEAPON_GUN: + subClass = ITEM_SUBCLASS_BULLET; + break; + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + subClass = ITEM_SUBCLASS_ARROW; + break; + } + + if (!subClass) + { + return; + } + + QueryResult *results = WorldDatabase.PQuery("select max(`entry`), max(`RequiredLevel`) from `item_template` where `class` = '%u' and `subclass` = '%u' and `RequiredLevel` <= '%u'", + ITEM_CLASS_PROJECTILE, subClass, bot->getLevel()); + if (!results) + { + return; + } + + Field* fields = results->Fetch(); + if (fields) + { + uint32 entry = fields[0].GetUInt32(); + for (int i = 0; i < 5; i++) + { + Item* newItem = bot->StoreNewItemInInventorySlot(entry, 1000); + if (newItem) + { + newItem->AddToUpdateQueueOf(bot); + } + } + bot->SetAmmo(entry); + } + + delete results; +} + +void PlayerbotFactory::InitMounts() +{ + map > spells; + + for (uint32 spellId = 0; spellId < sSpellStore.GetNumRows(); ++spellId) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo || spellInfo->EffectApplyAuraName[0] != SPELL_AURA_MOUNTED) + { + continue; + } + + if (GetSpellCastTime(spellInfo) < 500 || GetSpellDuration(spellInfo) != -1) + { + continue; + } + + int32 effect = max(spellInfo->EffectBasePoints[1], spellInfo->EffectBasePoints[2]); + if (effect < 50) + { + continue; + } + + spells[effect].push_back(spellId); + } + + for (uint32 type = 0; type < 2; ++type) + { + for (map >::iterator i = spells.begin(); i != spells.end(); ++i) + { + int32 effect = i->first; + vector& ids = i->second; + uint32 index = urand(0, ids.size() - 1); + if (index >= ids.size()) + { + continue; + } + + bot->learnSpell(ids[index], false); + } + } +} + +void PlayerbotFactory::InitPotions() +{ + map > items; + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } + + if (proto->Class != ITEM_CLASS_CONSUMABLE || + proto->SubClass != ITEM_SUBCLASS_POTION || + proto->Spells[0].SpellCategory != 4 || + proto->Bonding != NO_BIND) + continue; + + if (proto->RequiredLevel > bot->getLevel() || proto->RequiredLevel < bot->getLevel() - 10) + { + continue; + } + + if (proto->RequiredSkill && !bot->HasSkill(proto->RequiredSkill)) + { + continue; + } + + if (proto->Area || proto->Map || proto->RequiredCityRank || proto->RequiredHonorRank) + { + continue; + } + + for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; j++) + { + const SpellEntry* const spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId); + if (!spellInfo) + { + continue; + } + + for (int i = 0 ; i < 3; i++) + { + if (spellInfo->Effect[i] == SPELL_EFFECT_HEAL || spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) + { + items[spellInfo->Effect[i]].push_back(itemId); + break; + } + } + } + } + + uint32 effects[] = { SPELL_EFFECT_HEAL, SPELL_EFFECT_ENERGIZE }; + for (int i = 0; i < sizeof(effects) / sizeof(uint32); ++i) + { + uint32 effect = effects[i]; + vector& ids = items[effect]; + uint32 index = urand(0, ids.size() - 1); + if (index >= ids.size()) + { + continue; + } + + uint32 itemId = ids[index]; + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + Item* newItem = bot->StoreNewItemInInventorySlot(itemId, urand(1, proto->GetMaxStackSize())); + if (newItem) + { + newItem->AddToUpdateQueueOf(bot); + } + } +} + +void PlayerbotFactory::InitFood() +{ + map > items; + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } + + if (proto->Class != ITEM_CLASS_CONSUMABLE || + proto->SubClass != ITEM_SUBCLASS_FOOD || + (proto->Spells[0].SpellCategory != 11 && proto->Spells[0].SpellCategory != 59) || + proto->Bonding != NO_BIND) + continue; + + if (proto->RequiredLevel > bot->getLevel() || proto->RequiredLevel < bot->getLevel() - 10) + { + continue; + } + + if (proto->RequiredSkill && !bot->HasSkill(proto->RequiredSkill)) + { + continue; + } + + if (proto->Area || proto->Map || proto->RequiredCityRank || proto->RequiredHonorRank) + { + continue; + } + + items[proto->Spells[0].SpellCategory].push_back(itemId); + } + + uint32 categories[] = { 11, 59 }; + for (int i = 0; i < sizeof(categories) / sizeof(uint32); ++i) + { + uint32 category = categories[i]; + vector& ids = items[category]; + uint32 index = urand(0, ids.size() - 1); + if (index >= ids.size()) + { + continue; + } + + uint32 itemId = ids[index]; + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + Item* newItem = bot->StoreNewItemInInventorySlot(itemId, urand(1, proto->GetMaxStackSize())); + if (newItem) + { + newItem->AddToUpdateQueueOf(bot); + } + } +} + + +void PlayerbotFactory::CancelAuras() +{ + bot->RemoveAllAuras(); +} + +void PlayerbotFactory::InitInventory() +{ + InitInventoryTrade(); + InitInventoryEquip(); + InitInventorySkill(); +} + +void PlayerbotFactory::InitInventorySkill() +{ + if (bot->HasSkill(SKILL_MINING)) { + { + StoreItem(2901, 1); // Mining Pick + } + } + /*if (bot->HasSkill(SKILL_JEWELCRAFTING)) { + StoreItem(20815, 1); // Jeweler's Kit + StoreItem(20824, 1); // Simple Grinder + }*/ + if (bot->HasSkill(SKILL_BLACKSMITHING) || bot->HasSkill(SKILL_ENGINEERING)) { + { + StoreItem(5956, 1); // Blacksmith Hammer + } + } + if (bot->HasSkill(SKILL_ENGINEERING)) { + { + StoreItem(6219, 1); // Arclight Spanner + } + } + if (bot->HasSkill(SKILL_ENCHANTING)) { + { + StoreItem(16207, 1); // Runed Arcanite Rod + } + } + /*if (bot->HasSkill(SKILL_INSCRIPTION)) { + StoreItem(39505, 1); // Virtuoso Inking Set + }*/ + if (bot->HasSkill(SKILL_SKINNING)) { + { + StoreItem(7005, 1); // Skinning Knife + } + } +} + +Item* PlayerbotFactory::StoreItem(uint32 itemId, uint32 count) +{ + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + Item* newItem = bot->StoreNewItemInInventorySlot(itemId, min(count, proto->GetMaxStackSize())); + if (newItem) + { + newItem->AddToUpdateQueueOf(bot); + } + + return newItem; +} + +void PlayerbotFactory::InitInventoryTrade() +{ + vector ids; + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } + + if (proto->Class != ITEM_CLASS_TRADE_GOODS || proto->Bonding != NO_BIND) + { + continue; + } + + if (proto->ItemLevel < bot->getLevel()) + { + continue; + } + + if (proto->RequiredLevel > bot->getLevel() || proto->RequiredLevel < bot->getLevel() - 10) + { + continue; + } + + if (proto->RequiredSkill && !bot->HasSkill(proto->RequiredSkill)) + { + continue; + } + + ids.push_back(itemId); + } + + if (ids.empty()) + { + sLog.outError("No trade items available for bot %s (%d level)", bot->GetName(), bot->getLevel()); + return; + } + + uint32 index = urand(0, ids.size() - 1); + if (index >= ids.size()) + { + return; + } + + uint32 itemId = ids[index]; + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + return; + } + + uint32 count = 1, stacks = 1; + switch (proto->Quality) + { + case ITEM_QUALITY_NORMAL: + count = proto->GetMaxStackSize(); + stacks = urand(1, 7) / auctionbot.GetRarityPriceMultiplier(proto); + break; + case ITEM_QUALITY_UNCOMMON: + stacks = 1; + count = urand(1, proto->GetMaxStackSize()); + break; + case ITEM_QUALITY_RARE: + stacks = 1; + count = urand(1, min(uint32(3), proto->GetMaxStackSize())); + break; + } + + for (uint32 i = 0; i < stacks; i++) + { + StoreItem(itemId, count); + } +} + +void PlayerbotFactory::InitInventoryEquip() +{ + vector ids; + + uint32 desiredQuality = itemQuality; + if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomGearLoweringChance && desiredQuality > ITEM_QUALITY_NORMAL) { + { + desiredQuality--; + } + } + + for (uint32 itemId = 0; itemId < sItemStorage.GetMaxEntry(); ++itemId) + { + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } + + if (proto->Class != ITEM_CLASS_ARMOR && proto->Class != ITEM_CLASS_WEAPON || (proto->Bonding == BIND_WHEN_PICKED_UP || + proto->Bonding == BIND_WHEN_USE)) + continue; + + if (proto->Class == ITEM_CLASS_ARMOR && !CanEquipArmor(proto)) + { + continue; + } + + if (proto->Class == ITEM_CLASS_WEAPON && !CanEquipWeapon(proto)) + { + continue; + } + + if (!CanEquipItem(proto, desiredQuality)) + { + continue; + } + + ids.push_back(itemId); + } + + int maxCount = urand(0, 3); + int count = 0; + for (int attempts = 0; attempts < 15; attempts++) + { + uint32 index = urand(0, ids.size() - 1); + if (index >= ids.size()) + { + continue; + } + + uint32 itemId = ids[index]; + if (StoreItem(itemId, 1) && count++ >= maxCount) + { + break; + } + } +} diff --git a/src/modules/Bots/playerbot/PlayerbotFactory.h b/src/modules/Bots/playerbot/PlayerbotFactory.h new file mode 100644 index 0000000000..a3e7644015 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotFactory.h @@ -0,0 +1,67 @@ +#pragma once + +#include "strategy/actions/InventoryAction.h" + +class Player; +class PlayerbotMgr; +class ChatHandler; + +using namespace std; +using ai::InventoryAction; + +class PlayerbotFactory : public InventoryAction +{ +public: + PlayerbotFactory(Player* bot, uint32 level, uint32 itemQuality = 0) : + bot(bot), level(level), itemQuality(itemQuality), InventoryAction(bot->GetPlayerbotAI(), "factory") {} + + static ObjectGuid GetRandomBot(); + void CleanRandomize(); + void Randomize(); + void Refresh(); + +private: + void Randomize(bool incremental); + void Prepare(); + void InitSecondEquipmentSet(); + void InitEquipment(bool incremental); + bool CanEquipItem(ItemPrototype const* proto, uint32 desiredQuality); + bool CanEquipUnseenItem(uint8 slot, uint16 &dest, uint32 item); + void InitSkills(); + void InitTradeSkills(); + void UpdateTradeSkills(); + void SetRandomSkill(uint16 id); + void InitSpells(); + void ClearSpells(); + void InitAvailableSpells(); + void InitSpecialSpells(); + void InitTalents(); + void InitTalents(uint32 specNo); + void InitQuests(); + void InitPet(); + void ClearInventory(); + void InitAmmo(); + void InitMounts(); + void InitPotions(); + void InitFood(); + bool CanEquipArmor(ItemPrototype const* proto); + bool CanEquipWeapon(ItemPrototype const* proto); + void EnchantItem(Item* item); + void AddItemStats(uint32 mod, uint8 &sp, uint8 &ap, uint8 &tank); + bool CheckItemStats(uint8 sp, uint8 ap, uint8 tank); + void CancelAuras(); + bool IsDesiredReplacement(Item* item); + void InitBags(); + void InitInventory(); + void InitInventoryTrade(); + void InitInventoryEquip(); + void InitInventorySkill(); + Item* StoreItem(uint32 itemId, uint32 count); + void InitGlyphs(); + +private: + Player* bot; + uint32 level; + uint32 itemQuality; + static uint32 tradeSkills[]; +}; diff --git a/src/modules/Bots/playerbot/PlayerbotMgr.cpp b/src/modules/Bots/playerbot/PlayerbotMgr.cpp new file mode 100644 index 0000000000..25c03dad31 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotMgr.cpp @@ -0,0 +1,490 @@ +#include "Config/Config.h" +#include "../botpch.h" +#include "playerbot.h" +#include "PlayerbotAIConfig.h" +#include "PlayerbotFactory.h" +#include "AccountMgr.h" +#include "RandomPlayerbotMgr.h" + + +class LoginQueryHolder; +class CharacterHandler; + +PlayerbotHolder::PlayerbotHolder() : PlayerbotAIBase() +{ + for (uint32 spellId = 0; spellId < sSpellStore.GetNumRows(); spellId++) + { + sSpellStore.LookupEntry(spellId); + } +} + +PlayerbotHolder::~PlayerbotHolder() +{ + LogoutAllBots(); +} + + +void PlayerbotHolder::UpdateAIInternal(uint32 elapsed) +{ +} + +void PlayerbotHolder::UpdateSessions(uint32 elapsed) +{ + for (PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); itr != GetPlayerBotsEnd(); ++itr) + { + Player* const bot = itr->second; + if (bot->IsBeingTeleported()) + { + bot->GetPlayerbotAI()->HandleTeleportAck(); + } + else if (bot->IsInWorld()) + { + bot->GetSession()->HandleBotPackets(); + } + } +} + +void PlayerbotHolder::LogoutAllBots() +{ + while (true) + { + PlayerBotMap::const_iterator itr = GetPlayerBotsBegin(); + if (itr == GetPlayerBotsEnd()) + { + break; + } + Player* bot= itr->second; + LogoutPlayerBot(bot->GetObjectGuid().GetRawValue()); + } +} + +void PlayerbotHolder::LogoutPlayerBot(uint64 guid) +{ + Player* bot = GetPlayerBot(guid); + if (bot) + { + bot->GetPlayerbotAI()->TellMaster("Goodbye!"); + //bot->SaveToDB(); + + WorldSession * botWorldSessionPtr = bot->GetSession(); + playerBots.erase(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap + botWorldSessionPtr->LogoutPlayer(true); // this will delete the bot Player object and PlayerbotAI object + delete botWorldSessionPtr; // finally delete the bot's WorldSession + } +} + +Player* PlayerbotHolder::GetPlayerBot(uint64 playerGuid) const +{ + PlayerBotMap::const_iterator it = playerBots.find(playerGuid); + return (it == playerBots.end()) ? 0 : it->second; +} + +void PlayerbotHolder::OnBotLogin(Player * const bot) +{ + PlayerbotAI* ai = new PlayerbotAI(bot); + bot->SetPlayerbotAI(ai); + OnBotLoginInternal(bot); + + playerBots[bot->GetObjectGuid().GetRawValue()] = bot; + + Player* master = ai->GetMaster(); + if (master) + { + ObjectGuid masterGuid = master->GetObjectGuid(); + if (master->GetGroup() && + ! master->GetGroup()->IsLeader(masterGuid)) + master->GetGroup()->ChangeLeader(masterGuid); + } + + Group *group = bot->GetGroup(); + if (group) + { + bool groupValid = false; + Group::MemberSlotList const& slots = group->GetMemberSlots(); + for (Group::MemberSlotList::const_iterator i = slots.begin(); i != slots.end(); ++i) + { + ObjectGuid member = i->guid; + uint32 account = sObjectMgr.GetPlayerAccountIdByGUID(member); + if (!sPlayerbotAIConfig.IsInRandomAccountList(account)) + { + groupValid = true; + break; + } + } + + if (!groupValid) + { + WorldPacket p; + string member = bot->GetName(); + p << uint32(PARTY_OP_LEAVE) << member << uint32(0); + bot->GetSession()->HandleGroupDisbandOpcode(p); + } + } + + ai->ResetStrategies(); + ai->TellMaster("Hello!"); +} + +bool PlayerbotHolder::ProcessBotCommand(string cmd, ObjectGuid guid, bool admin, uint32 masterAccountId) +{ + if (!sPlayerbotAIConfig.enabled || guid.IsEmpty()) + { + return false; + } + + bool isRandomBot = sRandomPlayerbotMgr.IsRandomBot(guid); + bool isRandomAccount = sPlayerbotAIConfig.IsInRandomAccountList(sObjectMgr.GetPlayerAccountIdByGUID(guid)); + + if (isRandomAccount && !isRandomBot && !admin) + { + return false; + } + + if (cmd == "add" || cmd == "login") + { + if (sObjectMgr.GetPlayer(guid)) + { + return false; + } + + AddPlayerBot(guid.GetRawValue(), masterAccountId); + return true; + } + else if (cmd == "remove" || cmd == "logout" || cmd == "rm") + { + if (!GetPlayerBot(guid.GetRawValue())) + { + return false; + } + + LogoutPlayerBot(guid.GetRawValue()); + return true; + } + + if (admin) + { + Player* bot = GetPlayerBot(guid.GetRawValue()); + if (!bot) + { + return false; + } + + Player* master = bot->GetPlayerbotAI()->GetMaster(); + if (master) + { + if (cmd == "init=white" || cmd == "init=common") + { + PlayerbotFactory factory(bot, master->getLevel(), ITEM_QUALITY_NORMAL); + factory.CleanRandomize(); + return true; + } + else if (cmd == "init=green" || cmd == "init=uncommon") + { + PlayerbotFactory factory(bot, master->getLevel(), ITEM_QUALITY_UNCOMMON); + factory.CleanRandomize(); + return true; + } + else if (cmd == "init=blue" || cmd == "init=rare") + { + PlayerbotFactory factory(bot, master->getLevel(), ITEM_QUALITY_RARE); + factory.CleanRandomize(); + return true; + } + else if (cmd == "init=epic" || cmd == "init=purple") + { + PlayerbotFactory factory(bot, master->getLevel(), ITEM_QUALITY_EPIC); + factory.CleanRandomize(); + return true; + } + } + + if (cmd == "update") + { + PlayerbotFactory factory(bot, bot->getLevel()); + factory.Refresh(); + return true; + } + else if (cmd == "random") + { + sRandomPlayerbotMgr.Randomize(bot); + return true; + } + } + + return false; +} + +bool ChatHandler::HandlePlayerbotCommand(char* args) +{ + if (!sPlayerbotAIConfig.enabled) + { + PSendSysMessage("|cffff0000Playerbot system is currently disabled!"); + SetSentErrorMessage(true); + return false; + } + + if (!m_session) + { + PSendSysMessage("You may only add bots from an active session"); + SetSentErrorMessage(true); + return false; + } + + Player* player = m_session->GetPlayer(); + PlayerbotMgr* mgr = player->GetPlayerbotMgr(); + if (!mgr) + { + PSendSysMessage("you cannot control bots yet"); + SetSentErrorMessage(true); + return false; + } + + list messages = mgr->HandlePlayerbotCommand(args, player); + if (messages.empty()) + { + return true; + } + + for (list::iterator i = messages.begin(); i != messages.end(); ++i) + { + PSendSysMessage(i->c_str()); + } + SetSentErrorMessage(true); + return false; +} + +list PlayerbotHolder::HandlePlayerbotCommand(char* args, Player* master) +{ + list messages; + + if (!*args) + { + messages.push_back("usage: add/init/remove PLAYERNAME"); + return messages; + } + + char *cmd = strtok ((char*)args, " "); + char *charname = strtok (NULL, " "); + if (!cmd || !charname) + { + messages.push_back("usage: add/init/remove PLAYERNAME"); + return messages; + } + + std::string cmdStr = cmd; + std::string charnameStr = charname; + + set bots; + if (charnameStr == "*" && master) + { + Group* group = master->GetGroup(); + if (!group) + { + messages.push_back("you must be in group"); + return messages; + } + + Group::MemberSlotList slots = group->GetMemberSlots(); + for (Group::member_citerator i = slots.begin(); i != slots.end(); i++) + { + ObjectGuid member = i->guid; + + if (member == master->GetObjectGuid()) + { + continue; + } + + string bot; + if (sObjectMgr.GetPlayerNameByGUID(member, bot)) + { + bots.insert(bot); + } + } + } + + if (charnameStr == "!" && master && master->GetSession()->GetSecurity() > SEC_GAMEMASTER) + { + for (PlayerBotMap::const_iterator i = GetPlayerBotsBegin(); i != GetPlayerBotsEnd(); ++i) + { + Player* bot = i->second; + if (bot && bot->IsInWorld()) + { + bots.insert(bot->GetName()); + } + } + } + + vector chars = split(charnameStr, ','); + for (vector::iterator i = chars.begin(); i != chars.end(); i++) + { + string s = *i; + + uint32 accountId = GetAccountId(s); + if (!accountId) + { + bots.insert(s); + continue; + } + + QueryResult* results = CharacterDatabase.PQuery( + "SELECT `name` FROM `characters` WHERE `account` = '%u'", + accountId); + if (results) + { + do + { + Field* fields = results->Fetch(); + string charName = fields[0].GetCppString(); + bots.insert(charName); + } while (results->NextRow()); + + delete results; + } + } + + for (set::iterator i = bots.begin(); i != bots.end(); ++i) + { + string bot = *i; + ostringstream out; + out << cmdStr << ": " << bot << " - "; + + ObjectGuid member = sObjectMgr.GetPlayerGuidByName(bot); + bool result = false; + if (master && member != master->GetObjectGuid()) + { + result = ProcessBotCommand(cmdStr, member, master->GetSession()->GetSecurity() >= SEC_GAMEMASTER, master->GetSession()->GetAccountId()); + } + else if (!master) + { + result = ProcessBotCommand(cmdStr, member, true, -1); + } + + out << (result ? "ok" : "not allowed"); + messages.push_back(out.str()); + } + + return messages; +} + +uint32 PlayerbotHolder::GetAccountId(string name) +{ + uint32 accountId = 0; + + QueryResult *results = LoginDatabase.PQuery("SELECT `id` FROM `account` WHERE `username` = '%s'", name.c_str()); + if(results) + { + Field* fields = results->Fetch(); + accountId = fields[0].GetUInt32(); + delete results; + } + + return accountId; +} + + + +PlayerbotMgr::PlayerbotMgr(Player* const master) : PlayerbotHolder(), master(master) +{ +} + +PlayerbotMgr::~PlayerbotMgr() +{ +} + +void PlayerbotMgr::UpdateAIInternal(uint32 elapsed) +{ + SetNextCheckDelay(sPlayerbotAIConfig.reactDelay); +} + +void PlayerbotMgr::HandleCommand(uint32 type, const string& text) +{ + Player *master = GetMaster(); + if (!master) + { + return; + } + + for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + bot->GetPlayerbotAI()->HandleCommand(type, text, *master); + } + + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + if (bot->GetPlayerbotAI()->GetMaster() == master) + { + bot->GetPlayerbotAI()->HandleCommand(type, text, *master); + } + } +} + +void PlayerbotMgr::HandleMasterIncomingPacket(const WorldPacket& packet) +{ + for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + bot->GetPlayerbotAI()->HandleMasterIncomingPacket(packet); + } + + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + if (bot->GetPlayerbotAI()->GetMaster() == GetMaster()) + { + bot->GetPlayerbotAI()->HandleMasterIncomingPacket(packet); + } + } + + switch (packet.GetOpcode()) + { + // if master is logging out, log out all bots + case CMSG_LOGOUT_REQUEST: + { + LogoutAllBots(); + return; + } + } +} +void PlayerbotMgr::HandleMasterOutgoingPacket(const WorldPacket& packet) +{ + for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + bot->GetPlayerbotAI()->HandleMasterOutgoingPacket(packet); + } + + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + if (bot->GetPlayerbotAI()->GetMaster() == GetMaster()) + { + bot->GetPlayerbotAI()->HandleMasterOutgoingPacket(packet); + } + } +} + +void PlayerbotMgr::SaveToDB() +{ + for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + bot->SaveToDB(); + } + for (PlayerBotMap::const_iterator it = sRandomPlayerbotMgr.GetPlayerBotsBegin(); it != sRandomPlayerbotMgr.GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + if (bot->GetPlayerbotAI()->GetMaster() == GetMaster()) + { + bot->SaveToDB(); + } + } +} + +void PlayerbotMgr::OnBotLoginInternal(Player * const bot) +{ + bot->GetPlayerbotAI()->SetMaster(master); + bot->GetPlayerbotAI()->ResetStrategies(); +} + diff --git a/src/modules/Bots/playerbot/PlayerbotMgr.h b/src/modules/Bots/playerbot/PlayerbotMgr.h new file mode 100644 index 0000000000..b6169c0956 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotMgr.h @@ -0,0 +1,67 @@ +#ifndef _PLAYERBOTMGR_H +#define _PLAYERBOTMGR_H + +#include "Common.h" +#include "PlayerbotAIBase.h" + +class WorldPacket; +class Player; +class Unit; +class Object; +class Item; + +typedef UNORDERED_MAP PlayerBotMap; + +class MANGOS_DLL_SPEC PlayerbotHolder : public PlayerbotAIBase +{ +public: + PlayerbotHolder(); + virtual ~PlayerbotHolder(); + + void AddPlayerBot(uint64 guid, uint32 masterAccountId); + void LogoutPlayerBot(uint64 guid); + Player* GetPlayerBot (uint64 guid) const; + PlayerBotMap::const_iterator GetPlayerBotsBegin() const { return playerBots.begin(); } + PlayerBotMap::const_iterator GetPlayerBotsEnd() const { return playerBots.end(); } + + virtual void UpdateAIInternal(uint32 elapsed); + void UpdateSessions(uint32 elapsed); + + void LogoutAllBots(); + void OnBotLogin(Player * const bot); + + list HandlePlayerbotCommand(char* args, Player* master = NULL); + bool ProcessBotCommand(string cmd, ObjectGuid guid, bool admin, uint32 masterAccountId); + uint32 GetAccountId(string name); + +protected: + virtual void OnBotLoginInternal(Player * const bot) = 0; + +protected: + PlayerBotMap playerBots; +}; + +class MANGOS_DLL_SPEC PlayerbotMgr : public PlayerbotHolder +{ +public: + PlayerbotMgr(Player* const master); + virtual ~PlayerbotMgr(); + + void HandleMasterIncomingPacket(const WorldPacket& packet); + void HandleMasterOutgoingPacket(const WorldPacket& packet); + void HandleCommand(uint32 type, const string& text); + + virtual void UpdateAIInternal(uint32 elapsed); + + Player* GetMaster() const { return master; }; + + void SaveToDB(); + +protected: + virtual void OnBotLoginInternal(Player * const bot); + +private: + Player* const master; +}; + +#endif diff --git a/src/modules/Bots/playerbot/PlayerbotSecurity.cpp b/src/modules/Bots/playerbot/PlayerbotSecurity.cpp new file mode 100644 index 0000000000..45816e931b --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotSecurity.cpp @@ -0,0 +1,205 @@ +#include "Config/Config.h" +#include "../botpch.h" +#include "PlayerbotMgr.h" +#include "playerbot.h" +#include "PlayerbotAIConfig.h" +#include "PlayerbotAI.h" +#include "ChatHelper.h" + +PlayerbotSecurity::PlayerbotSecurity(Player* const bot) : bot(bot) +{ + if (bot) + { + account = sObjectMgr.GetPlayerAccountIdByGUID(bot->GetObjectGuid()); + } +} + +PlayerbotSecurityLevel PlayerbotSecurity::LevelFor(Player* from, DenyReason* reason, bool ignoreGroup) +{ + if (from->GetSession()->GetSecurity() >= SEC_GAMEMASTER) + { + return PLAYERBOT_SECURITY_ALLOW_ALL; + } + + if (from->GetPlayerbotAI()) + { + if (reason) *reason = PLAYERBOT_DENY_IS_BOT; + { + return PLAYERBOT_SECURITY_DENY_ALL; + } + } + + if (bot->GetPlayerbotAI()->IsOpposing(from)) + { + if (reason) *reason = PLAYERBOT_DENY_OPPOSING; + { + return PLAYERBOT_SECURITY_DENY_ALL; + } + } + + if (sPlayerbotAIConfig.IsInRandomAccountList(account)) + { + if (bot->GetPlayerbotAI()->IsOpposing(from)) + { + if (reason) *reason = PLAYERBOT_DENY_OPPOSING; + { + return PLAYERBOT_SECURITY_DENY_ALL; + } + } + + Group* group = from->GetGroup(); + if (group) + { + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->getSource(); + if (player == bot && !ignoreGroup) + { + return PLAYERBOT_SECURITY_ALLOW_ALL; + } + } + } + + if ((int)bot->getLevel() - (int)from->getLevel() > 5) + { + if (reason) *reason = PLAYERBOT_DENY_LOW_LEVEL; + { + return PLAYERBOT_SECURITY_TALK; + } + } + + if (bot->GetMapId() != from->GetMapId() || bot->GetDistance(from) > sPlayerbotAIConfig.whisperDistance) + { + if (!bot->GetGuildId() || bot->GetGuildId() != from->GetGuildId()) + { + if (reason) *reason = PLAYERBOT_DENY_FAR; + { + return PLAYERBOT_SECURITY_TALK; + } + } + } + + if (bot->IsDead()) + { + if (reason) *reason = PLAYERBOT_DENY_DEAD; + { + return PLAYERBOT_SECURITY_TALK; + } + } + + group = bot->GetGroup(); + if (!group) + { + if (reason) *reason = PLAYERBOT_DENY_INVITE; + { + return PLAYERBOT_SECURITY_INVITE; + } + } + + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->getSource(); + if (player == from) + { + return PLAYERBOT_SECURITY_ALLOW_ALL; + } + } + + if (group->IsFull()) + { + if (reason) *reason = PLAYERBOT_DENY_FULL_GROUP; + { + return PLAYERBOT_SECURITY_TALK; + } + } + + if (reason) *reason = PLAYERBOT_DENY_INVITE; + { + return PLAYERBOT_SECURITY_INVITE; + } + } + + return PLAYERBOT_SECURITY_ALLOW_ALL; +} + +bool PlayerbotSecurity::CheckLevelFor(PlayerbotSecurityLevel level, bool silent, Player* from, bool ignoreGroup) +{ + DenyReason reason = PLAYERBOT_DENY_NONE; + PlayerbotSecurityLevel realLevel = LevelFor(from, &reason, ignoreGroup); + if (realLevel >= level) + { + return true; + } + + if (silent || from->GetPlayerbotAI()) + { + return false; + } + + Player* master = bot->GetPlayerbotAI()->GetMaster(); + if (master && bot->GetPlayerbotAI() && bot->GetPlayerbotAI()->IsOpposing(master) && master->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + return false; + } + + ostringstream out; + switch (realLevel) + { + case PLAYERBOT_SECURITY_DENY_ALL: + out << "I'm kind of busy now"; + break; + case PLAYERBOT_SECURITY_TALK: + switch (reason) + { + case PLAYERBOT_DENY_NONE: + out << "I'll do it later"; + break; + case PLAYERBOT_DENY_LOW_LEVEL: + out << "You are too low level: |cffff0000" << from->getLevel() << "|cffffffff/|cff00ff00" << bot->getLevel(); + break; + case PLAYERBOT_DENY_NOT_YOURS: + out << "I have a master already"; + break; + case PLAYERBOT_DENY_IS_BOT: + out << "You are a bot"; + break; + case PLAYERBOT_DENY_OPPOSING: + out << "You are the enemy"; + break; + case PLAYERBOT_DENY_DEAD: + out << "I'm dead. Will do it later"; + break; + case PLAYERBOT_DENY_INVITE: + out << "Invite me to your group first"; + break; + case PLAYERBOT_DENY_FAR: + { + out << "I am too far away"; + + uint32 area = bot->GetAreaId(); + if (area) + { + const AreaTableEntry* entry = sAreaStore.LookupEntry(area); + if (entry) + { + out << " |cffffffff(|cffff0000" << entry->area_name[0] << "|cffffffff)"; + } + } + } + break; + case PLAYERBOT_DENY_FULL_GROUP: + out << "I am in a full group. Will do it later"; + break; + default: + out << "I can't do that"; + break; + } + break; + case PLAYERBOT_SECURITY_INVITE: + out << "Invite me to your group first"; + break; + } + + bot->Whisper(out.str(), LANG_UNIVERSAL, from->GetObjectGuid()); + return false; +} diff --git a/src/modules/Bots/playerbot/PlayerbotSecurity.h b/src/modules/Bots/playerbot/PlayerbotSecurity.h new file mode 100644 index 0000000000..c28b1adc96 --- /dev/null +++ b/src/modules/Bots/playerbot/PlayerbotSecurity.h @@ -0,0 +1,42 @@ +#ifndef _PlayerbotSecurity_H +#define _PlayerbotSecurity_H + +using namespace std; + +enum PlayerbotSecurityLevel +{ + PLAYERBOT_SECURITY_DENY_ALL = 0, + PLAYERBOT_SECURITY_TALK = 1, + PLAYERBOT_SECURITY_INVITE = 2, + PLAYERBOT_SECURITY_ALLOW_ALL = 3 +}; + +enum DenyReason +{ + PLAYERBOT_DENY_NONE, + PLAYERBOT_DENY_LOW_LEVEL, + PLAYERBOT_DENY_GEARSCORE, + PLAYERBOT_DENY_NOT_YOURS, + PLAYERBOT_DENY_IS_BOT, + PLAYERBOT_DENY_OPPOSING, + PLAYERBOT_DENY_DEAD, + PLAYERBOT_DENY_FAR, + PLAYERBOT_DENY_INVITE, + PLAYERBOT_DENY_FULL_GROUP +}; + +class MANGOS_DLL_SPEC PlayerbotSecurity +{ + public: + PlayerbotSecurity(Player* const bot); + + public: + PlayerbotSecurityLevel LevelFor(Player* from, DenyReason* reason = NULL, bool ignoreGroup = false); + bool CheckLevelFor(PlayerbotSecurityLevel level, bool silent, Player* from, bool ignoreGroup = false); + + private: + Player* const bot; + uint32 account; +}; + +#endif diff --git a/src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp b/src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp new file mode 100644 index 0000000000..724cdbf590 --- /dev/null +++ b/src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp @@ -0,0 +1,144 @@ +#include "Config/Config.h" +#include "../botpch.h" +#include "playerbot.h" +#include "PlayerbotAIConfig.h" +#include "PlayerbotFactory.h" +#include "AccountMgr.h" +#include "ObjectMgr.h" +#include "Database/DatabaseEnv.h" +#include "PlayerbotAI.h" +#include "Player.h" +#include "RandomPlayerbotFactory.h" +#include "SystemConfig.h" + +map > RandomPlayerbotFactory::availableRaces; + +RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(accountId) +{ + availableRaces[CLASS_WARRIOR].push_back(RACE_HUMAN); + availableRaces[CLASS_WARRIOR].push_back(RACE_NIGHTELF); + availableRaces[CLASS_WARRIOR].push_back(RACE_GNOME); + availableRaces[CLASS_WARRIOR].push_back(RACE_DWARF); + availableRaces[CLASS_WARRIOR].push_back(RACE_ORC); + availableRaces[CLASS_WARRIOR].push_back(RACE_UNDEAD); + availableRaces[CLASS_WARRIOR].push_back(RACE_TAUREN); + availableRaces[CLASS_WARRIOR].push_back(RACE_TROLL); + + availableRaces[CLASS_PALADIN].push_back(RACE_HUMAN); + availableRaces[CLASS_PALADIN].push_back(RACE_DWARF); + + availableRaces[CLASS_ROGUE].push_back(RACE_HUMAN); + availableRaces[CLASS_ROGUE].push_back(RACE_DWARF); + availableRaces[CLASS_ROGUE].push_back(RACE_NIGHTELF); + availableRaces[CLASS_ROGUE].push_back(RACE_GNOME); + availableRaces[CLASS_ROGUE].push_back(RACE_ORC); + availableRaces[CLASS_ROGUE].push_back(RACE_TROLL); + + availableRaces[CLASS_PRIEST].push_back(RACE_HUMAN); + availableRaces[CLASS_PRIEST].push_back(RACE_DWARF); + availableRaces[CLASS_PRIEST].push_back(RACE_NIGHTELF); + availableRaces[CLASS_PRIEST].push_back(RACE_TROLL); + availableRaces[CLASS_PRIEST].push_back(RACE_UNDEAD); + + availableRaces[CLASS_MAGE].push_back(RACE_HUMAN); + availableRaces[CLASS_MAGE].push_back(RACE_GNOME); + availableRaces[CLASS_MAGE].push_back(RACE_UNDEAD); + availableRaces[CLASS_MAGE].push_back(RACE_TROLL); + + availableRaces[CLASS_WARLOCK].push_back(RACE_HUMAN); + availableRaces[CLASS_WARLOCK].push_back(RACE_GNOME); + availableRaces[CLASS_WARLOCK].push_back(RACE_UNDEAD); + availableRaces[CLASS_WARLOCK].push_back(RACE_ORC); + + availableRaces[CLASS_SHAMAN].push_back(RACE_ORC); + availableRaces[CLASS_SHAMAN].push_back(RACE_TAUREN); + availableRaces[CLASS_SHAMAN].push_back(RACE_TROLL); + + availableRaces[CLASS_HUNTER].push_back(RACE_DWARF); + availableRaces[CLASS_HUNTER].push_back(RACE_NIGHTELF); + availableRaces[CLASS_HUNTER].push_back(RACE_ORC); + availableRaces[CLASS_HUNTER].push_back(RACE_TAUREN); + availableRaces[CLASS_HUNTER].push_back(RACE_TROLL); + + availableRaces[CLASS_DRUID].push_back(RACE_NIGHTELF); + availableRaces[CLASS_DRUID].push_back(RACE_TAUREN); +} + +bool RandomPlayerbotFactory::CreateRandomBot(uint8 cls) +{ + sLog.outDetail("Creating new random bot for class %d", cls); + + uint8 gender = rand() % 2 ? GENDER_MALE : GENDER_FEMALE; + + uint8 race = availableRaces[cls][urand(0, availableRaces[cls].size() - 1)]; + string name = CreateRandomBotName(); + if (name.empty()) + { + return false; + } + + uint8 skin = urand(0, 7); + uint8 face = urand(0, 7); + uint8 hairStyle = urand(0, 7); + uint8 hairColor = urand(0, 7); + uint8 facialHair = urand(0, 7); + uint8 outfitId = 0; + + WorldSession* session = new WorldSession(accountId, NULL, SEC_PLAYER, 2, 0, LOCALE_enUS); + if (!session) + { + sLog.outError("Couldn't create session for random bot account %d", accountId); + delete session; + return false; + } + + Player *player = new Player(session); + if (!player->Create(sObjectMgr.GeneratePlayerLowGuid(), name, race, cls, gender, skin, face, hairStyle, hairColor, facialHair, outfitId)) + { + player->DeleteFromDB(player->GetObjectGuid(), accountId, true, true); + delete session; + delete player; + sLog.outError("Unable to create random bot for account %d - name: \"%s\"; race: %u; class: %u; gender: %u; skin: %u; face: %u; hairStyle: %u; hairColor: %u; facialHair: %u; outfitId: %u", + accountId, name.c_str(), race, cls, gender, skin, face, hairStyle, hairColor, facialHair, outfitId); + return false; + } + + player->setCinematic(2); + player->SetAtLoginFlag(AT_LOGIN_NONE); + player->SaveToDB(); + + sLog.outDetail("Random bot created for account %d - name: \"%s\"; race: %u; class: %u; gender: %u; skin: %u; face: %u; hairStyle: %u; hairColor: %u; facialHair: %u; outfitId: %u", + accountId, name.c_str(), race, cls, gender, skin, face, hairStyle, hairColor, facialHair, outfitId); + + return true; +} + +string RandomPlayerbotFactory::CreateRandomBotName() +{ + QueryResult *result = CharacterDatabase.Query("SELECT MAX(`name_id`) FROM `ai_playerbot_names`"); + if (!result) + { + return ""; + } + + Field *fields = result->Fetch(); + uint32 maxId = fields[0].GetUInt32(); + delete result; + + uint32 id = urand(0, maxId); + result = CharacterDatabase.PQuery("SELECT `n`.`name` FROM `ai_playerbot_names` n " + "LEFT OUTER JOIN `characters` e ON `e`.`name` = `n`.`name` " + "WHERE `e`.`guid` IS NULL AND `n`.`name_id` >= '%u' LIMIT 1", id); + if (!result) + { + sLog.outError("No more names left for random bots"); + return ""; + } + + Field *nfields = result->Fetch(); + string name = nfields[0].GetCppString(); + delete result; + + return name; +} + diff --git a/src/modules/Bots/playerbot/RandomPlayerbotFactory.h b/src/modules/Bots/playerbot/RandomPlayerbotFactory.h new file mode 100644 index 0000000000..2cc81d16e8 --- /dev/null +++ b/src/modules/Bots/playerbot/RandomPlayerbotFactory.h @@ -0,0 +1,32 @@ +#ifndef _RandomPlayerbotFactory_H +#define _RandomPlayerbotFactory_H + +#include "Common.h" +#include "PlayerbotAIBase.h" + +class WorldPacket; +class Player; +class Unit; +class Object; +class Item; + +using namespace std; + +class MANGOS_DLL_SPEC RandomPlayerbotFactory +{ + public: + RandomPlayerbotFactory(uint32 accountId); + virtual ~RandomPlayerbotFactory() {} + + public: + bool CreateRandomBot(uint8 cls); + + private: + string CreateRandomBotName(); + + private: + uint32 accountId; + static map > availableRaces; +}; + +#endif diff --git a/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp new file mode 100644 index 0000000000..82984536d8 --- /dev/null +++ b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp @@ -0,0 +1,966 @@ +#include "Config/Config.h" +#include "../botpch.h" +#include "playerbot.h" +#include "PlayerbotAIConfig.h" +#include "PlayerbotFactory.h" +#include "AccountMgr.h" +#include "ObjectMgr.h" +#include "Database/DatabaseEnv.h" +#include "PlayerbotAI.h" +#include "Player.h" +#include "AiFactory.h" + +INSTANTIATE_SINGLETON_1(RandomPlayerbotMgr); + +RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0) +{ +} + +RandomPlayerbotMgr::~RandomPlayerbotMgr() +{ +} + +void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed) +{ + SetNextCheckDelay(sPlayerbotAIConfig.randomBotUpdateInterval * 1000); + + if (!sPlayerbotAIConfig.randomBotAutologin || !sPlayerbotAIConfig.enabled) + { + return; + } + + sLog.outBasic("Processing random bots..."); + + int maxAllowedBotCount = GetEventValue(0, "bot_count"); + if (!maxAllowedBotCount) + { + maxAllowedBotCount = urand(sPlayerbotAIConfig.minRandomBots, sPlayerbotAIConfig.maxRandomBots); + SetEventValue(0, "bot_count", maxAllowedBotCount, + urand(sPlayerbotAIConfig.randomBotCountChangeMinInterval, sPlayerbotAIConfig.randomBotCountChangeMaxInterval)); + } + + list bots = GetBots(); + int botCount = bots.size(); + int allianceNewBots = 0, hordeNewBots = 0; + int randomBotsPerInterval = (int)urand(sPlayerbotAIConfig.minRandomBotsPerInterval, sPlayerbotAIConfig.maxRandomBotsPerInterval); + if (!processTicks) + { + if (sPlayerbotAIConfig.randomBotLoginAtStartup) + { + randomBotsPerInterval = bots.size(); + } + } + + while (botCount++ < maxAllowedBotCount) + { + bool alliance = botCount % 2; + uint32 bot = AddRandomBot(alliance); + if (bot) + { + if (alliance) + { + allianceNewBots++; + } + else + { + hordeNewBots++; + } + + bots.push_back(bot); + } + else + { + break; + } + } + + int botProcessed = 0; + for (list::iterator i = bots.begin(); i != bots.end(); ++i) + { + uint32 bot = *i; + if (ProcessBot(bot)) + { + botProcessed++; + } + + if (botProcessed >= randomBotsPerInterval) + { + break; + } + } + + sLog.outString("%d bots processed. %d alliance and %d horde bots added. %d bots online. Next check in %d seconds", + botProcessed, allianceNewBots, hordeNewBots, playerBots.size(), sPlayerbotAIConfig.randomBotUpdateInterval); + + if (processTicks++ == 1) + { + PrintStats(); + } +} + +uint32 RandomPlayerbotMgr::AddRandomBot(bool alliance) +{ + vector bots = GetFreeBots(alliance); + if (bots.size() == 0) + { + return 0; + } + + int index = urand(0, bots.size() - 1); + uint32 bot = bots[index]; + SetEventValue(bot, "add", 1, urand(sPlayerbotAIConfig.minRandomBotInWorldTime, sPlayerbotAIConfig.maxRandomBotInWorldTime)); + uint32 randomTime = 30 + urand(sPlayerbotAIConfig.randomBotUpdateInterval, sPlayerbotAIConfig.randomBotUpdateInterval * 3); + ScheduleRandomize(bot, randomTime); + sLog.outDetail("Random bot %d added", bot); + return bot; +} + +void RandomPlayerbotMgr::ScheduleRandomize(uint32 bot, uint32 time) +{ + SetEventValue(bot, "randomize", 1, time); + SetEventValue(bot, "logout", 1, time + 30 + urand(sPlayerbotAIConfig.randomBotUpdateInterval, sPlayerbotAIConfig.randomBotUpdateInterval * 3)); +} + +void RandomPlayerbotMgr::ScheduleTeleport(uint32 bot) +{ + SetEventValue(bot, "teleport", 1, 60 + urand(sPlayerbotAIConfig.randomBotUpdateInterval, sPlayerbotAIConfig.randomBotUpdateInterval * 3)); +} + +bool RandomPlayerbotMgr::ProcessBot(uint32 bot) +{ + uint32 isValid = GetEventValue(bot, "add"); + if (!isValid) + { + Player* player = GetPlayerBot(bot); + if (!player || !player->GetGroup()) + { + sLog.outDetail("Bot %d expired", bot); + SetEventValue(bot, "add", 0, 0); + } + return true; + } + + if (!GetPlayerBot(bot)) + { + sLog.outDetail("Bot %d logged in", bot); + AddPlayerBot(bot, 0); + if (!GetEventValue(bot, "online")) + { + SetEventValue(bot, "online", 1, sPlayerbotAIConfig.minRandomBotInWorldTime); + } + return true; + } + + Player* player = GetPlayerBot(bot); + if (!player) + { + return false; + } + + PlayerbotAI* ai = player->GetPlayerbotAI(); + if (!ai) + { + return false; + } + + if (player->GetGroup()) + { + sLog.outDetail("Skipping bot %d as it is in group", bot); + return false; + } + + if (player->IsDead()) + { + if (!GetEventValue(bot, "dead")) + { + sLog.outDetail("Setting dead flag for bot %d", bot); + uint32 randomTime = urand(sPlayerbotAIConfig.minRandomBotReviveTime, sPlayerbotAIConfig.maxRandomBotReviveTime); + SetEventValue(bot, "dead", 1, randomTime); + SetEventValue(bot, "revive", 1, randomTime - 60); + return false; + } + + if (!GetEventValue(bot, "revive")) + { + sLog.outDetail("Reviving dead bot %d", bot); + SetEventValue(bot, "dead", 0, 0); + SetEventValue(bot, "revive", 0, 0); + RandomTeleport(player, player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); + return true; + } + + return false; + } + + uint32 randomize = GetEventValue(bot, "randomize"); + if (!randomize) + { + sLog.outDetail("Randomizing bot %d", bot); + Randomize(player); + uint32 randomTime = urand(sPlayerbotAIConfig.minRandomBotRandomizeTime, sPlayerbotAIConfig.maxRandomBotRandomizeTime); + ScheduleRandomize(bot, randomTime); + return true; + } + + uint32 logout = GetEventValue(bot, "logout"); + if (!logout) + { + sLog.outDetail("Logging out bot %d", bot); + LogoutPlayerBot(bot); + SetEventValue(bot, "logout", 1, sPlayerbotAIConfig.maxRandomBotInWorldTime); + return true; + } + + uint32 teleport = GetEventValue(bot, "teleport"); + if (!teleport) + { + sLog.outDetail("Random teleporting bot %d", bot); + RandomTeleportForLevel(ai->GetBot()); + SetEventValue(bot, "teleport", 1, sPlayerbotAIConfig.maxRandomBotInWorldTime); + return true; + } + + return false; +} + +void RandomPlayerbotMgr::RandomTeleport(Player* bot, vector &locs) +{ + if (bot->IsBeingTeleported()) + { + return; + } + + if (locs.empty()) + { + sLog.outError("Cannot teleport bot %s - no locations available", bot->GetName()); + return; + } + + for (int attemtps = 0; attemtps < 10; ++attemtps) + { + int index = urand(0, locs.size() - 1); + WorldLocation loc = locs[index]; + float x = loc.coord_x + urand(0, sPlayerbotAIConfig.grindDistance) - sPlayerbotAIConfig.grindDistance / 2; + float y = loc.coord_y + urand(0, sPlayerbotAIConfig.grindDistance) - sPlayerbotAIConfig.grindDistance / 2; + float z = loc.coord_z; + + Map* map = sMapMgr.FindMap(loc.mapid); + if (!map) + { + continue; + } + + const TerrainInfo * terrain = map->GetTerrain(); + if (!terrain) + { + continue; + } + + AreaTableEntry const* area = sAreaStore.LookupEntry(terrain->GetAreaId(x, y, z)); + if (!area) + { + continue; + } + + if (!terrain->IsOutdoors(x, y, z) || + terrain->IsUnderWater(x, y, z) || + terrain->IsInWater(x, y, z)) + continue; + + sLog.outDetail("Random teleporting bot %s to %s %f,%f,%f", bot->GetName(), area->area_name[0], x, y, z); + float height = map->GetTerrain()->GetHeightStatic(x, y, 0.5f + z, true, MAX_HEIGHT); + if (height <= INVALID_HEIGHT) + { + continue; + } + + z = 0.05f + map->GetTerrain()->GetHeightStatic(x, y, 0.05f + z, true, MAX_HEIGHT); + + bot->GetMotionMaster()->Clear(); + bot->TeleportTo(loc.mapid, x, y, z, 0); + return; + } + + sLog.outError("Cannot teleport bot %s - no locations available", bot->GetName()); +} + +void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot) +{ + vector locs; + QueryResult* results = WorldDatabase.PQuery("SELECT `map`, `position_x`, `position_y`, `position_z` FROM (" + "SELECT MIN(`c`.`map`) `map`, MIN(`c`.`position_x`) `position_x`, MIN(`c`.`position_y`) `position_y`, " + "MIN(`c`.`position_z`) `position_z`, AVG(`t`.`maxlevel`), AVG(`t`.`minlevel`), " + "%u - (AVG(`t`.`maxlevel`) + AVG(`t`.`minlevel`)) / 2 `delta` FROM `creature` `c` " + "INNER JOIN `creature_template` `t` ON `c`.`id` = `t`.`entry` GROUP BY `t`.`entry`) `q` " + "WHERE `delta` >= 0 AND `delta` <= %u AND `map` IN (%s)", + + bot->getLevel(), sPlayerbotAIConfig.randomBotTeleLevel, sPlayerbotAIConfig.randomBotMapsAsString.c_str()); + if (results) + { + do + { + Field* fields = results->Fetch(); + uint32 mapId = fields[0].GetUInt32(); + float x = fields[1].GetFloat(); + float y = fields[2].GetFloat(); + float z = fields[3].GetFloat(); + WorldLocation loc(mapId, x, y, z, 0); + locs.push_back(loc); + } while (results->NextRow()); + delete results; + } + + RandomTeleport(bot, locs); +} + +void RandomPlayerbotMgr::RandomTeleport(Player* bot, uint32 mapId, float teleX, float teleY, float teleZ) +{ + vector locs; + QueryResult* results = WorldDatabase.PQuery("SELECT `position_x`, `position_y`, `position_z` FROM `creature` WHERE `map` = '%u' AND ABS(`position_x` - '%f') < '%u' AND ABS(`position_y` - '%f') < '%u'", + mapId, teleX, sPlayerbotAIConfig.randomBotTeleportDistance / 2, teleY, sPlayerbotAIConfig.randomBotTeleportDistance / 2); + if (results) + { + do + { + Field* fields = results->Fetch(); + float x = fields[0].GetFloat(); + float y = fields[1].GetFloat(); + float z = fields[2].GetFloat(); + WorldLocation loc(mapId, x, y, z, 0); + locs.push_back(loc); + } while (results->NextRow()); + delete results; + } + + RandomTeleport(bot, locs); + Refresh(bot); +} + +void RandomPlayerbotMgr::Randomize(Player* bot) +{ + if (bot->getLevel() == 1) + { + RandomizeFirst(bot); + } + else + { + IncreaseLevel(bot); + } +} + +void RandomPlayerbotMgr::IncreaseLevel(Player* bot) +{ + uint32 maxLevel = sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL); + uint32 level = min(bot->getLevel() + 1, maxLevel); + PlayerbotFactory factory(bot, level); + if (bot->GetGuildId()) + { + factory.Refresh(); + } + else + { + factory.Randomize(); + } + RandomTeleportForLevel(bot); +} + +void RandomPlayerbotMgr::RandomizeFirst(Player* bot) +{ + uint32 maxLevel = sPlayerbotAIConfig.randomBotMaxLevel; + if (maxLevel > sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)) + { + maxLevel = sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL); + } + + for (int attempt = 0; attempt < 100; ++attempt) + { + int index = urand(0, sPlayerbotAIConfig.randomBotMaps.size() - 1); + uint32 mapId = sPlayerbotAIConfig.randomBotMaps[index]; + + vector locs; + GameTeleMap const & teleMap = sObjectMgr.GetGameTeleMap(); + for(GameTeleMap::const_iterator itr = teleMap.begin(); itr != teleMap.end(); ++itr) + { + GameTele const* tele = &itr->second; + if (tele->mapId == mapId) + { + locs.push_back(tele); + } + } + + index = urand(0, locs.size() - 1); + if (index >= locs.size()) + { + return; + } + GameTele const* tele = locs[index]; + uint32 level = GetZoneLevel(tele->mapId, tele->position_x, tele->position_y, tele->position_z); + if (level > maxLevel + 5) + { + continue; + } + + level = min(level, maxLevel); + if (!level) level = 1; + + if (urand(0, 100) < 100 * sPlayerbotAIConfig.randomBotMaxLevelChance) + { + level = maxLevel; + } + + if (level < sPlayerbotAIConfig.randomBotMinLevel) + { + continue; + } + + PlayerbotFactory factory(bot, level); + factory.CleanRandomize(); + RandomTeleport(bot, tele->mapId, tele->position_x, tele->position_y, tele->position_z); + break; + } +} + +uint32 RandomPlayerbotMgr::GetZoneLevel(uint32 mapId, float teleX, float teleY, float teleZ) +{ + uint32 maxLevel = sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL); + + uint32 level; + QueryResult *results = WorldDatabase.PQuery("SELECT AVG(`t`.`minlevel`) `minlevel`, AVG(`t`.`maxlevel`) `maxlevel` FROM `creature` `c` " + "INNER JOIN `creature_template` `t` ON `c`.`id` = `t`.`entry` " + "WHERE `map` = '%u' AND `minlevel` > 1 AND ABS(`position_x` - '%f') < '%u' AND ABS(`position_y` - '%f') < '%u'", + mapId, teleX, sPlayerbotAIConfig.randomBotTeleportDistance / 2, teleY, sPlayerbotAIConfig.randomBotTeleportDistance / 2); + + if (results) + { + Field* fields = results->Fetch(); + uint32 minLevel = fields[0].GetUInt32(); + uint32 maxLevel = fields[1].GetUInt32(); + level = urand(minLevel, maxLevel); + if (level > maxLevel) + { + level = maxLevel; + } + delete results; + } + else + { + level = urand(1, maxLevel); + } + + return level; +} + +void RandomPlayerbotMgr::Refresh(Player* bot) +{ + if (bot->IsDead()) + { + PlayerbotChatHandler ch(bot); + ch.revive(*bot); + bot->GetPlayerbotAI()->ResetStrategies(); + } + + bot->GetPlayerbotAI()->Reset(); + + HostileReference *ref = bot->GetHostileRefManager().getFirst(); + while( ref ) + { + ThreatManager *threatManager = ref->getSource(); + Unit *unit = threatManager->getOwner(); + float threat = ref->getThreat(); + + unit->RemoveAllAttackers(); + unit->ClearInCombat(); + + ref = ref->next(); + } + + bot->RemoveAllAttackers(); + bot->ClearInCombat(); + + bot->DurabilityRepairAll(false, 1.0f, false); + bot->SetHealthPercent(100); + bot->SetPvP(true); + + if (bot->GetMaxPower(POWER_MANA) > 0) + { + bot->SetPower(POWER_MANA, bot->GetMaxPower(POWER_MANA)); + } + + if (bot->GetMaxPower(POWER_ENERGY) > 0) + { + bot->SetPower(POWER_ENERGY, bot->GetMaxPower(POWER_ENERGY)); + } +} + + +bool RandomPlayerbotMgr::IsRandomBot(Player* bot) +{ + return IsRandomBot(bot->GetObjectGuid()); +} + +bool RandomPlayerbotMgr::IsRandomBot(uint32 bot) +{ + return GetEventValue(bot, "add"); +} + +list RandomPlayerbotMgr::GetBots() +{ + list bots; + + QueryResult* results = CharacterDatabase.Query( + "SELECT `bot` FROM `ai_playerbot_random_bots` WHERE `owner` = 0 AND `event` = 'add'"); + + if (results) + { + do + { + Field* fields = results->Fetch(); + uint32 bot = fields[0].GetUInt32(); + bots.push_back(bot); + } while (results->NextRow()); + delete results; + } + + return bots; +} + +vector RandomPlayerbotMgr::GetFreeBots(bool alliance) +{ + set bots; + + QueryResult* results = CharacterDatabase.PQuery( + "SELECT `bot` FROM `ai_playerbot_random_bots` WHERE `event` = 'add'" + ); + + if (results) + { + do + { + Field* fields = results->Fetch(); + uint32 bot = fields[0].GetUInt32(); + bots.insert(bot); + } while (results->NextRow()); + delete results; + } + + vector guids; + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); i++) + { + uint32 accountId = *i; + if (!sAccountMgr.GetCharactersCount(accountId)) + { + continue; + } + + QueryResult *result = CharacterDatabase.PQuery("SELECT `guid`, `race` FROM `characters` WHERE `account` = '%u'", accountId); + if (!result) + { + continue; + } + + do + { + Field* fields = result->Fetch(); + uint32 guid = fields[0].GetUInt32(); + uint32 race = fields[1].GetUInt32(); + if (bots.find(guid) == bots.end() && + ((alliance && IsAlliance(race)) || ((!alliance && !IsAlliance(race)) + ))) + guids.push_back(guid); + } while (result->NextRow()); + delete result; + } + + + return guids; +} + +uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, string event) +{ + uint32 value = 0; + + QueryResult* results = CharacterDatabase.PQuery( + "SELECT `value`, `time`, `validIn` FROM `ai_playerbot_random_bots` WHERE `owner` = 0 AND `bot` = '%u' AND `event` = '%s'", + bot, event.c_str()); + + if (results) + { + Field* fields = results->Fetch(); + value = fields[0].GetUInt32(); + uint32 lastChangeTime = fields[1].GetUInt32(); + uint32 validIn = fields[2].GetUInt32(); + if ((time(0) - lastChangeTime) >= validIn) + { + value = 0; + } + delete results; + } + + return value; +} + +uint32 RandomPlayerbotMgr::SetEventValue(uint32 bot, string event, uint32 value, uint32 validIn) +{ + CharacterDatabase.PExecute("DELETE FROM `ai_playerbot_random_bots` WHERE `owner` = 0 and `bot` = '%u' and `event` = '%s'", + bot, event.c_str()); + if (value) + { + CharacterDatabase.PExecute( + "INSERT INTO `ai_playerbot_random_bots` (`owner`, `bot`, `time`, `validIn`, `event`, `value`) VALUES ('%u', '%u', '%u', '%u', '%s', '%u')", + 0, bot, (uint32)time(0), validIn, event.c_str(), value); + } + + return value; +} + +bool ChatHandler::HandlePlayerbotConsoleCommand(char* args) +{ + if (!sPlayerbotAIConfig.enabled) + { + PSendSysMessage("Playerbot system is currently disabled!"); + SetSentErrorMessage(true); + return false; + } + + if (!args || !*args) + { + sLog.outError("Usage: rndbot stats/update/reset/init/refresh/add/remove"); + return false; + } + + string cmd = args; + + if (cmd == "reset") + { + CharacterDatabase.PExecute("DELETE FROM `ai_playerbot_random_bots`"); + sLog.outBasic("Random bots were reset for all players"); + return true; + } + else if (cmd == "stats") + { + sRandomPlayerbotMgr.PrintStats(); + return true; + } + else if (cmd == "update") + { + sRandomPlayerbotMgr.UpdateAIInternal(0); + return true; + } + else if (cmd == "init" || cmd == "refresh") + { + sLog.outString("Randomizing bots for %d accounts", sPlayerbotAIConfig.randomBotAccounts.size()); + BarGoLink bar(sPlayerbotAIConfig.randomBotAccounts.size()); + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); ++i) + { + uint32 account = *i; + bar.step(); + if (QueryResult *results = CharacterDatabase.PQuery("SELECT `guid` FROM `characters` where `account` = '%u'", account)) + { + do + { + Field* fields = results->Fetch(); + ObjectGuid guid = ObjectGuid(fields[0].GetUInt64()); + Player* bot = sObjectMgr.GetPlayer(guid, true); + if (!bot) + { + continue; + } + + if (cmd == "init") + { + sLog.outDetail("Randomizing bot %s for account %u", bot->GetName(), account); + sRandomPlayerbotMgr.RandomizeFirst(bot); + } + else + { + sLog.outDetail("Refreshing bot %s for account %u", bot->GetName(), account); + bot->SetLevel(bot->getLevel() - 1); + sRandomPlayerbotMgr.IncreaseLevel(bot); + } + uint32 randomTime = urand(sPlayerbotAIConfig.minRandomBotRandomizeTime, sPlayerbotAIConfig.maxRandomBotRandomizeTime); + CharacterDatabase.PExecute("UPDATE `ai_playerbot_random_bots` SET `validIn` = '%u' WHERE `event` = 'randomize' AND `bot` = '%u'", + randomTime, bot->GetGUIDLow()); + CharacterDatabase.PExecute("UPDATE `ai_playerbot_random_bots` SET `validIn` = '%u' WHERE `event` = 'logout' AND `bot` = '%u'", + sPlayerbotAIConfig.maxRandomBotInWorldTime, bot->GetGUIDLow()); + } while (results->NextRow()); + + delete results; + } + } + return true; + } + else + { + list messages = sRandomPlayerbotMgr.HandlePlayerbotCommand(args, NULL); + for (list::iterator i = messages.begin(); i != messages.end(); ++i) + { + sLog.outString(i->c_str()); + } + return true; + } + + return false; +} + +void RandomPlayerbotMgr::HandleCommand(uint32 type, const string& text, Player& fromPlayer) +{ + for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + bot->GetPlayerbotAI()->HandleCommand(type, text, fromPlayer); + } +} + +void RandomPlayerbotMgr::OnPlayerLogout(Player* player) +{ + for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + PlayerbotAI* ai = bot->GetPlayerbotAI(); + if (player == ai->GetMaster()) + { + ai->SetMaster(NULL); + ai->ResetStrategies(); + } + } + + if (!player->GetPlayerbotAI()) + { + vector::iterator i = find(players.begin(), players.end(), player); + if (i != players.end()) + { + players.erase(i); + } + } +} + +void RandomPlayerbotMgr::OnPlayerLogin(Player* player) +{ + for (PlayerBotMap::const_iterator it = GetPlayerBotsBegin(); it != GetPlayerBotsEnd(); ++it) + { + Player* const bot = it->second; + if (player == bot || player->GetPlayerbotAI()) + { + continue; + } + + Group* group = bot->GetGroup(); + if (!group) + { + continue; + } + + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->getSource(); + PlayerbotAI* ai = bot->GetPlayerbotAI(); + if (member == player && (!ai->GetMaster() || ai->GetMaster()->GetPlayerbotAI())) + { + ai->SetMaster(player); + ai->ResetStrategies(); + ai->TellMaster("Hello"); + break; + } + } + } + + if (!player->GetPlayerbotAI()) + { + players.push_back(player); + } +} + +Player* RandomPlayerbotMgr::GetRandomPlayer() +{ + if (players.empty()) + { + return NULL; + } + + uint32 index = urand(0, players.size() - 1); + return players[index]; +} + +void RandomPlayerbotMgr::PrintStats() +{ + sLog.outString("%d Random Bots online", playerBots.size()); + + map alliance, horde; + for (uint32 i = 0; i < 10; ++i) + { + alliance[i] = 0; + horde[i] = 0; + } + + map perRace, perClass; + for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race) + { + perRace[race] = 0; + } + for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES; ++cls) + { + perClass[cls] = 0; + } + + int dps = 0, heal = 0, tank = 0; + for (PlayerBotMap::iterator i = playerBots.begin(); i != playerBots.end(); ++i) + { + Player* bot = i->second; + if (IsAlliance(bot->getRace())) + { + alliance[bot->getLevel() / 10]++; + } + else + { + horde[bot->getLevel() / 10]++; + } + + perRace[bot->getRace()]++; + perClass[bot->getClass()]++; + + int spec = AiFactory::GetPlayerSpecTab(bot); + switch (bot->getClass()) + { + case CLASS_DRUID: + if (spec == 2) + { + heal++; + } + else + { + dps++; + } + break; + case CLASS_PALADIN: + if (spec == 1) + { + tank++; + } + else if (spec == 0) + { + heal++; + } + else + { + dps++; + } + break; + case CLASS_PRIEST: + if (spec != 2) + { + heal++; + } + else + { + dps++; + } + break; + case CLASS_SHAMAN: + if (spec == 2) + { + heal++; + } + else + { + dps++; + } + break; + case CLASS_WARRIOR: + if (spec == 2) + { + tank++; + } + else + { + dps++; + } + break; + default: + dps++; + break; + } + } + + sLog.outString("Per level:"); + uint32 maxLevel = sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL); + for (uint32 i = 0; i < 10; ++i) + { + if (!alliance[i] && !horde[i]) + { + continue; + } + + uint32 from = i*10; + uint32 to = min(from + 9, maxLevel); + if (!from) from = 1; + { + sLog.outString(" %d..%d: %d alliance, %d horde", from, to, alliance[i], horde[i]); + } + } + sLog.outString("Per race:"); + for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race) + { + if (perRace[race]) + { + sLog.outString(" %s: %d", ChatHelper::formatRace(race).c_str(), perRace[race]); + } + } + sLog.outString("Per class:"); + for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES; ++cls) + { + if (perClass[cls]) + { + sLog.outString(" %s: %d", ChatHelper::formatClass(cls).c_str(), perClass[cls]); + } + } + sLog.outString("Per role:"); + sLog.outString(" tank: %d", tank); + sLog.outString(" heal: %d", heal); + sLog.outString(" dps: %d", dps); +} + +double RandomPlayerbotMgr::GetBuyMultiplier(Player* bot) +{ + uint32 id = bot->GetObjectGuid(); + uint32 value = GetEventValue(id, "buymultiplier"); + if (!value) + { + value = urand(1, 120); + uint32 validIn = urand(sPlayerbotAIConfig.minRandomBotsPriceChangeInterval, sPlayerbotAIConfig.maxRandomBotsPriceChangeInterval); + SetEventValue(id, "buymultiplier", value, validIn); + } + + return (double)value / 100.0; +} + +double RandomPlayerbotMgr::GetSellMultiplier(Player* bot) +{ + uint32 id = bot->GetObjectGuid(); + uint32 value = GetEventValue(id, "sellmultiplier"); + if (!value) + { + value = urand(80, 250); + uint32 validIn = urand(sPlayerbotAIConfig.minRandomBotsPriceChangeInterval, sPlayerbotAIConfig.maxRandomBotsPriceChangeInterval); + SetEventValue(id, "sellmultiplier", value, validIn); + } + + return (double)value / 100.0; +} + +uint32 RandomPlayerbotMgr::GetLootAmount(Player* bot) +{ + uint32 id = bot->GetObjectGuid(); + return GetEventValue(id, "lootamount"); +} + +void RandomPlayerbotMgr::SetLootAmount(Player* bot, uint32 value) +{ + uint32 id = bot->GetObjectGuid(); + SetEventValue(id, "lootamount", value, 24 * 3600); +} + +uint32 RandomPlayerbotMgr::GetTradeDiscount(Player* bot) +{ + Group* group = bot->GetGroup(); + return GetLootAmount(bot) / (group ? group->GetMembersCount() : 10); +} diff --git a/src/modules/Bots/playerbot/RandomPlayerbotMgr.h b/src/modules/Bots/playerbot/RandomPlayerbotMgr.h new file mode 100644 index 0000000000..818cb94576 --- /dev/null +++ b/src/modules/Bots/playerbot/RandomPlayerbotMgr.h @@ -0,0 +1,66 @@ +#ifndef _RandomPlayerbotMgr_H +#define _RandomPlayerbotMgr_H + +#include "Common.h" +#include "PlayerbotAIBase.h" +#include "PlayerbotMgr.h" + +class WorldPacket; +class Player; +class Unit; +class Object; +class Item; + +using namespace std; + +class MANGOS_DLL_SPEC RandomPlayerbotMgr : public PlayerbotHolder +{ + public: + RandomPlayerbotMgr(); + virtual ~RandomPlayerbotMgr(); + + virtual void UpdateAIInternal(uint32 elapsed); + + public: + bool IsRandomBot(Player* bot); + bool IsRandomBot(uint32 bot); + void Randomize(Player* bot); + void RandomizeFirst(Player* bot); + void IncreaseLevel(Player* bot); + void ScheduleTeleport(uint32 bot); + void HandleCommand(uint32 type, const string& text, Player& fromPlayer); + void OnPlayerLogout(Player* player); + void OnPlayerLogin(Player* player); + Player* GetRandomPlayer(); + void PrintStats(); + double GetBuyMultiplier(Player* bot); + double GetSellMultiplier(Player* bot); + uint32 GetLootAmount(Player* bot); + void SetLootAmount(Player* bot, uint32 value); + uint32 GetTradeDiscount(Player* bot); + void Refresh(Player* bot); + + protected: + virtual void OnBotLoginInternal(Player * const bot) {} + + private: + uint32 GetEventValue(uint32 bot, string event); + uint32 SetEventValue(uint32 bot, string event, uint32 value, uint32 validIn); + list GetBots(); + vector GetFreeBots(bool alliance); + uint32 AddRandomBot(bool alliance); + bool ProcessBot(uint32 bot); + void ScheduleRandomize(uint32 bot, uint32 time); + void RandomTeleport(Player* bot, uint32 mapId, float teleX, float teleY, float teleZ); + void RandomTeleportForLevel(Player* bot); + void RandomTeleport(Player* bot, vector &locs); + uint32 GetZoneLevel(uint32 mapId, float teleX, float teleY, float teleZ); + + private: + vector players; + int processTicks; +}; + +#define sRandomPlayerbotMgr MaNGOS::Singleton::Instance() + +#endif diff --git a/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in b/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in new file mode 100644 index 0000000000..a4191acfe4 --- /dev/null +++ b/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in @@ -0,0 +1,164 @@ +########################################## +# MANGOS Ai Playerbot Configuration file # +########################################## + +[AiPlayerbotConf] +ConfVersion=2010102201 + +# Enable or disable AI Playerbot +AiPlayerbot.Enabled = 1 + +# Warrior +AiPlayerbot.RandomClassSpecProbability.1.0 = 20 +AiPlayerbot.RandomClassSpecProbability.1.1 = 30 +AiPlayerbot.RandomClassSpecProbability.1.2 = 50 +# Paladin +AiPlayerbot.RandomClassSpecProbability.2.0 = 20 +AiPlayerbot.RandomClassSpecProbability.2.1 = 50 +AiPlayerbot.RandomClassSpecProbability.2.2 = 30 +# Hunter +AiPlayerbot.RandomClassSpecProbability.3.0 = 25 +AiPlayerbot.RandomClassSpecProbability.3.1 = 50 +AiPlayerbot.RandomClassSpecProbability.3.2 = 25 +# Rogue +AiPlayerbot.RandomClassSpecProbability.4.0 = 40 +AiPlayerbot.RandomClassSpecProbability.4.1 = 50 +AiPlayerbot.RandomClassSpecProbability.4.2 = 10 +# Priest +AiPlayerbot.RandomClassSpecProbability.5.0 = 40 +AiPlayerbot.RandomClassSpecProbability.5.1 = 40 +AiPlayerbot.RandomClassSpecProbability.5.2 = 20 +# Shaman +AiPlayerbot.RandomClassSpecProbability.7.0 = 10 +AiPlayerbot.RandomClassSpecProbability.7.1 = 45 +AiPlayerbot.RandomClassSpecProbability.7.2 = 45 +# Mage +AiPlayerbot.RandomClassSpecProbability.8.0 = 20 +AiPlayerbot.RandomClassSpecProbability.8.1 = 10 +AiPlayerbot.RandomClassSpecProbability.8.2 = 70 +# Warlock +AiPlayerbot.RandomClassSpecProbability.9.0 = 33 +AiPlayerbot.RandomClassSpecProbability.9.1 = 33 +AiPlayerbot.RandomClassSpecProbability.9.2 = 33 +# Druid +AiPlayerbot.RandomClassSpecProbability.11.0 = 10 +AiPlayerbot.RandomClassSpecProbability.11.1 = 45 +AiPlayerbot.RandomClassSpecProbability.11.2 = 45 + +# +# All other parameters are optional but can be changed by uncommenting them here +# + +# Prefix for bot chat commands (e.g. follow, stay) +AiPlayerbot.CommandPrefix = ~ + +# Max AI iterations per tick +#AiPlayerbot.IterationsPerTick = 10 + +# Allow/deny bots from your guild +#AiPlayerbot.AllowGuildBots = 1 + +# Delay between two short-time spells cast +#AiPlayerbot.GlobalCooldown = 500 + +# Max wait time when moving +#AiPlayerbot.MaxWaitForMove = 5000 + +# Delay between two bot actions +#AiPlayerbot.ReactDelay = 100 + +# Distances +#AiPlayerbot.SightDistance = 50.0 +#AiPlayerbot.SpellDistance = 30.0 +#AiPlayerbot.ReactDistance = 150.0 +#AiPlayerbot.GrindDistance = 100.0 +#AiPlayerbot.LootDistance = 20.0 +#AiPlayerbot.FleeDistance = 20.0 +#AiPlayerbot.TooCloseDistance = 7.0 +#AiPlayerbot.MeleeDistance = 1.0 +#AiPlayerbot.FollowDistance = 1.5 +#AiPlayerbot.WhisperDistance = 6000.0 +#AiPlayerbot.ContactDistance = 0.5 + +# Bot can flee for enemy +#AiPlayerbot.FleeingEnabled = 1 + +# Health/Mana levels +#AiPlayerbot.CriticalHealth = 25 +#AiPlayerbot.LowHealth = 45 +#AiPlayerbot.MediumHealth = 65 +#AiPlayerbot.AlmostFullHealth = 85 +#AiPlayerbot.LowMana = 15 +#AiPlayerbot.MediumMana = 40 + +# Enable random bot system +#AiPlayerbot.RandomBotAutologin = 1 + +# Random bot default strategies (applied after defaults) +#AiPlayerbot.RandomBotCombatStrategies = +dps,+attack weak +#AiPlayerbot.RandomBotNonCombatStrategies = +grind,+move random,+loot + +# Create random bot characters automatically +#AiPlayerbot.RandomBotAutoCreate = 1 + +# Random bot count +#AiPlayerbot.MinRandomBots = 50 +#AiPlayerbot.MaxRandomBots = 200 +#AiPlayerbot.RandomBotMinLevel = 1 +#AiPlayerbot.RandomBotMaxLevel = 255 (ignored if more than MaxPlayerLevel mangosd.conf value) + +# Accounts to create for random bots +#AiPlayerbot.RandomBotAccountPrefix = rndbot +#AiPlayerbot.RandomBotAccountCount = 50 + +# Delete all random bot accounts +#AiPlayerbot.DeleteRandomBotAccounts = 0 + +# Maps to teleport random bots +#AiPlayerbot.RandomBotMaps = 0,1,530,571 + +# Change random bot has lower gear +#AiPlayerbot.RandomGearLoweringChance = 0.15 + +# Chance random bot has max level on first randomize +#AiPlayerbot.RandomBotMaxLevelChance = 0.4 + +# Quest items to leave (do not destroy) +#AiPlayerbot.RandomBotQuestItems = 6948,5175,5176,5177,5178 + +# Spells every random bot will learn on randomize (54197 - cold weather flying) +#AiPlayerbot.RandomBotSpellIds = 54197 + +# Enable LFG for random bots +#AiPlayerbot.RandomBotJoinLfg = 1 + +# Level diff between random bots and nearby creatures for random teleports +AiPlayerbot.RandomBotTeleLevel = 3 + +# Intervals +#AiPlayerbot.RandomBotUpdateInterval = 60 +#AiPlayerbot.RandomBotCountChangeMinInterval = 86400 +#AiPlayerbot.RandomBotCountChangeMaxInterval = 259200 +#AiPlayerbot.MinRandomBotInWorldTime = 7200 +#AiPlayerbot.MaxRandomBotInWorldTime = 1209600 +#AiPlayerbot.MinRandomBotRandomizeTime = 7200 +#AiPlayerbot.MaxRandomRandomizeTime = 1209600 +#AiPlayerbot.MinRandomBotsPerInterval = 50 +#AiPlayerbot.MaxRandomBotsPerInterval = 100 +#AiPlayerbot.MinRandomBotsPriceChangeInterval = 7200 +#AiPlayerbot.MaxRandomBotsPriceChangeInterval = 172800 + +# Log on all random bots on start +#AiPlayerbot.RandomBotLoginAtStartup = 1 + +# How far random bots are teleported after death +#AiPlayerbot.RandomBotTeleportDistance = 1000 + +# Debug switches +#AiPlayerbot.SpellDump = 0 +#AiPlayerbot.LogInGroupOnly = 1 +#AiPlayerbot.LogValuesPerTick = 0 +#AiPlayerbot.RandomChangeMultiplier = 1 + +# Command server port, 0 - disabled +#AiPlayerbot.CommandServerPort = 8888 diff --git a/src/modules/Bots/playerbot/playerbot.h b/src/modules/Bots/playerbot/playerbot.h new file mode 100644 index 0000000000..449e5a7aff --- /dev/null +++ b/src/modules/Bots/playerbot/playerbot.h @@ -0,0 +1,28 @@ +#pragma once + +std::vector split(const std::string &s, char delim); +#ifndef WIN32 +int strcmpi(std::string s1, std::string s2); +#endif + +#include "Spell.h" +#include "WorldPacket.h" +#include "LootMgr.h" +#include "GossipDef.h" +#include "Chat.h" +#include "Common.h" +#include "World.h" +#include "SpellMgr.h" +#include "ObjectMgr.h" +#include "Unit.h" +#include "SharedDefines.h" +#include "MotionMaster.h" +#include "SpellAuras.h" +#include "Guild.h" + +#include "playerbotDefs.h" +#include "PlayerbotAIAware.h" +#include "PlayerbotMgr.h" +#include "RandomPlayerbotMgr.h" +#include "ChatHelper.h" +#include "PlayerbotAI.h" diff --git a/src/modules/Bots/playerbot/playerbotDefs.h b/src/modules/Bots/playerbot/playerbotDefs.h new file mode 100644 index 0000000000..3f59c932d3 --- /dev/null +++ b/src/modules/Bots/playerbot/playerbotDefs.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/src/modules/Bots/playerbot/strategy/Action.cpp b/src/modules/Bots/playerbot/strategy/Action.cpp new file mode 100644 index 0000000000..c601ec150e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Action.cpp @@ -0,0 +1,111 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "AiObjectContext.h" +#include "Action.h" + +using namespace ai; + +int NextAction::size(NextAction** actions) +{ + if (!actions) + { + return 0; + } + + int size; + for (size=0; size<10 && actions[size]; ) + { + size++; + } + return size; +} + +NextAction** NextAction::clone(NextAction** actions) +{ + if (!actions) + { + return NULL; + } + + int size = NextAction::size(actions); + + NextAction** res = new NextAction*[size + 1]; + for (int i=0; i* Action::GetTargetValue() +{ + return context->GetValue(GetTargetName()); +} + +Unit* Action::GetTarget() +{ + return GetTargetValue()->Get(); +} diff --git a/src/modules/Bots/playerbot/strategy/Action.h b/src/modules/Bots/playerbot/strategy/Action.h new file mode 100644 index 0000000000..84213a9784 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Action.h @@ -0,0 +1,138 @@ +#pragma once +#include "Event.h" +#include "Value.h" +#include "AiObject.h" + +namespace ai +{ + class NextAction + { + public: + NextAction(string name, float relevance = 0.0f) + { + this->name = name; + this->relevance = relevance; + } + NextAction(const NextAction& o) + { + this->name = o.name; + this->relevance = o.relevance; + } + + public: + string getName() { return name; } + float getRelevance() {return relevance;} + + public: + static int size(NextAction** actions); + static NextAction** clone(NextAction** actions); + static NextAction** merge(NextAction** what, NextAction** with); + static NextAction** array(uint8 _nil,...); + static void destroy(NextAction** actions); + + private: + float relevance; + std::string name; + }; + + //--------------------------------------------------------------------------------------------------------------------- + + class ActionBasket; + + enum ActionThreatType + { + ACTION_THREAT_NONE = 0, + ACTION_THREAT_SINGLE= 1, + ACTION_THREAT_AOE = 2 + }; + + class Action : public AiNamedObject + { + public: + Action(PlayerbotAI* ai, string name = "action") : verbose(false), AiNamedObject(ai, name) { } + virtual ~Action(void) {} + + public: + virtual bool Execute(Event event) { return true; } + virtual bool isPossible() { return true; } + virtual bool isUseful() { return true; } + virtual NextAction** getPrerequisites() { return NULL; } + virtual NextAction** getAlternatives() { return NULL; } + virtual NextAction** getContinuers() { return NULL; } + virtual ActionThreatType getThreatType() { return ACTION_THREAT_NONE; } + void Update() {} + void Reset() {} + virtual Unit* GetTarget(); + virtual Value* GetTargetValue(); + virtual string GetTargetName() { return "self target"; } + void MakeVerbose() { verbose = true; } + + protected: + bool verbose; + }; + + class ActionNode + { + public: + ActionNode(string name, NextAction** prerequisites = NULL, NextAction** alternatives = NULL, NextAction** continuers = NULL) + { + this->action = NULL; + this->name = name; + this->prerequisites = prerequisites; + this->alternatives = alternatives; + this->continuers = continuers; + } + virtual ~ActionNode() + { + NextAction::destroy(prerequisites); + NextAction::destroy(alternatives); + NextAction::destroy(continuers); + } + + public: + Action* getAction() { return action; } + void setAction(Action* action) { this->action = action; } + string getName() { return name; } + + public: + NextAction** getContinuers() { return NextAction::merge(NextAction::clone(continuers), action->getContinuers()); } + NextAction** getAlternatives() { return NextAction::merge(NextAction::clone(alternatives), action->getAlternatives()); } + NextAction** getPrerequisites() { return NextAction::merge(NextAction::clone(prerequisites), action->getPrerequisites()); } + + private: + string name; + Action* action; + NextAction** continuers; + NextAction** alternatives; + NextAction** prerequisites; + }; + + //--------------------------------------------------------------------------------------------------------------------- + + class ActionBasket + { + public: + ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, Event event) : + action(action), relevance(relevance), skipPrerequisites(skipPrerequisites), event(event) {} + virtual ~ActionBasket(void) {} + public: + float getRelevance() {return relevance;} + ActionNode* getAction() {return action;} + Event getEvent() { return event; } + bool isSkipPrerequisites() { return skipPrerequisites; } + void AmendRelevance(float k) {relevance *= k; } + void setRelevance(float relevance) { this->relevance = relevance; } + private: + ActionNode* action; + float relevance; + bool skipPrerequisites; + Event event; + }; + + //--------------------------------------------------------------------------------------------------------------------- + + +} + +#define AI_VALUE(type, name) context->GetValue(name)->Get() +#define AI_VALUE2(type, name, param) context->GetValue(name, param)->Get() diff --git a/src/modules/Bots/playerbot/strategy/ActionBasket.cpp b/src/modules/Bots/playerbot/strategy/ActionBasket.cpp new file mode 100644 index 0000000000..9b3c77edf9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/ActionBasket.cpp @@ -0,0 +1,4 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "ActionBasket.h" + diff --git a/src/modules/Bots/playerbot/strategy/ActionBasket.h b/src/modules/Bots/playerbot/strategy/ActionBasket.h new file mode 100644 index 0000000000..d85293b018 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/ActionBasket.h @@ -0,0 +1,5 @@ +#pragma once +namespace ai +{ + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/AiObject.cpp b/src/modules/Bots/playerbot/strategy/AiObject.cpp new file mode 100644 index 0000000000..86907f640f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/AiObject.cpp @@ -0,0 +1,16 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "AiObject.h" + +AiObject::AiObject(PlayerbotAI* ai) : + PlayerbotAIAware(ai), + bot(ai->GetBot()), + context(ai->GetAiObjectContext()), + chat(ai->GetChatHelper()) +{ +} + +Player* AiObject::GetMaster() +{ + return ai->GetMaster(); +} diff --git a/src/modules/Bots/playerbot/strategy/AiObject.h b/src/modules/Bots/playerbot/strategy/AiObject.h new file mode 100644 index 0000000000..b16756c607 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/AiObject.h @@ -0,0 +1,33 @@ +#pragma once + +class PlayerbotAI; + +namespace ai +{ + class AiObjectContext; + class ChatHelper; + + class AiObject : public PlayerbotAIAware + { + public: + AiObject(PlayerbotAI* ai); + + protected: + Player* bot; + Player* GetMaster(); + AiObjectContext* context; + ChatHelper* chat; + }; + + class AiNamedObject : public AiObject + { + public: + AiNamedObject(PlayerbotAI* ai, string name) : AiObject(ai), name(name) {} + + public: + virtual string getName() { return name; } + + protected: + string name; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/AiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/AiObjectContext.cpp new file mode 100644 index 0000000000..0c25862620 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/AiObjectContext.cpp @@ -0,0 +1,48 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "AiObjectContext.h" +#include "NamedObjectContext.h" +#include "StrategyContext.h" +#include "triggers/TriggerContext.h" +#include "actions/ActionContext.h" +#include "triggers/ChatTriggerContext.h" +#include "actions/ChatActionContext.h" +#include "triggers/WorldPacketTriggerContext.h" +#include "actions/WorldPacketActionContext.h" +#include "values/ValueContext.h" + +using namespace ai; + +AiObjectContext::AiObjectContext(PlayerbotAI* ai) : PlayerbotAIAware(ai) +{ + strategyContexts.Add(new StrategyContext()); + strategyContexts.Add(new MovementStrategyContext()); + strategyContexts.Add(new AssistStrategyContext()); + strategyContexts.Add(new QuestStrategyContext()); + + actionContexts.Add(new ActionContext()); + actionContexts.Add(new ChatActionContext()); + actionContexts.Add(new WorldPacketActionContext()); + + triggerContexts.Add(new TriggerContext()); + triggerContexts.Add(new ChatTriggerContext()); + triggerContexts.Add(new WorldPacketTriggerContext()); + + valueContexts.Add(new ValueContext()); +} + +void AiObjectContext::Update() +{ + strategyContexts.Update(); + triggerContexts.Update(); + actionContexts.Update(); + valueContexts.Update(); +} + +void AiObjectContext::Reset() +{ + strategyContexts.Reset(); + triggerContexts.Reset(); + actionContexts.Reset(); + valueContexts.Reset(); +} diff --git a/src/modules/Bots/playerbot/strategy/AiObjectContext.h b/src/modules/Bots/playerbot/strategy/AiObjectContext.h new file mode 100644 index 0000000000..7a3d24e198 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/AiObjectContext.h @@ -0,0 +1,85 @@ +#pragma once + +#include "../PlayerbotAIAware.h" +#include "Action.h" +#include "Value.h" +#include "NamedObjectContext.h" +#include "Strategy.h" + +namespace ai +{ + class AiObjectContext : public PlayerbotAIAware + { + public: + AiObjectContext(PlayerbotAI* ai); + virtual ~AiObjectContext() {} + + public: + virtual Strategy* GetStrategy(string name) { return strategyContexts.GetObject(name, ai); } + virtual set GetSiblingStrategy(string name) { return strategyContexts.GetSiblings(name); } + virtual Trigger* GetTrigger(string name) { return triggerContexts.GetObject(name, ai); } + virtual Action* GetAction(string name) { return actionContexts.GetObject(name, ai); } + virtual UntypedValue* GetUntypedValue(string name) { return valueContexts.GetObject(name, ai); } + + template + Value* GetValue(string name) + { + return dynamic_cast*>(GetUntypedValue(name)); + } + + template + Value* GetValue(string name, string param) + { + return GetValue((string(name) + "::" + param)); + } + + template + Value* GetValue(string name, uint32 param) + { + ostringstream out; out << param; + return GetValue(name, out.str()); + } + + set GetSupportedStrategies() + { + return strategyContexts.supports(); + } + + string FormatValues() + { + ostringstream out; + set names = valueContexts.GetCreated(); + for (set::iterator i = names.begin(); i != names.end(); ++i) + { + UntypedValue* value = GetUntypedValue(*i); + if (!value) + { + continue; + } + + string text = value->Format(); + if (text == "?") + { + continue; + } + + out << "{" << *i << "=" << text << "} "; + } + return out.str(); + } + + public: + virtual void Update(); + virtual void Reset(); + virtual void AddShared(NamedObjectContext* sharedValues) + { + valueContexts.Add(sharedValues); + } + + protected: + NamedObjectContextList strategyContexts; + NamedObjectContextList actionContexts; + NamedObjectContextList triggerContexts; + NamedObjectContextList valueContexts; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/Engine.cpp b/src/modules/Bots/playerbot/strategy/Engine.cpp new file mode 100644 index 0000000000..5cc25d633f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Engine.cpp @@ -0,0 +1,578 @@ +#include "../../botpch.h" +#include "../playerbot.h" + +#include "Engine.h" +#include "../PlayerbotAIConfig.h" + +using namespace ai; +using namespace std; + +Engine::Engine(PlayerbotAI* ai, AiObjectContext *factory) : PlayerbotAIAware(ai), aiObjectContext(factory) +{ + lastRelevance = 0.0f; + testMode = false; +} + +bool ActionExecutionListeners::Before(Action* action, Event event) +{ + bool result = true; + for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + { + result &= (*i)->Before(action, event); + } + return result; +} + +void ActionExecutionListeners::After(Action* action, bool executed, Event event) +{ + for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + { + (*i)->After(action, executed, event); + } +} + +bool ActionExecutionListeners::OverrideResult(Action* action, bool executed, Event event) +{ + bool result = executed; + for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + { + result = (*i)->OverrideResult(action, result, event); + } + return result; +} + +bool ActionExecutionListeners::AllowExecution(Action* action, Event event) +{ + bool result = true; + for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + { + result &= (*i)->AllowExecution(action, event); + } + return result; +} + +ActionExecutionListeners::~ActionExecutionListeners() +{ + for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + { + delete *i; + } + listeners.clear(); +} + + +Engine::~Engine(void) +{ + Reset(); + + strategies.clear(); +} + +void Engine::Reset() +{ + ActionNode* action = NULL; + do + { + action = queue.Pop(); + delete action; + } while (action); + + for (list::iterator i = triggers.begin(); i != triggers.end(); i++) + { + TriggerNode* trigger = *i; + delete trigger; + } + triggers.clear(); + + for (list::iterator i = multipliers.begin(); i != multipliers.end(); i++) + { + Multiplier* multiplier = *i; + delete multiplier; + } + multipliers.clear(); +} + +void Engine::Init() +{ + Reset(); + + for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + { + Strategy* strategy = i->second; + strategy->InitMultipliers(multipliers); + strategy->InitTriggers(triggers); + Event emptyEvent; + MultiplyAndPush(strategy->getDefaultActions(), 0.0f, false, emptyEvent); + } + + if (testMode) + { + FILE* file = fopen("test.log", "w"); + fprintf(file, "\n"); + fclose(file); + } +} + + +bool Engine::DoNextAction(Unit* unit, int depth) +{ + LogAction("--- AI Tick ---"); + if (sPlayerbotAIConfig.logValuesPerTick) + { + LogValues(); + } + + bool actionExecuted = false; + ActionBasket* basket = NULL; + + time_t currentTime = time(0); + aiObjectContext->Update(); + ProcessTriggers(); + + int iterations = 0; + int iterationsPerTick = queue.Size() * sPlayerbotAIConfig.iterationsPerTick; + do { + basket = queue.Peek(); + if (basket) { + if (++iterations > iterationsPerTick) + { + break; + } + + float relevance = basket->getRelevance(); // just for reference + bool skipPrerequisites = basket->isSkipPrerequisites(); + Event event = basket->getEvent(); + // NOTE: queue.Pop() deletes basket + ActionNode* actionNode = queue.Pop(); + Action* action = InitializeAction(actionNode); + + if (!action) + { + LogAction("A:%s - UNKNOWN", actionNode->getName().c_str()); + } + else if (action->isUseful()) + { + for (list::iterator i = multipliers.begin(); i!= multipliers.end(); i++) + { + Multiplier* multiplier = *i; + relevance *= multiplier->GetValue(action); + if (!relevance) + { + LogAction("Multiplier %s made action %s useless", multiplier->getName().c_str(), action->getName().c_str()); + break; + } + } + + if (action->isPossible() && relevance) + { + if ((!skipPrerequisites || lastRelevance-relevance > 0.04) && + MultiplyAndPush(actionNode->getPrerequisites(), relevance + 0.02, false, event)) + { + PushAgain(actionNode, relevance + 0.01, event); + continue; + } + + actionExecuted = ListenAndExecute(action, event); + + if (actionExecuted) + { + LogAction("A:%s - OK", action->getName().c_str()); + MultiplyAndPush(actionNode->getContinuers(), 0, false, event); + lastRelevance = relevance; + delete actionNode; + break; + } + else + { + MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event); + LogAction("A:%s - FAILED", action->getName().c_str()); + } + } + else + { + MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event); + LogAction("A:%s - IMPOSSIBLE", action->getName().c_str()); + } + } + else + { + lastRelevance = relevance; + LogAction("A:%s - USELESS", action->getName().c_str()); + } + delete actionNode; + } + } + while (basket); + + if (!basket) + { + lastRelevance = 0.0f; + PushDefaultActions(); + if (queue.Peek() && depth < 2) + { + return DoNextAction(unit, depth + 1); + } + } + + if (time(0) - currentTime > 1) { + { + LogAction("too long execution"); + } + } + + if (!actionExecuted) + { + LogAction("no actions executed"); + } + + return actionExecuted; +} + +ActionNode* Engine::CreateActionNode(string name) +{ + for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + { + Strategy* strategy = i->second; + ActionNode* node = strategy->GetAction(name); + if (node) + { + return node; + } + } + return new ActionNode (name, + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); +} + +bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, Event event) +{ + bool pushed = false; + if (actions) + { + for (int j=0; j<10; j++) // TODO: remove 10 + { + NextAction* nextAction = actions[j]; + if (nextAction) + { + ActionNode* action = CreateActionNode(nextAction->getName()); + InitializeAction(action); + + float k = nextAction->getRelevance(); + if (forceRelevance > 0.0f) + { + k = forceRelevance; + } + + if (k > 0) + { + LogAction("PUSH:%s %f", action->getName().c_str(), k); + queue.Push(new ActionBasket(action, k, skipPrerequisites, event)); + pushed = true; + } + + delete nextAction; + } + else + { + break; + } + } + delete actions; + } + return pushed; +} + +ActionResult Engine::ExecuteAction(string name) +{ + bool result = false; + + ActionNode *actionNode = CreateActionNode(name); + if (!actionNode) + { + return ACTION_RESULT_UNKNOWN; + } + + Action* action = InitializeAction(actionNode); + if (!action) + { + return ACTION_RESULT_UNKNOWN; + } + + if (!action->isPossible()) + { + delete actionNode; + return ACTION_RESULT_IMPOSSIBLE; + } + + if (!action->isUseful()) + { + delete actionNode; + return ACTION_RESULT_USELESS; + } + + action->MakeVerbose(); + Event emptyEvent; + result = ListenAndExecute(action, emptyEvent); + MultiplyAndPush(action->getContinuers(), 0.0f, false, emptyEvent); + delete actionNode; + return result ? ACTION_RESULT_OK : ACTION_RESULT_FAILED; +} + +void Engine::addStrategy(string name) +{ + removeStrategy(name); + + Strategy* strategy = aiObjectContext->GetStrategy(name); + if (strategy) + { + set siblings = aiObjectContext->GetSiblingStrategy(name); + for (set::iterator i = siblings.begin(); i != siblings.end(); i++) + { + removeStrategy(*i); + } + + LogAction("S:+%s", strategy->getName().c_str()); + strategies[strategy->getName()] = strategy; + } + Init(); +} + +void Engine::addStrategies(string first, ...) +{ + addStrategy(first); + + va_list vl; + va_start(vl, first); + + const char* cur; + do + { + cur = va_arg(vl, const char*); + if (cur) + { + addStrategy(cur); + } + } + while (cur); + + va_end(vl); +} + +bool Engine::removeStrategy(string name) +{ + map::iterator i = strategies.find(name); + if (i == strategies.end()) + { + return false; + } + + LogAction("S:-%s", name.c_str()); + strategies.erase(i); + Init(); + return true; +} + +void Engine::removeAllStrategies() +{ + strategies.clear(); + Init(); +} + +void Engine::toggleStrategy(string name) +{ + if (!removeStrategy(name)) + { + addStrategy(name); + } +} + +bool Engine::HasStrategy(string name) +{ + return strategies.find(name) != strategies.end(); +} + +void Engine::ProcessTriggers() +{ + for (list::iterator i = triggers.begin(); i != triggers.end(); i++) + { + TriggerNode* node = *i; + if (!node) + { + continue; + } + + Trigger* trigger = node->getTrigger(); + if (!trigger) + { + trigger = aiObjectContext->GetTrigger(node->getName()); + node->setTrigger(trigger); + } + + if (!trigger) + { + continue; + } + + if (testMode || trigger->needCheck()) + { + Event event = trigger->Check(); + if (!event) + { + continue; + } + + LogAction("T:%s", trigger->getName().c_str()); + MultiplyAndPush(node->getHandlers(), 0.0f, false, event); + } + } + for (list::iterator i = triggers.begin(); i != triggers.end(); i++) + { + Trigger* trigger = (*i)->getTrigger(); + if (trigger) trigger->Reset(); + } +} + +void Engine::PushDefaultActions() +{ + for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + { + Strategy* strategy = i->second; + Event emptyEvent; + MultiplyAndPush(strategy->getDefaultActions(), 0.0f, false, emptyEvent); + } +} + +string Engine::ListStrategies() +{ + string s = "Strategies: "; + + if (strategies.empty()) + { + return s; + } + + for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + { + s.append(i->first); + s.append(", "); + } + return s.substr(0, s.length() - 2); +} + +void Engine::PushAgain(ActionNode* actionNode, float relevance, Event event) +{ + NextAction** nextAction = new NextAction*[2]; + nextAction[0] = new NextAction(actionNode->getName(), relevance); + nextAction[1] = NULL; + MultiplyAndPush(nextAction, relevance, true, event); + delete actionNode; +} + +bool Engine::ContainsStrategy(StrategyType type) +{ + for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + { + Strategy* strategy = i->second; + if (strategy->GetType() & type) + { + return true; + } + } + return false; +} + +Action* Engine::InitializeAction(ActionNode* actionNode) +{ + Action* action = actionNode->getAction(); + if (!action) + { + action = aiObjectContext->GetAction(actionNode->getName()); + actionNode->setAction(action); + } + return action; +} + +bool Engine::ListenAndExecute(Action* action, Event event) +{ + bool actionExecuted = false; + + if (actionExecutionListeners.Before(action, event)) + { + actionExecuted = actionExecutionListeners.AllowExecution(action, event) ? action->Execute(event) : true; + } + + actionExecuted = actionExecutionListeners.OverrideResult(action, actionExecuted, event); + actionExecutionListeners.After(action, actionExecuted, event); + return actionExecuted; +} + +void Engine::LogAction(const char* format, ...) +{ + char buf[1024]; + + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + lastAction = buf; + + if (testMode) + { + FILE* file = fopen("test.log", "a"); + fprintf(file, buf); + fprintf(file, "\n"); + fclose(file); + } + else + { + Player* bot = ai->GetBot(); + if (sPlayerbotAIConfig.logInGroupOnly && !bot->GetGroup()) + { + return; + } + + sLog.outDebug("%s %s", bot->GetName(), buf); + } +} + +void Engine::ChangeStrategy(string names) +{ + vector splitted = split(names, ','); + for (vector::iterator i = splitted.begin(); i != splitted.end(); i++) + { + const char* name = i->c_str(); + switch (name[0]) + { + case '+': + addStrategy(name+1); + break; + case '-': + removeStrategy(name+1); + break; + case '~': + toggleStrategy(name+1); + break; + case '?': + ai->TellMaster(ListStrategies()); + break; + } + } +} + +void Engine::LogValues() +{ + if (testMode) + { + return; + } + + Player* bot = ai->GetBot(); + if (sPlayerbotAIConfig.logInGroupOnly && !bot->GetGroup()) + { + return; + } + + string text = ai->GetAiObjectContext()->FormatValues(); + sLog.outDebug("Values for %s: %s", bot->GetName(), text.c_str()); +} diff --git a/src/modules/Bots/playerbot/strategy/Engine.h b/src/modules/Bots/playerbot/strategy/Engine.h new file mode 100644 index 0000000000..5e658eb928 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Engine.h @@ -0,0 +1,123 @@ +#pragma once + +#include "Action.h" +#include "Queue.h" +#include "Trigger.h" +#include "Multiplier.h" +#include "AiObjectContext.h" +#include "Strategy.h" + +namespace ai +{ + class ActionExecutionListener + { + public: + virtual bool Before(Action* action, Event event) = 0; + virtual bool AllowExecution(Action* action, Event event) = 0; + virtual void After(Action* action, bool executed, Event event) = 0; + virtual bool OverrideResult(Action* action, bool executed, Event event) = 0; + }; + + // ----------------------------------------------------------------------------------------------------------------------- + + class ActionExecutionListeners : public ActionExecutionListener + { + public: + virtual ~ActionExecutionListeners(); + + // ActionExecutionListener + public: + virtual bool Before(Action* action, Event event); + virtual bool AllowExecution(Action* action, Event event); + virtual void After(Action* action, bool executed, Event event); + virtual bool OverrideResult(Action* action, bool executed, Event event); + + public: + void Add(ActionExecutionListener* listener) + { + listeners.push_back(listener); + } + void Remove(ActionExecutionListener* listener) + { + listeners.remove(listener); + } + + private: + std::list listeners; + }; + + // ----------------------------------------------------------------------------------------------------------------------- + + enum ActionResult + { + ACTION_RESULT_UNKNOWN, + ACTION_RESULT_OK, + ACTION_RESULT_IMPOSSIBLE, + ACTION_RESULT_USELESS, + ACTION_RESULT_FAILED + }; + + class Engine : public PlayerbotAIAware + { + public: + Engine(PlayerbotAI* ai, AiObjectContext *factory); + + void Init(); + void addStrategy(string name); + void addStrategies(string first, ...); + bool removeStrategy(string name); + bool HasStrategy(string name); + void removeAllStrategies(); + void toggleStrategy(string name); + std::string ListStrategies(); + bool ContainsStrategy(StrategyType type); + void ChangeStrategy(string names); + string GetLastAction() { return lastAction; } + + public: + virtual bool DoNextAction(Unit*, int depth = 0); + ActionResult ExecuteAction(string name); + + public: + void AddActionExecutionListener(ActionExecutionListener* listener) + { + actionExecutionListeners.Add(listener); + } + void removeActionExecutionListener(ActionExecutionListener* listener) + { + actionExecutionListeners.Remove(listener); + } + + public: + virtual ~Engine(void); + + private: + bool MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, Event event); + void Reset(); + void ProcessTriggers(); + void PushDefaultActions(); + void PushAgain(ActionNode* actionNode, float relevance, Event event); + ActionNode* CreateActionNode(string name); + Action* InitializeAction(ActionNode* actionNode); + bool ListenAndExecute(Action* action, Event event); + + private: + void LogAction(const char* format, ...); + void LogValues(); + + protected: + Queue queue; + std::list triggers; + std::list multipliers; + AiObjectContext* aiObjectContext; + std::map strategies; + float lastRelevance; + std::string lastAction; + + public: + bool testMode; + + private: + ActionExecutionListeners actionExecutionListeners; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/Event.cpp b/src/modules/Bots/playerbot/strategy/Event.cpp new file mode 100644 index 0000000000..0fdf4ccee4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Event.cpp @@ -0,0 +1,22 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "Event.h" + + +using namespace ai; + +ObjectGuid Event::getObject() +{ + if (packet.empty()) + { + return ObjectGuid(); + } + + WorldPacket p(packet); + p.rpos(0); + + ObjectGuid guid; + p >> guid; + + return guid; +} diff --git a/src/modules/Bots/playerbot/strategy/Event.h b/src/modules/Bots/playerbot/strategy/Event.h new file mode 100644 index 0000000000..68d8b5186e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Event.h @@ -0,0 +1,36 @@ +#pragma once + +namespace ai +{ + class Event + { + public: + Event(Event const& other) + { + source = other.source; + param = other.param; + packet = other.packet; + owner = other.owner; + } + Event() {} + Event(string source) : source(source) {} + Event(string source, string param, Player* owner = NULL) : source(source), param(param), owner(owner) {} + Event(string source, WorldPacket &packet, Player* owner = NULL) : source(source), packet(packet), owner(owner) {} + virtual ~Event() {} + + public: + string getSource() { return source; } + string getParam() { return param; } + WorldPacket& getPacket() { return packet; } + ObjectGuid getObject(); + Player* getOwner() { return owner; } + bool operator! () const { return source.empty(); } + + protected: + string source; + string param; + WorldPacket packet; + ObjectGuid object; + Player* owner; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/ExternalEventHelper.h b/src/modules/Bots/playerbot/strategy/ExternalEventHelper.h new file mode 100644 index 0000000000..b80830422e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/ExternalEventHelper.h @@ -0,0 +1,83 @@ +#pragma once + +#include "Trigger.h" + +namespace ai +{ + class ExternalEventHelper { + public: + ExternalEventHelper(AiObjectContext* aiObjectContext) : aiObjectContext(aiObjectContext) {} + + bool ParseChatCommand(string command, Player* owner = NULL) + { + if (HandleCommand(command, "", owner)) + { + return true; + } + + size_t i = string::npos; + while (true) + { + size_t found = command.rfind(" ", i); + if (found == string::npos || !found) + { + break; + } + + string name = command.substr(0, found); + string param = command.substr(found + 1); + + i = found - 1; + + if (HandleCommand(name, param, owner)) + { + return true; + } + } + + if (!ChatHelper::parseable(command)) + { + return false; + } + + HandleCommand("q", command, owner); + HandleCommand("c", command, owner); + HandleCommand("t", command, owner); + return true; + } + + void HandlePacket(map &handlers, const WorldPacket &packet, Player* owner = NULL) + { + uint16 opcode = packet.GetOpcode(); + string name = handlers[opcode]; + if (name.empty()) + { + return; + } + + Trigger* trigger = aiObjectContext->GetTrigger(name); + if (!trigger) + { + return; + } + + WorldPacket p(packet); + trigger->ExternalEvent(p, owner); + } + + bool HandleCommand(string name, string param, Player* owner = NULL) + { + Trigger* trigger = aiObjectContext->GetTrigger(name); + if (!trigger) + { + return false; + } + + trigger->ExternalEvent(param, owner); + return true; + } + + private: + AiObjectContext* aiObjectContext; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/ItemVisitors.h b/src/modules/Bots/playerbot/strategy/ItemVisitors.h new file mode 100644 index 0000000000..8fe03d8cab --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/ItemVisitors.h @@ -0,0 +1,282 @@ +#pragma once + +char * strstri (const char* str1, const char* str2); + +namespace ai +{ + class IterateItemsVisitor + { + public: + IterateItemsVisitor() {} + + virtual bool Visit(Item* item) = 0; + }; + + class FindItemVisitor : public IterateItemsVisitor { + public: + FindItemVisitor() : IterateItemsVisitor() {} + + virtual bool Visit(Item* item) + { + if (!Accept(item->GetProto())) + { + return true; + } + + result.push_back(item); + return true; + } + + list& GetResult() { return result; } + + protected: + virtual bool Accept(const ItemPrototype* proto) = 0; + + private: + list result; + }; + + enum IterateItemsMask + { + ITERATE_ITEMS_IN_BAGS = 1, + ITERATE_ITEMS_IN_EQUIP = 2, + ITERATE_ALL_ITEMS = 255 + }; + + class FindUsableItemVisitor : public FindItemVisitor { + public: + FindUsableItemVisitor(Player* bot) : FindItemVisitor() + { + this->bot = bot; + } + + virtual bool Visit(Item* item) + { + if (bot->CanUseItem(item->GetProto()) == EQUIP_ERR_OK) + { + return FindItemVisitor::Visit(item); + } + + return true; + } + + private: + Player* bot; + }; + + + class FindItemsByQualityVisitor : public IterateItemsVisitor + { + public: + FindItemsByQualityVisitor(uint32 quality, int count) : IterateItemsVisitor() + { + this->quality = quality; + this->count = count; + } + + virtual bool Visit(Item* item) + { + if (item->GetProto()->Quality != quality) + { + return true; + } + + if (result.size() >= (size_t)count) + { + return false; + } + + result.push_back(item); + return true; + } + + list& GetResult() + { + return result; + } + + private: + uint32 quality; + int count; + list result; + }; + + class FindItemsToTradeByQualityVisitor : public FindItemsByQualityVisitor + { + public: + FindItemsToTradeByQualityVisitor(uint32 quality, int count) : FindItemsByQualityVisitor(quality, count) {} + + virtual bool Visit(Item* item) + { + if (item->IsSoulBound()) + { + return true; + } + + return FindItemsByQualityVisitor::Visit(item); + } + }; + + class FindItemsToTradeByClassVisitor : public IterateItemsVisitor + { + public: + FindItemsToTradeByClassVisitor(uint32 itemClass, uint32 itemSubClass, int count) + : IterateItemsVisitor(), count(count), itemClass(itemClass), itemSubClass(itemSubClass) {} + + virtual bool Visit(Item* item) + { + if (item->IsSoulBound()) + { + return true; + } + + if (item->GetProto()->Class != itemClass || item->GetProto()->SubClass != itemSubClass) + { + return true; + } + + if (result.size() >= (size_t)count) + { + return false; + } + + result.push_back(item); + return true; + } + + list& GetResult() + { + return result; + } + + private: + uint32 itemClass; + uint32 itemSubClass; + int count; + list result; + }; + + class QueryItemCountVisitor : public IterateItemsVisitor + { + public: + QueryItemCountVisitor(uint32 itemId) + { + count = 0; + this->itemId = itemId; + } + + virtual bool Visit(Item* item) + { + if (item->GetProto()->ItemId == itemId) + { + count += item->GetCount(); + } + + return true; + } + + int GetCount() { return count; } + + protected: + int count; + uint32 itemId; + }; + + + class QueryNamedItemCountVisitor : public QueryItemCountVisitor + { + public: + QueryNamedItemCountVisitor(string name) : QueryItemCountVisitor(0) + { + this->name = name; + } + + virtual bool Visit(Item* item) + { + const ItemPrototype* proto = item->GetProto(); + if (proto && proto->Name1 && strstri(proto->Name1, name.c_str())) + { + count += item->GetCount(); + } + + return true; + } + + private: + string name; + }; + + class FindUsableNamedItemVisitor : public FindUsableItemVisitor { + public: + FindUsableNamedItemVisitor(Player* bot, string name) : FindUsableItemVisitor(bot) + { + this->name = name; + } + + virtual bool Accept(const ItemPrototype* proto) + { + return proto && proto->Name1 && strstri(proto->Name1, name.c_str()); + } + + private: + string name; + }; + + class FindItemByIdVisitor : public FindItemVisitor { + public: + FindItemByIdVisitor(uint32 id) : FindItemVisitor() + { + this->id = id; + } + + virtual bool Accept(const ItemPrototype* proto) + { + return proto->ItemId == id; + } + + private: + uint32 id; + }; + + class ListItemsVisitor : public IterateItemsVisitor + { + public: + ListItemsVisitor() : IterateItemsVisitor() {} + + map items; + + virtual bool Visit(Item* item) + { + uint32 id = item->GetProto()->ItemId; + + if (items.find(id) == items.end()) + { + items[id] = 0; + } + + items[id] += item->GetCount(); + return true; + } + }; + + class ItemCountByQuality : public IterateItemsVisitor + { + public: + ItemCountByQuality() : IterateItemsVisitor() + { + for (uint32 i = 0; i < MAX_ITEM_QUALITY; ++i) + { + count[i] = 0; + } + } + + virtual bool Visit(Item* item) + { + count[item->GetProto()->Quality]++; + return true; + } + + public: + map count; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/Multiplier.cpp b/src/modules/Bots/playerbot/strategy/Multiplier.cpp new file mode 100644 index 0000000000..2c16b9ade8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Multiplier.cpp @@ -0,0 +1,5 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "Multiplier.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/Multiplier.h b/src/modules/Bots/playerbot/strategy/Multiplier.h new file mode 100644 index 0000000000..e86fa05c28 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Multiplier.h @@ -0,0 +1,16 @@ +#pragma once +#include "Action.h" + +namespace ai +{ + class Multiplier : public AiNamedObject + { + public: + Multiplier(PlayerbotAI* ai, string name) : AiNamedObject(ai, name) {} + virtual ~Multiplier() {} + + public: + virtual float GetValue(Action* action) { return 1.0f; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/NamedObjectContext.h b/src/modules/Bots/playerbot/strategy/NamedObjectContext.h new file mode 100644 index 0000000000..77bf1beb8f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/NamedObjectContext.h @@ -0,0 +1,281 @@ +#pragma once + +namespace ai +{ + using namespace std; + + class Qualified + { + public: + Qualified() {}; + + public: + void Qualify(string qualifier) { this->qualifier = qualifier; } + + protected: + string qualifier; + }; + + template class NamedObjectFactory + { + protected: + typedef T* (*ActionCreator) (PlayerbotAI* ai); + map creators; + + public: + T* create(string name, PlayerbotAI* ai) + { + size_t found = name.find("::"); + string qualifier; + if (found != string::npos) + { + qualifier = name.substr(found + 2); + name = name.substr(0, found); + } + + if (creators.find(name) == creators.end()) + { + return NULL; + } + + ActionCreator creator = creators[name]; + if (!creator) + { + return NULL; + } + + T *object = (*creator)(ai); + Qualified *q = dynamic_cast(object); + if (q) + { + q->Qualify(qualifier); + } + + return object; + } + + set supports() + { + set keys; + for (typename map::iterator it = creators.begin(); it != creators.end(); it++) + { + keys.insert(it->first); + } + return keys; + } + }; + + + template class NamedObjectContext : public NamedObjectFactory + { + public: + NamedObjectContext(bool shared = false, bool supportsSiblings = false) : + NamedObjectFactory(), shared(shared), supportsSiblings(supportsSiblings) {} + + T* create(string name, PlayerbotAI* ai) + { + if (created.find(name) == created.end()) + { + return created[name] = NamedObjectFactory::create(name, ai); + } + + return created[name]; + } + + virtual ~NamedObjectContext() + { + Clear(); + } + + void Clear() + { + for (typename map::iterator i = created.begin(); i != created.end(); i++) + { + if (i->second) + { + delete i->second; + } + } + + created.clear(); + } + + void Update() + { + for (typename map::iterator i = created.begin(); i != created.end(); i++) + { + if (i->second) + { + i->second->Update(); + } + } + } + + void Reset() + { + for (typename map::iterator i = created.begin(); i != created.end(); i++) + { + if (i->second) + { + i->second->Reset(); + } + } + } + + bool IsShared() { return shared; } + bool IsSupportsSiblings() { return supportsSiblings; } + + set GetCreated() + { + set keys; + for (typename map::iterator it = created.begin(); it != created.end(); it++) + { + keys.insert(it->first); + } + return keys; + } + + protected: + map created; + bool shared; + bool supportsSiblings; + }; + + template class NamedObjectContextList + { + public: + virtual ~NamedObjectContextList() + { + for (typename list*>::iterator i = contexts.begin(); i != contexts.end(); i++) + { + NamedObjectContext* context = *i; + if (!context->IsShared()) + { + delete context; + } + } + } + + void Add(NamedObjectContext* context) + { + contexts.push_back(context); + } + + T* GetObject(string name, PlayerbotAI* ai) + { + for (typename list*>::iterator i = contexts.begin(); i != contexts.end(); i++) + { + T* object = (*i)->create(name, ai); + if (object) return object; + } + return NULL; + } + + void Update() + { + for (typename list*>::iterator i = contexts.begin(); i != contexts.end(); i++) + { + if (!(*i)->IsShared()) + { + (*i)->Update(); + } + } + } + + void Reset() + { + for (typename list*>::iterator i = contexts.begin(); i != contexts.end(); i++) + { + (*i)->Reset(); + } + } + + set GetSiblings(string name) + { + for (typename list*>::iterator i = contexts.begin(); i != contexts.end(); i++) + { + if (!(*i)->IsSupportsSiblings()) + { + continue; + } + + set supported = (*i)->supports(); + set::iterator found = supported.find(name); + if (found == supported.end()) + { + continue; + } + + supported.erase(found); + return supported; + } + + return set(); + } + + set supports() + { + set result; + + for (typename list*>::iterator i = contexts.begin(); i != contexts.end(); i++) + { + set supported = (*i)->supports(); + + for (set::iterator j = supported.begin(); j != supported.end(); j++) + { + result.insert(*j); + } + } + return result; + } + + set GetCreated() + { + set result; + + for (typename list*>::iterator i = contexts.begin(); i != contexts.end(); i++) + { + set createdKeys = (*i)->GetCreated(); + + for (set::iterator j = createdKeys.begin(); j != createdKeys.end(); j++) + { + result.insert(*j); + } + } + return result; + } + + private: + list*> contexts; + }; + + template class NamedObjectFactoryList + { + public: + virtual ~NamedObjectFactoryList() + { + for (typename list*>::iterator i = factories.begin(); i != factories.end(); i++) + { + delete *i; + } + } + + void Add(NamedObjectFactory* context) + { + factories.push_front(context); + } + + T* GetObject(string name, PlayerbotAI* ai) + { + for (typename list*>::iterator i = factories.begin(); i != factories.end(); i++) + { + T* object = (*i)->create(name, ai); + if (object) return object; + } + return NULL; + } + + private: + list*> factories; + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp b/src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp new file mode 100644 index 0000000000..060805a9be --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp @@ -0,0 +1,53 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "PassiveMultiplier.h" + +using namespace ai; + +list PassiveMultiplier::allowedActions; +list PassiveMultiplier::allowedParts; + +PassiveMultiplier::PassiveMultiplier(PlayerbotAI* ai) : Multiplier(ai, "passive") +{ + if (allowedActions.empty()) + { + allowedActions.push_back("co"); + allowedActions.push_back("nc"); + allowedActions.push_back("reset ai"); + allowedActions.push_back("check mount state"); + } + + if (allowedParts.empty()) + { + allowedParts.push_back("follow"); + allowedParts.push_back("stay"); + allowedParts.push_back("chat shortcut"); + } +} + +float PassiveMultiplier::GetValue(Action* action) { + if (!action) + { + return 1.0f; + } + + string name = action->getName(); + + for (list::iterator i = allowedActions.begin(); i != allowedActions.end(); i++) + { + if (name == *i) + { + return 1.0f; + } + } + + for (list::iterator i = allowedParts.begin(); i != allowedParts.end(); i++) + { + if (name.find(*i) != string::npos) + { + return 1.0f; + } + } + + return 0; +} diff --git a/src/modules/Bots/playerbot/strategy/PassiveMultiplier.h b/src/modules/Bots/playerbot/strategy/PassiveMultiplier.h new file mode 100644 index 0000000000..37985a06e3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/PassiveMultiplier.h @@ -0,0 +1,20 @@ +#pragma once +#include "Action.h" +#include "Multiplier.h" + +namespace ai +{ + class PassiveMultiplier : public Multiplier + { + public: + PassiveMultiplier(PlayerbotAI* ai); + + public: + virtual float GetValue(Action* action); + + private: + static list allowedActions; + static list allowedParts; + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/Queue.cpp b/src/modules/Bots/playerbot/strategy/Queue.cpp new file mode 100644 index 0000000000..b65f9c663d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Queue.cpp @@ -0,0 +1,83 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "Action.h" +#include "Queue.h" + +using namespace ai; + + +void Queue::Push(ActionBasket *action) +{ + if (action) + { + for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) + { + ActionBasket* basket = *iter; + if (action->getAction()->getName() == basket->getAction()->getName()) + { + if (basket->getRelevance() < action->getRelevance()) + { + basket->setRelevance(action->getRelevance()); + } + delete action; + return; + } + } + actions.push_back(action); + } +} + +void Queue::Push(ActionBasket **actions) +{ + if (actions) + { + for (int i=0; i::iterator iter = actions.begin(); iter != actions.end(); iter++) + { + ActionBasket* basket = *iter; + if (basket->getRelevance() > max) + { + max = basket->getRelevance(); + selection = basket; + } + } + if (selection != NULL) + { + ActionNode* action = selection->getAction(); + actions.remove(selection); + delete selection; + return action; + } + return NULL; +} + +ActionBasket* Queue::Peek() +{ + float max = -1; + ActionBasket* selection = NULL; + for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) + { + ActionBasket* basket = *iter; + if (basket->getRelevance() > max) + { + max = basket->getRelevance(); + selection = basket; + } + } + return selection; +} + +int Queue::Size() +{ + return actions.size(); +} diff --git a/src/modules/Bots/playerbot/strategy/Queue.h b/src/modules/Bots/playerbot/strategy/Queue.h new file mode 100644 index 0000000000..220cf7badd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Queue.h @@ -0,0 +1,21 @@ +#include "ActionBasket.h" + +#pragma once +namespace ai +{ +class Queue +{ +public: + Queue(void) {} +public: + ~Queue(void) {} +public: + void Push(ActionBasket *action); + void Push(ActionBasket **actions); + ActionNode* Pop(); + ActionBasket* Peek(); + int Size(); +private: + std::list actions; +}; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/Strategy.cpp b/src/modules/Bots/playerbot/strategy/Strategy.cpp new file mode 100644 index 0000000000..1ef653527c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Strategy.cpp @@ -0,0 +1,117 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "Strategy.h" +#include "NamedObjectContext.h" + +using namespace ai; +using namespace std; + + +class ActionNodeFactoryInternal : public NamedObjectFactory +{ +public: + ActionNodeFactoryInternal() + { + creators["melee"] = &melee; + creators["healthstone"] = &healthstone; + creators["be near"] = &follow_master_random; + creators["attack anything"] = &attack_anything; + creators["move random"] = &move_random; + creators["move to loot"] = &move_to_loot; + creators["food"] = &food; + creators["drink"] = &drink; + creators["mana potion"] = &mana_potion; + creators["healing potion"] = &healing_potion; + creators["flee"] = &flee; + } + +private: + static ActionNode* melee(PlayerbotAI* ai) + { + return new ActionNode ("melee", + /*P*/ NextAction::array(0, new NextAction("reach melee"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* healthstone(PlayerbotAI* ai) + { + return new ActionNode ("healthstone", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("healing potion"), NULL), + /*C*/ NULL); + } + static ActionNode* follow_master_random(PlayerbotAI* ai) + { + return new ActionNode ("be near", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("follow master"), NULL), + /*C*/ NULL); + } + static ActionNode* attack_anything(PlayerbotAI* ai) + { + return new ActionNode ("attack anything", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* move_random(PlayerbotAI* ai) + { + return new ActionNode ("move random", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("stay line"), NULL), + /*C*/ NULL); + } + static ActionNode* move_to_loot(PlayerbotAI* ai) + { + return new ActionNode ("move to loot", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* food(PlayerbotAI* ai) + { + return new ActionNode ("food", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* drink(PlayerbotAI* ai) + { + return new ActionNode ("drink", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* mana_potion(PlayerbotAI* ai) + { + return new ActionNode ("mana potion", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("drink"), NULL), + /*C*/ NULL); + } + static ActionNode* healing_potion(PlayerbotAI* ai) + { + return new ActionNode ("healing potion", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("food"), NULL), + /*C*/ NULL); + } + static ActionNode* flee(PlayerbotAI* ai) + { + return new ActionNode ("flee", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } +}; + +Strategy::Strategy(PlayerbotAI* ai) : PlayerbotAIAware(ai) +{ + actionNodeFactories.Add(new ActionNodeFactoryInternal()); +} + +ActionNode* Strategy::GetAction(string name) +{ + return actionNodeFactories.GetObject(name, ai); +} + diff --git a/src/modules/Bots/playerbot/strategy/Strategy.h b/src/modules/Bots/playerbot/strategy/Strategy.h new file mode 100644 index 0000000000..a2cbe40d1e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Strategy.h @@ -0,0 +1,55 @@ +#pragma once +#include "Action.h" +#include "Multiplier.h" +#include "Trigger.h" +#include "NamedObjectContext.h" + +namespace ai +{ + enum StrategyType + { + STRATEGY_TYPE_GENERIC = 0, + STRATEGY_TYPE_COMBAT = 1, + STRATEGY_TYPE_NONCOMBAT = 2, + STRATEGY_TYPE_TANK = 4, + STRATEGY_TYPE_DPS = 8, + STRATEGY_TYPE_HEAL = 16, + STRATEGY_TYPE_RANGED = 32, + STRATEGY_TYPE_MELEE = 64 + }; + + enum ActionPriority + { + ACTION_IDLE = 0, + ACTION_NORMAL = 10, + ACTION_HIGH = 20, + ACTION_MOVE = 30, + ACTION_INTERRUPT = 40, + ACTION_DISPEL = 50, + ACTION_LIGHT_HEAL = 60, + ACTION_MEDIUM_HEAL = 70, + ACTION_CRITICAL_HEAL = 80, + ACTION_EMERGENCY = 90 + }; + + class Strategy : public PlayerbotAIAware + { + public: + Strategy(PlayerbotAI* ai); + virtual ~Strategy() {} + + public: + virtual NextAction** getDefaultActions() { return NULL; } + virtual void InitTriggers(std::list &triggers) {} + virtual void InitMultipliers(std::list &multipliers) {} + virtual string getName() = 0; + virtual int GetType() { return STRATEGY_TYPE_GENERIC; } + virtual ActionNode* GetAction(string name); + void Update() {} + void Reset() {} + + protected: + NamedObjectFactoryList actionNodeFactories; + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/StrategyContext.h b/src/modules/Bots/playerbot/strategy/StrategyContext.h new file mode 100644 index 0000000000..05f11871b8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/StrategyContext.h @@ -0,0 +1,161 @@ +#pragma once + +#include "generic/NonCombatStrategy.h" +#include "generic/RacialsStrategy.h" +#include "generic/ChatCommandHandlerStrategy.h" +#include "generic/WorldPacketHandlerStrategy.h" +#include "generic/DeadStrategy.h" +#include "generic/QuestStrategies.h" +#include "generic/LootNonCombatStrategy.h" +#include "generic/DuelStrategy.h" +#include "generic/KiteStrategy.h" +#include "generic/FleeStrategy.h" +#include "generic/FollowMasterStrategy.h" +#include "generic/FollowMasterRandomStrategy.h" +#include "generic/FollowLineStrategy.h" +#include "generic/RunawayStrategy.h" +#include "generic/StayCircleStrategy.h" +#include "generic/StayLineStrategy.h" +#include "generic/StayCombatStrategy.h" +#include "generic/StayStrategy.h" +#include "generic/UseFoodStrategy.h" +#include "generic/ConserveManaStrategy.h" +#include "generic/EmoteStrategy.h" +#include "generic/AttackRtiStrategy.h" +#include "generic/AttackWeakStrategy.h" +#include "generic/TankAoeStrategy.h" +#include "generic/TankAssistStrategy.h" +#include "generic/DpsAoeStrategy.h" +#include "generic/DpsAssistStrategy.h" +#include "generic/PassiveStrategy.h" +#include "generic/GrindingStrategy.h" +#include "generic/UsePotionsStrategy.h" +#include "generic/GuardStrategy.h" +#include "generic/CastTimeStrategy.h" +#include "generic/ThreatStrategy.h" +#include "generic/TellTargetStrategy.h" +#include "generic/AttackEnemyPlayersStrategy.h" +#include "generic/MoveRandomStrategy.h" + +namespace ai +{ + class StrategyContext : public NamedObjectContext + { + public: + StrategyContext() + { + creators["racials"] = &StrategyContext::racials; + creators["loot"] = &StrategyContext::loot; + creators["gather"] = &StrategyContext::gather; + creators["emote"] = &StrategyContext::emote; + creators["passive"] = &StrategyContext::passive; + creators["conserve mana"] = &StrategyContext::conserve_mana; + creators["food"] = &StrategyContext::food; + creators["chat"] = &StrategyContext::chat; + creators["default"] = &StrategyContext::world_packet; + creators["ready check"] = &StrategyContext::ready_check; + creators["dead"] = &StrategyContext::dead; + creators["flee"] = &StrategyContext::flee; + creators["duel"] = &StrategyContext::duel; + creators["kite"] = &StrategyContext::kite; + creators["potions"] = &StrategyContext::potions; + creators["cast time"] = &StrategyContext::cast_time; + creators["threat"] = &StrategyContext::threat; + creators["tell target"] = &StrategyContext::tell_target; + creators["pvp"] = &StrategyContext::pvp; + creators["move random"] = &StrategyContext::move_random; + } + + private: + static Strategy* tell_target(PlayerbotAI* ai) { return new TellTargetStrategy(ai); } + static Strategy* threat(PlayerbotAI* ai) { return new ThreatStrategy(ai); } + static Strategy* cast_time(PlayerbotAI* ai) { return new CastTimeStrategy(ai); } + static Strategy* potions(PlayerbotAI* ai) { return new UsePotionsStrategy(ai); } + static Strategy* kite(PlayerbotAI* ai) { return new KiteStrategy(ai); } + static Strategy* duel(PlayerbotAI* ai) { return new DuelStrategy(ai); } + static Strategy* flee(PlayerbotAI* ai) { return new FleeStrategy(ai); } + static Strategy* dead(PlayerbotAI* ai) { return new DeadStrategy(ai); } + static Strategy* racials(PlayerbotAI* ai) { return new RacialsStrategy(ai); } + static Strategy* loot(PlayerbotAI* ai) { return new LootNonCombatStrategy(ai); } + static Strategy* gather(PlayerbotAI* ai) { return new GatherStrategy(ai); } + static Strategy* emote(PlayerbotAI* ai) { return new EmoteStrategy(ai); } + static Strategy* passive(PlayerbotAI* ai) { return new PassiveStrategy(ai); } + static Strategy* conserve_mana(PlayerbotAI* ai) { return new ConserveManaStrategy(ai); } + static Strategy* food(PlayerbotAI* ai) { return new UseFoodStrategy(ai); } + static Strategy* chat(PlayerbotAI* ai) { return new ChatCommandHandlerStrategy(ai); } + static Strategy* world_packet(PlayerbotAI* ai) { return new WorldPacketHandlerStrategy(ai); } + static Strategy* ready_check(PlayerbotAI* ai) { return new ReadyCheckStrategy(ai); } + static Strategy* pvp(PlayerbotAI* ai) { return new AttackEnemyPlayersStrategy(ai); } + static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); } + }; + + class MovementStrategyContext : public NamedObjectContext + { + public: + MovementStrategyContext() : NamedObjectContext(false, true) + { + creators["follow master"] = &MovementStrategyContext::follow_master; + creators["be near"] = &MovementStrategyContext::follow_master_random; + creators["follow line"] = &MovementStrategyContext::follow_line; + creators["stay"] = &MovementStrategyContext::stay; + creators["runaway"] = &MovementStrategyContext::runaway; + creators["flee from adds"] = &MovementStrategyContext::flee_from_adds; + creators["stay circle"] = &MovementStrategyContext::stay_circle; + creators["stay combat"] = &MovementStrategyContext::stay_combat; + creators["stay line"] = &MovementStrategyContext::stay_line; + creators["guard"] = &MovementStrategyContext::guard; + creators["move random"] = &MovementStrategyContext::move_random; + } + + private: + static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); } + static Strategy* guard(PlayerbotAI* ai) { return new GuardStrategy(ai); } + static Strategy* follow_master_random(PlayerbotAI* ai) { return new FollowMasterRandomStrategy(ai); } + static Strategy* follow_master(PlayerbotAI* ai) { return new FollowMasterStrategy(ai); } + static Strategy* follow_line(PlayerbotAI* ai) { return new FollowLineStrategy(ai); } + static Strategy* stay(PlayerbotAI* ai) { return new StayStrategy(ai); } + static Strategy* runaway(PlayerbotAI* ai) { return new RunawayStrategy(ai); } + static Strategy* flee_from_adds(PlayerbotAI* ai) { return new FleeFromAddsStrategy(ai); } + static Strategy* stay_circle(PlayerbotAI* ai) { return new StayCircleStrategy(ai); } + static Strategy* stay_combat(PlayerbotAI* ai) { return new StayCombatStrategy(ai); } + static Strategy* stay_line(PlayerbotAI* ai) { return new StayLineStrategy(ai); } + }; + + class AssistStrategyContext : public NamedObjectContext + { + public: + AssistStrategyContext() : NamedObjectContext(false, true) + { + creators["dps assist"] = &AssistStrategyContext::dps_assist; + creators["dps aoe"] = &AssistStrategyContext::dps_aoe; + creators["tank assist"] = &AssistStrategyContext::tank_assist; + creators["tank aoe"] = &AssistStrategyContext::tank_aoe; + creators["attack weak"] = &AssistStrategyContext::attack_weak; + creators["grind"] = &AssistStrategyContext::grind; + creators["attack rti"] = &AssistStrategyContext::attack_rti; + } + + private: + static Strategy* dps_assist(PlayerbotAI* ai) { return new DpsAssistStrategy(ai); } + static Strategy* dps_aoe(PlayerbotAI* ai) { return new DpsAoeStrategy(ai); } + static Strategy* tank_assist(PlayerbotAI* ai) { return new TankAssistStrategy(ai); } + static Strategy* tank_aoe(PlayerbotAI* ai) { return new TankAoeStrategy(ai); } + static Strategy* attack_weak(PlayerbotAI* ai) { return new AttackWeakStrategy(ai); } + static Strategy* grind(PlayerbotAI* ai) { return new GrindingStrategy(ai); } + static Strategy* attack_rti(PlayerbotAI* ai) { return new AttackRtiStrategy(ai); } + }; + + class QuestStrategyContext : public NamedObjectContext + { + public: + QuestStrategyContext() : NamedObjectContext(false, true) + { + creators["quest"] = &QuestStrategyContext::quest; + creators["accept all quests"] = &QuestStrategyContext::accept_all_quests; + } + + private: + static Strategy* quest(PlayerbotAI* ai) { return new DefaultQuestStrategy(ai); } + static Strategy* accept_all_quests(PlayerbotAI* ai) { return new AcceptAllQuestsStrategy(ai); } + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/Trigger.cpp b/src/modules/Bots/playerbot/strategy/Trigger.cpp new file mode 100644 index 0000000000..b8ab30b348 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Trigger.cpp @@ -0,0 +1,27 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "Trigger.h" +#include "Action.h" + +using namespace ai; + +Event Trigger::Check() +{ + if (IsActive()) + { + Event event(getName()); + return event; + } + Event event; + return event; +} + +Value* Trigger::GetTargetValue() +{ + return context->GetValue(GetTargetName()); +} + +Unit* Trigger::GetTarget() +{ + return GetTargetValue()->Get(); +} diff --git a/src/modules/Bots/playerbot/strategy/Trigger.h b/src/modules/Bots/playerbot/strategy/Trigger.h new file mode 100644 index 0000000000..d36c767821 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Trigger.h @@ -0,0 +1,86 @@ +#pragma once +#include "Action.h" +#include "Event.h" +#include "../PlayerbotAIAware.h" + +#define NEXT_TRIGGERS(name, relevance) \ + virtual NextAction* getNextAction() { return new NextAction(name, relevance); } + +#define BEGIN_TRIGGER(clazz, super) \ +class clazz : public super \ + { \ + public: \ + clazz(PlayerbotAI* ai) : super(ai) {} \ + public: \ + virtual bool IsActive(); + +#define END_TRIGGER() \ + }; + +namespace ai +{ + class Trigger : public AiNamedObject + { + public: + Trigger(PlayerbotAI* ai, string name = "trigger", int checkInterval = 1) : AiNamedObject(ai, name) { + this->checkInterval = checkInterval; + ticksElapsed = 0; + } + virtual ~Trigger() {} + + public: + virtual Event Check(); + virtual void ExternalEvent(string param, Player* owner = NULL) {} + virtual void ExternalEvent(WorldPacket &packet, Player* owner = NULL) {} + virtual bool IsActive() { return false; } + virtual NextAction** getHandlers() { return NULL; } + void Update() {} + virtual void Reset() {} + virtual Unit* GetTarget(); + virtual Value* GetTargetValue(); + virtual string GetTargetName() { return "self target"; } + + bool needCheck() { + if (++ticksElapsed >= checkInterval) { + { + ticksElapsed = 0; + } + return true; + } + return false; + } + + protected: + int checkInterval; + int ticksElapsed; + }; + + + class TriggerNode + { + public: + TriggerNode(string name, NextAction** handlers = NULL) + { + this->name = name; + this->handlers = handlers; + this->trigger = NULL; + } + virtual ~TriggerNode() + { + NextAction::destroy(handlers); + } + + public: + Trigger* getTrigger() { return trigger; } + void setTrigger(Trigger* trigger) { this->trigger = trigger; } + string getName() { return name; } + + public: + NextAction** getHandlers() { return NextAction::merge(NextAction::clone(handlers), trigger->getHandlers()); } + + private: + Trigger* trigger; + NextAction** handlers; + std::string name; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/Value.cpp b/src/modules/Bots/playerbot/strategy/Value.cpp new file mode 100644 index 0000000000..66a7f0d0bf --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Value.cpp @@ -0,0 +1,5 @@ +#include "../../botpch.h" +#include "../playerbot.h" +#include "Value.h" + +using namespace ai; diff --git a/src/modules/Bots/playerbot/strategy/Value.h b/src/modules/Bots/playerbot/strategy/Value.h new file mode 100644 index 0000000000..e0ba55f7f4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/Value.h @@ -0,0 +1,181 @@ +#pragma once +#include "Action.h" +#include "Event.h" +#include "../PlayerbotAIAware.h" +#include "AiObject.h" + +namespace ai +{ + class UntypedValue : public AiNamedObject + { + public: + UntypedValue(PlayerbotAI* ai, string name) : AiNamedObject(ai, name) {} + virtual void Update() {} + virtual void Reset() {} + virtual string Format() { return "?"; } + }; + + template + class Value + { + public: + virtual T Get() = 0; + virtual void Set(T value) = 0; + operator T() { return Get(); } + }; + + template + class CalculatedValue : public UntypedValue, public Value + { + public: + CalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : UntypedValue(ai, name), + checkInterval(checkInterval), ticksElapsed(checkInterval) + { } + virtual ~CalculatedValue() {} + + public: + virtual T Get() + { + if (ticksElapsed >= checkInterval) { + { + ticksElapsed = 0; + } + value = Calculate(); + } + return value; + } + virtual void Set(T value) { this->value = value; } + virtual void Update() + { + if (ticksElapsed < checkInterval) { + { + ticksElapsed++; + } + } + } + + protected: + virtual T Calculate() = 0; + + protected: + int checkInterval; + int ticksElapsed; + T value; + }; + + class Uint8CalculatedValue : public CalculatedValue + { + public: + Uint8CalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + CalculatedValue(ai, name, checkInterval) {} + + virtual string Format() + { + ostringstream out; out << (int)Calculate(); + return out.str(); + } + }; + + class Uint32CalculatedValue : public CalculatedValue + { + public: + Uint32CalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + CalculatedValue(ai, name, checkInterval) {} + + virtual string Format() + { + ostringstream out; out << (int)Calculate(); + return out.str(); + } + }; + + class FloatCalculatedValue : public CalculatedValue + { + public: + FloatCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + CalculatedValue(ai, name, checkInterval) {} + + virtual string Format() + { + ostringstream out; out << Calculate(); + return out.str(); + } + }; + + class BoolCalculatedValue : public CalculatedValue + { + public: + BoolCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + CalculatedValue(ai, name, checkInterval) {} + + virtual string Format() + { + return Calculate() ? "true" : "false"; + } + }; + + class UnitCalculatedValue : public CalculatedValue + { + public: + UnitCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + CalculatedValue(ai, name, checkInterval) {} + + virtual string Format() + { + Unit* unit = Calculate(); + return unit ? unit->GetName() : ""; + } + }; + + class ObjectGuidListCalculatedValue : public CalculatedValue > + { + public: + ObjectGuidListCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + CalculatedValue >(ai, name, checkInterval) {} + + virtual string Format() + { + ostringstream out; out << "{"; + list guids = Calculate(); + for (list::iterator i = guids.begin(); i != guids.end(); ++i) + { + ObjectGuid guid = *i; + out << guid.GetRawValue() << ","; + } + out << "}"; + return out.str(); + } + }; + + template + class ManualSetValue : public UntypedValue, public Value + { + public: + ManualSetValue(PlayerbotAI* ai, T defaultValue, string name = "value") : + UntypedValue(ai, name), value(defaultValue), defaultValue(defaultValue) {} + virtual ~ManualSetValue() {} + + public: + virtual T Get() { return value; } + virtual void Set(T value) { this->value = value; } + virtual void Update() { } + virtual void Reset() { value = defaultValue; } + + protected: + T value; + T defaultValue; + }; + + class UnitManualSetValue : public ManualSetValue + { + public: + UnitManualSetValue(PlayerbotAI* ai, Unit* defaultValue, string name = "value") : + ManualSetValue(ai, defaultValue, name) {} + + virtual string Format() + { + Unit* unit = Get(); + return unit ? unit->GetName() : ""; + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AcceptDuelAction.h b/src/modules/Bots/playerbot/strategy/actions/AcceptDuelAction.h new file mode 100644 index 0000000000..461ea7e7b2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AcceptDuelAction.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class AcceptDuelAction : public Action + { + public: + AcceptDuelAction(PlayerbotAI* ai) : Action(ai, "accept duel") + {} + + virtual bool Execute(Event event) + { + WorldPacket p(event.getPacket()); + + ObjectGuid flagGuid; + p >> flagGuid; + ObjectGuid playerGuid; + p >> playerGuid; + + WorldPacket* const packet = new WorldPacket(CMSG_DUEL_ACCEPTED, 8); + *packet << flagGuid; + bot->GetSession()->QueuePacket(packet); + + ai->ResetStrategies(); + return true; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AcceptInvitationAction.h b/src/modules/Bots/playerbot/strategy/actions/AcceptInvitationAction.h new file mode 100644 index 0000000000..41191213b2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AcceptInvitationAction.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class AcceptInvitationAction : public Action { + public: + AcceptInvitationAction(PlayerbotAI* ai) : Action(ai, "accept invitation") {} + + virtual bool Execute(Event event) + { + Player* master = GetMaster(); + + Group* grp = bot->GetGroupInvite(); + if (!grp) + { + return false; + } + + Player* inviter = sObjectMgr.GetPlayer(grp->GetLeaderGuid()); + if (!inviter) + { + return false; + } + + if (!ai->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, inviter)) + { + WorldPacket data(SMSG_GROUP_DECLINE, 10); + data << bot->GetName(); + inviter->GetSession()->SendPacket(&data); + bot->UninviteFromGroup(); + return false; + } + + WorldPacket p; + uint32 roles_mask = 0; + p << roles_mask; + bot->GetSession()->HandleGroupAcceptOpcode(p); + + if (sRandomPlayerbotMgr.IsRandomBot(bot)) + { + bot->GetPlayerbotAI()->SetMaster(inviter); + } + + ai->ResetStrategies(); + ai->TellMaster("Hello"); + return true; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.cpp b/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.cpp new file mode 100644 index 0000000000..245acce423 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.cpp @@ -0,0 +1,117 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AcceptQuestAction.h" + +using namespace ai; + +void AcceptAllQuestsAction::ProcessQuest(Quest const* quest, WorldObject* questGiver) +{ + AcceptQuest(quest, questGiver->GetObjectGuid()); +} + +bool AcceptQuestAction::Execute(Event event) +{ + Player* master = GetMaster(); + + if (!master) + { + return false; + } + + Player *bot = ai->GetBot(); + uint64 guid; + uint32 quest; + + string text = event.getParam(); + PlayerbotChatHandler ch(master); + quest = ch.extractQuestId(text); + if (quest) + { + guid = master->GetSelectionGuid().GetRawValue(); + if (!guid) + { + ai->TellMaster("Please select quest giver NPC"); + return false; + } + } + else if (!event.getPacket().empty()) + { + WorldPacket& p = event.getPacket(); + p.rpos(0); + p >> guid >> quest; + } + else if (text == "*") + { + return QuestAction::Execute(event); + } + else + { + return false; + } + + Quest const* qInfo = sObjectMgr.GetQuestTemplate(quest); + if (!qInfo) + { + return false; + } + + return AcceptQuest(qInfo, guid); +} + +bool AcceptQuestShareAction::Execute(Event event) +{ + Player* master = GetMaster(); + Player *bot = ai->GetBot(); + + WorldPacket& p = event.getPacket(); + p.rpos(0); + uint32 quest; + p >> quest; + Quest const* qInfo = sObjectMgr.GetQuestTemplate(quest); + + if (!qInfo || !bot->GetDividerGuid()) + { + return false; + } + + quest = qInfo->GetQuestId(); + if( !bot->CanTakeQuest( qInfo, false ) ) + { + // can't take quest + bot->SetDividerGuid( ObjectGuid() ); + ai->TellMaster("I can't take this quest"); + + return false; + } + + if( !bot->GetDividerGuid().IsEmpty() ) + { + // send msg to quest giving player + master->SendPushToPartyResponse( bot, QUEST_PARTY_MSG_ACCEPT_QUEST ); + bot->SetDividerGuid( ObjectGuid() ); + } + + if( bot->CanAddQuest( qInfo, false ) ) + { + bot->AddQuest( qInfo, master ); + + if( bot->CanCompleteQuest( quest ) ) + { + bot->CompleteQuest( quest ); + } + + // Runsttren: did not add typeid switch from WorldSession::HandleQuestgiverAcceptQuestOpcode! + // I think it's not needed, cause typeid should be TYPEID_PLAYER - and this one is not handled + // there and there is no default case also. + + if( qInfo->GetSrcSpell() > 0 ) + { + bot->CastSpell( bot, qInfo->GetSrcSpell(), true ); + } + + ai->TellMaster("Quest accepted"); + return true; + } + + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h b/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h new file mode 100644 index 0000000000..856c697180 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h @@ -0,0 +1,27 @@ +#pragma once + +#include "../Action.h" +#include "QuestAction.h" + +namespace ai +{ + class AcceptAllQuestsAction : public QuestAction { + public: + AcceptAllQuestsAction(PlayerbotAI* ai, string name = "accept all quests") : QuestAction(ai, name) {} + + protected: + virtual void ProcessQuest(Quest const* quest, WorldObject* questGiver); + }; + + class AcceptQuestAction : public AcceptAllQuestsAction { + public: + AcceptQuestAction(PlayerbotAI* ai) : AcceptAllQuestsAction(ai, "accept quest") {} + virtual bool Execute(Event event); + }; + + class AcceptQuestShareAction : public Action { + public: + AcceptQuestShareAction(PlayerbotAI* ai) : Action(ai, "accept quest share") {} + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AcceptResurrectAction.h b/src/modules/Bots/playerbot/strategy/actions/AcceptResurrectAction.h new file mode 100644 index 0000000000..b1cfd29ca9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AcceptResurrectAction.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class AcceptResurrectAction : public Action { + public: + AcceptResurrectAction(PlayerbotAI* ai) : Action(ai, "accept resurrect") {} + + virtual bool Execute(Event event) + { + if (bot->IsAlive()) + { + return false; + } + + WorldPacket p(event.getPacket()); + p.rpos(0); + ObjectGuid guid; + p >> guid; + + WorldPacket* const packet = new WorldPacket(CMSG_RESURRECT_RESPONSE, 8+1); + *packet << guid; + *packet << uint8(1); // accept + bot->GetSession()->QueuePacket(packet); // queue the packet to get around race condition + + ai->ChangeEngine(BOT_STATE_NON_COMBAT); + return true; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ActionContext.h b/src/modules/Bots/playerbot/strategy/actions/ActionContext.h new file mode 100644 index 0000000000..6bbd235942 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ActionContext.h @@ -0,0 +1,117 @@ +#pragma once + +#include "GenericActions.h" +#include "NonCombatActions.h" +#include "EmoteAction.h" +#include "AddLootAction.h" +#include "LootAction.h" +#include "AddLootAction.h" +#include "StayActions.h" +#include "FollowActions.h" +#include "ChangeStrategyAction.h" +#include "ChooseTargetActions.h" +#include "SuggestWhatToDoAction.h" +#include "PositionAction.h" +#include "AttackAction.h" + +namespace ai +{ + class ActionContext : public NamedObjectContext + { + public: + ActionContext() + { + creators["attack"] = &ActionContext::melee; + creators["melee"] = &ActionContext::melee; + creators["reach spell"] = &ActionContext::ReachSpell; + creators["reach melee"] = &ActionContext::ReachMelee; + creators["flee"] = &ActionContext::flee; + creators["gift of the naaru"] = &ActionContext::gift_of_the_naaru; + creators["shoot"] = &ActionContext::shoot; + creators["lifeblood"] = &ActionContext::lifeblood; + creators["arcane torrent"] = &ActionContext::arcane_torrent; + creators["end pull"] = &ActionContext::end_pull; + creators["healthstone"] = &ActionContext::healthstone; + creators["healing potion"] = &ActionContext::healing_potion; + creators["mana potion"] = &ActionContext::mana_potion; + creators["food"] = &ActionContext::food; + creators["drink"] = &ActionContext::drink; + creators["tank assist"] = &ActionContext::tank_assist; + creators["dps assist"] = &ActionContext::dps_assist; + creators["attack rti target"] = &ActionContext::attack_rti_target; + creators["loot"] = &ActionContext::loot; + creators["add loot"] = &ActionContext::add_loot; + creators["add gathering loot"] = &ActionContext::add_gathering_loot; + creators["add all loot"] = &ActionContext::add_all_loot; + creators["shoot"] = &ActionContext::shoot; + creators["follow line"] = &ActionContext::follow_line; + creators["follow"] = &ActionContext::follow_master; + creators["follow master"] = &ActionContext::follow_master; + creators["be near"] = &ActionContext::follow_master_random; + creators["runaway"] = &ActionContext::runaway; + creators["stay"] = &ActionContext::stay; + creators["stay circle"] = &ActionContext::stay_circle; + creators["stay line"] = &ActionContext::stay_line; + creators["stay combat"] = &ActionContext::stay_combat; + creators["attack anything"] = &ActionContext::attack_anything; + creators["attack least hp target"] = &ActionContext::attack_least_hp_target; + creators["attack enemy player"] = &ActionContext::enemy_player_target; + creators["emote"] = &ActionContext::emote; + creators["suggest what to do"] = &ActionContext::suggest_what_to_do; + creators["move random"] = &ActionContext::move_random; + creators["move to loot"] = &ActionContext::move_to_loot; + creators["open loot"] = &ActionContext::open_loot; + creators["guard"] = &ActionContext::guard; + creators["move out of enemy contact"] = &ActionContext::move_out_of_enemy_contact; + creators["set facing"] = &ActionContext::set_facing; + creators["attack duel opponent"] = &ActionContext::attack_duel_opponent; + creators["drop target"] = &ActionContext::drop_target; + } + + private: + static Action* drop_target(PlayerbotAI* ai) { return new DropTargetAction(ai); } + static Action* attack_duel_opponent(PlayerbotAI* ai) { return new AttackDuelOpponentAction(ai); } + static Action* guard(PlayerbotAI* ai) { return new GuardAction(ai); } + static Action* open_loot(PlayerbotAI* ai) { return new OpenLootAction(ai); } + static Action* move_to_loot(PlayerbotAI* ai) { return new MoveToLootAction(ai); } + static Action* move_random(PlayerbotAI* ai) { return new MoveRandomAction(ai); } + static Action* shoot(PlayerbotAI* ai) { return new CastShootAction(ai); } + static Action* melee(PlayerbotAI* ai) { return new MeleeAction(ai); } + static Action* ReachSpell(PlayerbotAI* ai) { return new ReachSpellAction(ai); } + static Action* ReachMelee(PlayerbotAI* ai) { return new ReachMeleeAction(ai); } + static Action* flee(PlayerbotAI* ai) { return new FleeAction(ai); } + static Action* gift_of_the_naaru(PlayerbotAI* ai) { return new CastGiftOfTheNaaruAction(ai); } + static Action* lifeblood(PlayerbotAI* ai) { return new CastLifeBloodAction(ai); } + static Action* arcane_torrent(PlayerbotAI* ai) { return new CastArcaneTorrentAction(ai); } + static Action* end_pull(PlayerbotAI* ai) { return new ChangeCombatStrategyAction(ai, "-pull"); } + + static Action* emote(PlayerbotAI* ai) { return new EmoteAction(ai); } + static Action* suggest_what_to_do(PlayerbotAI* ai) { return new SuggestWhatToDoAction(ai); } + static Action* attack_anything(PlayerbotAI* ai) { return new AttackAnythingAction(ai); } + static Action* attack_least_hp_target(PlayerbotAI* ai) { return new AttackLeastHpTargetAction(ai); } + static Action* enemy_player_target(PlayerbotAI* ai) { return new AttackEnemyPlayerAction(ai); } + static Action* stay_combat(PlayerbotAI* ai) { return new StayCombatAction(ai); } + static Action* stay_line(PlayerbotAI* ai) { return new StayLineAction(ai); } + static Action* stay_circle(PlayerbotAI* ai) { return new StayCircleAction(ai); } + static Action* stay(PlayerbotAI* ai) { return new StayAction(ai); } + static Action* runaway(PlayerbotAI* ai) { return new RunAwayAction(ai); } + static Action* follow_master_random(PlayerbotAI* ai) { return new FollowMasterRandomAction(ai); } + static Action* follow_master(PlayerbotAI* ai) { return new FollowMasterAction(ai); } + static Action* follow_line(PlayerbotAI* ai) { return new FollowLineAction(ai); } + static Action* add_gathering_loot(PlayerbotAI* ai) { return new AddGatheringLootAction(ai); } + static Action* add_loot(PlayerbotAI* ai) { return new AddLootAction(ai); } + static Action* add_all_loot(PlayerbotAI* ai) { return new AddAllLootAction(ai); } + static Action* loot(PlayerbotAI* ai) { return new LootAction(ai); } + static Action* dps_assist(PlayerbotAI* ai) { return new DpsAssistAction(ai); } + static Action* attack_rti_target(PlayerbotAI* ai) { return new AttackRtiTargetAction(ai); } + static Action* tank_assist(PlayerbotAI* ai) { return new TankAssistAction(ai); } + static Action* drink(PlayerbotAI* ai) { return new DrinkAction(ai); } + static Action* food(PlayerbotAI* ai) { return new EatAction(ai); } + static Action* mana_potion(PlayerbotAI* ai) { return new UseManaPotion(ai); } + static Action* healing_potion(PlayerbotAI* ai) { return new UseHealingPotion(ai); } + static Action* healthstone(PlayerbotAI* ai) { return new UseItemAction(ai, "healthstone"); } + static Action* move_out_of_enemy_contact(PlayerbotAI* ai) { return new MoveOutOfEnemyContactAction(ai); } + static Action* set_facing(PlayerbotAI* ai) { return new SetFacingTargetAction(ai); } + }; + +}; diff --git a/src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp new file mode 100644 index 0000000000..704ff2e278 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp @@ -0,0 +1,74 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AddLootAction.h" + +#include "../../LootObjectStack.h" + +using namespace ai; + +bool AddLootAction::Execute(Event event) +{ + ObjectGuid guid = event.getObject(); + if (!guid) + { + return false; + } + + return AI_VALUE(LootObjectStack*, "available loot")->Add(guid); +} + +bool AddAllLootAction::Execute(Event event) +{ + bool added = false; + + list gos = context->GetValue >("nearest game objects")->Get(); + for (list::iterator i = gos.begin(); i != gos.end(); i++) + { + added |= AddLoot(*i); + } + + list corpses = context->GetValue >("nearest corpses")->Get(); + for (list::iterator i = corpses.begin(); i != corpses.end(); i++) + { + added |= AddLoot(*i); + } + + return added; +} + +bool AddLootAction::isUseful() +{ + return AI_VALUE(uint8, "bag space") < 80; +} + +bool AddAllLootAction::isUseful() +{ + return AI_VALUE(uint8, "bag space") < 80; +} + +bool AddAllLootAction::AddLoot(ObjectGuid guid) +{ + return AI_VALUE(LootObjectStack*, "available loot")->Add(guid); +} + +bool AddGatheringLootAction::AddLoot(ObjectGuid guid) +{ + LootObject loot(bot, guid); + + if (loot.IsEmpty() || !loot.GetWorldObject(bot)) + { + return false; + } + + if (loot.skillId == SKILL_NONE) + { + return false; + } + + if (!loot.IsLootPossible(bot)) + { + return false; + } + + return AddAllLootAction::AddLoot(guid); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AddLootAction.h b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.h new file mode 100644 index 0000000000..402c50ad4d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.h @@ -0,0 +1,32 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class AddLootAction : public Action { + public: + AddLootAction(PlayerbotAI* ai) : Action(ai, "add loot") {} + virtual bool Execute(Event event); + virtual bool isUseful(); + }; + + class AddAllLootAction : public Action { + public: + AddAllLootAction(PlayerbotAI* ai, string name = "add all loot") : Action(ai, name) {} + virtual bool Execute(Event event); + virtual bool isUseful(); + + protected: + virtual bool AddLoot(ObjectGuid guid); + }; + + class AddGatheringLootAction : public AddAllLootAction { + public: + AddGatheringLootAction(PlayerbotAI* ai) : AddAllLootAction(ai, "add gathering loot") {} + + protected: + virtual bool AddLoot(ObjectGuid guid); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.cpp b/src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.cpp new file mode 100644 index 0000000000..b41ac57c5c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.cpp @@ -0,0 +1,93 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AreaTriggerAction.h" +#include "../../PlayerbotAIConfig.h" + + +using namespace ai; + +bool ReachAreaTriggerAction::Execute(Event event) +{ + uint32 triggerId; + WorldPacket p(event.getPacket()); + p.rpos(0); + p >> triggerId; + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(triggerId); + if(!atEntry) + { + return false; + } + + AreaTrigger const* at = sObjectMgr.GetAreaTrigger(triggerId); + if (!at) + { + WorldPacket p1(CMSG_AREATRIGGER); + p1 << triggerId; + p1.rpos(0); + bot->GetSession()->HandleAreaTriggerOpcode(p1); + + return true; + } + + // if (at->condition && !sObjectMgr.IsPlayerMeetToCondition(at->condition, bot, bot->GetMap(), NULL, CONDITION_AREA_TRIGGER)) + if (at->requiredLevel && at->requiredLevel > bot->getLevel()) + { + ai->TellMaster("I won't follow: I don't meet the conditions"); + return false; + } + + if (bot->GetMapId() != atEntry->mapid || bot->GetDistance(atEntry->x, atEntry->y, atEntry->z) > sPlayerbotAIConfig.sightDistance) + { + ai->TellMaster("I won't follow: too far away"); + return true; + } + + ai->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT); + + MotionMaster &mm = *bot->GetMotionMaster(); + mm.Clear(); + mm.MovePoint(atEntry->mapid, atEntry->x, atEntry->y, atEntry->z); + float distance = bot->GetDistance(atEntry->x, atEntry->y, atEntry->z); + float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay; + ai->TellMaster("Wait for me"); + ai->SetNextCheckDelay(delay); + context->GetValue("last movement")->Get().lastAreaTrigger = triggerId; + + return true; +} + + + +bool AreaTriggerAction::Execute(Event event) +{ + LastMovement& movement = context->GetValue("last movement")->Get(); + + uint32 triggerId = movement.lastAreaTrigger; + movement.lastAreaTrigger = 0; + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(triggerId); + if(!atEntry) + { + return false; + } + + AreaTrigger const* at = sObjectMgr.GetAreaTrigger(triggerId); + if (!at) + { + return true; + } + + ai->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT); + + MotionMaster &mm = *bot->GetMotionMaster(); + mm.Clear(); + + WorldPacket p(CMSG_AREATRIGGER); + p << triggerId; + p.rpos(0); + bot->GetSession()->HandleAreaTriggerOpcode(p); + + ai->TellMaster("Hello"); + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.h b/src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.h new file mode 100644 index 0000000000..de2b63aaa5 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AreaTriggerAction.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" +#include "../values/LastMovementValue.h" + +namespace ai +{ + class ReachAreaTriggerAction : public MovementAction { + public: + ReachAreaTriggerAction(PlayerbotAI* ai) : MovementAction(ai, "reach area trigger") {} + + virtual bool Execute(Event event); + }; + + class AreaTriggerAction : public MovementAction { + public: + AreaTriggerAction(PlayerbotAI* ai) : MovementAction(ai, "area trigger") {} + + virtual bool Execute(Event event); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/AttackAction.cpp b/src/modules/Bots/playerbot/strategy/actions/AttackAction.cpp new file mode 100644 index 0000000000..2a3bee2171 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AttackAction.cpp @@ -0,0 +1,118 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AttackAction.h" +#include "MovementGenerator.h" +#include "CreatureAI.h" +#include "../../LootObjectStack.h" + +using namespace ai; + +bool AttackAction::Execute(Event event) +{ + Unit* target = GetTarget(); + + if (!target) + { + return false; + } + + return Attack(target); +} + +bool AttackMyTargetAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ObjectGuid guid = master->GetSelectionGuid(); + if (!guid) + { + if (verbose) ai->TellMaster("You have no target"); + { + return false; + } + } + + return Attack(ai->GetUnit(guid)); +} + +bool AttackAction::Attack(Unit* target) +{ + MotionMaster &mm = *bot->GetMotionMaster(); + if (mm.GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE || bot->IsTaxiFlying()) + { + if (verbose) ai->TellMaster("I cannot attack in flight"); + { + return false; + } + } + + if (!target) + { + if (verbose) ai->TellMaster("I have no target"); + { + return false; + } + } + + ostringstream msg; + msg << target->GetName(); + if (bot->IsFriendlyTo(target)) + { + msg << " is friendly to me"; + if (verbose) ai->TellMaster(msg.str()); + { + return false; + } + } + if (!bot->IsWithinLOSInMap(target)) + { + msg << " is not on my sight"; + if (verbose) ai->TellMaster(msg.str()); + { + return false; + } + } + + if (bot->IsMounted()) + { + WorldPacket emptyPacket; + bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); + } + + ObjectGuid guid = target->GetObjectGuid(); + bot->SetSelectionGuid(target->GetObjectGuid()); + + Unit* oldTarget = context->GetValue("current target")->Get(); + context->GetValue("old target")->Set(oldTarget); + + context->GetValue("current target")->Set(target); + context->GetValue("available loot")->Get()->Add(guid); + + Pet* pet = bot->GetPet(); + if (pet) + { + CreatureAI* creatureAI = ((Creature*)pet)->AI(); + if (creatureAI) + { + creatureAI->AttackStart(target); + } + } + + bot->Attack(target, true); + ai->ChangeEngine(BOT_STATE_COMBAT); + return true; +} + +bool AttackDuelOpponentAction::isUseful() +{ + return AI_VALUE(Unit*, "duel target"); +} + +bool AttackDuelOpponentAction::Execute(Event event) +{ + return Attack(AI_VALUE(Unit*, "duel target")); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/AttackAction.h b/src/modules/Bots/playerbot/strategy/actions/AttackAction.h new file mode 100644 index 0000000000..e13eb40943 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/AttackAction.h @@ -0,0 +1,38 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" + +namespace ai +{ + class AttackAction : public MovementAction + { + public: + AttackAction(PlayerbotAI* ai, string name) : MovementAction(ai, name) {} + + public: + virtual bool Execute(Event event); + + protected: + bool Attack(Unit* target); + }; + + class AttackMyTargetAction : public AttackAction + { + public: + AttackMyTargetAction(PlayerbotAI* ai, string name = "attack my target") : AttackAction(ai, name) {} + + public: + virtual bool Execute(Event event); + }; + + class AttackDuelOpponentAction : public AttackAction + { + public: + AttackDuelOpponentAction(PlayerbotAI* ai, string name = "attack duel opponent") : AttackAction(ai, name) {} + + public: + virtual bool Execute(Event event); + virtual bool isUseful(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/BankAction.cpp b/src/modules/Bots/playerbot/strategy/actions/BankAction.cpp new file mode 100644 index 0000000000..294f27f375 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/BankAction.cpp @@ -0,0 +1,186 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "BankAction.h" + +#include "../values/ItemCountValue.h" + +using namespace std; +using namespace ai; + +bool BankAction::Execute(Event event) +{ + string text = event.getParam(); + + list npcs = AI_VALUE(list, "nearest npcs"); + for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + { + Unit* npc = ai->GetUnit(*i); + if (!npc || !bot->GetNPCIfCanInteractWith(npc->GetObjectGuid(), UNIT_NPC_FLAG_BANKER)) + { + continue; + } + + return Execute(text, npc); + } + + ai->TellMaster("Cannot find banker nearby"); + return false; +} + +bool BankAction::Execute(string text, Unit* bank) +{ + if (text.empty() || text == "?") + { + ListItems(); + return true; + } + + bool result = false; + if (text[0] == '-') + { + ItemIds found = chat->parseItems(text); + for (ItemIds::iterator i = found.begin(); i != found.end(); i++) + { + uint32 itemId = *i; + result &= Withdraw(itemId); + } + } + else + { + list found = parseItems(text); + if (found.empty()) + { + return false; + } + + for (list::iterator i = found.begin(); i != found.end(); i++) + { + Item* item = *i; + if (!item) + { + continue; + } + + result &= Deposit(item); + } + } + + return result; +} + +bool BankAction::Withdraw(const uint32 itemid) +{ + Item* pItem = FindItemInBank(itemid); + if (!pItem) + { + return false; + } + + ItemPosCountVec dest; + InventoryResult msg = bot->CanStoreItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + bot->SendEquipError(msg, pItem, NULL); + return false; + } + + bot->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + bot->StoreItem(dest, pItem, true); + + std::ostringstream out; + out << "got " << chat->formatItem(pItem->GetProto(), pItem->GetCount()) << " from bank"; + ai->TellMaster(out.str()); + return true; +} + +bool BankAction::Deposit(Item* pItem) +{ + std::ostringstream out; + + ItemPosCountVec dest; + InventoryResult msg = bot->CanBankItem(NULL_BAG, NULL_SLOT, dest, pItem, false); + if (msg != EQUIP_ERR_OK) + { + bot->SendEquipError(msg, pItem, NULL); + return false; + } + + bot->RemoveItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + bot->BankItem(dest, pItem, true); + + out << "put " << chat->formatItem(pItem->GetProto(), pItem->GetCount()) << " to bank"; + ai->TellMaster(out.str()); + return true; +} + +void BankAction::ListItems() +{ + ai->TellMaster("=== Bank ==="); + + map items; + for (uint8 bag = BANK_SLOT_BAG_START; bag < BANK_SLOT_BAG_END; ++bag) + { + const Bag* const pBag = static_cast(bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag)); + if (pBag) + { + const ItemPrototype* const pBagProto = pBag->GetProto(); + std::string bagName = pBagProto->Name1; + + for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot) + { + Item* const item = bot->GetItemByPos(bag, slot); + if (item) + { + items[item->GetProto()->ItemId] = item->GetCount(); + } + } + } + } + + TellItems(items); +} + +Item* BankAction::FindItemInBank(uint32 ItemId) +{ + for (uint8 slot = BANK_SLOT_ITEM_START; slot < BANK_SLOT_ITEM_END; slot++) + { + Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + if (pItem) + { + const ItemPrototype* const pItemProto = pItem->GetProto(); + if (!pItemProto) + { + continue; + } + + if (pItemProto->ItemId == ItemId) // have required item + { + return pItem; + } + } + } + + for (uint8 bag = BANK_SLOT_BAG_START; bag < BANK_SLOT_BAG_END; ++bag) + { + const Bag* const pBag = (Bag *) bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag); + if (pBag) + for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot) + { + Item* const pItem = bot->GetItemByPos(bag, slot); + if (pItem) + { + const ItemPrototype* const pItemProto = pItem->GetProto(); + if (!pItemProto) + { + continue; + } + + if (pItemProto->ItemId == ItemId) + { + return pItem; + } + } + } + } + return NULL; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/BankAction.h b/src/modules/Bots/playerbot/strategy/actions/BankAction.h new file mode 100644 index 0000000000..6b22095e53 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/BankAction.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class BankAction : public InventoryAction { + public: + BankAction(PlayerbotAI* ai) : InventoryAction(ai, "bank") {} + virtual bool Execute(Event event); + + private: + bool Execute(string text, Unit* bank); + void ListItems(); + bool Withdraw(const uint32 itemid); + bool Deposit(Item* pItem); + Item* FindItemInBank(uint32 ItemId); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp b/src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp new file mode 100644 index 0000000000..333e98e2dd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp @@ -0,0 +1,132 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "BuffAction.h" + +#include "../values/ItemCountValue.h" + +using namespace ai; + +class FindBuffVisitor : public IterateItemsVisitor { +public: + FindBuffVisitor(Player* bot) : IterateItemsVisitor(), bot(bot) + { + } + + virtual bool Visit(Item* item) + { + if (bot->CanUseItem(item->GetProto()) != EQUIP_ERR_OK) + { + return true; + } + + const ItemPrototype* proto = item->GetProto(); + + if (proto->Class != ITEM_CLASS_CONSUMABLE) + { + return true; + } + + if (proto->SubClass != ITEM_SUBCLASS_ELIXIR && + proto->SubClass != ITEM_SUBCLASS_FLASK && + proto->SubClass != ITEM_SUBCLASS_SCROLL && + proto->SubClass != ITEM_SUBCLASS_FOOD && + proto->SubClass != ITEM_SUBCLASS_CONSUMABLE_OTHER && + proto->SubClass != ITEM_SUBCLASS_ITEM_ENHANCEMENT) + return true; + + for (int i=0; iSpells[i].SpellId; + if (!spellId) + { + continue; + } + + if (bot->HasAura(spellId)) + { + return true; + } + + Item* itemForSpell = *bot->GetPlayerbotAI()->GetAiObjectContext()->GetValue("item for spell", spellId); + if (itemForSpell && itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + { + return true; + } + + if (items.find(proto->SubClass) == items.end()) + { + items[proto->SubClass] = list(); + } + + items[proto->SubClass].push_back(item); + break; + } + + return true; + } + +public: + map > items; + +private: + Player* bot; +}; + +void BuffAction::TellHeader(uint32 subClass) +{ + switch (subClass) + { + case ITEM_SUBCLASS_ELIXIR: + ai->TellMaster("--- Elixir ---"); + return; + case ITEM_SUBCLASS_FLASK: + ai->TellMaster("--- Flask ---"); + return; + case ITEM_SUBCLASS_SCROLL: + ai->TellMaster("--- Scroll ---"); + return; + case ITEM_SUBCLASS_FOOD: + ai->TellMaster("--- Food ---"); + return; + case ITEM_SUBCLASS_CONSUMABLE_OTHER: + ai->TellMaster("--- Other ---"); + return; + case ITEM_SUBCLASS_ITEM_ENHANCEMENT: + ai->TellMaster("--- Enchant ---"); + return; + } +} + + +bool BuffAction::Execute(Event event) +{ + string text = event.getParam(); + + FindBuffVisitor visitor(bot); + IterateItems(&visitor); + + uint32 oldSubClass = -1; + for (map >::iterator i = visitor.items.begin(); i != visitor.items.end(); ++i) + { + list items = i->second; + + uint32 subClass = i->first; + if (oldSubClass != subClass) + { + if (!items.empty()) + { + TellHeader(subClass); + } + oldSubClass = subClass; + } + for (list::iterator j = items.begin(); j != items.end(); ++j) + { + Item* item = *j; + ostringstream out; + out << chat->formatItem(item->GetProto(), item->GetCount()); + ai->TellMaster(out); + } + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/BuffAction.h b/src/modules/Bots/playerbot/strategy/actions/BuffAction.h new file mode 100644 index 0000000000..da8b6a6250 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/BuffAction.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class BuffAction : public InventoryAction { + public: + BuffAction(PlayerbotAI* ai) : InventoryAction(ai, "buff") {} + virtual bool Execute(Event event); + + private: + void TellHeader(uint32 subClass); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp b/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp new file mode 100644 index 0000000000..f2977a9927 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp @@ -0,0 +1,60 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "BuyAction.h" +#include "../ItemVisitors.h" +#include "../values/ItemCountValue.h" + +using namespace ai; + +bool BuyAction::Execute(Event event) +{ + string link = event.getParam(); + + ItemIds itemIds = chat->parseItems(link); + if (itemIds.empty()) + { + return false; + } + + Player* master = GetMaster(); + + if (!master) + { + return false; + } + + ObjectGuid vendorguid = master->GetSelectionGuid(); + if (!vendorguid) + { + return false; + } + + Creature *pCreature = bot->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR); + if (!pCreature) + { + ai->TellMaster("Cannot talk to vendor"); + return false; + } + + VendorItemData const* tItems = pCreature->GetVendorItems(); + if (!tItems) + { + ai->TellMaster("This vendor has no items"); + return false; + } + + for (ItemIds::iterator i = itemIds.begin(); i != itemIds.end(); i++) + { + for (uint32 slot = 0; slot < tItems->GetItemCount(); slot++) + { + if (tItems->GetItem(slot)->item == *i) + { + bot->BuyItemFromVendor(vendorguid, *i, 1, NULL_BAG, NULL_SLOT); + ai->TellMaster("Bought item"); + } + } + } +BuyAction.cpp:(.text+0x247): undefined reference to `Player::BuyItemFromVendor(ObjectGuid, unsigned int, unsigned char, unsigned char, unsigned char)' + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/BuyAction.h b/src/modules/Bots/playerbot/strategy/actions/BuyAction.h new file mode 100644 index 0000000000..2e0822c222 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/BuyAction.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class BuyAction : public InventoryAction { + public: + BuyAction(PlayerbotAI* ai) : InventoryAction(ai, "buy") {} + virtual bool Execute(Event event); + + private: + bool TradeItem(FindItemVisitor *visitor, int8 slot); + bool TradeItem(const Item& item, int8 slot); + + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.cpp b/src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.cpp new file mode 100644 index 0000000000..cd406e3867 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.cpp @@ -0,0 +1,56 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CastCustomSpellAction.h" + +using namespace ai; + +bool CastCustomSpellAction::Execute(Event event) +{ + Unit* target = NULL; + + Player* master = GetMaster(); + if (master && master->GetSelectionGuid()) + { + target = ai->GetUnit(master->GetSelectionGuid()); + } + + if (!target) + { + target = bot; + } + + string text = event.getParam(); + + uint32 spell = chat->parseSpell(text); + + ostringstream msg; + if (!ai->CanCastSpell(spell, target)) + { + msg << "Cannot cast " << text << " on " << target->GetName(); + ai->TellMaster(msg.str()); + return false; + } + + bool result = false; + if (spell) + { + result = ai->CastSpell(spell, target); + } + else + { + ai->CastSpell(text, target); + } + + if (result) + { + msg << "Casting " << text << " on " << target->GetName(); + ai->TellMasterNoFacing(msg.str()); + } + else + { + msg << "Cast " << text << " on " << target->GetName() << " is failed"; + ai->TellMaster(msg.str()); + } + + return result; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.h b/src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.h new file mode 100644 index 0000000000..976a9e464a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/CastCustomSpellAction.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../Action.h" +#include "QuestAction.h" + +namespace ai +{ + class CastCustomSpellAction : public Action + { + public: + CastCustomSpellAction(PlayerbotAI* ai) : Action(ai, "cast custom spell") {} + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.cpp new file mode 100644 index 0000000000..d584a672ab --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.cpp @@ -0,0 +1,26 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ChangeChatAction.h" + + +using namespace ai; + + +bool ChangeChatAction::Execute(Event event) +{ + string text = event.getParam(); + ChatMsg parsed = chat->parseChat(text); + if (parsed == CHAT_MSG_SYSTEM) + { + ostringstream out; out << "Current chat is " << chat->formatChat(*context->GetValue("chat")); + ai->TellMaster(out); + } + else + { + context->GetValue("chat")->Set(parsed); + ostringstream out; out << "Chat set to " << chat->formatChat(parsed); + ai->TellMaster(out); + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.h b/src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.h new file mode 100644 index 0000000000..2f115519b6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChangeChatAction.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class ChangeChatAction : public Action { + public: + ChangeChatAction(PlayerbotAI* ai) : Action(ai, "chat") {} + virtual bool Execute(Event event); + + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.cpp new file mode 100644 index 0000000000..bcb0cbfc3d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.cpp @@ -0,0 +1,38 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ChangeStrategyAction.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool ChangeCombatStrategyAction::Execute(Event event) +{ + string text = event.getParam(); + ai->ChangeStrategy(text.empty() ? getName() : text, BOT_STATE_COMBAT); + return true; +} + +bool ChangeNonCombatStrategyAction::Execute(Event event) +{ + string text = event.getParam(); + + uint32 account = sObjectMgr.GetPlayerAccountIdByGUID(bot->GetObjectGuid()); + if (sPlayerbotAIConfig.IsInRandomAccountList(account) && ai->GetMaster() && ai->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + if (text.find("loot") != string::npos || text.find("gather") != string::npos) + { + ai->TellMaster("You can change any strategy except loot and gather"); + return false; + } + } + + ai->ChangeStrategy(text, BOT_STATE_NON_COMBAT); + return true; +} + +bool ChangeDeadStrategyAction::Execute(Event event) +{ + string text = event.getParam(); + ai->ChangeStrategy(text, BOT_STATE_DEAD); + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h b/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h new file mode 100644 index 0000000000..c1e53109c0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class ChangeCombatStrategyAction : public Action { + public: + ChangeCombatStrategyAction(PlayerbotAI* ai, string name = "co") : Action(ai, name) {} + + public: + virtual bool Execute(Event event); + }; + + class ChangeNonCombatStrategyAction : public Action { + public: + ChangeNonCombatStrategyAction(PlayerbotAI* ai) : Action(ai, "nc") {} + + public: + virtual bool Execute(Event event); + }; + + class ChangeDeadStrategyAction : public Action { + public: + ChangeDeadStrategyAction(PlayerbotAI* ai) : Action(ai, "dead") {} + + public: + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.cpp new file mode 100644 index 0000000000..bddf747eae --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ChangeTalentsAction.h" + +using namespace ai; + +bool ChangeTalentsAction::Execute(Event event) +{ + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.h b/src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.h new file mode 100644 index 0000000000..01730c6237 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChangeTalentsAction.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class ChangeTalentsAction : public Action { + public: + ChangeTalentsAction(PlayerbotAI* ai) : Action(ai, "talents") {} + + public: + virtual bool Execute(Event event); + + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h b/src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h new file mode 100644 index 0000000000..f8dad51a90 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h @@ -0,0 +1,179 @@ +#pragma once + +#include "ListQuestsActions.h" +#include "StatsAction.h" +#include "LeaveGroupAction.h" +#include "TellReputationAction.h" +#include "LogLevelAction.h" +#include "TellLosAction.h" +#include "DropQuestAction.h" +#include "QueryQuestAction.h" +#include "QueryItemUsageAction.h" +#include "LootStrategyAction.h" +#include "AddLootAction.h" +#include "ReleaseSpiritAction.h" +#include "TeleportAction.h" +#include "TaxiAction.h" +#include "RepairAllAction.h" +#include "UseItemAction.h" +#include "TellItemCountAction.h" +#include "RewardAction.h" +#include "BuyAction.h" +#include "SellAction.h" +#include "UnequipAction.h" +#include "EquipAction.h" +#include "TradeAction.h" +#include "ChangeTalentsAction.h" +#include "ListSpellsAction.h" +#include "ChangeStrategyAction.h" +#include "TrainerAction.h" +#include "ChangeChatAction.h" +#include "SetHomeAction.h" +#include "ResetAiAction.h" +#include "DestroyItemAction.h" +#include "BuffAction.h" +#include "AttackAction.h" +#include "HelpAction.h" +//#include "GuildBankAction.h" +#include "ChatShortcutActions.h" +#include "GossipHelloAction.h" +#include "CastCustomSpellAction.h" +#include "InviteToGroupAction.h" +#include "TellCastFailedAction.h" +#include "RtiAction.h" +#include "ReviveFromCorpseAction.h" +#include "BankAction.h" +#include "PositionAction.h" +#include "TellTargetAction.h" +#include "UseMeetingStoneAction.h" +#include "WhoAction.h" +#include "SaveManaAction.h" + +namespace ai +{ + class ChatActionContext : public NamedObjectContext + { + public: + ChatActionContext() + { + creators["stats"] = &ChatActionContext::stats; + creators["quests"] = &ChatActionContext::quests; + creators["leave"] = &ChatActionContext::leave; + creators["reputation"] = &ChatActionContext::reputation; + creators["log"] = &ChatActionContext::log; + creators["los"] = &ChatActionContext::los; + creators["drop"] = &ChatActionContext::drop; + creators["query quest"] = &ChatActionContext::query_quest; + creators["query item usage"] = &ChatActionContext::query_item_usage; + creators["ll"] = &ChatActionContext::ll; + creators["add all loot"] = &ChatActionContext::add_all_loot; + creators["release"] = &ChatActionContext::release; + creators["teleport"] = &ChatActionContext::teleport; + creators["taxi"] = &ChatActionContext::taxi; + creators["repair"] = &ChatActionContext::repair; + creators["use"] = &ChatActionContext::use; + creators["item count"] = &ChatActionContext::item_count; + creators["equip"] = &ChatActionContext::equip; + creators["unequip"] = &ChatActionContext::unequip; + creators["sell"] = &ChatActionContext::sell; + creators["buy"] = &ChatActionContext::buy; + creators["reward"] = &ChatActionContext::reward; + creators["trade"] = &ChatActionContext::trade; + creators["talents"] = &ChatActionContext::talents; + creators["spells"] = &ChatActionContext::spells; + creators["co"] = &ChatActionContext::co; + creators["nc"] = &ChatActionContext::nc; + creators["dead"] = &ChatActionContext::dead; + creators["trainer"] = &ChatActionContext::trainer; + creators["attack my target"] = &ChatActionContext::attack_my_target; + creators["chat"] = &ChatActionContext::chat; + creators["home"] = &ChatActionContext::home; + creators["destroy"] = &ChatActionContext::destroy; + creators["reset ai"] = &ChatActionContext::reset_ai; + creators["buff"] = &ChatActionContext::buff; + creators["help"] = &ChatActionContext::help; + creators["bank"] = &ChatActionContext::bank; + creators["follow chat shortcut"] = &ChatActionContext::follow_chat_shortcut; + creators["stay chat shortcut"] = &ChatActionContext::stay_chat_shortcut; + creators["flee chat shortcut"] = &ChatActionContext::flee_chat_shortcut; + creators["runaway chat shortcut"] = &ChatActionContext::runaway_chat_shortcut; + creators["grind chat shortcut"] = &ChatActionContext::grind_chat_shortcut; + creators["tank attack chat shortcut"] = &ChatActionContext::tank_attack_chat_shortcut; + creators["gossip hello"] = &ChatActionContext::gossip_hello; + creators["cast custom spell"] = &ChatActionContext::cast_custom_spell; + creators["invite"] = &ChatActionContext::invite; + creators["spell"] = &ChatActionContext::spell; + creators["rti"] = &ChatActionContext::rti; + creators["spirit healer"] = &ChatActionContext::spirit_healer; + creators["position"] = &ChatActionContext::position; + creators["tell target"] = &ChatActionContext::tell_target; + creators["summon"] = &ChatActionContext::summon; + creators["who"] = &ChatActionContext::who; + creators["save mana"] = &ChatActionContext::save_mana; + creators["max dps chat shortcut"] = &ChatActionContext::max_dps_chat_shortcut; + creators["tell attackers"] = &ChatActionContext::tell_attackers; + } + + private: + static Action* tell_attackers(PlayerbotAI* ai) { return new TellAttackersAction(ai); } + static Action* max_dps_chat_shortcut(PlayerbotAI* ai) { return new MaxDpsChatShortcutAction(ai); } + static Action* save_mana(PlayerbotAI* ai) { return new SaveManaAction(ai); } + static Action* who(PlayerbotAI* ai) { return new WhoAction(ai); } + static Action* summon(PlayerbotAI* ai) { return new SummonAction(ai); } + static Action* tell_target(PlayerbotAI* ai) { return new TellTargetAction(ai); } + static Action* position(PlayerbotAI* ai) { return new PositionAction(ai); } + static Action* spirit_healer(PlayerbotAI* ai) { return new SpiritHealerAction(ai); } + static Action* rti(PlayerbotAI* ai) { return new RtiAction(ai); } + static Action* invite(PlayerbotAI* ai) { return new InviteToGroupAction(ai); } + static Action* spell(PlayerbotAI* ai) { return new TellSpellAction(ai); } + static Action* cast_custom_spell(PlayerbotAI* ai) { return new CastCustomSpellAction(ai); } + static Action* tank_attack_chat_shortcut(PlayerbotAI* ai) { return new TankAttackChatShortcutAction(ai); } + static Action* grind_chat_shortcut(PlayerbotAI* ai) { return new GrindChatShortcutAction(ai); } + static Action* flee_chat_shortcut(PlayerbotAI* ai) { return new FleeChatShortcutAction(ai); } + static Action* runaway_chat_shortcut(PlayerbotAI* ai) { return new GoawayChatShortcutAction(ai); } + static Action* stay_chat_shortcut(PlayerbotAI* ai) { return new StayChatShortcutAction(ai); } + static Action* follow_chat_shortcut(PlayerbotAI* ai) { return new FollowChatShortcutAction(ai); } + static Action* bank(PlayerbotAI* ai) { return new BankAction(ai); } + static Action* help(PlayerbotAI* ai) { return new HelpAction(ai); } + static Action* buff(PlayerbotAI* ai) { return new BuffAction(ai); } + static Action* destroy(PlayerbotAI* ai) { return new DestroyItemAction(ai); } + static Action* home(PlayerbotAI* ai) { return new SetHomeAction(ai); } + static Action* chat(PlayerbotAI* ai) { return new ChangeChatAction(ai); } + static Action* attack_my_target(PlayerbotAI* ai) { return new AttackMyTargetAction(ai); } + static Action* trainer(PlayerbotAI* ai) { return new TrainerAction(ai); } + static Action* co(PlayerbotAI* ai) { return new ChangeCombatStrategyAction(ai); } + static Action* nc(PlayerbotAI* ai) { return new ChangeNonCombatStrategyAction(ai); } + static Action* dead(PlayerbotAI* ai) { return new ChangeDeadStrategyAction(ai); } + static Action* spells(PlayerbotAI* ai) { return new ListSpellsAction(ai); } + static Action* talents(PlayerbotAI* ai) { return new ChangeTalentsAction(ai); } + + static Action* equip(PlayerbotAI* ai) { return new EquipAction(ai); } + static Action* unequip(PlayerbotAI* ai) { return new UnequipAction(ai); } + static Action* sell(PlayerbotAI* ai) { return new SellAction(ai); } + static Action* buy(PlayerbotAI* ai) { return new BuyAction(ai); } + static Action* reward(PlayerbotAI* ai) { return new RewardAction(ai); } + static Action* trade(PlayerbotAI* ai) { return new TradeAction(ai); } + + static Action* item_count(PlayerbotAI* ai) { return new TellItemCountAction(ai); } + static Action* use(PlayerbotAI* ai) { return new UseItemAction(ai); } + static Action* repair(PlayerbotAI* ai) { return new RepairAllAction(ai); } + static Action* taxi(PlayerbotAI* ai) { return new TaxiAction(ai); } + static Action* teleport(PlayerbotAI* ai) { return new TeleportAction(ai); } + static Action* release(PlayerbotAI* ai) { return new ReleaseSpiritAction(ai); } + static Action* query_item_usage(PlayerbotAI* ai) { return new QueryItemUsageAction(ai); } + static Action* query_quest(PlayerbotAI* ai) { return new QueryQuestAction(ai); } + static Action* drop(PlayerbotAI* ai) { return new DropQuestAction(ai); } + static Action* stats(PlayerbotAI* ai) { return new StatsAction(ai); } + static Action* quests(PlayerbotAI* ai) { return new ListQuestsAction(ai); } + static Action* leave(PlayerbotAI* ai) { return new LeaveGroupAction(ai); } + static Action* reputation(PlayerbotAI* ai) { return new TellReputationAction(ai); } + static Action* log(PlayerbotAI* ai) { return new LogLevelAction(ai); } + static Action* los(PlayerbotAI* ai) { return new TellLosAction(ai); } + static Action* ll(PlayerbotAI* ai) { return new LootStrategyAction(ai); } + static Action* add_all_loot(PlayerbotAI* ai) { return new AddAllLootAction(ai); } + static Action* reset_ai(PlayerbotAI* ai) { return new ResetAiAction(ai); } + static Action* gossip_hello(PlayerbotAI* ai) { return new GossipHelloAction(ai); } + }; + + +}; diff --git a/src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.cpp b/src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.cpp new file mode 100644 index 0000000000..0f8824c67f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.cpp @@ -0,0 +1,124 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ChatShortcutActions.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool FollowChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ai->Reset(); + ai->ChangeStrategy("+follow master,-passive", BOT_STATE_NON_COMBAT); + ai->ChangeStrategy("-follow master,-passive", BOT_STATE_COMBAT); + if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig.sightDistance) + { + ai->TellMaster("I will not follow you - too far away"); + return true; + } + ai->TellMaster("Following"); + return true; +} + +bool StayChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ai->Reset(); + ai->ChangeStrategy("+stay,-passive", BOT_STATE_NON_COMBAT); + ai->ChangeStrategy("-follow master,-passive", BOT_STATE_COMBAT); + ai->TellMaster("Staying"); + return true; +} + +bool FleeChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ai->Reset(); + ai->ChangeStrategy("+follow master,+passive", BOT_STATE_NON_COMBAT); + ai->ChangeStrategy("+follow master,+passive", BOT_STATE_COMBAT); + if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig.sightDistance) + { + ai->TellMaster("I will not flee with you - too far away"); + return true; + } + ai->TellMaster("Fleeing"); + return true; +} + +bool GoawayChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ai->Reset(); + ai->ChangeStrategy("+runaway", BOT_STATE_NON_COMBAT); + ai->ChangeStrategy("+runaway", BOT_STATE_COMBAT); + ai->TellMaster("Running away"); + return true; +} + +bool GrindChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ai->Reset(); + ai->ChangeStrategy("+grind,-passive", BOT_STATE_NON_COMBAT); + ai->TellMaster("Grinding"); + return true; +} + +bool TankAttackChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + if (!ai->IsTank(bot)) + { + return false; + } + + ai->Reset(); + ai->ChangeStrategy("-passive", BOT_STATE_NON_COMBAT); + ai->ChangeStrategy("-passive", BOT_STATE_COMBAT); + ai->TellMaster("Attacking"); + return true; +} + +bool MaxDpsChatShortcutAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ai->Reset(); + ai->ChangeStrategy("-threat,-conserve mana,-cast time,+dps debuff", BOT_STATE_COMBAT); + ai->TellMaster("Max DPS"); + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.h b/src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.h new file mode 100644 index 0000000000..de9a86a52e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChatShortcutActions.h @@ -0,0 +1,57 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class FollowChatShortcutAction : public Action + { + public: + FollowChatShortcutAction(PlayerbotAI* ai) : Action(ai, "follow chat shortcut") {} + virtual bool Execute(Event event); + }; + + class StayChatShortcutAction : public Action + { + public: + StayChatShortcutAction(PlayerbotAI* ai) : Action(ai, "stay chat shortcut") {} + virtual bool Execute(Event event); + }; + + class FleeChatShortcutAction : public Action + { + public: + FleeChatShortcutAction(PlayerbotAI* ai) : Action(ai, "flee chat shortcut") {} + virtual bool Execute(Event event); + }; + + class GoawayChatShortcutAction : public Action + { + public: + GoawayChatShortcutAction(PlayerbotAI* ai) : Action(ai, "runaway chat shortcut") {} + virtual bool Execute(Event event); + }; + + class GrindChatShortcutAction : public Action + { + public: + GrindChatShortcutAction(PlayerbotAI* ai) : Action(ai, "grind chat shortcut") {} + virtual bool Execute(Event event); + }; + + class TankAttackChatShortcutAction : public Action + { + public: + TankAttackChatShortcutAction(PlayerbotAI* ai) : Action(ai, "tank attack chat shortcut") {} + virtual bool Execute(Event event); + }; + + class MaxDpsChatShortcutAction : public Action + { + public: + MaxDpsChatShortcutAction(PlayerbotAI* ai) : Action(ai, "max dps chat shortcut") {} + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp b/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp new file mode 100644 index 0000000000..3f3c39ac1b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp @@ -0,0 +1,81 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CheckMountStateAction.h" + +using namespace ai; + +uint64 extractGuid(WorldPacket& packet); + +bool CheckMountStateAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!bot->GetGroup() || !master) + { + return false; + } + + if (bot->IsTaxiFlying()) + { + return false; + } + + if (master->IsMounted() && !bot->IsMounted()) + { + return Mount(); + } + else if (!master->IsMounted() && bot->IsMounted()) + { + WorldPacket emptyPacket; + bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); + return true; + } + return false; +} + +bool CheckMountStateAction::Mount() +{ + Player* master = GetMaster(); + ai->RemoveShapeshift(); + + const SpellEntry* masterSpell = master->GetAurasByType(SPELL_AURA_MOUNTED).front()->GetSpellProto(); + int32 masterSpeed = max(masterSpell->EffectBasePoints[1], masterSpell->EffectBasePoints[2]); + + map > spells; + for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) + { + uint32 spellId = itr->first; + if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled || IsPassiveSpell(spellId)) + { + continue; + } + + const SpellEntry* spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo || spellInfo->EffectApplyAuraName[0] != SPELL_AURA_MOUNTED) + { + continue; + } + + int32 effect = max(spellInfo->EffectBasePoints[1], spellInfo->EffectBasePoints[2]); + if (effect < masterSpeed) + { + continue; + } + + spells[effect].push_back(spellId); + } + + for (map >::iterator i = spells.begin(); i != spells.end(); ++i) + { + vector& ids = i->second; + int index = urand(0, ids.size() - 1); + if (index >= ids.size()) + { + continue; + } + + ai->CastSpell(ids[index], bot); + return true; + } + + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.h b/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.h new file mode 100644 index 0000000000..c5b087e9be --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" +#include "../values/LastMovementValue.h" + +namespace ai +{ + class CheckMountStateAction : public Action { + public: + CheckMountStateAction(PlayerbotAI* ai) : Action(ai, "check mount state") {} + + virtual bool Execute(Event event); + + private: + bool Mount(); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChooseTargetActions.h b/src/modules/Bots/playerbot/strategy/actions/ChooseTargetActions.h new file mode 100644 index 0000000000..96067de49f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ChooseTargetActions.h @@ -0,0 +1,79 @@ +#pragma once + +#include "../Action.h" +#include "AttackAction.h" + +namespace ai +{ + class DpsAssistAction : public AttackAction + { + public: + DpsAssistAction(PlayerbotAI* ai) : AttackAction(ai, "dps assist") {} + + virtual string GetTargetName() { return "dps target"; } + }; + + class TankAssistAction : public AttackAction + { + public: + TankAssistAction(PlayerbotAI* ai) : AttackAction(ai, "tank assist") {} + virtual string GetTargetName() { return "tank target"; } + }; + + class AttackAnythingAction : public AttackAction + { + public: + AttackAnythingAction(PlayerbotAI* ai) : AttackAction(ai, "attack anything") {} + virtual string GetTargetName() { return "grind target"; } + virtual bool Execute(Event event) + { + return AttackAction::Execute(event); + } + virtual bool isUseful() { + return GetTarget() && + (AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.mediumHealth && + (!AI_VALUE2(uint8, "mana", "self target") || AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumMana)) || AI_VALUE2(bool, "combat", "self target"); + } + virtual bool isPossible() + { + return AttackAction::isPossible() && GetTarget(); + } + }; + + class AttackLeastHpTargetAction : public AttackAction + { + public: + AttackLeastHpTargetAction(PlayerbotAI* ai) : AttackAction(ai, "attack least hp target") {} + virtual string GetTargetName() { return "least hp target"; } + }; + + class AttackEnemyPlayerAction : public AttackAction + { + public: + AttackEnemyPlayerAction(PlayerbotAI* ai) : AttackAction(ai, "attack enemy player") {} + virtual string GetTargetName() { return "enemy player target"; } + }; + + class AttackRtiTargetAction : public AttackAction + { + public: + AttackRtiTargetAction(PlayerbotAI* ai) : AttackAction(ai, "attack rti target") {} + virtual string GetTargetName() { return "rti target"; } + }; + + class DropTargetAction : public Action + { + public: + DropTargetAction(PlayerbotAI* ai) : Action(ai, "drop target") {} + + virtual bool Execute(Event event) + { + context->GetValue("current target")->Set(NULL); + bot->SetSelectionGuid(ObjectGuid()); + ai->ChangeEngine(BOT_STATE_NON_COMBAT); + ai->InterruptSpell(); + return true; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp b/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp new file mode 100644 index 0000000000..83f81696fc --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp @@ -0,0 +1,35 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DestroyItemAction.h" + +#include "../values/ItemCountValue.h" + +using namespace ai; + +bool DestroyItemAction::Execute(Event event) +{ + string text = event.getParam(); + ItemIds ids = chat->parseItems(text); + + for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + { + FindItemByIdVisitor visitor(*i); + DestroyItem(&visitor); + } + + return true; +} + +void DestroyItemAction::DestroyItem(FindItemVisitor* visitor) +{ + IterateItems(visitor); + list items = visitor->GetResult(); + for (list::iterator i = items.begin(); i != items.end(); ++i) + { + Item* item = *i; + bot->DestroyItem(item->GetBagSlot(),item->GetSlot(), true); + bot->SaveInventoryAndGoldToDB(); + ostringstream out; out << chat->formatItem(item->GetProto()) << " destroyed"; + ai->TellMaster(out); + } +} diff --git a/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.h b/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.h new file mode 100644 index 0000000000..ad1ab05b21 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class DestroyItemAction : public InventoryAction { + public: + DestroyItemAction(PlayerbotAI* ai) : InventoryAction(ai, "destroy") {} + virtual bool Execute(Event event); + + private: + void DestroyItem(FindItemVisitor* visitor); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/DropQuestAction.cpp b/src/modules/Bots/playerbot/strategy/actions/DropQuestAction.cpp new file mode 100644 index 0000000000..4e42e19d7b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/DropQuestAction.cpp @@ -0,0 +1,22 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DropQuestAction.h" + + +using namespace ai; + +bool DropQuestAction::Execute(Event event) +{ + string link = event.getParam(); + + PlayerbotChatHandler ch(bot); + if (!ch.dropQuest(link)) + { + ostringstream out; out << "Could not drop quest: " << link; + ai->TellMaster(out); + return false; + } + + ai->TellMaster("Quest removed"); + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/DropQuestAction.h b/src/modules/Bots/playerbot/strategy/actions/DropQuestAction.h new file mode 100644 index 0000000000..af5d4ca670 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/DropQuestAction.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class DropQuestAction : public Action { + public: + DropQuestAction(PlayerbotAI* ai) : Action(ai, "drop quest") {} + virtual bool Execute(Event event); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/EmoteAction.cpp b/src/modules/Bots/playerbot/strategy/actions/EmoteAction.cpp new file mode 100644 index 0000000000..10a8c41dcc --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/EmoteAction.cpp @@ -0,0 +1,100 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "EmoteAction.h" + +using namespace ai; + +map EmoteAction::emotes; + +bool EmoteAction::Execute(Event event) +{ + if (emotes.empty()) + { + InitEmotes(); + } + + uint32 emote = 0; + + string param = event.getParam(); + if (param.empty() || emotes.find(param) == emotes.end()) + { + int index = rand() % emotes.size(); + for (map::iterator i = emotes.begin(); i != emotes.end() && index; ++i, --index) + { + emote = i->second; + } + } + else + { + emote = emotes[param]; + } + + bot->CastStop(); + ai->InterruptSpell(); + bot->SetStandState(UNIT_STAND_STATE_STAND); + + Player* master = GetMaster(); + if (master) + { + ObjectGuid masterSelection = master->GetSelectionGuid(); + if (masterSelection) + { + ObjectGuid oldSelection = bot->GetSelectionGuid(); + bot->SetSelectionGuid(masterSelection); + bot->HandleEmoteCommand(emote); + bot->SetSelectionGuid(oldSelection); + return true; + } + } + + bot->HandleEmoteCommand(emote); + return true; +} + +void EmoteAction::InitEmotes() +{ + emotes["dance"] = EMOTE_ONESHOT_DANCE; + emotes["drown"] = EMOTE_ONESHOT_DROWN; + emotes["land"] = EMOTE_ONESHOT_LAND; + emotes["laugh_nosheathe"] = EMOTE_ONESHOT_LAUGH_NOSHEATHE; + emotes["liftoff"] = EMOTE_ONESHOT_LIFTOFF; + emotes["loot"] = EMOTE_ONESHOT_LOOT; + emotes["no"] = EMOTE_ONESHOT_NO; + emotes["point_nosheathe"] = EMOTE_ONESHOT_POINT_NOSHEATHE; + emotes["roar"] = EMOTE_STATE_ROAR; + emotes["salute"] = EMOTE_ONESHOT_SALUTE; + emotes["stomp"] = EMOTE_ONESHOT_STOMP; + emotes["train"] = EMOTE_ONESHOT_TRAIN; + emotes["yes"] = EMOTE_ONESHOT_YES; + emotes["applaud"] = EMOTE_ONESHOT_APPLAUD; + emotes["battleroar"] = EMOTE_ONESHOT_BATTLEROAR; + emotes["beg"] = EMOTE_ONESHOT_BEG; + emotes["bow"] = EMOTE_ONESHOT_BOW; + emotes["cheer"] = EMOTE_ONESHOT_CHEER; + emotes["chicken"] = EMOTE_ONESHOT_CHICKEN; + emotes["cry"] = EMOTE_ONESHOT_CRY; + emotes["dance"] = EMOTE_STATE_DANCE; + emotes["eat"] = EMOTE_ONESHOT_EAT; + emotes["exclamation"] = EMOTE_ONESHOT_EXCLAMATION; + emotes["flex"] = EMOTE_ONESHOT_FLEX; + emotes["kick"] = EMOTE_ONESHOT_KICK; + emotes["kiss"] = EMOTE_ONESHOT_KISS; + emotes["kneel"] = EMOTE_ONESHOT_KNEEL; + emotes["laugh"] = EMOTE_ONESHOT_LAUGH; + emotes["parryshield"] = EMOTE_ONESHOT_PARRYSHIELD; + emotes["parryunarmed"] = EMOTE_ONESHOT_PARRYUNARMED; + emotes["point"] = EMOTE_ONESHOT_POINT; + emotes["question"] = EMOTE_ONESHOT_QUESTION; + emotes["ready1h"] = EMOTE_ONESHOT_READY1H; + emotes["readybow"] = EMOTE_ONESHOT_READYBOW; + emotes["readyunarmed"] = EMOTE_ONESHOT_READYUNARMED; + emotes["roar"] = EMOTE_ONESHOT_ROAR; + emotes["rude"] = EMOTE_ONESHOT_RUDE; + emotes["shout"] = EMOTE_ONESHOT_SHOUT; + emotes["shy"] = EMOTE_ONESHOT_SHY; + emotes["sleep"] = EMOTE_STATE_SLEEP; + emotes["talk"] = EMOTE_ONESHOT_TALK; + emotes["wave"] = EMOTE_ONESHOT_WAVE; + emotes["woundcritical"] = EMOTE_ONESHOT_WOUNDCRITICAL; + emotes["wound"] = EMOTE_ONESHOT_WOUND; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/EmoteAction.h b/src/modules/Bots/playerbot/strategy/actions/EmoteAction.h new file mode 100644 index 0000000000..8aa8fdad2e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/EmoteAction.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class EmoteAction : public Action + { + public: + EmoteAction(PlayerbotAI* ai) : Action(ai, "emote") {} + virtual bool Execute(Event event); + + private: + void InitEmotes(); + static map emotes; + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp b/src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp new file mode 100644 index 0000000000..14a7bd4fad --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp @@ -0,0 +1,51 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "EquipAction.h" + +#include "../values/ItemCountValue.h" + +using namespace ai; + +bool EquipAction::Execute(Event event) +{ + string text = event.getParam(); + + ItemIds ids = chat->parseItems(text); + + for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + { + FindItemByIdVisitor visitor(*i); + EquipItem(&visitor); + } + + return true; +} + +void EquipAction::EquipItem(FindItemVisitor* visitor) +{ + IterateItems(visitor); + list items = visitor->GetResult(); + if (!items.empty()) EquipItem(**items.begin()); +} + + +void EquipAction::EquipItem(Item& item) +{ + uint8 bagIndex = item.GetBagSlot(); + uint8 slot = item.GetSlot(); + uint32 itemId = item.GetProto()->ItemId; + + if (item.GetProto()->InventoryType == INVTYPE_AMMO) + { + bot->SetAmmo(itemId); + } + else + { + WorldPacket* const packet = new WorldPacket(CMSG_AUTOEQUIP_ITEM, 2); + *packet << bagIndex << slot; + bot->GetSession()->QueuePacket(packet); + } + + ostringstream out; out << "equipping " << chat->formatItem(item.GetProto()); + ai->TellMaster(out); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/EquipAction.h b/src/modules/Bots/playerbot/strategy/actions/EquipAction.h new file mode 100644 index 0000000000..e6bd7c9c20 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/EquipAction.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class EquipAction : public InventoryAction { + public: + EquipAction(PlayerbotAI* ai) : InventoryAction(ai, "equip") {} + virtual bool Execute(Event event); + + private: + void EquipItem(FindItemVisitor* visitor); + void EquipItem(Item& item); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/FollowActions.cpp b/src/modules/Bots/playerbot/strategy/actions/FollowActions.cpp new file mode 100644 index 0000000000..ad8d4fc8e6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/FollowActions.cpp @@ -0,0 +1,33 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "FollowActions.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool FollowLineAction::Execute(Event event) +{ + return Follow(AI_VALUE(Unit*, "line target"), sPlayerbotAIConfig.followDistance, 0.0f); +} + +bool FollowMasterAction::Execute(Event event) +{ + return Follow(AI_VALUE(Unit*, "master target")); +} + +bool FollowMasterRandomAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + float range = rand() % 10 + 2; + float angle = GetFollowAngle(); + float x = master->GetPositionX() + cos(angle) * range; + float y = master->GetPositionY() + sin(angle) * range; + float z = master->GetPositionZ(); + + return MoveTo(master->GetMapId(), x, y, z); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/FollowActions.h b/src/modules/Bots/playerbot/strategy/actions/FollowActions.h new file mode 100644 index 0000000000..408ecb82af --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/FollowActions.h @@ -0,0 +1,37 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" + +namespace ai +{ + class FollowAction : public MovementAction { + public: + FollowAction(PlayerbotAI* ai, string name) : MovementAction(ai, name) {} + }; + + class FollowLineAction : public FollowAction { + public: + FollowLineAction(PlayerbotAI* ai) : FollowAction(ai, "follow line") {} + virtual bool Execute(Event event); + }; + + class FollowMasterAction : public MovementAction { + public: + FollowMasterAction(PlayerbotAI* ai) : MovementAction(ai, "follow master") {} + virtual bool Execute(Event event); + + virtual bool isUseful() + { + return AI_VALUE2(float, "distance", "master target") > sPlayerbotAIConfig.followDistance && + !AI_VALUE(bool, "can loot"); + } + + }; + + class FollowMasterRandomAction : public MovementAction { + public: + FollowMasterRandomAction(PlayerbotAI* ai) : MovementAction(ai, "be near") {} + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/GenericActions.cpp b/src/modules/Bots/playerbot/strategy/actions/GenericActions.cpp new file mode 100644 index 0000000000..ed6efc6cf8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GenericActions.cpp @@ -0,0 +1,5 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "GenericActions.h" + +using namespace ai; diff --git a/src/modules/Bots/playerbot/strategy/actions/GenericActions.h b/src/modules/Bots/playerbot/strategy/actions/GenericActions.h new file mode 100644 index 0000000000..8ac0d9c64b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GenericActions.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Action.h" +#include "GenericSpellActions.h" +#include "ReachTargetActions.h" +#include "ChooseTargetActions.h" +#include "MovementActions.h" + +namespace ai +{ + class MeleeAction : public AttackAction + { + public: + MeleeAction(PlayerbotAI* ai) : AttackAction(ai, "melee") {} + + virtual string GetTargetName() { return "current target"; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.cpp b/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.cpp new file mode 100644 index 0000000000..3f3abb0553 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.cpp @@ -0,0 +1,62 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GenericActions.h" + +using namespace ai; + +bool CastSpellAction::Execute(Event event) +{ + return ai->CastSpell(spell, GetTarget()); +} + +bool CastSpellAction::isPossible() +{ + if (AI_VALUE2(float, "distance", GetTargetName()) > range) + { + return false; + } + + return ai->CanCastSpell(spell, GetTarget()); +} + +bool CastSpellAction::isUseful() +{ + return GetTarget() && AI_VALUE2(bool, "spell cast useful", spell); +} + +bool CastAuraSpellAction::isUseful() +{ + return CastSpellAction::isUseful() && !ai->HasAura(spell, GetTarget()); +} + +bool CastEnchantItemAction::isUseful() +{ + if (!CastSpellAction::isUseful()) + { + return false; + } + + uint32 spellId = AI_VALUE2(uint32, "spell id", spell); + return spellId && AI_VALUE2(Item*, "item for spell", spellId); +} + +bool CastHealingSpellAction::isUseful() +{ + return CastAuraSpellAction::isUseful() && AI_VALUE2(uint8, "health", GetTargetName()) < (100 - estAmount); +} + +bool CastAoeHealSpellAction::isUseful() +{ + return CastSpellAction::isUseful() && AI_VALUE2(uint8, "aoe heal", "medium") > 0; +} + + +Value* CurePartyMemberAction::GetTargetValue() +{ + return context->GetValue("party member to dispel", dispelType); +} + +Value* BuffOnPartyAction::GetTargetValue() +{ + return context->GetValue("party member without aura", spell); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h b/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h new file mode 100644 index 0000000000..71824f49c3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h @@ -0,0 +1,277 @@ +#pragma once + +#include "../Action.h" +#include "../../PlayerbotAIConfig.h" + +#define BEGIN_SPELL_ACTION(clazz, name) \ +class clazz : public CastSpellAction \ + { \ + public: \ + clazz(PlayerbotAI* ai) : CastSpellAction(ai, name) {} \ + + +#define END_SPELL_ACTION() \ + }; + +#define BEGIN_DEBUFF_ACTION(clazz, name) \ +class clazz : public CastDebuffSpellAction \ + { \ + public: \ + clazz(PlayerbotAI* ai) : CastDebuffSpellAction(ai, name) {} \ + +#define BEGIN_RANGED_SPELL_ACTION(clazz, name) \ +class clazz : public CastSpellAction \ + { \ + public: \ + clazz(PlayerbotAI* ai) : CastSpellAction(ai, name) {} \ + +#define BEGIN_MELEE_SPELL_ACTION(clazz, name) \ +class clazz : public CastMeleeSpellAction \ + { \ + public: \ + clazz(PlayerbotAI* ai) : CastMeleeSpellAction(ai, name) {} \ + + +#define END_RANGED_SPELL_ACTION() \ + }; + + +#define BEGIN_BUFF_ON_PARTY_ACTION(clazz, name) \ +class clazz : public BuffOnPartyAction \ + { \ + public: \ + clazz(PlayerbotAI* ai) : BuffOnPartyAction(ai, name) {} + +namespace ai +{ + class CastSpellAction : public Action + { + public: + CastSpellAction(PlayerbotAI* ai, string spell) : Action(ai, spell), + range(sPlayerbotAIConfig.spellDistance) + { + this->spell = spell; + } + + virtual string GetTargetName() { return "current target"; }; + virtual bool Execute(Event event); + virtual bool isPossible(); + virtual bool isUseful(); + virtual ActionThreatType getThreatType() { return ACTION_THREAT_SINGLE; } + + virtual NextAction** getPrerequisites() + { + if (range > sPlayerbotAIConfig.spellDistance) + { + return NULL; + } + else if (range > ATTACK_DISTANCE) + { + return NextAction::merge( NextAction::array(0, new NextAction("reach spell"), NULL), Action::getPrerequisites()); + } + else + { + return NextAction::merge( NextAction::array(0, new NextAction("reach melee"), NULL), Action::getPrerequisites()); + } + } + + protected: + string spell; + float range; + }; + + //--------------------------------------------------------------------------------------------------------------------- + class CastAuraSpellAction : public CastSpellAction + { + public: + CastAuraSpellAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) {} + + virtual bool isUseful(); + }; + + //--------------------------------------------------------------------------------------------------------------------- + class CastMeleeSpellAction : public CastSpellAction + { + public: + CastMeleeSpellAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) { + range = ATTACK_DISTANCE; + } + }; + + //--------------------------------------------------------------------------------------------------------------------- + class CastDebuffSpellAction : public CastAuraSpellAction + { + public: + CastDebuffSpellAction(PlayerbotAI* ai, string spell) : CastAuraSpellAction(ai, spell) {} + }; + + class CastDebuffSpellOnAttackerAction : public CastAuraSpellAction + { + public: + CastDebuffSpellOnAttackerAction(PlayerbotAI* ai, string spell) : CastAuraSpellAction(ai, spell) {} + Value* GetTargetValue() + { + return context->GetValue("attacker without aura", spell); + } + virtual string getName() { return spell + " on attacker"; } + virtual ActionThreatType getThreatType() { return ACTION_THREAT_AOE; } + }; + + class CastBuffSpellAction : public CastAuraSpellAction + { + public: + CastBuffSpellAction(PlayerbotAI* ai, string spell) : CastAuraSpellAction(ai, spell) + { + range = sPlayerbotAIConfig.spellDistance; + } + + virtual string GetTargetName() { return "self target"; } + }; + + class CastEnchantItemAction : public CastSpellAction + { + public: + CastEnchantItemAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) + { + range = sPlayerbotAIConfig.spellDistance; + } + + virtual bool isUseful(); + virtual string GetTargetName() { return "self target"; } + }; + + //--------------------------------------------------------------------------------------------------------------------- + + class CastHealingSpellAction : public CastAuraSpellAction + { + public: + CastHealingSpellAction(PlayerbotAI* ai, string spell, uint8 estAmount = 15.0f) : CastAuraSpellAction(ai, spell) + { + this->estAmount = estAmount; + range = sPlayerbotAIConfig.spellDistance; + } + virtual string GetTargetName() { return "self target"; } + virtual bool isUseful(); + virtual ActionThreatType getThreatType() { return ACTION_THREAT_AOE; } + + protected: + uint8 estAmount; + }; + + class CastAoeHealSpellAction : public CastHealingSpellAction + { + public: + CastAoeHealSpellAction(PlayerbotAI* ai, string spell, uint8 estAmount = 15.0f) : CastHealingSpellAction(ai, spell, estAmount) {} + virtual string GetTargetName() { return "party member to heal"; } + virtual bool isUseful(); + }; + + class CastCureSpellAction : public CastSpellAction + { + public: + CastCureSpellAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) + { + range = sPlayerbotAIConfig.spellDistance; + } + + virtual string GetTargetName() { return "self target"; } + }; + + class PartyMemberActionNameSupport { + public: + PartyMemberActionNameSupport(string spell) + { + name = string(spell) + " on party"; + } + + virtual string getName() { return name; } + + private: + string name; + }; + + class HealPartyMemberAction : public CastHealingSpellAction, public PartyMemberActionNameSupport + { + public: + HealPartyMemberAction(PlayerbotAI* ai, string spell, uint8 estAmount = 15.0f) : + CastHealingSpellAction(ai, spell, estAmount), PartyMemberActionNameSupport(spell) {} + + virtual string GetTargetName() { return "party member to heal"; } + virtual string getName() { return PartyMemberActionNameSupport::getName(); } + }; + + class ResurrectPartyMemberAction : public CastSpellAction + { + public: + ResurrectPartyMemberAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) {} + + virtual string GetTargetName() { return "party member to resurrect"; } + }; + //--------------------------------------------------------------------------------------------------------------------- + + class CurePartyMemberAction : public CastSpellAction, public PartyMemberActionNameSupport + { + public: + CurePartyMemberAction(PlayerbotAI* ai, string spell, uint32 dispelType) : + CastSpellAction(ai, spell), PartyMemberActionNameSupport(spell) + { + this->dispelType = dispelType; + } + + virtual Value* GetTargetValue(); + virtual string getName() { return PartyMemberActionNameSupport::getName(); } + + protected: + uint32 dispelType; + }; + + //--------------------------------------------------------------------------------------------------------------------- + + class BuffOnPartyAction : public CastBuffSpellAction, public PartyMemberActionNameSupport + { + public: + BuffOnPartyAction(PlayerbotAI* ai, string spell) : + CastBuffSpellAction(ai, spell), PartyMemberActionNameSupport(spell) {} + public: + virtual Value* GetTargetValue(); + virtual string getName() { return PartyMemberActionNameSupport::getName(); } + }; + + //--------------------------------------------------------------------------------------------------------------------- + + class CastShootAction : public CastSpellAction + { + public: + CastShootAction(PlayerbotAI* ai) : CastSpellAction(ai, "shoot") {} + virtual ActionThreatType getThreatType() { return ACTION_THREAT_NONE; } + }; + + class CastLifeBloodAction : public CastHealingSpellAction + { + public: + CastLifeBloodAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "lifeblood") {} + }; + + class CastGiftOfTheNaaruAction : public CastHealingSpellAction + { + public: + CastGiftOfTheNaaruAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "gift of the naaru") {} + }; + + class CastArcaneTorrentAction : public CastBuffSpellAction + { + public: + CastArcaneTorrentAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "arcane torrent") {} + }; + + class CastSpellOnEnemyHealerAction : public CastSpellAction + { + public: + CastSpellOnEnemyHealerAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) {} + Value* GetTargetValue() + { + return context->GetValue("enemy healer target", spell); + } + virtual string getName() { return spell + " on enemy healer"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.cpp b/src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.cpp new file mode 100644 index 0000000000..cbb7e2cb58 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.cpp @@ -0,0 +1,77 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GossipHelloAction.h" + + +using namespace ai; + +bool GossipHelloAction::Execute(Event event) +{ + ObjectGuid guid; + + WorldPacket &p = event.getPacket(); + if (p.empty()) + { + Player* master = GetMaster(); + if (master) + { + guid = master->GetSelectionGuid(); + } + } + else + { + p.rpos(0); + p >> guid; + } + + if (!guid) + { + return false; + } + + Creature *pCreature = bot->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE); + if (!pCreature) + { + DEBUG_LOG ("[PlayerbotMgr]: HandleMasterIncomingPacket - Received CMSG_GOSSIP_HELLO %s not found or you can't interact with him.", guid.GetString().c_str()); + return false; + } + + GossipMenuItemsMapBounds pMenuItemBounds = sObjectMgr.GetGossipMenuItemsMapBounds(pCreature->GetCreatureInfo()->GossipMenuId); + if (pMenuItemBounds.first == pMenuItemBounds.second) + { + return false; + } + + WorldPacket p1; + p1 << guid; + bot->GetSession()->HandleGossipHelloOpcode(p1); + bot->SetFacingToObject(pCreature); + + ostringstream out; out << "--- " << pCreature->GetName() << " ---"; + ai->TellMasterNoFacing(out.str()); + + GossipMenu& menu = bot->PlayerTalkClass->GetGossipMenu(); + unsigned int i = 0, loops = 0; + set alreadyTalked; + while (i < menu.MenuItemCount() && loops++ < 100) + { + GossipMenuItem const& item = menu.GetItem(i); + ai->TellMasterNoFacing(item.m_gMessage); + + if (item.m_gOptionId < 1000 && item.m_gOptionId != GOSSIP_OPTION_GOSSIP) + { + i++; + continue; + } + + WorldPacket p1; + std::string code; + p1 << guid << menu.GetMenuId() << i << code; + bot->GetSession()->HandleGossipSelectOptionOpcode(p1); + + i = 0; + } + + bot->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.h b/src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.h new file mode 100644 index 0000000000..603737cef6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GossipHelloAction.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class GossipHelloAction : public Action { + public: + GossipHelloAction(PlayerbotAI* ai) : Action(ai, "gossip hello") {} + virtual bool Execute(Event event); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.cpp b/src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.cpp new file mode 100644 index 0000000000..b4fb75f824 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.cpp @@ -0,0 +1,44 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GuildAcceptAction.h" + +using namespace std; +using namespace ai; + +bool GuildAcceptAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + bool accept = true; + uint32 guildId = master->GetGuildId(); + if (!guildId) + { + ai->TellMaster("You are not in a guild"); + accept = false; + } + else if (bot->GetGuildId()) + { + ai->TellMaster("Sorry, I am in a guild already"); + accept = false; + } + else if (!ai->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, false, master, true)) + { + accept = false; + } + + WorldPacket packet; + if (accept) + { + bot->SetGuildIdInvited(guildId); + bot->GetSession()->HandleGuildAcceptOpcode(packet); + } + else + { + bot->GetSession()->HandleGuildDeclineOpcode(packet); + } + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.h b/src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.h new file mode 100644 index 0000000000..ab8910cc64 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GuildAcceptAction.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class GuildAcceptAction : public Action { + public: + GuildAcceptAction(PlayerbotAI* ai) : Action(ai, "guild accept") {} + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/GuildBankAction.cpp b/src/modules/Bots/playerbot/strategy/actions/GuildBankAction.cpp new file mode 100644 index 0000000000..74dee52863 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GuildBankAction.cpp @@ -0,0 +1,67 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "GuildBankAction.h" + +//#include "../values/ItemCountValue.h" + +using namespace std; +using namespace ai; + +/*bool GuildBankAction::Execute(Event event) +{ + string text = event.getParam(); + if (text.empty()) + { + return false; + } + + list gos = AI_VALUE(list, "nearest game objects"); + for (list::iterator i = gos.begin(); i != gos.end(); i++) + { + GameObject* go = ai->GetGameObject(*i); + if (!go || !bot->GetGameObjectIfCanInteractWith(go->GetObjectGuid(), GAMEOBJECT_TYPE_GUILD_BANK)) + { + continue; + } + + return Execute(text, go); + } + + ai->TellMaster("Cannot find the guild bank nearby"); + return false; +} + +bool GuildBankAction::Execute(string text, GameObject* bank) +{ + bool result = true; + + list found = parseItems(text); + if (found.empty()) + { + return false; + } + + for (list::iterator i = found.begin(); i != found.end(); i++) + { + Item* item = *i; + if (item) + { + result &= MoveFromCharToBank(item, bank); + } + } + + return result; +} + +bool GuildBankAction::MoveFromCharToBank(Item* item, GameObject* bank) +{ + uint32 playerSlot = item->GetSlot(); + uint32 playerBag = item->GetBagSlot(); + + Guild* guild = sGuildMgr.GetGuildById(bot->GetGuildId()); + guild->MoveFromCharToBank(bot, playerBag, playerSlot, 0, INVENTORY_SLOT_BAG_0, 0); + + ostringstream out; out << chat->formatItem(item->GetProto()) << " put to guild bank"; + ai->TellMaster(out); + return true; +}*/ diff --git a/src/modules/Bots/playerbot/strategy/actions/GuildBankAction.h b/src/modules/Bots/playerbot/strategy/actions/GuildBankAction.h new file mode 100644 index 0000000000..374fc0fdea --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/GuildBankAction.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class GuildBankAction : public InventoryAction { + public: + GuildBankAction(PlayerbotAI* ai) : InventoryAction(ai, "guild bank") {} + virtual bool Execute(Event event); + + private: + bool Execute(string text, GameObject* bank); + bool MoveFromCharToBank(Item* item, GameObject* bank); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/HelpAction.cpp b/src/modules/Bots/playerbot/strategy/actions/HelpAction.cpp new file mode 100644 index 0000000000..6d4c9db49e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/HelpAction.cpp @@ -0,0 +1,56 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "HelpAction.h" +#include "ChatActionContext.h" + +using namespace ai; + +HelpAction::HelpAction(PlayerbotAI* ai) : Action(ai, "help") +{ + chatContext = new ChatActionContext(); +} + +HelpAction::~HelpAction() +{ + delete chatContext; +} + +bool HelpAction::Execute(Event event) +{ + TellChatCommands(); + TellStrategies(); + return true; +} + +void HelpAction::TellChatCommands() +{ + ostringstream out; + out << "Whisper any of: "; + out << CombineSupported(chatContext->supports()); + out << ", [item], [quest] or [object] link"; + ai->TellMaster(out); +} + +void HelpAction::TellStrategies() +{ + ostringstream out; + out << "Possible strategies (co/nc/dead commands): "; + out << CombineSupported(ai->GetAiObjectContext()->GetSupportedStrategies()); + ai->TellMaster(out); +} + +string HelpAction::CombineSupported(set commands) +{ + ostringstream out; + + for (set::iterator i = commands.begin(); i != commands.end(); ) + { + out << *i; + if (++i != commands.end()) + { + out << ", "; + } + } + + return out.str(); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/HelpAction.h b/src/modules/Bots/playerbot/strategy/actions/HelpAction.h new file mode 100644 index 0000000000..c0bc5e3278 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/HelpAction.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class HelpAction : public Action { + public: + HelpAction(PlayerbotAI* ai); + virtual ~HelpAction(); + virtual bool Execute(Event event); + + private: + void TellChatCommands(); + void TellStrategies(); + string CombineSupported(set commands); + + private: + NamedObjectContext* chatContext; + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp new file mode 100644 index 0000000000..48a5222e73 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp @@ -0,0 +1,308 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "InventoryAction.h" + +#include "../values/ItemCountValue.h" + +using namespace ai; + + +class FindPotionVisitor : public FindUsableItemVisitor +{ +public: + FindPotionVisitor(Player* bot, uint32 effectId) : FindUsableItemVisitor(bot), effectId(effectId) {} + + virtual bool Accept(const ItemPrototype* proto) + { + if (proto->Class == ITEM_CLASS_CONSUMABLE && + proto->SubClass == ITEM_SUBCLASS_POTION && + proto->Spells[0].SpellCategory == 4) + { + for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; j++) + { + const SpellEntry* const spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId); + if (!spellInfo) + { + return false; + } + + for (int i = 0 ; i < 3; i++) + { + if (spellInfo->Effect[i] == effectId) + { + return true; + } + } + } + } + return false; + } + +private: + uint32 effectId; +}; + +class FindFoodVisitor : public FindUsableItemVisitor +{ +public: + FindFoodVisitor(Player* bot, uint32 spellCategory) : FindUsableItemVisitor(bot) + { + this->spellCategory = spellCategory; + } + + virtual bool Accept(const ItemPrototype* proto) + { + return proto->Class == ITEM_CLASS_CONSUMABLE && + proto->SubClass == ITEM_SUBCLASS_FOOD && + proto->Spells[0].SpellCategory == spellCategory; + } + +private: + uint32 spellCategory; +}; + +void InventoryAction::IterateItems(IterateItemsVisitor* visitor, IterateItemsMask mask) +{ + if (mask & ITERATE_ITEMS_IN_BAGS) + { + IterateItemsInBags(visitor); + } + + if (mask & ITERATE_ITEMS_IN_EQUIP) + { + IterateItemsInEquip(visitor); + } +} + +void InventoryAction::IterateItemsInBags(IterateItemsVisitor* visitor) +{ + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + if (Item *pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if (!visitor->Visit(pItem)) + { + return; + } + + 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 (!visitor->Visit(pItem)) + { + return; + } + } + } + } + } +} + +void InventoryAction::IterateItemsInEquip(IterateItemsVisitor* visitor) +{ + for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++) + { + Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + if(!pItem) + { + continue; + } + + if (!visitor->Visit(pItem)) + { + return; + } + } +} + +bool compare_items(const ItemPrototype *proto1, const ItemPrototype *proto2) +{ + if (proto1->Class != proto2->Class) + { + return proto1->Class > proto2->Class; + } + + if (proto1->SubClass != proto2->SubClass) + { + return proto1->SubClass < proto2->SubClass; + } + + if (proto1->Quality != proto2->Quality) + { + return proto1->Quality < proto2->Quality; + } + + if (proto1->ItemLevel != proto2->ItemLevel) + { + return proto1->ItemLevel > proto2->ItemLevel; + } + + return false; +} + +bool compare_items_by_level(const Item* item1, const Item* item2) +{ + return compare_items(item1->GetProto(), item2->GetProto()); +} + +void InventoryAction::TellItems(map itemMap) +{ + list items; + for (map::iterator i = itemMap.begin(); i != itemMap.end(); i++) + { + items.push_back(sItemStorage.LookupEntry(i->first)); + } + + items.sort(compare_items); + + uint32 oldClass = -1; + for (list::iterator i = items.begin(); i != items.end(); i++) + { + ItemPrototype const *proto = *i; + + if (proto->Class != oldClass) + { + oldClass = proto->Class; + switch (proto->Class) + { + case ITEM_CLASS_CONSUMABLE: + ai->TellMaster("--- consumable ---"); + break; + case ITEM_CLASS_CONTAINER: + ai->TellMaster("--- container ---"); + break; + case ITEM_CLASS_WEAPON: + ai->TellMaster("--- weapon ---"); + break; + case ITEM_CLASS_ARMOR: + ai->TellMaster("--- armor ---"); + break; + case ITEM_CLASS_REAGENT: + ai->TellMaster("--- reagent ---"); + break; + case ITEM_CLASS_PROJECTILE: + ai->TellMaster("--- projectile ---"); + break; + case ITEM_CLASS_TRADE_GOODS: + ai->TellMaster("--- trade goods ---"); + break; + case ITEM_CLASS_RECIPE: + ai->TellMaster("--- recipe ---"); + break; + case ITEM_CLASS_QUIVER: + ai->TellMaster("--- quiver ---"); + break; + case ITEM_CLASS_QUEST: + ai->TellMaster("--- quest items ---"); + break; + case ITEM_CLASS_KEY: + ai->TellMaster("--- keys ---"); + break; + case ITEM_CLASS_MISC: + ai->TellMaster("--- other ---"); + break; + } + } + + TellItem(proto, itemMap[proto->ItemId]); + } +} + +void InventoryAction::TellItem(ItemPrototype const * proto, int count) +{ + ai->TellMaster(chat->formatItem(proto, count)); +} + +list InventoryAction::parseItems(string text) +{ + set found; + size_t pos = text.find(" "); + int count = pos!=string::npos ? atoi(text.substr(pos + 1).c_str()) : TRADE_SLOT_TRADED_COUNT; + if (count < 1) + { + count = 1; + } + else if (count > TRADE_SLOT_TRADED_COUNT) + { + count = TRADE_SLOT_TRADED_COUNT; + } + + if (text == "food") + { + FindFoodVisitor visitor(bot, 11); + IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } + + if (text == "drink") + { + FindFoodVisitor visitor(bot, 59); + IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } + + if (text == "mana potion") + { + FindPotionVisitor visitor(bot, SPELL_EFFECT_ENERGIZE); + IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } + + if (text == "healing potion") + { + FindPotionVisitor visitor(bot, SPELL_EFFECT_HEAL); + IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } + + FindUsableNamedItemVisitor visitor(bot, text); + IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + + uint32 quality = chat->parseItemQuality(text); + if (quality != MAX_ITEM_QUALITY) + { + FindItemsToTradeByQualityVisitor visitor(quality, count); + IterateItems(&visitor); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } + + uint32 itemClass = MAX_ITEM_CLASS, itemSubClass = 0; + if (chat->parseItemClass(text, &itemClass, &itemSubClass)) + { + FindItemsToTradeByClassVisitor visitor(itemClass, itemSubClass, count); + IterateItems(&visitor); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } + + uint32 fromSlot = chat->parseSlot(text); + if (fromSlot != EQUIPMENT_SLOT_END) + { + Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, fromSlot); + if (item) + { + found.insert(item); + } + } + + ItemIds ids = chat->parseItems(text); + for (ItemIds::iterator i = ids.begin(); i != ids.end(); i++) + { + FindItemByIdVisitor visitor(*i); + IterateItems(&visitor, ITERATE_ALL_ITEMS); + found.insert(visitor.GetResult().begin(), visitor.GetResult().end()); + } + + list result; + for (set::iterator i = found.begin(); i != found.end(); ++i) + { + result.push_back(*i); + } + + result.sort(compare_items_by_level); + + return result; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/InventoryAction.h b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.h new file mode 100644 index 0000000000..ab90bf6f9d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../Action.h" +#include "../ItemVisitors.h" + +namespace ai +{ + + + class InventoryAction : public Action { + public: + InventoryAction(PlayerbotAI* ai, string name) : Action(ai, name) {} + + protected: + void IterateItems(IterateItemsVisitor* visitor, IterateItemsMask mask = ITERATE_ITEMS_IN_BAGS); + void TellItems(map items); + void TellItem(ItemPrototype const * proto, int count); + list parseItems(string text); + + private: + void IterateItemsInBags(IterateItemsVisitor* visitor); + void IterateItemsInEquip(IterateItemsVisitor* visitor); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.cpp b/src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.cpp new file mode 100644 index 0000000000..e94ff32113 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.cpp @@ -0,0 +1,54 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "InventoryChangeFailureAction.h" + + +using namespace ai; + +bool InventoryChangeFailureAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + uint8 err; + p >> err; + if (err == EQUIP_ERR_OK) + { + return false; + } + + switch (err) + { + case EQUIP_ERR_CANT_CARRY_MORE_OF_THIS: + ai->TellMaster("I can't carry anymore of those."); + break; + case EQUIP_ERR_MISSING_REAGENT: + ai->TellMaster("I'm missing some reagents for that."); + break; + case EQUIP_ERR_ITEM_LOCKED: + ai->TellMaster("That item is locked."); + break; + case EQUIP_ERR_ALREADY_LOOTED: + break; + case EQUIP_ERR_INVENTORY_FULL: + ai->TellMaster("My inventory is full."); + break; + case EQUIP_ERR_NOT_IN_COMBAT: + ai->TellMaster("I can't use that in combat."); + break; + case EQUIP_ERR_LOOT_CANT_LOOT_THAT_NOW: + ai->TellMaster("I can't get that now."); + break; + case EQUIP_ERR_BANK_FULL: + ai->TellMaster("My bank is full."); + break; + case EQUIP_ERR_ITEM_NOT_FOUND: + ai->TellMaster("I can't find the item."); + break; + case EQUIP_ERR_TOO_FAR_AWAY_FROM_BANK: + ai->TellMaster("I'm too far from the bank."); + break; + default: + ai->TellMaster("I can't use that."); + } + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.h b/src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.h new file mode 100644 index 0000000000..4125cd289b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/InventoryChangeFailureAction.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class InventoryChangeFailureAction : public Action { + public: + InventoryChangeFailureAction(PlayerbotAI* ai) : Action(ai, "inventory change failure") {} + virtual bool Execute(Event event); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/InviteToGroupAction.h b/src/modules/Bots/playerbot/strategy/actions/InviteToGroupAction.h new file mode 100644 index 0000000000..babbedb643 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/InviteToGroupAction.h @@ -0,0 +1,30 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class InviteToGroupAction : public Action + { + public: + InviteToGroupAction(PlayerbotAI* ai) : Action(ai, "invite") {} + + virtual bool Execute(Event event) + { + Player* master = event.getOwner(); + if (!master) + { + return false; + } + + WorldPacket p; + uint32 roles_mask = 0; + p << master->GetName(); + p << roles_mask; + bot->GetSession()->HandleGroupInviteOpcode(p); + + return true; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h b/src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h new file mode 100644 index 0000000000..4541270903 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h @@ -0,0 +1,87 @@ +#pragma once + +#include "../Action.h" +#include "../../RandomPlayerbotMgr.h" + +namespace ai +{ + class LeaveGroupAction : public Action { + public: + LeaveGroupAction(PlayerbotAI* ai, string name = "leave") : Action(ai, name) {} + + virtual bool Execute(Event event) + { + if (!bot->GetGroup()) + { + return false; + } + + ai->TellMaster("Goodbye!", PLAYERBOT_SECURITY_TALK); + + WorldPacket p; + string member = bot->GetName(); + p << uint32(PARTY_OP_LEAVE) << member << uint32(0); + bot->GetSession()->HandleGroupDisbandOpcode(p); + + if (sRandomPlayerbotMgr.IsRandomBot(bot)) + { + bot->GetPlayerbotAI()->SetMaster(NULL); + sRandomPlayerbotMgr.ScheduleTeleport(bot->GetGUIDLow()); + sRandomPlayerbotMgr.SetLootAmount(bot, 0); + } + + ai->ResetStrategies(); + return true; + } + }; + + class PartyCommandAction : public LeaveGroupAction { + public: + PartyCommandAction(PlayerbotAI* ai) : LeaveGroupAction(ai, "party command") {} + + virtual bool Execute(Event event) + { + WorldPacket& p = event.getPacket(); + p.rpos(0); + uint32 operation; + string member; + + p >> operation >> member; + + if (operation != PARTY_OP_LEAVE) + { + return false; + } + + Player* master = GetMaster(); + if (master && member == master->GetName()) + { + return LeaveGroupAction::Execute(event); + } + + return false; + } + }; + + class UninviteAction : public LeaveGroupAction { + public: + UninviteAction(PlayerbotAI* ai) : LeaveGroupAction(ai, "party command") {} + + virtual bool Execute(Event event) + { + WorldPacket& p = event.getPacket(); + p.rpos(0); + ObjectGuid guid; + + p >> guid; + + if (bot->GetObjectGuid() == guid) + { + return LeaveGroupAction::Execute(event); + } + + return false; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LfgActions.cpp b/src/modules/Bots/playerbot/strategy/actions/LfgActions.cpp new file mode 100644 index 0000000000..a759fbc623 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LfgActions.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "LfgActions.h" +//#include "../../AiFactory.h" +//#include "../../PlayerbotAIConfig.h" +//#include "../ItemVisitors.h" +//#include "../../RandomPlayerbotMgr.h" +//#include "../../../../game/LFGMgr.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/LfgActions.h b/src/modules/Bots/playerbot/strategy/actions/LfgActions.h new file mode 100644 index 0000000000..f11237243f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LfgActions.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.cpp b/src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.cpp new file mode 100644 index 0000000000..0893e82d9e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.cpp @@ -0,0 +1,81 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ListQuestsActions.h" + + +using namespace ai; + +bool ListQuestsAction::Execute(Event event) +{ + if (event.getParam() == "completed") + { + ListQuests(QUEST_LIST_FILTER_COMPLETED); + } + else if (event.getParam() == "incompleted") + { + ListQuests(QUEST_LIST_FILTER_INCOMPLETED); + } + else if (event.getParam() == "all") + { + ListQuests(QUEST_LIST_FILTER_ALL); + } + else + { + ListQuests(QUEST_LIST_FILTER_SUMMARY); + } + return true; +} + +void ListQuestsAction::ListQuests(QuestListFilter filter) +{ + bool showIncompleted = filter & QUEST_LIST_FILTER_INCOMPLETED; + bool showCompleted = filter & QUEST_LIST_FILTER_COMPLETED; + + if (showIncompleted) + { + ai->TellMaster("--- Incomplete quests ---"); + } + int incompleteCount = ListQuests(false, !showIncompleted); + + if (showCompleted) + { + ai->TellMaster("--- Complete quests ---"); + } + int completeCount = ListQuests(true, !showCompleted); + + ai->TellMaster("--- Summary ---"); + std::ostringstream out; + out << "Total: " << (completeCount + incompleteCount) << " / 25 (incomplete: " << incompleteCount << ", complete: " << completeCount << ")"; + ai->TellMaster(out); +} + +int ListQuestsAction::ListQuests(bool completed, bool silent) +{ + int count = 0; + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + uint32 questId = bot->GetQuestSlotQuestId(slot); + if (!questId) + { + continue; + } + + Quest const* pQuest = sObjectMgr.GetQuestTemplate(questId); + bool isCompletedQuest = bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE; + if (completed != isCompletedQuest) + { + continue; + } + + count++; + + if (silent) + { + continue; + } + + ai->TellMaster(chat->formatQuest(pQuest)); + } + + return count; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.h b/src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.h new file mode 100644 index 0000000000..961acb874f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ListQuestsActions.h @@ -0,0 +1,25 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + enum QuestListFilter { + QUEST_LIST_FILTER_SUMMARY = 0, + QUEST_LIST_FILTER_COMPLETED = 1, + QUEST_LIST_FILTER_INCOMPLETED = 2, + QUEST_LIST_FILTER_ALL = QUEST_LIST_FILTER_COMPLETED | QUEST_LIST_FILTER_INCOMPLETED + }; + + class ListQuestsAction : public Action { + public: + ListQuestsAction(PlayerbotAI* ai) : Action(ai, "quests") {} + virtual bool Execute(Event event); + + private: + int ListQuests(bool completed, bool silent); + void ListQuests(QuestListFilter filter); + + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.cpp new file mode 100644 index 0000000000..6d90a3b745 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.cpp @@ -0,0 +1,76 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ListSpellsAction.h" +#include "../ItemVisitors.h" + +using namespace ai; + +bool ListSpellsAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + int loc = master->GetSession()->GetSessionDbcLocale(); + + std::ostringstream posOut; + std::ostringstream negOut; + + string filter = event.getParam(); + + const std::string ignoreList = ",Opening,Closing,Stuck,Remove Insignia,Opening - No Text,Grovel,Duel,Honorless Target,"; + std::string alreadySeenList = ","; + + for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) + { + const uint32 spellId = itr->first; + + if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled || IsPassiveSpell(spellId)) + { + continue; + } + + const SpellEntry* const pSpellInfo = sSpellStore.LookupEntry(spellId); + if (!pSpellInfo) + { + continue; + } + + //|| name.find("Teleport") != -1 + + std::string comp = ","; + comp.append(pSpellInfo->SpellName[loc]); + comp.append(","); + + if (!(ignoreList.find(comp) == std::string::npos && alreadySeenList.find(comp) == std::string::npos)) + { + continue; + } + + if (!filter.empty() && !strstri(pSpellInfo->SpellName[loc], filter.c_str())) + { + continue; + } + + alreadySeenList += pSpellInfo->SpellName[loc]; + alreadySeenList += ","; + + if (IsPositiveSpell(spellId)) + posOut << " |cffffffff|Hspell:" << spellId << "|h[" + << pSpellInfo->SpellName[loc] << "]|h|r"; + else + negOut << " |cffffffff|Hspell:" << spellId << "|h[" + << pSpellInfo->SpellName[loc] << "]|h|r"; + } + + ai->TellMaster("here's my non-attack spells:"); + ai->TellMaster(posOut); + + ai->TellMaster("here's my attack spells:"); + ai->TellMaster(negOut); + + return true; +} + diff --git a/src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.h b/src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.h new file mode 100644 index 0000000000..9d34575c82 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ListSpellsAction.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../Action.h" + + +namespace ai +{ + class ListSpellsAction : public Action { + public: + ListSpellsAction(PlayerbotAI* ai) : Action(ai, "spells") {} + + virtual bool Execute(Event event); + + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp new file mode 100644 index 0000000000..f4869cfd27 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp @@ -0,0 +1,59 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "LogLevelAction.h" + + +using namespace ai; + +bool LogLevelAction::Execute(Event event) +{ + string param = event.getParam(); + Value *value = ai->GetAiObjectContext()->GetValue("log level"); + + ostringstream out; + if (param != "?") + { + value->Set(string2logLevel(param)); + out << "My log level set to " << logLevel2string(value->Get()); + } + else + { + out << "My log level is " << logLevel2string(value->Get()); + } + ai->TellMaster(out); + return true; +} + +string LogLevelAction::logLevel2string(LogLevel level) +{ + switch (level) + { + case LOG_LVL_BASIC: + return "basic"; + case LOG_LVL_MINIMAL: + return "minimal"; + case LOG_LVL_DETAIL: + return "detail"; + default: + return "debug"; + } +} +LogLevel LogLevelAction::string2logLevel(string level) +{ + if (level == "debug") + { + return LOG_LVL_DEBUG; + } + else if (level == "minimal") + { + return LOG_LVL_MINIMAL; + } + else if (level == "detail") + { + return LOG_LVL_DETAIL; + } + else + { + return LOG_LVL_BASIC; + } +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h new file mode 100644 index 0000000000..4ad2a33f11 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class LogLevelAction : public Action { + public: + LogLevelAction(PlayerbotAI* ai) : Action(ai, "log") {} + virtual bool Execute(Event event); + + public: + static string logLevel2string(LogLevel level); + static LogLevel string2logLevel(string level); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/LootAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LootAction.cpp new file mode 100644 index 0000000000..d2e21b9649 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LootAction.cpp @@ -0,0 +1,392 @@ +#include "botpch.h" +#include "playerbot.h" +#include "ahbot/AhBot.h" +#include "LootAction.h" + +#include "LootObjectStack.h" +#include "PlayerbotAIConfig.h" + +#include "RandomPlayerbotMgr.h" +#include "strategy/values/ItemUsageValue.h" + +using namespace ai; + +bool LootAction::Execute(Event event) +{ + if (!AI_VALUE(bool, "has available loot")) + { + return false; + } + + LootObject const& lootObject = AI_VALUE(LootObjectStack*, "available loot")->GetLoot(sPlayerbotAIConfig.lootDistance); + context->GetValue("loot target")->Set(lootObject); + return true; +} + +enum ProfessionSpells +{ + ALCHEMY = 2259, + BLACKSMITHING = 2018, + COOKING = 2550, + ENCHANTING = 7411, + ENGINEERING = 49383, + FIRST_AID = 3273, + FISHING = 7620, + HERB_GATHERING = 2366, + INSCRIPTION = 45357, + JEWELCRAFTING = 25229, + MINING = 2575, + SKINNING = 8613, + TAILORING = 3908 +}; + +bool OpenLootAction::Execute(Event event) +{ + LootObject lootObject = AI_VALUE(LootObject, "loot target"); + bool result = DoLoot(lootObject); + if (result) + { + AI_VALUE(LootObjectStack*, "available loot")->Remove(lootObject.guid); + context->GetValue("loot target")->Set(LootObject()); + } + return result; +} + +bool OpenLootAction::DoLoot(LootObject& lootObject) +{ + if (lootObject.IsEmpty()) + { + return false; + } + + Creature* creature = ai->GetCreature(lootObject.guid); + if (creature && bot->GetDistance(creature) > INTERACTION_DISTANCE) + { + return false; + } + + if (creature && creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) + { + bot->GetMotionMaster()->Clear(); + WorldPacket* const packet = new WorldPacket(CMSG_LOOT, 8); + *packet << lootObject.guid; + bot->GetSession()->QueuePacket(packet); + return true; + } + + if (creature) + { + SkillType skill = creature->GetCreatureInfo()->GetRequiredLootSkill(); + if (!CanOpenLock(skill, lootObject.reqSkillValue)) + { + return false; + } + + bot->GetMotionMaster()->Clear(); + switch (skill) + { + case SKILL_ENGINEERING: + return bot->HasSkill(SKILL_ENGINEERING) ? ai->CastSpell(ENGINEERING, creature) : false; + case SKILL_HERBALISM: + return bot->HasSkill(SKILL_HERBALISM) ? ai->CastSpell(32605, creature) : false; + case SKILL_MINING: + return bot->HasSkill(SKILL_MINING) ? ai->CastSpell(32606, creature) : false; + default: + return bot->HasSkill(SKILL_SKINNING) ? ai->CastSpell(SKINNING, creature) : false; + } + } + + GameObject* go = ai->GetGameObject(lootObject.guid); + if (go && bot->GetDistance(go) > INTERACTION_DISTANCE) + { + return false; + } + + bot->GetMotionMaster()->Clear(); + if (lootObject.skillId == SKILL_MINING) + { + return bot->HasSkill(SKILL_MINING) ? ai->CastSpell(MINING, bot) : false; + } + + if (lootObject.skillId == SKILL_HERBALISM) + { + return bot->HasSkill(SKILL_HERBALISM) ? ai->CastSpell(HERB_GATHERING, bot) : false; + } + + uint32 spellId = GetOpeningSpell(lootObject); + if (!spellId) + { + return false; + } + + return ai->CastSpell(spellId, bot); +} + +uint32 OpenLootAction::GetOpeningSpell(LootObject& lootObject) +{ + GameObject* go = ai->GetGameObject(lootObject.guid); + if (go && go->isSpawned()) + { + return GetOpeningSpell(lootObject, go); + } + + return 0; +} + +uint32 OpenLootAction::GetOpeningSpell(LootObject& lootObject, GameObject* go) +{ + for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) + { + uint32 spellId = itr->first; + + if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled || IsPassiveSpell(spellId)) + { + continue; + } + + if (spellId == MINING || spellId == HERB_GATHERING) + { + continue; + } + + const SpellEntry* pSpellInfo = sSpellStore.LookupEntry(spellId); + if (!pSpellInfo) + { + continue; + } + + if (CanOpenLock(lootObject, pSpellInfo, go)) + { + return spellId; + } + } + + for (uint32 spellId = 0; spellId < sSpellStore.GetNumRows(); spellId++) + { + if (spellId == MINING || spellId == HERB_GATHERING) + { + continue; + } + + const SpellEntry* pSpellInfo = sSpellStore.LookupEntry(spellId); + if (!pSpellInfo) + { + continue; + } + + if (CanOpenLock(lootObject, pSpellInfo, go)) + { + return spellId; + } + } + + return 0; //Spell 3365 = Opening? +} + +bool OpenLootAction::CanOpenLock(LootObject& lootObject, const SpellEntry* pSpellInfo, GameObject* go) +{ + for (int effIndex = 0; effIndex < MAX_EFFECT_INDEX; effIndex++) + { + if (pSpellInfo->Effect[effIndex] != SPELL_EFFECT_OPEN_LOCK && pSpellInfo->Effect[effIndex] != SPELL_EFFECT_SKINNING) + { + return false; + } + + uint32 lockId = go->GetGOInfo()->GetLockId(); + if (!lockId) + { + return false; + } + + LockEntry const *lockInfo = sLockStore.LookupEntry(lockId); + if (!lockInfo) + { + return false; + } + + bool reqKey = false; // some locks not have reqs + + for(int j = 0; j < 8; ++j) + { + switch(lockInfo->Type[j]) + { + /* + case LOCK_KEY_ITEM: + return true; + */ + case LOCK_KEY_SKILL: + { + if(uint32(pSpellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) + { + continue; + } + + uint32 skillId = SkillByLockType(LockType(lockInfo->Index[j])); + if (skillId == SKILL_NONE) + { + return true; + } + + if (CanOpenLock(skillId, lockInfo->Skill[j])) + { + return true; + } + } + } + } + } + + return false; +} + +bool OpenLootAction::CanOpenLock(uint32 skillId, uint32 reqSkillValue) +{ + uint32 skillValue = bot->GetSkillValue(skillId); + return skillValue >= reqSkillValue || !reqSkillValue; +} + +bool StoreLootAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); // (8+1+4+1+1+4+4+4+4+4+1) + ObjectGuid guid; + uint8 loot_type; + uint32 gold; + uint8 items; + + p.rpos(0); + p >> guid; // 8 corpse guid + p >> loot_type; // 1 loot type + p >> gold; // 4 money on corpse + p >> items; // 1 number of items on corpse + + if (gold > 0) + { + WorldPacket* const packet = new WorldPacket(CMSG_LOOT_MONEY, 0); + bot->GetSession()->QueuePacket(packet); + } + + for (uint8 i = 0; i < items; ++i) + { + uint32 itemid; + uint32 itemcount; + uint8 lootslot_type; + uint8 itemindex; + bool grab = false; + + p >> itemindex; + p >> itemid; + p >> itemcount; + p.read_skip(); // display id + p.read_skip(); // randomSuffix + p.read_skip(); // randomPropertyId + p >> lootslot_type; // 0 = can get, 1 = look only, 2 = master get + + if (lootslot_type != LOOT_SLOT_NORMAL) + { + continue; + } + + if (loot_type != LOOT_SKINNING && !IsLootAllowed(itemid)) + { + continue; + } + + if (sRandomPlayerbotMgr.IsRandomBot(bot)) + { + ItemPrototype const *proto = sItemStorage.LookupEntry(itemid); + if (proto) + { + uint32 price = itemcount * auctionbot.GetSellPrice(proto) * sRandomPlayerbotMgr.GetSellMultiplier(bot) + gold; + uint32 lootAmount = sRandomPlayerbotMgr.GetLootAmount(bot); + if (bot->GetGroup() && price) + { + sRandomPlayerbotMgr.SetLootAmount(bot, lootAmount + price); + } + else if (lootAmount) + { + sRandomPlayerbotMgr.SetLootAmount(bot, 0); + } + } + } + + WorldPacket* const packet = new WorldPacket(CMSG_AUTOSTORE_LOOT_ITEM, 1); + *packet << itemindex; + bot->GetSession()->QueuePacket(packet); + } + + AI_VALUE(LootObjectStack*, "available loot")->Remove(guid); + + // release loot + WorldPacket* const packet = new WorldPacket(CMSG_LOOT_RELEASE, 8); + *packet << guid; + bot->GetSession()->QueuePacket(packet); + return true; +} + +bool StoreLootAction::IsLootAllowed(uint32 itemid) +{ + LootStrategy lootStrategy = AI_VALUE(LootStrategy, "loot strategy"); + + if (lootStrategy == LOOTSTRATEGY_ALL) + { + return true; + } + + set& lootItems = AI_VALUE(set&, "always loot list"); + if (lootItems.find(itemid) != lootItems.end()) + { + return true; + } + + ItemPrototype const *proto = sItemStorage.LookupEntry(itemid); + if (!proto) + { + return false; + } + + uint32 max = proto->MaxCount; + if (max > 0 && bot->HasItemCount(itemid, max, true)) + { + return false; + } + + if (proto->StartQuest || + proto->Bonding == BIND_QUEST_ITEM || + proto->Bonding == BIND_QUEST_ITEM1 || + proto->Class == ITEM_CLASS_QUEST) + return true; + + if (lootStrategy == LOOTSTRATEGY_QUEST) + { + return false; + } + + ostringstream out; out << itemid; + ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", out.str()); + if (usage == ITEM_USAGE_SKILL || usage == ITEM_USAGE_USE) + { + return true; + } + + if (lootStrategy == LOOTSTRATEGY_SKILL) + { + return false; + } + + if (proto->Quality == ITEM_QUALITY_POOR) + { + return true; + } + + if (lootStrategy == LOOTSTRATEGY_GRAY) + { + return true; + } + + if (proto->Bonding == BIND_WHEN_PICKED_UP) + { + return false; + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LootAction.h b/src/modules/Bots/playerbot/strategy/actions/LootAction.h new file mode 100644 index 0000000000..7ba5d46507 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LootAction.h @@ -0,0 +1,39 @@ +#pragma once + +#include "../Action.h" +#include "../../LootObjectStack.h" +#include "MovementActions.h" + +namespace ai +{ + class LootAction : public MovementAction + { + public: + LootAction(PlayerbotAI* ai) : MovementAction(ai, "loot") {} + virtual bool Execute(Event event); + }; + + class OpenLootAction : public MovementAction + { + public: + OpenLootAction(PlayerbotAI* ai) : MovementAction(ai, "open loot") {} + virtual bool Execute(Event event); + + private: + bool DoLoot(LootObject& lootObject); + uint32 GetOpeningSpell(LootObject& lootObject); + uint32 GetOpeningSpell(LootObject& lootObject, GameObject* go); + bool CanOpenLock(LootObject& lootObject, const SpellEntry* pSpellInfo, GameObject* go); + bool CanOpenLock(uint32 skillId, uint32 reqSkillValue); + }; + + class StoreLootAction : public MovementAction + { + public: + StoreLootAction(PlayerbotAI* ai) : MovementAction(ai, "store loot") {} + virtual bool Execute(Event event); + + protected: + bool IsLootAllowed(uint32 itemid); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LootRollAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LootRollAction.cpp new file mode 100644 index 0000000000..b70f8441c1 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LootRollAction.cpp @@ -0,0 +1,62 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "LootRollAction.h" + + +using namespace ai; + +bool LootRollAction::Execute(Event event) +{ + Player *bot = QueryItemUsageAction::ai->GetBot(); + + WorldPacket p(event.getPacket()); //WorldPacket packet for CMSG_LOOT_ROLL, (8+4+1) + ObjectGuid guid; + uint32 slot; + uint8 rollType; + p.rpos(0); //reset packet pointer + p >> guid; //guid of the item rolled + p >> slot; //number of players invited to roll + p >> rollType; //need,greed or pass on roll + + Group* group = bot->GetGroup(); + if(!group) + { + return false; + } + + RollVote vote = ROLL_PASS; + + ItemPrototype const *proto = sItemStorage.LookupEntry(guid.GetEntry()); + if(proto) + { + switch (proto->Class) + { + case ITEM_CLASS_WEAPON: + case ITEM_CLASS_ARMOR: + if (QueryItemUsage(proto)) + { + vote = ROLL_NEED; + } + break; + default: + if (IsLootAllowed(guid.GetEntry())) + { + vote = ROLL_NEED; + } + break; + } + } + + switch (group->GetLootMethod()) + { + case MASTER_LOOT: + case FREE_FOR_ALL: + group->CountRollVote(bot, guid, slot, ROLL_PASS); + break; + default: + group->CountRollVote(bot, guid, slot, vote); + break; + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LootRollAction.h b/src/modules/Bots/playerbot/strategy/actions/LootRollAction.h new file mode 100644 index 0000000000..05651a4e5c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LootRollAction.h @@ -0,0 +1,15 @@ +#pragma once + +#include "../Action.h" +#include "QueryItemUsageAction.h" +#include "LootAction.h" + +namespace ai +{ + class LootRollAction : public QueryItemUsageAction, public StoreLootAction { + public: + LootRollAction(PlayerbotAI* ai) : QueryItemUsageAction(ai, "loot roll"), StoreLootAction(ai) {} + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp new file mode 100644 index 0000000000..24f4cd2448 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp @@ -0,0 +1,114 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "LootStrategyAction.h" + + +using namespace ai; + + +bool LootStrategyAction::Execute(Event event) +{ + string strategy = event.getParam(); + + LootObjectStack* lootItems = AI_VALUE(LootObjectStack*, "available loot"); + set& alwaysLootItems = AI_VALUE(set&, "always loot list"); + Value* lootStrategy = context->GetValue("loot strategy"); + + if (strategy == "?") + { + ostringstream out; + out << "Loot strategy: "; + out << LootStrategy2string(lootStrategy->Get()); + 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->TellMaster(out); + } + else + { + ItemIds items = chat->parseItems(strategy); + + if (items.size() == 0) + { + lootStrategy->Set(String2LootStrategy(strategy)); + ostringstream out; + out << "Loot strategy set to " << LootStrategy2string(lootStrategy->Get()); + ai->TellMaster(out); + return true; + } + + bool remove = strategy.size() > 1 && strategy.substr(0, 1) == "-"; + for (ItemIds::iterator i = items.begin(); i != items.end(); i++) + { + uint32 itemid = *i; + if (remove) + { + set::iterator j = alwaysLootItems.find(itemid); + if (j != alwaysLootItems.end()) + { + alwaysLootItems.erase(j); + } + + ai->TellMaster("Item(s) removed from always loot list"); + } + else + { + alwaysLootItems.insert(itemid); + ai->TellMaster("Item(s) added to always loot list"); + } + } + } + + return true; +} + + +LootStrategy LootStrategyAction::String2LootStrategy(string strategy) +{ + if (strategy == "*" || strategy == "all") + { + return LOOTSTRATEGY_ALL; + } + else if (strategy == "q" || strategy == "quest") + { + return LOOTSTRATEGY_QUEST; + } + else if (strategy == "s" || strategy == "skill") + { + return LOOTSTRATEGY_SKILL; + } + else if (strategy == "g" || strategy == "gray") + { + return LOOTSTRATEGY_GRAY; + } + else + { + return LOOTSTRATEGY_NORMAL; + } +} + +string LootStrategyAction::LootStrategy2string(LootStrategy lootStrategy) +{ + switch (lootStrategy) + { + case LOOTSTRATEGY_ALL: + return "all"; + case LOOTSTRATEGY_QUEST: + return "quest"; + case LOOTSTRATEGY_SKILL: + return "skill"; + case LOOTSTRATEGY_GRAY: + return "gray"; + default: + return "normal"; + } +} diff --git a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h new file mode 100644 index 0000000000..935c442071 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Action.h" +#include "../../LootObjectStack.h" + +namespace ai +{ + class LootStrategyAction : public Action { + public: + LootStrategyAction(PlayerbotAI* ai) : Action(ai, "ll") {} + virtual bool Execute(Event event); + + private: + static LootStrategy String2LootStrategy(string strategy); + static string LootStrategy2string(LootStrategy lootStrategy); + + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp b/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp new file mode 100644 index 0000000000..a04926d51e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp @@ -0,0 +1,419 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "../values/LastMovementValue.h" +#include "MovementActions.h" +#include "MotionMaster.h" +#include "MovementGenerator.h" +#include "../../FleeManager.h" +#include "../../LootObjectStack.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool MovementAction::MoveNear(uint32 mapId, float x, float y, float z, float distance) +{ + float angle = GetFollowAngle(); + return MoveTo(mapId, x + cos(angle) * distance, y + sin(angle) * distance, z); +} + +bool MovementAction::MoveNear(WorldObject* target, float distance) +{ + if (!target) + { + return false; + } + + distance += target->GetObjectBoundingRadius(); + + float followAngle = GetFollowAngle(); + for (float angle = followAngle - M_PI; angle <= followAngle + M_PI; angle += M_PI / 4) + { + bool moved = MoveTo(target->GetMapId(), + target->GetPositionX() + cos(angle) * distance, + target->GetPositionY()+ sin(angle) * distance, + target->GetPositionZ()); + if (moved) + { + return true; + } + } + return false; +} + +bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z) +{ + bot->UpdateGroundPositionZ(x, y, z); + if (!IsMovingAllowed(mapId, x, y, z)) + { + return false; + } + + float distance = bot->GetDistance(x, y, z); + if (distance > sPlayerbotAIConfig.contactDistance) + { + WaitForReach(distance); + + if (bot->IsSitState()) + { + bot->SetStandState(UNIT_STAND_STATE_STAND); + } + + if (bot->IsNonMeleeSpellCasted(true)) + { + bot->CastStop(); + ai->InterruptSpell(); + } + + MotionMaster &mm = *bot->GetMotionMaster(); + mm.Clear(); + + float botZ = bot->GetPositionZ(); + mm.MovePoint(mapId, x, y, z); + } + + AI_VALUE(LastMovement&, "last movement").Set(x, y, z, bot->GetOrientation()); + return true; +} + +bool MovementAction::MoveTo(Unit* target, float distance) +{ + if (!IsMovingAllowed(target)) + { + return false; + } + + float bx = bot->GetPositionX(); + float by = bot->GetPositionY(); + float bz = bot->GetPositionZ(); + + float tx = target->GetPositionX(); + float ty = target->GetPositionY(); + float tz = target->GetPositionZ(); + + float distanceToTarget = bot->GetDistance(target); + float angle = bot->GetAngle(target); + float needToGo = distanceToTarget - distance; + + float maxDistance = sPlayerbotAIConfig.spellDistance; + if (needToGo > 0 && needToGo > maxDistance) + { + needToGo = maxDistance; + } + else if (needToGo < 0 && needToGo < -maxDistance) + { + needToGo = -maxDistance; + } + + float dx = cos(angle) * needToGo + bx; + float dy = sin(angle) * needToGo + by; + + return MoveTo(target->GetMapId(), dx, dy, tz); +} + +float MovementAction::GetFollowAngle() +{ + Player* master = GetMaster(); + Group* group = master ? master->GetGroup() : bot->GetGroup(); + if (!group) + { + return 0.0f; + } + + int index = 1; + for (GroupReference *ref = group->GetFirstMember(); ref; ref = ref->next()) + { + if( ref->getSource() == master) + { + continue; + } + + if( ref->getSource() == bot) + { + return 2 * M_PI / (group->GetMembersCount() -1) * index; + } + + index++; + } + return 0; +} + +bool MovementAction::IsMovingAllowed(Unit* target) +{ + if (!target) + { + return false; + } + + if (bot->GetMapId() != target->GetMapId()) + { + return false; + } + + float distance = bot->GetDistance(target); + if (distance > sPlayerbotAIConfig.reactDistance) + { + return false; + } + + return IsMovingAllowed(); +} + +bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z) +{ + float distance = bot->GetDistance(x, y, z); + if (distance > sPlayerbotAIConfig.reactDistance) + { + return false; + } + + return IsMovingAllowed(); +} + +bool MovementAction::IsMovingAllowed() +{ + if (bot->IsFrozen() || bot->IsPolymorphed() || + (bot->IsDead() && !bot->GetCorpse()) || + bot->IsBeingTeleported() || + bot->IsInRoots() || + bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || + bot->HasAuraType(SPELL_AURA_MOD_STUN) || bot->IsTaxiFlying()) + return false; + + MotionMaster &mm = *bot->GetMotionMaster(); + return mm.GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE; +} + +bool MovementAction::Follow(Unit* target, float distance) +{ + return Follow(target, distance, GetFollowAngle()); +} + +bool MovementAction::Follow(Unit* target, float distance, float angle) +{ + MotionMaster &mm = *bot->GetMotionMaster(); + + if (!target) + { + return false; + } + + if (bot->GetDistance2d(target->GetPositionX(), target->GetPositionY()) <= sPlayerbotAIConfig.sightDistance && + abs(bot->GetPositionZ() - target->GetPositionZ()) >= sPlayerbotAIConfig.spellDistance) + { + mm.Clear(); + float x = bot->GetPositionX(), y = bot->GetPositionY(), z = target->GetPositionZ(); + if (target->GetMapId() && bot->GetMapId() != target->GetMapId()) + { + bot->TeleportTo(target->GetMapId(), x, y, z, bot->GetOrientation()); + } + else + { + bot->SetPosition(x, y, z, bot->GetOrientation(), true); + } + AI_VALUE(LastMovement&, "last movement").Set(target); + return true; + } + + if (!IsMovingAllowed(target)) + { + return false; + } + + if (target->IsFriendlyTo(bot) && bot->IsMounted() && AI_VALUE(list, "possible targets").empty()) + { + distance += angle; + } + + if (bot->GetDistance(target) <= sPlayerbotAIConfig.followDistance) + { + return false; + } + + if (bot->IsSitState()) + { + bot->SetStandState(UNIT_STAND_STATE_STAND); + } + + if (bot->IsNonMeleeSpellCasted(true)) + { + bot->CastStop(); + ai->InterruptSpell(); + } + + mm.MoveFollow(target, distance, angle); + + AI_VALUE(LastMovement&, "last movement").Set(target); + return true; +} + +void MovementAction::WaitForReach(float distance) +{ + float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay; + + if (delay > sPlayerbotAIConfig.maxWaitForMove) + { + delay = sPlayerbotAIConfig.maxWaitForMove; + } + + Unit* target = *ai->GetAiObjectContext()->GetValue("current target"); + Unit* player = *ai->GetAiObjectContext()->GetValue("enemy player target"); + if ((player || target) && delay > sPlayerbotAIConfig.globalCoolDown) + { + delay = sPlayerbotAIConfig.globalCoolDown; + } + + ai->SetNextCheckDelay((uint32)delay); +} + +bool MovementAction::Flee(Unit *target) +{ + Player* master = GetMaster(); + if (!target) + { + target = master; + } + + if (!target) + { + return false; + } + + if (!sPlayerbotAIConfig.fleeingEnabled) + { + return false; + } + + if (!IsMovingAllowed()) + { + return false; + } + + FleeManager manager(bot, sPlayerbotAIConfig.fleeDistance, GetFollowAngle()); + + float rx, ry, rz; + if (!manager.CalculateDestination(&rx, &ry, &rz)) + { + return false; + } + + return MoveTo(target->GetMapId(), rx, ry, rz); +} + +bool FleeAction::Execute(Event event) +{ + return Flee(AI_VALUE(Unit*, "current target")); +} + +bool FleeAction::isUseful() +{ + return AI_VALUE(uint8, "attacker count") > 0 && + AI_VALUE2(float, "distance", "current target") <= sPlayerbotAIConfig.tooCloseDistance; +} + +bool RunAwayAction::Execute(Event event) +{ + return Flee(AI_VALUE(Unit*, "master target")); +} + +bool MoveRandomAction::Execute(Event event) +{ + WorldObject* target = NULL; + + if (!(rand() % 3)) + { + list npcs = AI_VALUE(list, "nearest npcs"); + for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + { + target = ai->GetUnit(*i); + + if (target && bot->GetDistance(target) > sPlayerbotAIConfig.tooCloseDistance) + { + break; + } + } + } + + if (!target || !(rand() % 3)) + { + list gos = AI_VALUE(list, "nearest game objects"); + for (list::iterator i = gos.begin(); i != gos.end(); i++) + { + target = ai->GetGameObject(*i); + + if (target && bot->GetDistance(target) > sPlayerbotAIConfig.tooCloseDistance) + { + break; + } + } + } + + float distance = sPlayerbotAIConfig.tooCloseDistance + sPlayerbotAIConfig.grindDistance * urand(3, 10) / 10.0f; + + if (target) + { + return MoveNear(target); + } + + for (int i = 0; i < 10; ++i) + { + float x = bot->GetPositionX(); + float y = bot->GetPositionY(); + float z = bot->GetPositionZ(); + x += urand(0, distance) - distance / 2; + y += urand(0, distance) - distance / 2; + bot->UpdateGroundPositionZ(x, y, z); + + bool moved = MoveNear(bot->GetMapId(), x, y, z); + if (moved) + { + return true; + } + } + + return false; +} + +bool MoveToLootAction::Execute(Event event) +{ + LootObject loot = AI_VALUE(LootObject, "loot target"); + if (!loot.IsLootPossible(bot)) + { + return false; + } + + return MoveNear(loot.GetWorldObject(bot)); +} + +bool MoveOutOfEnemyContactAction::Execute(Event event) +{ + Unit* target = AI_VALUE(Unit*, "current target"); + if (!target) + { + return false; + } + + return MoveNear(target, sPlayerbotAIConfig.meleeDistance); +} + +bool MoveOutOfEnemyContactAction::isUseful() +{ + return AI_VALUE2(float, "distance", "current target") <= sPlayerbotAIConfig.contactDistance; +} + +bool SetFacingTargetAction::Execute(Event event) +{ + Unit* target = AI_VALUE(Unit*, "current target"); + if (!target) + { + return false; + } + + bot->SetFacingTo(bot->GetAngle(target)); + ai->SetNextCheckDelay(sPlayerbotAIConfig.globalCoolDown); + return true; +} + +bool SetFacingTargetAction::isUseful() +{ + return !AI_VALUE2(bool, "facing", "current target"); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/MovementActions.h b/src/modules/Bots/playerbot/strategy/actions/MovementActions.h new file mode 100644 index 0000000000..96d8d51820 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/MovementActions.h @@ -0,0 +1,92 @@ +#pragma once + +#include "../Action.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class MovementAction : public Action { + public: + MovementAction(PlayerbotAI* ai, string name) : Action(ai, name) + { + bot = ai->GetBot(); + } + + protected: + bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig.followDistance); + bool MoveTo(uint32 mapId, float x, float y, float z); + bool MoveTo(Unit* target, float distance = 0.0f); + bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig.followDistance); + float GetFollowAngle(); + bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance); + bool Follow(Unit* target, float distance, float angle); + void WaitForReach(float distance); + bool IsMovingAllowed(Unit* target); + bool IsMovingAllowed(uint32 mapId, float x, float y, float z); + bool IsMovingAllowed(); + bool Flee(Unit *target); + + protected: + Player* bot; + }; + + class FleeAction : public MovementAction + { + public: + FleeAction(PlayerbotAI* ai, float distance = sPlayerbotAIConfig.spellDistance) : MovementAction(ai, "flee") + { + this->distance = distance; + } + + virtual bool Execute(Event event); + virtual bool isUseful(); + + private: + float distance; + }; + + + class RunAwayAction : public MovementAction + { + public: + RunAwayAction(PlayerbotAI* ai) : MovementAction(ai, "runaway") {} + virtual bool Execute(Event event); + }; + + class MoveRandomAction : public MovementAction + { + public: + MoveRandomAction(PlayerbotAI* ai) : MovementAction(ai, "move random") {} + virtual bool Execute(Event event); + virtual bool isPossible() + { + return MovementAction::isPossible() && + AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.mediumHealth && + (!AI_VALUE2(uint8, "mana", "self target") || AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumMana); + } + }; + + class MoveToLootAction : public MovementAction + { + public: + MoveToLootAction(PlayerbotAI* ai) : MovementAction(ai, "move to loot") {} + virtual bool Execute(Event event); + }; + + class MoveOutOfEnemyContactAction : public MovementAction + { + public: + MoveOutOfEnemyContactAction(PlayerbotAI* ai) : MovementAction(ai, "move out of enemy contact") {} + virtual bool Execute(Event event); + virtual bool isUseful(); + }; + + class SetFacingTargetAction : public MovementAction + { + public: + SetFacingTargetAction(PlayerbotAI* ai) : MovementAction(ai, "set facing") {} + virtual bool Execute(Event event); + virtual bool isUseful(); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/NonCombatActions.cpp b/src/modules/Bots/playerbot/strategy/actions/NonCombatActions.cpp new file mode 100644 index 0000000000..48be5c3be4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/NonCombatActions.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "NonCombatActions.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/actions/NonCombatActions.h b/src/modules/Bots/playerbot/strategy/actions/NonCombatActions.h new file mode 100644 index 0000000000..ee17deb2c6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/NonCombatActions.h @@ -0,0 +1,51 @@ +#pragma once + +#include "../Action.h" +#include "UseItemAction.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class DrinkAction : public UseItemAction + { + public: + DrinkAction(PlayerbotAI* ai) : UseItemAction(ai, "drink") {} + + virtual bool Execute(Event event) + { + if (bot->IsInCombat()) + { + return false; + } + + return UseItemAction::Execute(event); + } + + virtual bool isUseful() + { + return UseItemAction::isUseful() && AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana; + } + }; + + class EatAction : public UseItemAction + { + public: + EatAction(PlayerbotAI* ai) : UseItemAction(ai, "food") {} + + virtual bool Execute(Event event) + { + if (bot->IsInCombat()) + { + return false; + } + + return UseItemAction::Execute(event); + } + + virtual bool isUseful() + { + return UseItemAction::isUseful() && AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig.lowHealth; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/PassLeadershipToMasterAction.h b/src/modules/Bots/playerbot/strategy/actions/PassLeadershipToMasterAction.h new file mode 100644 index 0000000000..15e631c549 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/PassLeadershipToMasterAction.h @@ -0,0 +1,26 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class PassLeadershipToMasterAction : public Action { + public: + PassLeadershipToMasterAction(PlayerbotAI* ai) : Action(ai, "leader") {} + + virtual bool Execute(Event event) + { + Player* master = GetMaster(); + if (master && bot->GetGroup() && bot->GetGroup()->IsMember(master->GetObjectGuid())) + { + WorldPacket p(SMSG_GROUP_SET_LEADER, 8); + p << master->GetObjectGuid(); + bot->GetSession()->HandleGroupSetLeaderOpcode(p); + return true; + } + + return false; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/PositionAction.cpp b/src/modules/Bots/playerbot/strategy/actions/PositionAction.cpp new file mode 100644 index 0000000000..0ea762b19a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/PositionAction.cpp @@ -0,0 +1,42 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PositionAction.h" +#include "../values/PositionValue.h" + +using namespace ai; + +bool PositionAction::Execute(Event event) +{ + string qualifier = event.getParam(); + if (qualifier.empty()) + { + return false; + } + + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ai::Position& pos = context->GetValue("position", qualifier)->Get(); + pos.Set( master->GetPositionX(), master->GetPositionY(), master->GetPositionZ()); + + ostringstream out; out << "Position " << qualifier << " is set"; + ai->TellMaster(out); + return true; +} + +bool MoveToPositionAction::Execute(Event event) +{ + ai::Position& pos = context->GetValue("position", qualifier)->Get(); + if (!pos.isSet()) + { + ostringstream out; out << "Position " << qualifier << " is not set"; + ai->TellMaster(out); + return false; + } + + return MoveTo(bot->GetMapId(), pos.x, pos.y, pos.z); +} + diff --git a/src/modules/Bots/playerbot/strategy/actions/PositionAction.h b/src/modules/Bots/playerbot/strategy/actions/PositionAction.h new file mode 100644 index 0000000000..f96553b6ca --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/PositionAction.h @@ -0,0 +1,37 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" + +namespace ai +{ + class PositionAction : public Action + { + public: + PositionAction(PlayerbotAI* ai) : Action(ai, "position") + {} + + virtual bool Execute(Event event); + + }; + + class MoveToPositionAction : public MovementAction + { + public: + MoveToPositionAction(PlayerbotAI* ai, string qualifier) : MovementAction(ai, "move to position"), qualifier(qualifier) + {} + + virtual bool Execute(Event event); + + protected: + string qualifier; + }; + + class GuardAction : public MoveToPositionAction + { + public: + GuardAction(PlayerbotAI* ai) : MoveToPositionAction(ai, "guard") + {} + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp new file mode 100644 index 0000000000..c5db73730f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp @@ -0,0 +1,189 @@ +#include "botpch.h" +#include "playerbot.h" +#include "ahbot/AhBot.h" +#include "QueryItemUsageAction.h" + +#include "../values/ItemUsageValue.h" +#include "../../RandomPlayerbotMgr.h" + + +using namespace ai; + + +bool QueryItemUsageAction::Execute(Event event) +{ + WorldPacket& data = event.getPacket(); + if (!data.empty()) + { + data.rpos(0); + + ObjectGuid guid; + data >> guid; + if (guid != bot->GetObjectGuid()) + { + return false; + } + + uint32 received, created, isShowChatMessage, notUsed, itemId, + suffixFactor, itemRandomPropertyId, count, 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; + + ItemPrototype const *item = sItemStorage.LookupEntry(itemId); + if (!item) + { + return false; + } + + ostringstream out; out << chat->formatItem(item, count); + if (created) + { + out << " created"; + } + else if (received) + { + out << " received"; + } + ai->TellMaster(out); + + QueryItemUsage(item); + QueryQuestItem(itemId); + return true; + } + + string text = event.getParam(); + + ItemIds items = chat->parseItems(text); + QueryItemsUsage(items); + return true; +} + +bool QueryItemUsageAction::QueryItemUsage(ItemPrototype const *item) +{ + ostringstream out; out << item->ItemId; + ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", out.str()); + switch (usage) + { + case ITEM_USAGE_EQUIP: + ai->TellMaster("Equip"); + return true; + case ITEM_USAGE_REPLACE: + ai->TellMaster("Equip (replace)"); + return true; + case ITEM_USAGE_SKILL: + ai->TellMaster("Tradeskill"); + return true; + case ITEM_USAGE_USE: + ai->TellMaster("Use"); + return true; + } + + return false; +} + +void QueryItemUsageAction::QueryItemPrice(ItemPrototype const *item) +{ + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) + { + return; + } + + if (item->Bonding == BIND_WHEN_PICKED_UP) + { + return; + } + + list items = InventoryAction::parseItems(item->Name1); + if (!items.empty()) + { + for (list::iterator i = items.begin(); i != items.end(); ++i) + { + Item* sell = *i; + int32 sellPrice = sell->GetCount() * auctionbot.GetSellPrice(sell->GetProto()) * sRandomPlayerbotMgr.GetSellMultiplier(bot); + ostringstream out; + out << "Selling " << chat->formatItem(sell->GetProto(), sell->GetCount()) << " for " << chat->formatMoney(sellPrice); + ai->TellMaster(out.str()); + } + } + + ostringstream out; out << item->ItemId; + ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", out.str()); + if (usage == ITEM_USAGE_NONE) + { + return; + } + + int32 buyPrice = auctionbot.GetBuyPrice(item) * sRandomPlayerbotMgr.GetBuyMultiplier(bot); + if (buyPrice) + { + ostringstream out; + out << "Will buy for " << chat->formatMoney(buyPrice); + ai->TellMaster(out.str()); + } +} + +void QueryItemUsageAction::QueryItemsUsage(ItemIds items) +{ + for (ItemIds::iterator i = items.begin(); i != items.end(); i++) + { + ItemPrototype const *item = sItemStorage.LookupEntry(*i); + QueryItemUsage(item); + QueryQuestItem(*i); + QueryItemPrice(item); + } +} + +void QueryItemUsageAction::QueryQuestItem(uint32 itemId) +{ + Player *bot = ai->GetBot(); + QuestStatusMap& questMap = bot->getQuestStatusMap(); + for (QuestStatusMap::const_iterator i = questMap.begin(); i != questMap.end(); i++) + { + const Quest *questTemplate = sObjectMgr.GetQuestTemplate( i->first ); + if( !questTemplate ) + { + continue; + } + + uint32 questId = questTemplate->GetQuestId(); + QuestStatus status = bot->GetQuestStatus(questId); + if (status == QUEST_STATUS_INCOMPLETE || (status == QUEST_STATE_COMPLETE && !bot->GetQuestRewardStatus(questId))) + { + QuestStatusData const& questStatus = i->second; + QueryQuestItem(itemId, questTemplate, &questStatus); + } + } +} + + +void QueryItemUsageAction::QueryQuestItem(uint32 itemId, const Quest *questTemplate, const QuestStatusData *questStatus) +{ + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + if (questTemplate->ReqItemId[i] != itemId) + { + continue; + } + + int required = questTemplate->ReqItemCount[i]; + int available = questStatus->m_itemcount[i]; + + if (!required) + { + continue; + } + + ai->TellMaster(chat->formatQuestObjective(chat->formatQuest(questTemplate), available, required)); + } +} + diff --git a/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h new file mode 100644 index 0000000000..11899cb96e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class QueryItemUsageAction : public InventoryAction { + public: + QueryItemUsageAction(PlayerbotAI* ai, string name = "query item usage") : InventoryAction(ai, name) {} + virtual bool Execute(Event event); + + protected: + void QueryItemsUsage(ItemIds items); + bool QueryItemUsage(ItemPrototype const *item); + void QueryItemPrice(ItemPrototype const *item); + void QueryQuestItem(uint32 itemId, const Quest *questTemplate, const QuestStatusData *questStatus); + void QueryQuestItem(uint32 itemId); + + private: + ostringstream out; + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.cpp b/src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.cpp new file mode 100644 index 0000000000..e952b65cf5 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.cpp @@ -0,0 +1,98 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "QueryQuestAction.h" + + +using namespace ai; + +void QueryQuestAction::TellObjective(string name, int available, int required) +{ + ai->TellMaster(chat->formatQuestObjective(name, available, required)); +} + + +bool QueryQuestAction::Execute(Event event) +{ + + Player *bot = ai->GetBot(); + string text = event.getParam(); + + PlayerbotChatHandler ch(bot); + uint32 questId = ch.extractQuestId(text); + if (!questId) + { + return false; + } + + for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot) + { + if(questId != bot->GetQuestSlotQuestId(slot)) + { + continue; + } + + ostringstream out; + out << "--- " << chat->formatQuest(sObjectMgr.GetQuestTemplate(questId)) << " "; + if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + { + out << "|c0000FF00completed|r ---"; + ai->TellMaster(out); + } + else + { + out << "|c00FF0000not completed|r ---"; + ai->TellMaster(out); + TellObjectives(questId); + } + + return true; + } + + return false; +} + +void QueryQuestAction::TellObjectives(uint32 questId) +{ + Quest const* questTemplate = sObjectMgr.GetQuestTemplate(questId); + QuestStatusData questStatus = bot->getQuestStatusMap()[questId]; + + for (int i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + { + if (!questTemplate->ObjectiveText[i].empty()) + { + ai->TellMaster(questTemplate->ObjectiveText[i]); + } + + if (questTemplate->ReqItemId[i]) + { + int required = questTemplate->ReqItemCount[i]; + int available = questStatus.m_itemcount[i]; + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(questTemplate->ReqItemId[i]); + TellObjective(chat->formatItem(proto), available, required); + } + + if (questTemplate->ReqCreatureOrGOId[i]) + { + int required = questTemplate->ReqCreatureOrGOCount[i]; + int available = questStatus.m_creatureOrGOcount[i]; + + if (questTemplate->ReqCreatureOrGOId[i] < 0) + { + GameObjectInfo const* info = sObjectMgr.GetGameObjectInfo(-questTemplate->ReqCreatureOrGOId[i]); + if (info) + { + TellObjective(info->name, available, required); + } + } + else + { + + CreatureInfo const* info = sObjectMgr.GetCreatureTemplate(questTemplate->ReqCreatureOrGOId[i]); + if (info) + { + TellObjective(info->Name, available, required); + } + } + } + } +} diff --git a/src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.h b/src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.h new file mode 100644 index 0000000000..1822293558 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/QueryQuestAction.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class QueryQuestAction : public Action { + public: + QueryQuestAction(PlayerbotAI* ai) : Action(ai, "query quest") {} + virtual bool Execute(Event event); + + private: + void TellObjectives(uint32 questId); + void TellObjective(string name, int available, int required); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/QuestAction.cpp b/src/modules/Bots/playerbot/strategy/actions/QuestAction.cpp new file mode 100644 index 0000000000..71f5760e0a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/QuestAction.cpp @@ -0,0 +1,161 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "QuestAction.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool QuestAction::Execute(Event event) +{ + ObjectGuid guid = event.getObject(); + + Player* master = GetMaster(); + if (!master) + { + return false; + } + + if (!guid) + { + guid = master->GetSelectionGuid(); + } + + if (!guid) + { + return false; + } + + return ProcessQuests(guid); +} + +bool QuestAction::ProcessQuests(ObjectGuid questGiver) +{ + GameObject *gameObject = ai->GetGameObject(questGiver); + if (gameObject && gameObject->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER) + { + return ProcessQuests(gameObject); + } + + Creature* creature = ai->GetCreature(questGiver); + if (creature) + { + return ProcessQuests(creature); + } + + return false; +} + +bool QuestAction::ProcessQuests(WorldObject* questGiver) +{ + ObjectGuid guid = questGiver->GetObjectGuid(); + + if (bot->GetDistance(questGiver) > INTERACTION_DISTANCE) + { + ai->TellMaster("Cannot talk to quest giver"); + return false; + } + + if (!bot->IsInFront(questGiver, sPlayerbotAIConfig.sightDistance, M_PI / 2)) + { + bot->SetFacingTo(bot->GetAngle(questGiver)); + } + + bot->SetSelectionGuid(guid); + bot->PrepareQuestMenu(guid); + QuestMenu& questMenu = bot->PlayerTalkClass->GetQuestMenu(); + for (uint32 i = 0; i < questMenu.MenuItemCount(); ++i) + { + QuestMenuItem const& menuItem = questMenu.GetItem(i); + uint32 questID = menuItem.m_qId; + Quest const* quest = sObjectMgr.GetQuestTemplate(questID); + if (!quest) + { + continue; + } + + ProcessQuest(quest, questGiver); + } + + return true; +} + +bool QuestAction::AcceptQuest(Quest const* quest, uint64 questGiver) +{ + std::ostringstream out; + + uint32 questId = quest->GetQuestId(); + + if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + { + out << "Already completed"; + } + else if (! bot->CanTakeQuest(quest, false)) + { + if (! bot->SatisfyQuestStatus(quest, false)) + { + out << "Already on"; + } + else + { + out << "Can't take"; + } + } + else if (! bot->SatisfyQuestLog(false)) + { + out << "Quest log is full"; + } + else if (! bot->CanAddQuest(quest, false)) + { + out << "Bags are full"; + } + + else + { + WorldPacket p(CMSG_QUESTGIVER_ACCEPT_QUEST); + uint32 unk1 = 0; + p << questGiver << questId << unk1; + p.rpos(0); + bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p); + + if (bot->GetQuestStatus(questId) != QUEST_STATUS_NONE && bot->GetQuestStatus(questId) != QUEST_STATUS_AVAILABLE) + { + out << "Accepted " << chat->formatQuest(quest); + ai->TellMaster(out); + return true; + } + } + + out << " " << chat->formatQuest(quest); + ai->TellMaster(out); + return false; +} + +bool QuestObjectiveCompletedAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + + uint32 entry, questId, available, required; + ObjectGuid guid; + p >> questId >> entry >> available >> required >> guid; + + if (entry & 0x80000000) + { + entry &= 0x7FFFFFFF; + GameObjectInfo const* info = sObjectMgr.GetGameObjectInfo(entry); + if (info) + { + ai->TellMaster(chat->formatQuestObjective(info->name, available, required)); + } + } + else + { + CreatureInfo const* info = sObjectMgr.GetCreatureTemplate(entry); + if (info) + { + ai->TellMaster(chat->formatQuestObjective(info->Name, available, required)); + } + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/QuestAction.h b/src/modules/Bots/playerbot/strategy/actions/QuestAction.h new file mode 100644 index 0000000000..7708fc6d68 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/QuestAction.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../Action.h" +#include "QuestDef.h" + +namespace ai +{ + class QuestAction : public Action + { + public: + QuestAction(PlayerbotAI* ai, string name) : Action(ai, name) {} + + public: + virtual bool Execute(Event event); + + protected: + virtual void ProcessQuest(Quest const* quest, WorldObject* questGiver) = 0; + + protected: + bool AcceptQuest(Quest const* quest, uint64 questGiver); + bool ProcessQuests(ObjectGuid questGiver); + bool ProcessQuests(WorldObject* questGiver); + }; + + class QuestObjectiveCompletedAction : public Action + { + public: + QuestObjectiveCompletedAction(PlayerbotAI* ai) : Action(ai, "quest objective completed") {} + + public: + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h b/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h new file mode 100644 index 0000000000..426e72ec9e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h @@ -0,0 +1,57 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class ReachTargetAction : public MovementAction + { + public: + ReachTargetAction(PlayerbotAI* ai, string name, float distance) : MovementAction(ai, name) + { + this->distance = distance; + } + virtual bool Execute(Event event) + { + return MoveTo(AI_VALUE(Unit*, "current target"), distance); + } + virtual bool isUseful() + { + return AI_VALUE2(float, "distance", "current target") > distance; + } + virtual string GetTargetName() { return "current target"; } + + protected: + float distance; + }; + + class CastReachTargetSpellAction : public CastSpellAction + { + public: + CastReachTargetSpellAction(PlayerbotAI* ai, string spell, float distance) : CastSpellAction(ai, spell) + { + this->distance = distance; + } + virtual bool isUseful() + { + return AI_VALUE2(float, "distance", "current target") > distance; + } + + protected: + float distance; + }; + + class ReachMeleeAction : public ReachTargetAction + { + public: + ReachMeleeAction(PlayerbotAI* ai) : ReachTargetAction(ai, "reach melee", sPlayerbotAIConfig.meleeDistance) {} + }; + + class ReachSpellAction : public ReachTargetAction + { + public: + ReachSpellAction(PlayerbotAI* ai, float distance = sPlayerbotAIConfig.spellDistance) : ReachTargetAction(ai, "reach spell", distance) {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.cpp new file mode 100644 index 0000000000..b1293cf870 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.cpp @@ -0,0 +1,87 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ReadyCheckAction.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool ReadyCheckAction::Execute(Event event) +{ + WorldPacket &p = event.getPacket(); + ObjectGuid player; + p.rpos(0); + if (!p.empty()) + { + p >> player; + } + + if (player == bot->GetObjectGuid()) + { + return false; + } + + return ReadyCheck(); +} + +bool ReadyCheckAction::ReadyCheck() +{ + bool health = AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.almostFullHealth; + if (!health) + { + ai->TellMaster("Low health!"); + return false; + } + + bool mana = !AI_VALUE2(bool, "has mana", "self target") || AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth; + if (!mana) + { + ai->TellMaster("Low mana!"); + return false; + } + + Player* master = GetMaster(); + if (master) + { + bool distance = bot->GetDistance(master) <= sPlayerbotAIConfig.sightDistance; + if (!distance) + { + ai->TellMaster("Too far away!"); + return false; + } + } + + if (bot->getClass() == CLASS_HUNTER) + { + if (!bot->GetUInt32Value(PLAYER_AMMO_ID)) + { + ai->TellMaster("Out of ammo!"); + return false; + } + + if (!bot->GetPet()) + { + ai->TellMaster("No pet!"); + return false; + } + + if (bot->GetPet()->GetHappinessState() == UNHAPPY) + { + ai->TellMaster("Pet is unhappy!"); + return false; + } + } + + WorldPacket* const packet = new WorldPacket(MSG_RAID_READY_CHECK); + *packet << bot->GetObjectGuid(); + *packet << uint8(1); + bot->GetSession()->QueuePacket(packet); + + ai->ChangeStrategy("-ready check", BOT_STATE_NON_COMBAT); + + return true; +} + +bool FinishReadyCheckAction::Execute(Event event) +{ + return ReadyCheck(); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h b/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h new file mode 100644 index 0000000000..0e26b616ad --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h @@ -0,0 +1,26 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class ReadyCheckAction : public Action + { + public: + ReadyCheckAction(PlayerbotAI* ai, string name = "ready check") : Action(ai, name) {} + + virtual bool Execute(Event event); + + protected: + bool ReadyCheck(); + }; + + class FinishReadyCheckAction : public ReadyCheckAction + { + public: + FinishReadyCheckAction(PlayerbotAI* ai) : ReadyCheckAction(ai, "finish ready check") {} + + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ReleaseSpiritAction.h b/src/modules/Bots/playerbot/strategy/actions/ReleaseSpiritAction.h new file mode 100644 index 0000000000..820dddc87f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ReleaseSpiritAction.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" +#include "../values/LastMovementValue.h" + +namespace ai +{ + class ReleaseSpiritAction : public Action { + public: + ReleaseSpiritAction(PlayerbotAI* ai) : Action(ai, "release") {} + + public: + virtual bool Execute(Event event) + { + if (bot->IsAlive() || bot->GetCorpse()) + { + return false; + } + + ai->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT); + + bot->SetBotDeathTimer(); + bot->BuildPlayerRepop(); + + bot->RepopAtGraveyard(); + return true; + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.cpp b/src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.cpp new file mode 100644 index 0000000000..e78d39687d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.cpp @@ -0,0 +1,46 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RememberTaxiAction.h" +#include "../values/LastMovementValue.h" + +using namespace ai; + +bool RememberTaxiAction::Execute(Event event) +{ + + + WorldPacket p(event.getPacket()); + p.rpos(0); + + switch (p.GetOpcode()) + { + case CMSG_ACTIVATETAXI: + { + LastMovement& movement = context->GetValue("last movement")->Get(); + movement.taxiNodes.clear(); + movement.taxiNodes.resize(2); + + p >> movement.taxiMaster >> movement.taxiNodes[0] >> movement.taxiNodes[1]; + return true; + } + case CMSG_ACTIVATETAXIEXPRESS: + { + ObjectGuid guid; + uint32 node_count; + p >> guid >> node_count; + + LastMovement& movement = context->GetValue("last movement")->Get(); + movement.taxiNodes.clear(); + for (uint32 i = 0; i < node_count; ++i) + { + uint32 node; + p >> node; + movement.taxiNodes.push_back(node); + } + + return true; + } + } + + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.h b/src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.h new file mode 100644 index 0000000000..03b674b146 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/RememberTaxiAction.h @@ -0,0 +1,13 @@ +#pragma once + +namespace ai +{ + class RememberTaxiAction : public Action { + public: + RememberTaxiAction(PlayerbotAI* ai) : Action(ai, "remember taxi") {} + + public: + virtual bool Execute(Event event); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp b/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp new file mode 100644 index 0000000000..62301877f8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp @@ -0,0 +1,37 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RepairAllAction.h" + + +using namespace ai; + +bool RepairAllAction::Execute(Event event) +{ + list npcs = AI_VALUE(list, "nearest npcs"); + for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + { + Creature *unit = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_REPAIR); + if (!unit) + { + continue; + } + + if(bot->hasUnitState(UNIT_STAT_DIED)) + { + bot->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + } + + bot->SetFacingToObject(unit); + float discountMod = bot->GetReputationPriceDiscount(unit); + uint32 totalCost = bot->DurabilityRepairAll(true, discountMod, false); + + ostringstream out; + out << "Repair: " << chat->formatMoney(totalCost) << " (" << unit->GetName() << ")"; + ai->TellMasterNoFacing(out.str()); + + return true; + } + + ai->TellMaster("Cannot find any npc to repair at"); + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.h b/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.h new file mode 100644 index 0000000000..2630b5b417 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class RepairAllAction : public Action + { + public: + RepairAllAction(PlayerbotAI* ai) : Action(ai, "repair") {} + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ResetAiAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ResetAiAction.cpp new file mode 100644 index 0000000000..0379dbd442 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ResetAiAction.cpp @@ -0,0 +1,12 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ResetAiAction.h" + +using namespace ai; + +bool ResetAiAction::Execute(Event event) +{ + ai->ResetStrategies(); + ai->TellMaster("AI was reset to defaults"); + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ResetAiAction.h b/src/modules/Bots/playerbot/strategy/actions/ResetAiAction.h new file mode 100644 index 0000000000..929abcb54f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ResetAiAction.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class ResetAiAction : public Action { + public: + ResetAiAction(PlayerbotAI* ai) : Action(ai, "reset ai") {} + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp new file mode 100644 index 0000000000..5c6addc185 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp @@ -0,0 +1,62 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ReviveFromCorpseAction.h" +#include "../../PlayerbotFactory.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool ReviveFromCorpseAction::Execute(Event event) +{ + Corpse* corpse = bot->GetCorpse(); + if (!corpse) + { + return false; + } + + time_t reclaimTime = corpse->GetGhostTime() + bot->GetCorpseReclaimDelay( corpse->GetType()==CORPSE_RESURRECTABLE_PVP ); + if (reclaimTime > time(0) || corpse->GetDistance(bot) > sPlayerbotAIConfig.spellDistance) + { + return false; + } + + PlayerbotChatHandler ch(bot); + if (! ch.revive(*bot)) + { + ai->TellMaster(".. could not be revived .."); + return false; + } + context->GetValue("current target")->Set(NULL); + bot->SetSelectionGuid(ObjectGuid()); + return true; +} + +bool SpiritHealerAction::Execute(Event event) +{ + Corpse* corpse = bot->GetCorpse(); + if (!corpse) + { + return false; + } + + list npcs = AI_VALUE(list, "nearest npcs"); + for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + { + Unit* unit = ai->GetUnit(*i); + if (unit && unit->IsSpiritHealer()) + { + PlayerbotChatHandler ch(bot); + if (! ch.revive(*bot)) + { + ai->TellMaster(".. could not be revived .."); + return false; + } + context->GetValue("current target")->Set(NULL); + bot->SetSelectionGuid(ObjectGuid()); + return true; + } + } + + ai->TellMaster("Cannot find any spirit healer nearby"); + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.h b/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.h new file mode 100644 index 0000000000..d5e3cf2d8b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.h @@ -0,0 +1,21 @@ +#pragma once + +namespace ai +{ + class ReviveFromCorpseAction : public Action { + public: + ReviveFromCorpseAction(PlayerbotAI* ai) : Action(ai, "revive") {} + + public: + virtual bool Execute(Event event); + }; + + class SpiritHealerAction : public Action { + public: + SpiritHealerAction(PlayerbotAI* ai) : Action(ai, "spirit healer") {} + + public: + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp b/src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp new file mode 100644 index 0000000000..ed312e155f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp @@ -0,0 +1,81 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RewardAction.h" +#include "../ItemVisitors.h" +#include "../values/ItemCountValue.h" + +using namespace ai; + +bool RewardAction::Execute(Event event) +{ + string link = event.getParam(); + + ItemIds itemIds = chat->parseItems(link); + if (itemIds.empty()) + { + return false; + } + + uint32 itemId = *itemIds.begin(); + + list npcs = AI_VALUE(list, "nearest npcs"); + for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + { + Unit* npc = ai->GetUnit(*i); + if (npc && Reward(itemId, npc)) + { + return true; + } + } + + list gos = AI_VALUE(list, "nearest game objects"); + for (list::iterator i = gos.begin(); i != gos.end(); i++) + { + GameObject* go = ai->GetGameObject(*i); + if (go && Reward(itemId, go)) + { + return true; + } + } + + ai->TellMaster("Cannot talk to quest giver"); + return false; +} + +bool RewardAction::Reward(uint32 itemId, Object* questGiver) +{ + QuestMenu& questMenu = bot->PlayerTalkClass->GetQuestMenu(); + for (uint32 iI = 0; iI < questMenu.MenuItemCount(); ++iI) + { + QuestMenuItem const& qItem = questMenu.GetItem(iI); + + uint32 questID = qItem.m_qId; + Quest const* pQuest = sObjectMgr.GetQuestTemplate(questID); + QuestStatus status = bot->GetQuestStatus(questID); + + // if quest is complete, turn it in + if (status == QUEST_STATUS_COMPLETE && + ! bot->GetQuestRewardStatus(questID) && + pQuest->GetRewChoiceItemsCount() > 1 && + bot->CanRewardQuest(pQuest, false)) + { + for (uint8 rewardIdx=0; rewardIdx < pQuest->GetRewChoiceItemsCount(); ++rewardIdx) + { + ItemPrototype const * const pRewardItem = sObjectMgr.GetItemPrototype(pQuest->RewChoiceItemId[rewardIdx]); + if (itemId == pRewardItem->ItemId) + { + bot->RewardQuest(pQuest, rewardIdx, questGiver, false); + + string questTitle = pQuest->GetTitle(); + string itemName = pRewardItem->Name1; + + ostringstream out; out << chat->formatItem(pRewardItem) << " rewarded"; + ai->TellMaster(out); + return true; + } + } + } + } + + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/RewardAction.h b/src/modules/Bots/playerbot/strategy/actions/RewardAction.h new file mode 100644 index 0000000000..f4eda1335a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/RewardAction.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class RewardAction : public InventoryAction { + public: + RewardAction(PlayerbotAI* ai) : InventoryAction(ai, "reward") {} + virtual bool Execute(Event event); + + private: + bool Reward(uint32 itemId, Object* pNpc); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/RtiAction.h b/src/modules/Bots/playerbot/strategy/actions/RtiAction.h new file mode 100644 index 0000000000..6c2ef7b15d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/RtiAction.h @@ -0,0 +1,46 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class RtiAction : public Action + { + public: + RtiAction(PlayerbotAI* ai) : Action(ai, "rti") + {} + + virtual bool Execute(Event event) + { + string text = event.getParam(); + if (text.empty() || text == "?") + { + ostringstream out; out << "RTI: "; + AppendRti(out); + ai->TellMaster(out); + return true; + } + + context->GetValue("rti")->Set(text); + ostringstream out; out << "RTI set to: "; + AppendRti(out); + ai->TellMaster(out); + return true; + } + + private: + void AppendRti(ostringstream & out) + { + out << AI_VALUE(string, "rti"); + + Unit* target = AI_VALUE(Unit*, "rti target"); + if(target) + { + out << " (" << target->GetName() << ")"; + } + + } + + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SaveManaAction.cpp b/src/modules/Bots/playerbot/strategy/actions/SaveManaAction.cpp new file mode 100644 index 0000000000..1f45357cd9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SaveManaAction.cpp @@ -0,0 +1,81 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "SaveManaAction.h" +#include "../../AiFactory.h" +#include "../ItemVisitors.h" + +using namespace ai; + +bool SaveManaAction::Execute(Event event) +{ + string text = event.getParam(); + double value = AI_VALUE(double, "mana save level"); + + if (text == "?") + { + ostringstream out; out << "Mana save level: " << format(value); + ai->TellMaster(out); + return true; + } + + if (text == "*") + { + switch (bot->getClass()) + { + case CLASS_HUNTER: + case CLASS_SHAMAN: + case CLASS_DRUID: + value = 5.0; + break; + case CLASS_MAGE: + case CLASS_PRIEST: + case CLASS_WARLOCK: + value = 2.0; + break; + default: + value = 3.0; + } + } + else if (text.empty()) + { + value = 1.0; + } + else + { + value = atof(text.c_str()); + } + + value = min(10.0, value); + value = max(1.0, value); + value = floor(value * 100 + 0.5) / 100.0; + + ai->GetAiObjectContext()->GetValue("mana save level")->Set(value); + + ostringstream out; out << "Mana save level set: " << format(value); + ai->TellMaster(out); + + return true; +} + +string SaveManaAction::format(double value) +{ + ostringstream out; + if (value <= 1.0) + { + out << "|cFF808080"; + } + else if (value <= 5.0) + { + out << "|cFF00FF00"; + } + else if (value <= 7.0) + { + out << "|cFFFFFF00"; + } + else + { + out << "|cFFFF0000"; + } + out << value << "|cffffffff"; + return out.str(); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SaveManaAction.h b/src/modules/Bots/playerbot/strategy/actions/SaveManaAction.h new file mode 100644 index 0000000000..3d9b3e0f8b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SaveManaAction.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class SaveManaAction : public Action + { + public: + SaveManaAction(PlayerbotAI* ai) : Action(ai, "save mana") {} + + public: + virtual bool Execute(Event event); + + private: + string format(double value); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.cpp b/src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.cpp new file mode 100644 index 0000000000..91e5b8fb9a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.cpp @@ -0,0 +1,30 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "../../RandomPlayerbotMgr.h" +#include "SecurityCheckAction.h" + +using namespace ai; + + +bool SecurityCheckAction::isUseful() +{ + return sRandomPlayerbotMgr.IsRandomBot(bot) && ai->GetMaster() && ai->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER; +} + +bool SecurityCheckAction::Execute(Event event) +{ + Group* group = bot->GetGroup(); + if (group) + { + LootMethod method = group->GetLootMethod(); + ItemQualities threshold = group->GetLootThreshold(); + if (method == MASTER_LOOT || method == FREE_FOR_ALL || threshold > ITEM_QUALITY_UNCOMMON) + { + ai->TellMaster("I won't do anything until you change loot type to group loot with green threshold"); + ai->ChangeStrategy("+passive,+stay", BOT_STATE_NON_COMBAT); + ai->ChangeStrategy("+passive,+stay", BOT_STATE_COMBAT); + return true; + } + } + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.h b/src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.h new file mode 100644 index 0000000000..4ae38f05d3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SecurityCheckAction.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class SecurityCheckAction : public Action + { + public: + SecurityCheckAction(PlayerbotAI* ai) : Action(ai, "security check") {} + virtual bool isUseful(); + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SellAction.cpp b/src/modules/Bots/playerbot/strategy/actions/SellAction.cpp new file mode 100644 index 0000000000..e4cec28c6a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SellAction.cpp @@ -0,0 +1,101 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "SellAction.h" +#include "../ItemVisitors.h" + +using namespace ai; + +class SellItemsVisitor : public IterateItemsVisitor +{ +public: + SellItemsVisitor(SellAction* action) : IterateItemsVisitor() + { + this->action = action; + } + + virtual bool Visit(Item* item) + { + action->Sell(item); + return true; + } + +private: + SellAction* action; +}; + +class SellGrayItemsVisitor : public SellItemsVisitor +{ +public: + SellGrayItemsVisitor(SellAction* action) : SellItemsVisitor(action) {} + + virtual bool Visit(Item* item) + { + if (item->GetProto()->Quality != ITEM_QUALITY_POOR) + { + return true; + } + + return SellItemsVisitor::Visit(item); + } +}; + + +bool SellAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + string text = event.getParam(); + + if (text == "gray" || text == "*") + { + SellGrayItemsVisitor visitor(this); + IterateItems(&visitor); + return true; + } + + ItemIds ids = chat->parseItems(text); + + for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + { + FindItemByIdVisitor visitor(*i); + Sell(&visitor); + } + + return true; +} + + +void SellAction::Sell(FindItemVisitor* visitor) +{ + IterateItems(visitor); + list items = visitor->GetResult(); + for (list::iterator i = items.begin(); i != items.end(); ++i) + { + Sell(*i); + } +} + +void SellAction::Sell(Item* item) +{ + Player* master = GetMaster(); + ObjectGuid vendorguid = master->GetSelectionGuid(); + if (!vendorguid) + { + ai->TellMaster("Select a vendor first"); + return; + } + + ObjectGuid itemguid = item->GetObjectGuid(); + uint32 count = item->GetCount(); + + WorldPacket p; + p << vendorguid << itemguid << count; + bot->GetSession()->HandleSellItemOpcode(p); + + ostringstream out; out << chat->formatItem(item->GetProto()) << " sold"; + ai->TellMaster(out); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SellAction.h b/src/modules/Bots/playerbot/strategy/actions/SellAction.h new file mode 100644 index 0000000000..c1f091548a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SellAction.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class SellAction : public InventoryAction { + public: + SellAction(PlayerbotAI* ai) : InventoryAction(ai, "sell") {} + virtual bool Execute(Event event); + + void Sell(FindItemVisitor* visitor); + void Sell(Item* item); + + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp b/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp new file mode 100644 index 0000000000..f1f4863247 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp @@ -0,0 +1,50 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "SetHomeAction.h" +#include "../../PlayerbotAIConfig.h" + + +using namespace ai; + +bool SetHomeAction::Execute(Event event) +{ + Player* master = ai->GetMaster(); + if (!master) + { + return false; + } + + ObjectGuid selection = master->GetSelectionGuid(); + if (selection) + { + Unit* unit = master->GetMap()->GetUnit(selection); + if (unit && unit->IsInnkeeper()) + { + float angle = GetFollowAngle(); + float x = unit->GetPositionX() + sPlayerbotAIConfig.followDistance * cos(angle); + float y = unit->GetPositionY() + sPlayerbotAIConfig.followDistance * sin(angle); + float z = unit->GetPositionZ(); + WorldLocation loc(unit->GetMapId(), x, y, z); + bot->SetHomebindToLocation(loc, unit->GetAreaId()); + ai->TellMaster("This inn is my new home"); + return true; + } + } + + list npcs = AI_VALUE(list, "nearest npcs"); + for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + { + Creature *unit = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_INNKEEPER); + if (!unit) + { + continue; + } + + bot->GetSession()->SendBindPoint(unit); + ai->TellMaster("This inn is my new home"); + return true; + } + + ai->TellMaster("Can't find any innkeeper around"); + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.h b/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.h new file mode 100644 index 0000000000..b98a5b55ef --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.h @@ -0,0 +1,12 @@ +#pragma once + +#include "MovementActions.h" + +namespace ai +{ + class SetHomeAction : public MovementAction { + public: + SetHomeAction(PlayerbotAI* ai) : MovementAction(ai, "home") {} + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/StatsAction.cpp b/src/modules/Bots/playerbot/strategy/actions/StatsAction.cpp new file mode 100644 index 0000000000..4e37b5d69b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/StatsAction.cpp @@ -0,0 +1,165 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "StatsAction.h" + + +using namespace ai; + +bool StatsAction::Execute(Event event) +{ + ostringstream out; + + ListGold(out); + + out << ", "; + ListBagSlots(out); + + out << ", "; + ListRepairCost(out); + + if (bot->GetUInt32Value(PLAYER_NEXT_LEVEL_XP)) + { + out << ", "; + ListXP(out); + } + + ai->TellMaster(out); + return true; +} + +void StatsAction::ListGold(ostringstream &out) +{ + out << chat->formatMoney(bot->GetMoney()); +} + +void StatsAction::ListBagSlots(ostringstream &out) +{ + uint32 totalused = 0, total = 16; + // list out items in main backpack + for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++) + { + const Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + if (pItem) + { + totalused++; + } + } + uint32 totalfree = 16 - totalused; + // list out items in other removable backpacks + for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag) + { + const Bag* const pBag = (Bag*) bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag); + if (pBag) + { + ItemPrototype const* pBagProto = pBag->GetProto(); + if (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER) + { + total += pBag->GetBagSize(); + totalfree += pBag->GetFreeSlots(); + } + } + + } + + string color = "ff00ff00"; + if (totalfree < total / 2) + { + color = "ffffff00"; + } + if (totalfree < total / 4) + { + color = "ffff0000"; + } + out << "|h|c" << color << (total - totalfree) << "/" << total << "|h|cffffffff Bag"; +} + +void StatsAction::ListXP( ostringstream &out ) +{ + uint32 curXP = bot->GetUInt32Value(PLAYER_XP); + uint32 nextLevelXP = bot->GetUInt32Value(PLAYER_NEXT_LEVEL_XP); + uint32 xpPercent = 0; + if (nextLevelXP) + { + xpPercent = 100 * curXP / nextLevelXP; + } + + out << "|r|cff00ff00" << xpPercent << "|r|cffffd333%" << "|h|cffffffff XP"; +} + +void StatsAction::ListRepairCost(ostringstream &out) +{ + out << chat->formatMoney(EstRepairAll()) << " Repair"; +} + +uint32 StatsAction::EstRepairAll() +{ + uint32 TotalCost = 0; + // equipped, backpack, bags itself + for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + TotalCost += EstRepair(( (INVENTORY_SLOT_BAG_0 << 8) | i )); + } + + // bank, buyback and keys not repaired + + // items in inventory bags + for(int j = INVENTORY_SLOT_BAG_START; j < INVENTORY_SLOT_BAG_END; ++j) + { + for(int i = 0; i < MAX_BAG_SIZE; ++i) + { + TotalCost += EstRepair(( (j << 8) | i )); + } + } + return TotalCost; +} + +uint32 StatsAction::EstRepair(uint16 pos) +{ + Item* item = bot->GetItemByPos(pos); + + uint32 TotalCost = 0; + if(!item) + { + return TotalCost; + } + + uint32 maxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); + if(!maxDurability) + { + return TotalCost; + } + + uint32 curDurability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); + + uint32 LostDurability = maxDurability - curDurability; + if(LostDurability>0) + { + ItemPrototype const *ditemProto = item->GetProto(); + + DurabilityCostsEntry const *dcost = sDurabilityCostsStore.LookupEntry(ditemProto->ItemLevel); + if(!dcost) + { + sLog.outError("RepairDurability: Wrong item lvl %u", ditemProto->ItemLevel); + return TotalCost; + } + + uint32 dQualitymodEntryId = (ditemProto->Quality+1)*2; + DurabilityQualityEntry const *dQualitymodEntry = sDurabilityQualityStore.LookupEntry(dQualitymodEntryId); + if(!dQualitymodEntry) + { + sLog.outError("RepairDurability: Wrong dQualityModEntry %u", dQualitymodEntryId); + return TotalCost; + } + + uint32 dmultiplier = dcost->multiplier[ItemSubClassToDurabilityMultiplierId(ditemProto->Class,ditemProto->SubClass)]; + uint32 costs = uint32(LostDurability*dmultiplier*double(dQualitymodEntry->quality_mod)); + + if (costs==0) //fix for ITEM_QUALITY_ARTIFACT + { + costs = 1; + } + + TotalCost = costs; + } + return TotalCost; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/StatsAction.h b/src/modules/Bots/playerbot/strategy/actions/StatsAction.h new file mode 100644 index 0000000000..e30558c1db --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/StatsAction.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class StatsAction : public Action { + public: + StatsAction(PlayerbotAI* ai) : Action(ai, "stats") {} + virtual bool Execute(Event event); + + private: + void ListBagSlots(ostringstream &out); + void ListXP(ostringstream &out); + void ListRepairCost(ostringstream &out); + void ListGold(ostringstream &out); + uint32 EstRepairAll(); + uint32 EstRepair(uint16 pos); + + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/StayActions.cpp b/src/modules/Bots/playerbot/strategy/actions/StayActions.cpp new file mode 100644 index 0000000000..9bc41a27e8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/StayActions.cpp @@ -0,0 +1,274 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "StayActions.h" +#include "../values/LastMovementValue.h" +#include "MovementGenerator.h" + +using namespace ai; + +void StayActionBase::Stay() +{ + AI_VALUE(LastMovement&, "last movement").Set(NULL); + + MotionMaster &mm = *bot->GetMotionMaster(); + if (mm.GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE || bot->IsTaxiFlying()) + { + return; + } + + mm.Clear(); + mm.MoveIdle(); + bot->clearUnitState( UNIT_STAT_CHASE ); + bot->clearUnitState( UNIT_STAT_FOLLOW ); + + if (!bot->IsStandState()) + { + bot->SetStandState(UNIT_STAND_STATE_STAND); + } +} + +bool StayActionBase::StayLine(vector line, float diff, float cx, float cy, float cz, float orientation, float range) +{ + if (line.size() < 5) + { + return StaySingleLine(line, diff, cx, cy, cz, orientation, range); + } + + int lines = ceil((double)line.size() / 5.0); + for (int i = 0; i < lines; i++) + { + float radius = range * i; + float x = cx + cos(orientation) * radius; + float y = cy + sin(orientation) * radius; + vector singleLine; + for (int j = 0; j < 5 && !line.empty(); j++) + { + singleLine.push_back(line[line.size() - 1]); + line.pop_back(); + } + + bool ok = StaySingleLine(singleLine, diff, x, y, cz, orientation, range); + if (ok) + { + return true; + } + } + + return false; +} + +bool StayActionBase::StaySingleLine(vector line, float diff, float cx, float cy, float cz, float orientation, float range) +{ + Stay(); + + float count = line.size(); + float angle = orientation - M_PI / 2.0f; + float x = cx + cos(angle) * (range * floor(count / 2.0f) + diff); + float y = cy + sin(angle) * (range * floor(count / 2.0f) + diff); + + int index = 0; + for (vector::iterator i = line.begin(); i != line.end(); i++) + { + Player* member = *i; + + if (member == bot) + { + float angle = orientation + M_PI / 2.0f; + float radius = range * index; + + return MoveTo(bot->GetMapId(), x + cos(angle) * radius, y + sin(angle) * radius, cz); + } + + index++; + } + + return false; +} + +bool StayAction::Execute(Event event) +{ + Stay(); + + return true; +} + +bool StayAction::isUseful() +{ + return !AI_VALUE2(bool, "moving", "self target"); +} + +bool StayCircleAction::Execute(Event event) + { +Stay(); + +float range = 2.0f; + +Unit* target = AI_VALUE(Unit*, "current target"); +Player* master = GetMaster(); +if (!target) +{ + target = master; +} + +if (!target) +{ + return false; +} + +switch (bot->getClass()) + { +case CLASS_HUNTER: +case CLASS_MAGE: +case CLASS_PRIEST: +case CLASS_WARLOCK: +range = sPlayerbotAIConfig.fleeDistance; +break; +case CLASS_DRUID: +if (!ai->IsTank(bot)) +{ + range = sPlayerbotAIConfig.fleeDistance; +} +break; +case CLASS_SHAMAN: +if (ai->IsHeal(bot)) +{ + range = sPlayerbotAIConfig.fleeDistance; +} +break; +} + +float x = target->GetPositionX(); +float y = target->GetPositionY(); +float z = target->GetPositionZ(); +float angle = GetFollowAngle(); + +return MoveTo(bot->GetMapId(), x + cos(angle) * range, y + sin(angle) * range, z); +} + +bool StayLineAction::Execute(Event event) + { +Group* group = bot->GetGroup(); +if (!group) +{ + return false; +} + +float range = 2.0f; + +Player* master = GetMaster(); +if (!master) +{ + return false; +} + +float x = master->GetPositionX(); +float y = master->GetPositionY(); +float z = master->GetPositionZ(); +float orientation = master->GetOrientation(); + +vector players; +GroupReference *gref = group->GetFirstMember(); +while (gref) +{ +Player* member = gref->getSource(); +if (member != master) +{ + players.push_back(member); +} + +gref = gref->next(); +} + +players.insert(players.begin() + group->GetMembersCount() / 2, master); + +return StayLine(players, 0.0f, x, y, z, orientation, range); +} + +bool StayCombatAction::Execute(Event event) + { +Group* group = bot->GetGroup(); +if (!group) +{ + return false; +} + +float range = 2.0f; + +Player* master = GetMaster(); +if (!master) +{ + return false; +} + +float x = master->GetPositionX(); +float y = master->GetPositionY(); +float z = master->GetPositionZ(); +float orientation = master->GetOrientation(); + +vector tanks; +vector dps; +GroupReference *gref = group->GetFirstMember(); +while (gref) +{ +Player* member = gref->getSource(); +if (member != master) + { +if (ai->IsTank(member)) +{ + tanks.push_back(member); +} +else +{ + dps.push_back(member); +} +} + +gref = gref->next(); +} + +if (ai->IsTank(master)) +{ + tanks.insert(tanks.begin() + (tanks.size() + 1) / 2, master); +} +else +{ + dps.insert(dps.begin() + (dps.size() + 1) / 2, master); +} + +switch (rand() % 50) + { +case 5: +ai->TellMaster("Keep your eyes open!"); +break; +case 15: +ai->TellMaster("Stay alert!"); +break; +case 30: +ai->TellMaster("I hear something, keep order!"); +break; +} + +if (ai->IsTank(bot) && ai->IsTank(master)) + { +StayLine(tanks, 0.0f, x, y, z, orientation, range); +return true; +} +if (!ai->IsTank(bot) && !ai->IsTank(master)) + { +StayLine(dps, 0.0f, x, y, z, orientation, range); +return true; +} +if (ai->IsTank(bot) && !ai->IsTank(master)) +{ +float diff = tanks.size() % 2 == 0 ? -range / 2.0f : 0.0f; +StayLine(tanks, diff, x + cos(orientation) * range, y + sin(orientation) * range, z, orientation, range); +return true; +} +if (!ai->IsTank(bot) && ai->IsTank(master)) + { +float diff = dps.size() % 2 == 0 ? -range / 2.0f : 0.0f; +StayLine(dps, diff, x - cos(orientation) * range, y - sin(orientation) * range, z, orientation, range); +return true; +} +return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/StayActions.h b/src/modules/Bots/playerbot/strategy/actions/StayActions.h new file mode 100644 index 0000000000..809f32a8b2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/StayActions.h @@ -0,0 +1,42 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" + +namespace ai +{ + class StayActionBase : public MovementAction { + public: + StayActionBase(PlayerbotAI* ai, string name) : MovementAction(ai, name) {} + + protected: + void Stay(); + bool StayLine(vector line, float diff, float cx, float cy, float cz, float orientation, float range); + bool StaySingleLine(vector line, float diff, float cx, float cy, float cz, float orientation, float range); + }; + + class StayAction : public StayActionBase { + public: + StayAction(PlayerbotAI* ai) : StayActionBase(ai, "stay") {} + virtual bool Execute(Event event); + virtual bool isUseful(); + }; + + class StayCircleAction : public StayActionBase { + public: + StayCircleAction(PlayerbotAI* ai) : StayActionBase(ai, "stay circle") {} + virtual bool Execute(Event event); + }; + + class StayCombatAction : public StayActionBase { + public: + StayCombatAction(PlayerbotAI* ai) : StayActionBase(ai, "stay combat") {} + virtual bool Execute(Event event); + }; + + class StayLineAction : public StayActionBase { + public: + StayLineAction(PlayerbotAI* ai) : StayActionBase(ai, "stay line") {} + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.cpp b/src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.cpp new file mode 100644 index 0000000000..ad3daa9cb4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.cpp @@ -0,0 +1,287 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "SuggestWhatToDoAction.h" +#include "../../../ahbot/AhBot.h" +#include "ChannelMgr.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +SuggestWhatToDoAction::SuggestWhatToDoAction(PlayerbotAI* ai) : InventoryAction(ai, "suggest what to do"), suggested(false) +{ + suggestions.push_back(&SuggestWhatToDoAction::instance); + suggestions.push_back(&SuggestWhatToDoAction::specificQuest); + suggestions.push_back(&SuggestWhatToDoAction::newQuest); + suggestions.push_back(&SuggestWhatToDoAction::grindMaterials); + suggestions.push_back(&SuggestWhatToDoAction::trade); + suggestions.push_back(&SuggestWhatToDoAction::grindReputation); + suggestions.push_back(&SuggestWhatToDoAction::nothing); + suggestions.push_back(&SuggestWhatToDoAction::relax); +} + +bool SuggestWhatToDoAction::Execute(Event event) +{ + if (suggested) + { + trade(); + return true; + } + + if (bot->GetInstanceId() || suggested) + { + return false; + } + + int index = rand() % suggestions.size(); + (this->*suggestions[index])(); + + return suggested = true; +} + +void SuggestWhatToDoAction::instance() +{ + uint32 level = bot->getLevel(); + if (level > 15) + { + switch (urand(0, 5)) + { + case 0: + spam("Need a tank for an instance run"); + break; + case 1: + spam("Need a healer for an instance run"); + break; + case 2: + spam("I would like to do an instance run. Would you like to join me?"); + break; + case 3: + spam("Need better equipment. Why not do an instance run?"); + break; + case 4: + spam("Have dungeon quests? Can join your group!"); + break; + case 5: + spam("Have group quests? Invite me!"); + break; + default: + spam("Hey, why not join Dungeon Finder?"); + } + } +} + +vector SuggestWhatToDoAction::GetIncompletedQuests() +{ + 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(questId); + } + } + + return result; +} + +void SuggestWhatToDoAction::specificQuest() +{ + vector quests = GetIncompletedQuests(); + if (quests.empty()) + { + return; + } + + int index = rand() % quests.size(); + + Quest const* quest = sObjectMgr.GetQuestTemplate(quests[index]); + ostringstream out; out << "We could do some quest, for instance " << chat->formatQuest(quest); + spam(out.str()); +} + +void SuggestWhatToDoAction::newQuest() +{ + vector quests = GetIncompletedQuests(); + if (quests.size() < MAX_QUEST_LOG_SIZE - 5) + { + spam("I would like to pick up and do a new quest. Just invite me!"); + } +} + +void SuggestWhatToDoAction::grindMaterials() +{ + if (bot->getLevel() <= 5) + { + return; + } + + switch (urand(0, 5)) + { + case 0: + spam("Need help for tradeskill?"); + break; + case 1: + spam("Can we have some trade material grinding?"); + break; + case 2: + spam("I have some trade materials for sell"); + break; + default: + spam("I am going to grind some trade materials. Would you like to join me?"); + } +} + +void SuggestWhatToDoAction::grindReputation() +{ + if (bot->getLevel() > 15) + { + ai->TellMasterNoFacing("I think we should do something to improve our reputation", PLAYERBOT_SECURITY_ALLOW_ALL); + } +} + +void SuggestWhatToDoAction::nothing() +{ + ai->TellMasterNoFacing("I don't want to do anything", PLAYERBOT_SECURITY_ALLOW_ALL); +} + +void SuggestWhatToDoAction::relax() +{ + ai->TellMasterNoFacing("It is so boring... We could relax a bit", PLAYERBOT_SECURITY_ALLOW_ALL); +} + +class FindTradeItemsVisitor : public IterateItemsVisitor +{ +public: + FindTradeItemsVisitor(uint32 quality) : quality(quality), IterateItemsVisitor() {} + + virtual bool Visit(Item* item) + { + ItemPrototype const* proto = item->GetProto(); + if (proto->Quality != quality) + { + return true; + } + + if (proto->Class == ITEM_CLASS_TRADE_GOODS && proto->Bonding == NO_BIND) + { + if(proto->Quality == ITEM_QUALITY_NORMAL && item->GetCount() > 1 && item->GetCount() == item->GetMaxStackCount()) + { + stacks.push_back(proto->ItemId); + } + + items.push_back(proto->ItemId); + count[proto->ItemId] += item->GetCount(); + } + + return true; + } + + map count; + vector stacks; + vector items; + +private: + uint32 quality; +}; + + +void SuggestWhatToDoAction::trade() +{ + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) + { + return; + } + + uint32 quality = urand(0, 100); + if (quality > 90) + { + quality = ITEM_QUALITY_EPIC; + } + else if (quality >75) + { + quality = ITEM_QUALITY_RARE; + } + else if (quality > 50) + { + quality = ITEM_QUALITY_UNCOMMON; + } + else + { + quality = ITEM_QUALITY_NORMAL; + } + + uint32 item = 0, count = 0; + while (quality-- > ITEM_QUALITY_POOR) + { + FindTradeItemsVisitor visitor(quality); + IterateItems(&visitor); + if (!visitor.stacks.empty()) + { + int index = urand(0, visitor.stacks.size() - 1); + item = visitor.stacks[index]; + } + + if (!item) + { + if (!visitor.items.empty()) + { + int index = urand(0, visitor.items.size() - 1); + item = visitor.items[index]; + } + } + + if (item) + { + count = visitor.count[item]; + break; + } + } + + if (!item || !count) + { + return; + } + + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(item); + if (!proto) + { + return; + } + + uint32 price = auctionbot.GetSellPrice(proto) * sRandomPlayerbotMgr.GetSellMultiplier(bot) * count; + if (!price) + { + return; + } + + ostringstream out; out << "Selling " << chat->formatItem(proto, count) << " for " << chat->formatMoney(price); + spam(out.str()); +} + +void SuggestWhatToDoAction::spam(string msg) +{ + Player* player = sRandomPlayerbotMgr.GetRandomPlayer(); + if (!player || !player->IsInWorld()) + { + return; + } + + if (!ai->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_TALK, true, player)) + { + return; + } + + if (sPlayerbotAIConfig.whisperDistance && !bot->GetGroup() && sRandomPlayerbotMgr.IsRandomBot(bot) && + player->GetSession()->GetSecurity() < SEC_GAMEMASTER && + (bot->GetMapId() != player->GetMapId() || bot->GetDistance(player) > sPlayerbotAIConfig.whisperDistance)) + return; + + bot->Whisper(msg, LANG_UNIVERSAL, player->GetObjectGuid()); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.h b/src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.h new file mode 100644 index 0000000000..a45ea7355b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/SuggestWhatToDoAction.h @@ -0,0 +1,33 @@ +#pragma once + +#include "InventoryAction.h" + +namespace ai +{ + class SuggestWhatToDoAction : public InventoryAction + { + public: + SuggestWhatToDoAction(PlayerbotAI* ai); + virtual bool Execute(Event event); + + private: + typedef void (SuggestWhatToDoAction::*Suggestion) (); + vector suggestions; + + private: + void instance(); + void specificQuest(); + void newQuest(); + void grindMaterials(); + void grindReputation(); + void nothing(); + void relax(); + void trade(); + void spam(string msg); + + vector GetIncompletedQuests(); + + private: + bool suggested; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.cpp new file mode 100644 index 0000000000..a997d99c53 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.cpp @@ -0,0 +1,99 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TalkToQuestGiverAction.h" + + +using namespace ai; + +void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, WorldObject* questGiver) +{ + std::ostringstream out; out << "Quest "; + + QuestStatus 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_AVAILABLE: + case QUEST_STATUS_NONE: + out << "|cff00ff00Available|r"; + break; + case QUEST_STATUS_FAILED: + out << "|cffff0000Failed|r"; + break; + } + + out << ": " << chat->formatQuest(quest); + ai->TellMaster(out); +} + +void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, WorldObject* questGiver, ostringstream& out) +{ + uint32 questID = quest->GetQuestId(); + + if (bot->GetQuestRewardStatus(questID)) + { + return; + } + + if (quest->GetRewChoiceItemsCount() == 0) + { + RewardNoItem(quest, questGiver, out); + } + else if (quest->GetRewChoiceItemsCount() == 1) + { + RewardSingleItem(quest, questGiver, out); + } + else { + { + AskToSelectReward(quest, out); + } + } +} + +void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, WorldObject* questGiver, ostringstream& out) +{ + if (bot->CanRewardQuest(quest, false)) + { + bot->RewardQuest(quest, 0, questGiver, false); + out << "Completed"; + } + else + { + out << "|cffff0000Unable to turn in|r"; + } +} + +void TalkToQuestGiverAction::RewardSingleItem(Quest const* quest, WorldObject* questGiver, ostringstream& out) +{ + int index = 0; + ItemPrototype const *item = sObjectMgr.GetItemPrototype(quest->RewChoiceItemId[index]); + if (bot->CanRewardQuest(quest, index, false)) + { + bot->RewardQuest(quest, index, questGiver, true); + + out << "Rewarded " << chat->formatItem(item); + } + else + { + out << "|cffff0000Unable to turn in:|r, reward: " << chat->formatItem(item); + } +} + +void TalkToQuestGiverAction::AskToSelectReward(Quest const* quest, ostringstream& out) +{ + ostringstream msg; + msg << "Choose reward: "; + for (uint8 i=0; i < quest->GetRewChoiceItemsCount(); ++i) + { + ItemPrototype const* item = sObjectMgr.GetItemPrototype(quest->RewChoiceItemId[i]); + msg << chat->formatItem(item); + } + ai->TellMaster(msg); + + out << "Reward pending"; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.h b/src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.h new file mode 100644 index 0000000000..374dc69cab --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TalkToQuestGiverAction.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../Action.h" +#include "QuestAction.h" + +namespace ai +{ + class TalkToQuestGiverAction : public QuestAction { + public: + TalkToQuestGiverAction(PlayerbotAI* ai) : QuestAction(ai, "talk to quest giver") {} + + protected: + virtual void ProcessQuest(Quest const* quest, WorldObject* questGiver); + + private: + void TurnInQuest(Quest const* quest, WorldObject* questGiver, ostringstream& out); + void RewardNoItem(Quest const* quest, WorldObject* questGiver, ostringstream& out); + void RewardSingleItem(Quest const* quest, WorldObject* questGiver, ostringstream& out); + void AskToSelectReward(Quest const* quest, ostringstream& out); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp new file mode 100644 index 0000000000..69af4f9260 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp @@ -0,0 +1,53 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TaxiAction.h" +#include "../values/LastMovementValue.h" + +using namespace ai; + +bool TaxiAction::Execute(Event event) +{ + ai->RemoveShapeshift(); + + LastMovement& movement = context->GetValue("last movement")->Get(); + + WorldPacket& p = event.getPacket(); + if (!p.empty() && p.GetOpcode() == CMSG_MOVE_SPLINE_DONE) + { + WorldPacket p1(p); + p1.rpos(0); + bot->GetSession()->HandleMoveSplineDoneOpcode(p1); + movement.taxiNodes.clear(); + movement.Set(NULL); + return true; + } + + list units = *context->GetValue >("nearest npcs"); + for (list::iterator i = units.begin(); i != units.end(); i++) + { + Creature *npc = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_FLIGHTMASTER); + if (!npc) + { + continue; + } + + if (movement.taxiNodes.empty()) + { + ostringstream out; + out << "I will order the taxi from " << npc->GetName() << ". Please start flying, then instruct me again"; + ai->TellMaster(out); + return true; + } + + if (!bot->ActivateTaxiPathTo(movement.taxiNodes, npc)) + { + ai->TellMaster("I can't fly with you"); + return false; + } + + return true; + } + + ai->TellMaster("Cannot find any flightmaster to talk"); + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TaxiAction.h b/src/modules/Bots/playerbot/strategy/actions/TaxiAction.h new file mode 100644 index 0000000000..7e5a6d664b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TaxiAction.h @@ -0,0 +1,13 @@ +#pragma once + +namespace ai +{ + class TaxiAction : public Action { + public: + TaxiAction(PlayerbotAI* ai) : Action(ai, "taxi") {} + + public: + virtual bool Execute(Event event); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp new file mode 100644 index 0000000000..b9bceb1388 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp @@ -0,0 +1,60 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TeleportAction.h" +#include "../values/LastMovementValue.h" + +using namespace ai; + +bool TeleportAction::Execute(Event event) +{ + list gos = *context->GetValue >("nearest game objects"); + for (list::iterator i = gos.begin(); i != gos.end(); i++) + { + GameObject* go = ai->GetGameObject(*i); + if (!go) + { + continue; + } + + GameObjectInfo const *goInfo = go->GetGOInfo(); + if (goInfo->type != GAMEOBJECT_TYPE_SPELLCASTER) + { + continue; + } + + uint32 spellId = goInfo->spellcaster.spellId; + const SpellEntry* const pSpellInfo = sSpellStore.LookupEntry(spellId); + if (pSpellInfo->Effect[0] != SPELL_EFFECT_TELEPORT_UNITS && pSpellInfo->Effect[1] != SPELL_EFFECT_TELEPORT_UNITS && pSpellInfo->Effect[2] != SPELL_EFFECT_TELEPORT_UNITS) + { + continue; + } + + ostringstream out; out << "Teleporting using " << goInfo->name; + ai->TellMasterNoFacing(out.str()); + + ai->ChangeStrategy("-follow,+stay", BOT_STATE_NON_COMBAT); + + Spell *spell = new Spell(bot, pSpellInfo, false); + SpellCastTargets targets; + targets.setUnitTarget(bot); + spell->prepare(&targets, NULL); + spell->cast(true); + return true; + } + + + LastMovement& movement = context->GetValue("last movement")->Get(); + if (movement.lastAreaTrigger) + { + WorldPacket p(CMSG_AREATRIGGER); + p << movement.lastAreaTrigger; + p.rpos(0); + + bot->GetSession()->HandleAreaTriggerOpcode(p); + movement.lastAreaTrigger = 0; + return true; + } + + ai->TellMaster("Cannot find any portal to teleport"); + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TeleportAction.h b/src/modules/Bots/playerbot/strategy/actions/TeleportAction.h new file mode 100644 index 0000000000..6d4a020282 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TeleportAction.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" + +namespace ai +{ + class TeleportAction : public Action { + public: + TeleportAction(PlayerbotAI* ai) : Action(ai, "teleport") {} + + public: + virtual bool Execute(Event event); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.cpp new file mode 100644 index 0000000000..08d8d331c6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.cpp @@ -0,0 +1,75 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TellCastFailedAction.h" + + +using namespace ai; + +bool TellCastFailedAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + uint8 castCount, result; + uint32 spellId; + p >> castCount >> spellId >> result; + ai->SpellInterrupted(spellId); + + if (result == SPELL_CAST_OK) + { + return false; + } + + const SpellEntry *const pSpellInfo = sSpellStore.LookupEntry(spellId); + ostringstream out; out << chat->formatSpell(pSpellInfo) << ": "; + switch (result) + { + case SPELL_FAILED_NOT_READY: + out << "not ready"; + break; + case SPELL_FAILED_REQUIRES_SPELL_FOCUS: + out << "requires spell focus"; + break; + case SPELL_FAILED_REQUIRES_AREA: + out << "cannot cast here"; + break; + case SPELL_FAILED_EQUIPPED_ITEM_CLASS: + out << "requires item"; + break; + case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND: + case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND: + out << "requires weapon"; + break; + case SPELL_FAILED_PREVENTED_BY_MECHANIC: + out << "interrupted"; + break; + default: + out << "cannot cast"; + } + int32 castTime = GetSpellCastTime(pSpellInfo); + if (castTime >= 2000) + { + ai->TellMasterNoFacing(out.str()); + } + return true; +} + + +bool TellSpellAction::Execute(Event event) +{ + string spell = event.getParam(); + uint32 spellId = AI_VALUE2(uint32, "spell id", spell); + if (!spellId) + { + return false; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); + if (!spellInfo) + { + return false; + } + + ostringstream out; out << chat->formatSpell(spellInfo); + ai->TellMaster(out); + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.h b/src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.h new file mode 100644 index 0000000000..1de906a838 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellCastFailedAction.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class TellSpellAction : public Action + { + public: + TellSpellAction(PlayerbotAI* ai) : Action(ai, "spell") {} + + virtual bool Execute(Event event); + }; + + class TellCastFailedAction : public Action + { + public: + TellCastFailedAction(PlayerbotAI* ai) : Action(ai, "tell cast failed") {} + + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp new file mode 100644 index 0000000000..fe67ff4f0f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp @@ -0,0 +1,18 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TellItemCountAction.h" +#include "../values/ItemCountValue.h" + +using namespace ai; + +bool TellItemCountAction::Execute(Event event) +{ + string text = event.getParam(); + list found = parseItems(text); + for (list::iterator i = found.begin(); i != found.end(); i++) + { + TellItem((*i)->GetProto(), (*i)->GetCount()); + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.h b/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.h new file mode 100644 index 0000000000..093b0e0464 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class TellItemCountAction : public InventoryAction { + public: + TellItemCountAction(PlayerbotAI* ai) : InventoryAction(ai, "c") {} + virtual bool Execute(Event event); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp new file mode 100644 index 0000000000..da5c325606 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp @@ -0,0 +1,65 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TellLosAction.h" + + +using namespace ai; + +bool TellLosAction::Execute(Event event) +{ + string param = event.getParam(); + + if (param.empty() || param == "targets") + { + list targets = *context->GetValue >("possible targets"); + ListUnits("--- Targets ---", targets); + } + + if (param.empty() || param == "npcs") + { + list npcs = *context->GetValue >("nearest npcs"); + ListUnits("--- NPCs ---", npcs); + } + + if (param.empty() || param == "corpses") + { + list corpses = *context->GetValue >("nearest corpses"); + ListUnits("--- Corpses ---", corpses); + } + + if (param.empty() || param == "gos" || param == "game objects") + { + list gos = *context->GetValue >("nearest game objects"); + ListGameObjects("--- Game objects ---", gos); + } + + return true; +} + +void TellLosAction::ListUnits(string title, list units) +{ + ai->TellMaster(title); + + for (list::iterator i = units.begin(); i != units.end(); i++) + { + Unit* unit = ai->GetUnit(*i); + if (unit) + { + ai->TellMaster(unit->GetName()); + } + } + +} +void TellLosAction::ListGameObjects(string title, list gos) +{ + ai->TellMaster(title); + + for (list::iterator i = gos.begin(); i != gos.end(); i++) + { + GameObject* go = ai->GetGameObject(*i); + if (go) + { + ai->TellMaster(chat->formatGameobject(go)); + } + } +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellLosAction.h b/src/modules/Bots/playerbot/strategy/actions/TellLosAction.h new file mode 100644 index 0000000000..15d83fbc01 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellLosAction.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class TellLosAction : public Action { + public: + TellLosAction(PlayerbotAI* ai) : Action(ai, "los") {} + virtual bool Execute(Event event); + + private: + void ListUnits(string title, list units); + void ListGameObjects(string title, list gos); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h b/src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h new file mode 100644 index 0000000000..4174708d57 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h @@ -0,0 +1,38 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class TellMasterAction : public Action { + public: + TellMasterAction(PlayerbotAI* ai, string text) : Action(ai, "tell master"), text(text) {} + + virtual bool Execute(Event event) + { + ai->TellMaster(text); + return true; + } + + private: + string text; + }; + + class OutOfReactRangeAction : public MovementAction { + public: + OutOfReactRangeAction(PlayerbotAI* ai) : MovementAction(ai, "tell out of react range") {} + + virtual bool Execute(Event event) + { + bool canFollow = Follow(AI_VALUE(Unit*, "master target")); + if (!canFollow) + { + ai->SetNextCheckDelay(5000); + return false; + } + + ai->TellMaster("Wait for me!"); + return true; + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellReputationAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellReputationAction.cpp new file mode 100644 index 0000000000..56cacbb9f9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellReputationAction.cpp @@ -0,0 +1,79 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TellReputationAction.h" + + +using namespace ai; + +bool TellReputationAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + ObjectGuid selection = master->GetSelectionGuid(); + if (selection.IsEmpty()) + { + return false; + } + + Unit* unit = master->GetMap()->GetUnit(selection); + if (!unit) + { + return false; + } + + const FactionTemplateEntry *factionTemplate = unit->getFactionTemplateEntry(); + uint32 faction = factionTemplate->faction; + const FactionEntry* entry = sFactionStore.LookupEntry(faction); + int32 reputation = bot->GetReputationMgr().GetReputation(faction); + + ostringstream out; + out << entry->name[0] << ": "; + out << "|cff"; + ReputationRank rank = bot->GetReputationMgr().GetRank(entry); + switch (rank) { + case REP_HATED: + out << "cc2222hated"; + break; + case REP_HOSTILE: + out << "ff0000hostile"; + break; + case REP_UNFRIENDLY: + out << "ee6622unfriendly"; + break; + case REP_NEUTRAL: + out << "ffff00neutral"; + break; + case REP_FRIENDLY: + out << "00ff00friendly"; + break; + case REP_HONORED: + out << "00ff88honored"; + break; + case REP_REVERED: + out << "00ffccrevered"; + break; + case REP_EXALTED: + out << "00ffffexalted"; + break; + default: + out << "808080unknown"; + break; + } + + out << "|cffffffff"; + + int32 base = ReputationMgr::Reputation_Cap + 1; + for (int i = MAX_REPUTATION_RANK - 1; i >= rank; --i) + { + base -= ReputationMgr::PointsInRank[i]; + } + + out << " (" << (reputation - base) << "/" << ReputationMgr::PointsInRank[rank] << ")"; + ai->TellMaster(out); + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellReputationAction.h b/src/modules/Bots/playerbot/strategy/actions/TellReputationAction.h new file mode 100644 index 0000000000..449e67f2d0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellReputationAction.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class TellReputationAction : public Action { + public: + TellReputationAction(PlayerbotAI* ai) : Action(ai, "reputation") {} + virtual bool Execute(Event event); + + private: + + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp new file mode 100644 index 0000000000..33daaf3dad --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp @@ -0,0 +1,58 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TellTargetAction.h" +#include "ThreatManager.h" + + +using namespace ai; + +bool TellTargetAction::Execute(Event event) +{ + Unit* target = context->GetValue("current target")->Get(); + if (target) + { + ostringstream out; + out << "Attacking " << target->GetName(); + ai->TellMaster(out); + + context->GetValue("old target")->Set(target); + } + return true; +} + +bool TellAttackersAction::Execute(Event event) +{ + ai->TellMaster("--- Attackers ---"); + + list attackers = context->GetValue >("attackers")->Get(); + for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + { + Unit* unit = ai->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + + ai->TellMaster(unit->GetName()); + } + + ai->TellMaster("--- Threat ---"); + HostileReference *ref = bot->GetHostileRefManager().getFirst(); + if (!ref) + { + return true; + } + + while( ref ) + { + ThreatManager *threatManager = ref->getSource(); + Unit *unit = threatManager->getOwner(); + float threat = ref->getThreat(); + + ostringstream out; out << unit->GetName() << " (" << threat << ")"; + ai->TellMaster(out); + + ref = ref->next(); + } + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.h b/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.h new file mode 100644 index 0000000000..799510096e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class TellTargetAction : public Action + { + public: + TellTargetAction(PlayerbotAI* ai) : Action(ai, "tell target") {} + virtual bool Execute(Event event); + }; + + class TellAttackersAction : public Action + { + public: + TellAttackersAction(PlayerbotAI* ai) : Action(ai, "tell attackers") {} + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp new file mode 100644 index 0000000000..17f3ca9045 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp @@ -0,0 +1,95 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TradeAction.h" +#include "../ItemVisitors.h" +#include "../values/ItemCountValue.h" + +using namespace ai; + +bool TradeAction::Execute(Event event) +{ + string text = event.getParam(); + uint32 copper = chat->parseMoney(text); + if (copper > 0) + { + WorldPacket* const packet = new WorldPacket(CMSG_SET_TRADE_GOLD, 4); + *packet << copper; + bot->GetSession()->QueuePacket(packet); + } + + int8 slot = -1; + + list found = parseItems(text); + if (found.empty()) + { + return false; + } + + for (list::iterator i = found.begin(); i != found.end(); i++) + { + TradeItem(**i, slot); + } + + return true; +} + +bool TradeAction::TradeItem(const Item& item, int8 slot) +{ + if (!bot->GetTrader() || item.IsInTrade()) + { + return false; + } + + if (!item.CanBeTraded() && slot != TRADE_SLOT_NONTRADED) + { + slot = TRADE_SLOT_NONTRADED; + } + + int8 tradeSlot = -1; + Item* itemPtr = const_cast(&item); + + TradeData* pTrade = bot->GetTradeData(); + if ((slot >= 0 && slot < TRADE_SLOT_COUNT) && pTrade->GetItem(TradeSlots(slot)) == NULL) + { + tradeSlot = slot; + } + + if (slot == TRADE_SLOT_NONTRADED) + { + pTrade->SetItem(TRADE_SLOT_NONTRADED, itemPtr); + } + else + { + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT && tradeSlot == -1; i++) + { + if (pTrade->GetItem(TradeSlots(i)) == itemPtr) + { + tradeSlot = i; + + WorldPacket* const packet = new WorldPacket(CMSG_CLEAR_TRADE_ITEM, 1); + *packet << (uint8) tradeSlot; + bot->GetSession()->QueuePacket(packet); + pTrade->SetItem(TradeSlots(i), NULL); + return true; + } + } + + for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT && tradeSlot == -1; i++) + { + if (pTrade->GetItem(TradeSlots(i)) == NULL) + { + pTrade->SetItem(TradeSlots(i), itemPtr); + tradeSlot = i; + } + } + } + + if (tradeSlot == -1) return false; + + WorldPacket* const packet = new WorldPacket(CMSG_SET_TRADE_ITEM, 3); + *packet << (uint8) tradeSlot << (uint8) item.GetBagSlot() + << (uint8) item.GetSlot(); + bot->GetSession()->QueuePacket(packet); + return true; +} + diff --git a/src/modules/Bots/playerbot/strategy/actions/TradeAction.h b/src/modules/Bots/playerbot/strategy/actions/TradeAction.h new file mode 100644 index 0000000000..050a583deb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TradeAction.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class TradeAction : public InventoryAction { + public: + TradeAction(PlayerbotAI* ai) : InventoryAction(ai, "trade") {} + virtual bool Execute(Event event); + + private: + bool TradeItem(const Item& item, int8 slot); + + static map slots; + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.cpp new file mode 100644 index 0000000000..b702902bcd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.cpp @@ -0,0 +1,224 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TradeStatusAction.h" + +#include "../ItemVisitors.h" +#include "../../PlayerbotAIConfig.h" +#include "../../../ahbot/AhBot.h" +#include "../../RandomPlayerbotMgr.h" +#include "../values/ItemUsageValue.h" + +using namespace ai; + + + +bool TradeStatusAction::Execute(Event event) +{ + Player* trader = bot->GetTrader(); + Player* master = GetMaster(); + if (!trader) + { + return false; + } + + if (trader != master) + { + bot->Whisper("I'm kind of busy now", LANG_UNIVERSAL, trader->GetObjectGuid()); + } + + if (trader != master || !ai->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, true, master)) + { + WorldPacket p; + uint32 status = 0; + p << status; + bot->GetSession()->HandleCancelTradeOpcode(p); + return false; + } + + WorldPacket p(event.getPacket()); + p.rpos(0); + uint32 status; + p >> status; + + if (status == TRADE_STATUS_TRADE_ACCEPT) + { + WorldPacket p; + uint32 status = 0; + p << status; + + if (CheckTrade()) + { + int32 botMoney = CalculateCost(bot->GetTradeData(), true); + + bot->GetSession()->HandleAcceptTradeOpcode(p); + if (bot->GetTradeData()) + { + return false; + } + + if (sRandomPlayerbotMgr.IsRandomBot(bot)) + { + int32 lootAmount = sRandomPlayerbotMgr.GetLootAmount(bot); + sRandomPlayerbotMgr.SetLootAmount(bot, max(0, lootAmount - botMoney * 10)); + } + return true; + } + } + else if (status == TRADE_STATUS_BEGIN_TRADE) + { + if (!bot->IsInFront(trader, sPlayerbotAIConfig.sightDistance, M_PI / 2)) + { + bot->SetFacingToObject(trader); + } + BeginTrade(); + return true; + } + + return false; +} + + +void TradeStatusAction::BeginTrade() +{ + WorldPacket p; + bot->GetSession()->HandleBeginTradeOpcode(p); + + ListItemsVisitor visitor; + IterateItems(&visitor); + + ai->TellMaster("=== Trade ==="); + TellItems(visitor.items); + + if (sRandomPlayerbotMgr.IsRandomBot(bot)) + { + uint32 discount = sRandomPlayerbotMgr.GetTradeDiscount(bot); + if (discount) + { + ostringstream out; out << "Discount up to: " << chat->formatMoney(discount); + ai->TellMaster(out); + } + } +} + +bool TradeStatusAction::CheckTrade() +{ + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) + { + return true; + } + + Player* master = GetMaster(); + if (!bot->GetTradeData() || !master->GetTradeData()) + { + return false; + } + + for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot) + { + Item* item = bot->GetTradeData()->GetItem((TradeSlots)slot); + if (item && !auctionbot.GetSellPrice(item->GetProto())) + { + ostringstream out; + out << chat->formatItem(item->GetProto()) << " - This is not for sale"; + ai->TellMaster(out); + return false; + } + + item = master->GetTradeData()->GetItem((TradeSlots)slot); + if (item) + { + ostringstream out; out << item->GetProto()->ItemId; + ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", out.str()); + if (!auctionbot.GetBuyPrice(item->GetProto()) || usage == ITEM_USAGE_NONE) + { + ostringstream out; + out << chat->formatItem(item->GetProto()) << " - I don't need this"; + ai->TellMaster(out); + return false; + } + } + } + + int32 botItemsMoney = CalculateCost(bot->GetTradeData(), true); + int32 botMoney = bot->GetTradeData()->GetMoney() + botItemsMoney; + int32 playerItemsMoney = CalculateCost(master->GetTradeData(), false); + int32 playerMoney = master->GetTradeData()->GetMoney() + playerItemsMoney; + + if (!botMoney && !playerMoney) + { + return true; + } + + if (!botItemsMoney && !playerItemsMoney) + { + ai->TellMaster("There are no items to trade"); + return false; + } + + int32 discount = min(botItemsMoney, (int32)sRandomPlayerbotMgr.GetTradeDiscount(bot)); + botMoney = max(0, botMoney - discount); + + if (playerMoney >= botMoney) + { + switch (urand(0, 4)) { + case 0: + ai->TellMaster("A pleasure doing business with you"); + break; + case 1: + ai->TellMaster("Fair trade"); + break; + case 2: + ai->TellMaster("Thanks"); + break; + case 3: + ai->TellMaster("Off with you"); + break; + } + return true; + } + + ostringstream out; + out << "I want " << chat->formatMoney(botMoney - playerMoney) << " for this"; + ai->TellMaster(out); + return false; +} + +int32 TradeStatusAction::CalculateCost(TradeData* data, bool sell) +{ + if (!data) + { + return 0; + } + + uint32 sum = 0; + for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot) + { + Item* item = data->GetItem((TradeSlots)slot); + if (!item) + { + continue; + } + + ItemPrototype const* proto = item->GetProto(); + if (!proto) + { + continue; + } + + if (proto->Quality < ITEM_QUALITY_NORMAL) + { + return 0; + } + + if (sell) + { + sum += item->GetCount() * auctionbot.GetSellPrice(proto) * sRandomPlayerbotMgr.GetSellMultiplier(bot); + } + else + { + sum += item->GetCount() * auctionbot.GetBuyPrice(proto) * sRandomPlayerbotMgr.GetBuyMultiplier(bot); + } + } + + return sum; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.h b/src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.h new file mode 100644 index 0000000000..7500a64b83 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TradeStatusAction.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" +#include "QueryItemUsageAction.h" + +namespace ai +{ + class TradeStatusAction : public QueryItemUsageAction + { + public: + TradeStatusAction(PlayerbotAI* ai) : QueryItemUsageAction(ai, "accept trade") {} + virtual bool Execute(Event event); + + private: + void BeginTrade(); + bool CheckTrade(); + int32 CalculateCost(TradeData* data, bool sell); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TrainerAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TrainerAction.cpp new file mode 100644 index 0000000000..cbfd9806e1 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TrainerAction.cpp @@ -0,0 +1,140 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TrainerAction.h" + +using namespace ai; + +void TrainerAction::Learn(uint32 cost, TrainerSpell const* tSpell, ostringstream& msg) +{ + if (bot->GetMoney() < cost) + { + return; + } + + bot->ModifyMoney(-int32(cost)); + bot->CastSpell(bot, tSpell->spell, true); + + msg << " - learned"; +} + +void TrainerAction::List(Creature* creature, TrainerSpellAction action, SpellIds& spells) +{ + TellHeader(creature); + + TrainerSpellData const* cSpells = creature->GetTrainerSpells(); + TrainerSpellData const* tSpells = creature->GetTrainerTemplateSpells(); + float fDiscountMod = bot->GetReputationPriceDiscount(creature); + uint32 totalCost = 0; + + TrainerSpellData const* trainer_spells = cSpells; + if (!trainer_spells) + { + trainer_spells = tSpells; + } + + for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) + { + TrainerSpell const* tSpell = &itr->second; + + if (!tSpell) + { + continue; + } + + uint32 reqLevel = 0; + + reqLevel = tSpell->isProvidedReqLevel ? tSpell->reqLevel : std::max(reqLevel, tSpell->reqLevel); + TrainerSpellState state = bot->GetTrainerSpellState(tSpell, reqLevel); + if (state != TRAINER_SPELL_GREEN) + { + continue; + } + + uint32 spellId = tSpell->spell; + const SpellEntry *const pSpellInfo = sSpellStore.LookupEntry(spellId); + if (!pSpellInfo) + { + continue; + } + + uint32 cost = uint32(floor(tSpell->spellCost * fDiscountMod)); + totalCost += cost; + + ostringstream out; + out << chat->formatSpell(pSpellInfo) << chat->formatMoney(cost); + + if (action && (spells.empty() || spells.find(tSpell->spell) != spells.end())) + { + (this->*action)(cost, tSpell, out); + } + + ai->TellMaster(out); + } + + TellFooter(totalCost); +} + + +bool TrainerAction::Execute(Event event) +{ + string text = event.getParam(); + + Player* master = GetMaster(); + if (!master) + { + return false; + } + + Creature *creature = ai->GetCreature(master->GetSelectionGuid()); + if (!creature) + { + return false; + } + + if (!creature->IsTrainerOf(bot, false)) + { + return false; + } + + // check present spell in trainer spell list + TrainerSpellData const* cSpells = creature->GetTrainerSpells(); + TrainerSpellData const* tSpells = creature->GetTrainerTemplateSpells(); + if (!cSpells && !tSpells) + { + ai->TellMaster("No spells can be learned from this trainer"); + return false; + } + + uint32 spell = chat->parseSpell(text); + SpellIds spells; + if (spell) + { + spells.insert(spell); + } + + if (text == "learn") + { + List(creature, &TrainerAction::Learn, spells); + } + else + { + List(creature, NULL, spells); + } + + return true; +} + +void TrainerAction::TellHeader(Creature* creature) +{ + ostringstream out; out << "--- can learn from " << creature->GetName() << " ---"; + ai->TellMaster(out); +} + +void TrainerAction::TellFooter(uint32 totalCost) +{ + if (totalCost) + { + ostringstream out; out << "Total cost: " << chat->formatMoney(totalCost); + ai->TellMaster(out); + } +} diff --git a/src/modules/Bots/playerbot/strategy/actions/TrainerAction.h b/src/modules/Bots/playerbot/strategy/actions/TrainerAction.h new file mode 100644 index 0000000000..7522cce694 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/TrainerAction.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class TrainerAction : public Action { + public: + TrainerAction(PlayerbotAI* ai) : Action(ai, "trainer") {} + + public: + virtual bool Execute(Event event); + + private: + typedef void (TrainerAction::*TrainerSpellAction)(uint32, TrainerSpell const*, ostringstream& msg); + void List(Creature* creature, TrainerSpellAction action, SpellIds& spells); + void Learn(uint32 cost, TrainerSpell const* tSpell, ostringstream& msg); + void TellHeader(Creature* creature); + void TellFooter(uint32 totalCost); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp b/src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp new file mode 100644 index 0000000000..826caef67e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp @@ -0,0 +1,45 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "UnequipAction.h" + +#include "../values/ItemCountValue.h" + +using namespace ai; + +bool UnequipAction::Execute(Event event) +{ + string text = event.getParam(); + + ItemIds ids = chat->parseItems(text); + for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + { + FindItemByIdVisitor visitor(*i); + UnequipItem(&visitor); + } + + return true; +} + + +void UnequipAction::UnequipItem(FindItemVisitor* visitor) +{ + IterateItems(visitor, ITERATE_ALL_ITEMS); + list items = visitor->GetResult(); + if (!items.empty()) UnequipItem(**items.begin()); +} + +void UnequipAction::UnequipItem(Item& item) +{ + uint8 bagIndex = item.GetBagSlot(); + uint8 slot = item.GetSlot(); + uint8 dstBag = NULL_BAG; + + + WorldPacket* const packet = new WorldPacket(CMSG_AUTOSTORE_BAG_ITEM, 3); + *packet << bagIndex << slot << dstBag; + bot->GetSession()->QueuePacket(packet); + + ostringstream out; out << chat->formatItem(item.GetProto()) << " unequipped"; + ai->TellMaster(out); +} + diff --git a/src/modules/Bots/playerbot/strategy/actions/UnequipAction.h b/src/modules/Bots/playerbot/strategy/actions/UnequipAction.h new file mode 100644 index 0000000000..fdf7ebb1cb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/UnequipAction.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class UnequipAction : public InventoryAction { + public: + UnequipAction(PlayerbotAI* ai) : InventoryAction(ai, "unequip") {} + virtual bool Execute(Event event); + + private: + void UnequipItem(Item& item); + void UnequipItem(FindItemVisitor* visitor); + }; + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/UseItemAction.cpp b/src/modules/Bots/playerbot/strategy/actions/UseItemAction.cpp new file mode 100644 index 0000000000..7f9607db94 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/UseItemAction.cpp @@ -0,0 +1,327 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "UseItemAction.h" +#include "DBCStore.h" + +using namespace ai; + +bool UseItemAction::Execute(Event event) +{ + string name = event.getParam(); + if (name.empty()) + { + name = getName(); + } + + list items = AI_VALUE2(list, "inventory items", name); + list gos = chat->parseGameobjects(name); + + if (gos.empty()) + { + if (items.size() > 1) + { + list::iterator i = items.begin(); + Item* itemTarget = *i++; + Item* item = *i; + return UseItemOnItem(item, itemTarget); + } + else if (!items.empty()) + { + return UseItemAuto(*items.begin()); + } + } + else + { + if (items.empty()) + { + return UseGameObject(*gos.begin()); + } + else + { + return UseItemOnGameObject(*items.begin(), *gos.begin()); + } + } + + ai->TellMaster("No items (or game objects) available"); + return false; +} + +bool UseItemAction::UseGameObject(ObjectGuid guid) +{ + GameObject* go = ai->GetGameObject(guid); + if (!go || !go->isSpawned()) + { + return false; + } + + go->Use(bot); + ostringstream out; out << "Using " << chat->formatGameobject(go); + ai->TellMasterNoFacing(out.str()); + return true; +} + +bool UseItemAction::UseItemAuto(Item* item) +{ + return UseItem(item, ObjectGuid(), NULL); +} + +bool UseItemAction::UseItemOnGameObject(Item* item, ObjectGuid go) +{ + return UseItem(item, go, NULL); +} + +bool UseItemAction::UseItemOnItem(Item* item, Item* itemTarget) +{ + return UseItem(item, ObjectGuid(), itemTarget); +} + +bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget) +{ + if (bot->CanUseItem(item) != EQUIP_ERR_OK) + { + return false; + } + + if (bot->IsNonMeleeSpellCasted(true)) + { + return false; + } + + if (bot->IsInCombat()) + { + for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(item->GetProto()->Spells[i].SpellId); + if (spellInfo && IsNonCombatSpell(spellInfo)) + { + return false; + } + } + } + + uint8 bagIndex = item->GetBagSlot(); + uint8 slot = item->GetSlot(); + uint8 cast_count = 1; + uint64 item_guid = item->GetObjectGuid().GetRawValue(); + uint32 glyphIndex = 0; + uint8 unk_flags = 0; + + WorldPacket* const packet = new WorldPacket(CMSG_USE_ITEM, 1 + 1 + 1 + 4 + 8 + 4 + 1 + 8 + 1); + *packet << bagIndex << slot << cast_count << uint32(0) << item_guid + << glyphIndex << unk_flags; + + bool targetSelected = false; + ostringstream out; out << "Using " << chat->formatItem(item->GetProto()); + if (item->GetProto()->Stackable) + { + uint32 count = item->GetCount(); + if (count > 1) + { + out << " (" << count << " available) "; + } + else + { + out << " (the last one!)"; + } + } + + if (goGuid) + { + GameObject* go = ai->GetGameObject(goGuid); + if (go && go->isSpawned()) + { + uint32 targetFlag = TARGET_FLAG_OBJECT; + *packet << targetFlag << goGuid.WriteAsPacked(); + out << " on " << chat->formatGameobject(go); + targetSelected = true; + } + } + + Player* master = GetMaster(); + if (!targetSelected && item->GetProto()->Class != ITEM_CLASS_CONSUMABLE && master) + { + ObjectGuid masterSelection = master->GetSelectionGuid(); + if (masterSelection) + { + Unit* unit = ai->GetUnit(masterSelection); + if (unit) + { + uint32 targetFlag = TARGET_FLAG_UNIT; + *packet << targetFlag << masterSelection.WriteAsPacked(); + out << " on " << unit->GetName(); + targetSelected = true; + } + } + } + + if(uint32 questid = item->GetProto()->StartQuest) + { + Quest const* qInfo = sObjectMgr.GetQuestTemplate(questid); + if (qInfo) + { + WorldPacket* const packet = new WorldPacket(CMSG_QUESTGIVER_ACCEPT_QUEST, 8+4+4); + *packet << item_guid; + *packet << questid; + *packet << uint32(0); + bot->GetSession()->QueuePacket(packet); // queue the packet to get around race condition + ostringstream out; out << "Got quest " << chat->formatQuest(qInfo); + ai->TellMasterNoFacing(out.str()); + return true; + } + } + + MotionMaster &mm = *bot->GetMotionMaster(); + mm.Clear(); + bot->clearUnitState( UNIT_STAT_CHASE ); + bot->clearUnitState( UNIT_STAT_FOLLOW ); + + if (bot->isMoving()) + { + return false; + } + + for (int i=0; iGetProto()->Spells[i].SpellId; + if (!spellId) + { + continue; + } + + if (!ai->CanCastSpell(spellId, bot, false)) + { + continue; + } + + const SpellEntry* const pSpellInfo = sSpellStore.LookupEntry(spellId); + if (pSpellInfo->Targets & TARGET_FLAG_ITEM) + { + Item* itemForSpell = AI_VALUE2(Item*, "item for spell", spellId); + if (!itemForSpell) + { + continue; + } + + if (itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + { + continue; + } + + if (bot->GetTrader()) + { + if (selfOnly) + { + return false; + } + + *packet << TARGET_FLAG_TRADE_ITEM << (uint8)1 << (uint64)TRADE_SLOT_NONTRADED; + targetSelected = true; + out << " on traded item"; + ai->WaitForSpellCast(spellId); + } + else + { + *packet << TARGET_FLAG_ITEM; + *packet << itemForSpell->GetPackGUID(); + targetSelected = true; + out << " on "<< chat->formatItem(itemForSpell->GetProto()); + ai->WaitForSpellCast(spellId); + } + } + else + { + *packet << TARGET_FLAG_SELF; + targetSelected = true; + out << " on self"; + } + break; + } + + if (!targetSelected) + { + return false; + } + + if (item->GetProto()->Class == ITEM_CLASS_CONSUMABLE && item->GetProto()->SubClass == ITEM_SUBCLASS_FOOD) + { + if (bot->IsInCombat()) + { + return false; + } + + ai->InterruptSpell(); + ai->SetNextCheckDelay(30000); + } + + ai->TellMasterNoFacing(out.str()); + bot->GetSession()->QueuePacket(packet); + return true; +} + +/*bool UseItemAction::SocketItem(Item* item, Item* gem, bool replace) +{ + WorldPacket* const packet = new WorldPacket(CMSG_SOCKET_GEMS); + *packet << item->GetObjectGuid(); + + bool fits = false; + for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot) + { + uint8 SocketColor = item->GetProto()->Socket[enchant_slot-SOCK_ENCHANTMENT_SLOT].Color; + GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gem->GetProto()->GemProperties); + if (gemProperty && (gemProperty->color & SocketColor)) + { + if (fits) + { + *packet << ObjectGuid(); + continue; + } + + uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(enchant_slot)); + if (!enchant_id) + { + *packet << gem->GetObjectGuid(); + fits = true; + continue; + } + + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if (!enchantEntry || !enchantEntry->GemID) + { + *packet << gem->GetObjectGuid(); + fits = true; + continue; + } + + if (replace && enchantEntry->GemID != gem->GetProto()->ItemId) + { + *packet << gem->GetObjectGuid(); + fits = true; + continue; + } + + } + + *packet << ObjectGuid(); + } + + if (fits) + { + ostringstream out; out << "Socketing " << chat->formatItem(item->GetProto()); + out << " with "<< chat->formatItem(gem->GetProto()); + ai->TellMasterNoFacing(out.str()); + + bot->GetSession()->QueuePacket(packet); + } + return fits; +}*/ + + +bool UseItemAction::isPossible() +{ + return getName() == "use" || AI_VALUE2(uint8, "item count", getName()) > 0; +} + +bool UseSpellItemAction::isUseful() +{ + return AI_VALUE2(bool, "spell cast useful", getName()); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/UseItemAction.h b/src/modules/Bots/playerbot/strategy/actions/UseItemAction.h new file mode 100644 index 0000000000..5afb80b316 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/UseItemAction.h @@ -0,0 +1,47 @@ +#pragma once + +#include "../Action.h" + +namespace ai +{ + class UseItemAction : public Action { + public: + UseItemAction(PlayerbotAI* ai, string name = "use", bool selfOnly = false) : Action(ai, name), selfOnly(selfOnly) {} + + public: + virtual bool Execute(Event event); + virtual bool isPossible(); + + private: + bool UseItemAuto(Item* item); + bool UseItemOnGameObject(Item* item, ObjectGuid go); + bool UseItemOnItem(Item* item, Item* itemTarget); + bool UseItem(Item* item, ObjectGuid go, Item* itemTarget); + bool UseGameObject(ObjectGuid guid); + bool SocketItem(Item* item, Item* gem, bool replace = false); + + private: + bool selfOnly; + }; + + class UseSpellItemAction : public UseItemAction { + public: + UseSpellItemAction(PlayerbotAI* ai, string name, bool selfOnly = false) : UseItemAction(ai, name, selfOnly) {} + + public: + virtual bool isUseful(); + }; + + class UseHealingPotion : public UseItemAction { + public: + UseHealingPotion(PlayerbotAI* ai) : UseItemAction(ai, "healing potion") {} + virtual bool isUseful() { return AI_VALUE2(bool, "combat", "self target"); } + }; + + class UseManaPotion : public UseItemAction + { + public: + UseManaPotion(PlayerbotAI* ai) : UseItemAction(ai, "mana potion") {} + virtual bool isUseful() { return AI_VALUE2(bool, "combat", "self target"); } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp new file mode 100644 index 0000000000..84f2bd756c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp @@ -0,0 +1,145 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "UseMeetingStoneAction.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "../../PlayerbotAIConfig.h" + +namespace MaNGOS +{ + class GameObjectByGuidInRangeCheck + { + public: + GameObjectByGuidInRangeCheck(WorldObject const* obj, ObjectGuid guid, float range) : i_obj(obj), i_range(range), i_guid(guid) {} + WorldObject const& GetFocusObject() const { return *i_obj; } + bool operator()(GameObject* u) + { + if (u && i_obj->IsWithinDistInMap(u, i_range) && u->isSpawned() && u->GetGOInfo() && u->GetObjectGuid() == i_guid) + { + return true; + } + + return false; + } + private: + WorldObject const* i_obj; + float i_range; + ObjectGuid i_guid; + }; +}; + +bool UseMeetingStoneAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + WorldPacket p(event.getPacket()); + p.rpos(0); + ObjectGuid guid; + p >> guid; + + if (master->GetSelectionGuid() && master->GetSelectionGuid() != bot->GetObjectGuid()) + { + return false; + } + + if (!master->GetSelectionGuid() && master->GetGroup() != bot->GetGroup()) + { + return false; + } + + if (master->IsBeingTeleported()) + { + return false; + } + + if (bot->IsInCombat()) + { + ai->TellMasterNoFacing("I am in combat"); + return false; + } + + list targets; + + MaNGOS::GameObjectByGuidInRangeCheck u_check(master, guid, sPlayerbotAIConfig.sightDistance); + MaNGOS::GameObjectListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(master, searcher, sPlayerbotAIConfig.sightDistance); + + GameObject* gameObject = NULL; + for(list::iterator i = targets.begin(); i != targets.end(); i++) + { + GameObject* go = *i; + if (go && go->isSpawned()) + { + gameObject = go; + break; + } + } + + if (!gameObject) + { + return false; + } + + const GameObjectInfo* goInfo = gameObject->GetGOInfo(); + if (!goInfo || goInfo->type != GAMEOBJECT_TYPE_SUMMONING_RITUAL) + { + return false; + } + + return Teleport(); +} + + +bool SummonAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + if (master->GetSession()->GetSecurity() < SEC_GAMEMASTER) + { + ai->TellMasterNoFacing("You cannot summon me"); + return false; + } + + return Teleport(); +} + +bool SummonAction::Teleport() +{ + Player* master = GetMaster(); + if (!master->IsBeingTeleported()) + { + float followAngle = GetFollowAngle(); + for (float angle = followAngle - M_PI; angle <= followAngle + M_PI; angle += M_PI / 4) + { + uint32 mapId = master->GetMapId(); + float x = master->GetPositionX() + cos(angle) * sPlayerbotAIConfig.followDistance; + float y = master->GetPositionY()+ sin(angle) * sPlayerbotAIConfig.followDistance; + float z = master->GetPositionZ(); + if (master->IsWithinLOS(x, y, z)) + { + bot->GetMotionMaster()->Clear(); + bot->TeleportTo(mapId, x, y, z, 0); + return true; + } + } + } + + PlayerbotChatHandler ch(master); + if (!ch.teleport(*bot)) + { + ai->TellMasterNoFacing("You cannot summon me"); + return false; + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h new file mode 100644 index 0000000000..e787d24d4d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h @@ -0,0 +1,26 @@ +#pragma once + +#include "../Action.h" +#include "MovementActions.h" + +namespace ai +{ + class SummonAction : public MovementAction + { + public: + SummonAction(PlayerbotAI* ai, string name = "summon") : MovementAction(ai, name) {} + + virtual bool Execute(Event event); + + protected: + bool Teleport(); + }; + + class UseMeetingStoneAction : public SummonAction + { + public: + UseMeetingStoneAction(PlayerbotAI* ai) : SummonAction(ai, "use meeting stone") {} + + virtual bool Execute(Event event); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp b/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp new file mode 100644 index 0000000000..25b476218d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp @@ -0,0 +1,173 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WhoAction.h" +#include "../../AiFactory.h" +#include "../ItemVisitors.h" +#include "../../../ahbot/AhBot.h" +#include "../../RandomPlayerbotMgr.h" + +using namespace ai; + +map WhoAction::skills; + +#ifndef WIN32 +inline int strcmpi(const char* s1, const char* s2) +{ + for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2); + { + return *s1 - *s2; + } +} +#endif + +bool WhoAction::Execute(Event event) +{ + Player* owner = event.getOwner(); + if (!owner) + { + return false; + } + + string tell = ""; + string text = event.getParam(); + if (!text.empty()) + { + if (!sRandomPlayerbotMgr.IsRandomBot(bot)) + { + return false; + } + + tell = QuerySkill(text); + if (tell.empty()) + { + tell = QueryTrade(text); + } + } + else + { + tell = QuerySpec(text); + } + + if (tell.empty()) + { + return false; + } + + // ignore random bot chat filter + bot->Whisper(tell, LANG_UNIVERSAL, owner->GetObjectGuid()); + return true; +} + + +string WhoAction::QueryTrade(string text) +{ + ostringstream out; + + list items = InventoryAction::parseItems(text); + for (list::iterator i = items.begin(); i != items.end(); ++i) + { + Item* sell = *i; + int32 sellPrice = auctionbot.GetSellPrice(sell->GetProto()) * sRandomPlayerbotMgr.GetSellMultiplier(bot) * sell->GetCount(); + if (!sellPrice) + { + continue; + } + + out << "Selling " << chat->formatItem(sell->GetProto(), sell->GetCount()) << " for " << chat->formatMoney(sellPrice); + return out.str(); + } + + return ""; +} + +string WhoAction::QuerySkill(string text) +{ + ostringstream out; + InitSkills(); + + for (map::iterator i = skills.begin(); i != skills.end(); ++i) + { + string name = i->second; + uint16 skill = i->first; + if (!strcmpi(text.c_str(), name.c_str()) && bot->HasSkill(skill)) + { + string skillName = i->second; + uint32 spellId = AI_VALUE2(uint32, "spell id", skillName); + uint16 value = bot->GetSkillValue(skill); + uint16 maxSkill = bot->GetMaxSkillValue(skill); + ObjectGuid guid = bot->GetObjectGuid(); + string data = "0"; + out << "|cFFFFFF00|Htrade:" << spellId << ":" << value << ":" << maxSkill << ":" + << std::hex << std::uppercase << guid.GetRawValue() + << std::nouppercase << std::dec << ":" << data + << "|h[" << skills[skill] << "]|h|r" + << " |h|cff00ff00" << value << "|h|cffffffff/" + << "|h|cff00ff00" << maxSkill << "|h|cffffffff "; + } + } + + return out.str(); +} + +string WhoAction::QuerySpec(string text) +{ + ostringstream out; + + int spec = AiFactory::GetPlayerSpecTab(bot); + out << "|h|cffffffff" << chat->formatClass(bot, spec); + out << " (|h|cff00ff00" << bot->getLevel() << "|h|cffffffff lvl), "; + + ItemCountByQuality visitor; + IterateItems(&visitor, ITERATE_ITEMS_IN_EQUIP); + + bool needSlash = false; + if (visitor.count[ITEM_QUALITY_EPIC]) + { + out << "|h|cffff00ff" << visitor.count[ITEM_QUALITY_EPIC] << "|h|cffffffff"; + needSlash = true; + } + + if (visitor.count[ITEM_QUALITY_RARE]) + { + if (needSlash) out << "/"; + { + out << "|h|cff8080ff" << visitor.count[ITEM_QUALITY_RARE] << "|h|cffffffff"; + } + needSlash = true; + } + + if (visitor.count[ITEM_QUALITY_UNCOMMON]) + { + if (needSlash) out << "/"; + { + out << "|h|cff00ff00" << visitor.count[ITEM_QUALITY_UNCOMMON] << "|h|cffffffff"; + } + needSlash = true; + } + + out << ")"; + + return out.str(); +} + + +void WhoAction::InitSkills() +{ + if (!skills.empty()) + { + return; + } + + skills[SKILL_ALCHEMY] = "Alchemy"; + skills[SKILL_ENCHANTING] = "Enchanting"; + skills[SKILL_SKINNING] = "Skinning"; + skills[SKILL_TAILORING] = "Tailoring"; + skills[SKILL_LEATHERWORKING] = "Leatherworking"; + skills[SKILL_ENGINEERING] = "Engineering"; + skills[SKILL_HERBALISM] = "Herbalism"; + skills[SKILL_MINING] = "Mining"; + skills[SKILL_BLACKSMITHING] = "Blacksmithing"; + skills[SKILL_COOKING] = "Cooking"; + skills[SKILL_FIRST_AID] = "First Aid"; + skills[SKILL_FISHING] = "Fishing"; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/WhoAction.h b/src/modules/Bots/playerbot/strategy/actions/WhoAction.h new file mode 100644 index 0000000000..92ed834ace --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/WhoAction.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../Action.h" +#include "InventoryAction.h" + +namespace ai +{ + class WhoAction : public InventoryAction { + public: + WhoAction(PlayerbotAI* ai) : InventoryAction(ai, "who") {} + + public: + virtual bool Execute(Event event); + static map skills; + + private: + void InitSkills(); + string QueryTrade(string text); + string QuerySkill(string text); + string QuerySpec(string text); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/actions/WorldPacketActionContext.h b/src/modules/Bots/playerbot/strategy/actions/WorldPacketActionContext.h new file mode 100644 index 0000000000..5d0d265b6a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/WorldPacketActionContext.h @@ -0,0 +1,98 @@ +#pragma once + +#include "AcceptInvitationAction.h" +#include "PassLeadershipToMasterAction.h" +#include "TellMasterAction.h" +#include "TalkToQuestGiverAction.h" +#include "AcceptQuestAction.h" +#include "LootRollAction.h" +#include "ReviveFromCorpseAction.h" +#include "AcceptResurrectAction.h" +#include "UseMeetingStoneAction.h" +#include "AreaTriggerAction.h" +#include "CheckMountStateAction.h" +#include "RememberTaxiAction.h" +#include "TradeStatusAction.h" +#include "InventoryChangeFailureAction.h" +#include "LootAction.h" +#include "QuestAction.h" +#include "LeaveGroupAction.h" +#include "TellCastFailedAction.h" +#include "AcceptDuelAction.h" +#include "ReadyCheckAction.h" +#include "LfgActions.h" +#include "SecurityCheckAction.h" +#include "GuildAcceptAction.h" + +namespace ai +{ + class WorldPacketActionContext : public NamedObjectContext + { + public: + WorldPacketActionContext() + { + creators["accept invitation"] = &WorldPacketActionContext::accept_invitation; + creators["leader"] = &WorldPacketActionContext::pass_leadership_to_master; + 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["revive from corpse"] = &WorldPacketActionContext::revive_from_corpse; + creators["accept resurrect"] = &WorldPacketActionContext::accept_resurrect; + creators["use meeting stone"] = &WorldPacketActionContext::use_meeting_stone; + creators["area trigger"] = &WorldPacketActionContext::area_trigger; + creators["reach area trigger"] = &WorldPacketActionContext::reach_area_trigger; + creators["check mount state"] = &WorldPacketActionContext::check_mount_state; + creators["remember taxi"] = &WorldPacketActionContext::remember_taxi; + creators["accept trade"] = &WorldPacketActionContext::accept_trade; + creators["store loot"] = &WorldPacketActionContext::store_loot; + creators["tell out of react range"] = &WorldPacketActionContext::tell_out_of_react_range; + creators["quest objective completed"] = &WorldPacketActionContext::quest_objective_completed; + creators["party command"] = &WorldPacketActionContext::party_command; + creators["tell cast failed"] = &WorldPacketActionContext::tell_cast_failed; + creators["accept duel"] = &WorldPacketActionContext::accept_duel; + creators["ready check"] = &WorldPacketActionContext::ready_check; + creators["ready check finished"] = &WorldPacketActionContext::ready_check_finished; + creators["uninvite"] = &WorldPacketActionContext::uninvite; + creators["security check"] = &WorldPacketActionContext::security_check; + creators["guild accept"] = &WorldPacketActionContext::guild_accept; + } + + private: + static Action* guild_accept(PlayerbotAI* ai) { return new GuildAcceptAction(ai); } + static Action* security_check(PlayerbotAI* ai) { return new SecurityCheckAction(ai); } + static Action* uninvite(PlayerbotAI* ai) { return new UninviteAction(ai); } + static Action* ready_check_finished(PlayerbotAI* ai) { return new FinishReadyCheckAction(ai); } + static Action* ready_check(PlayerbotAI* ai) { return new ReadyCheckAction(ai); } + static Action* accept_duel(PlayerbotAI* ai) { return new AcceptDuelAction(ai); } + static Action* tell_cast_failed(PlayerbotAI* ai) { return new TellCastFailedAction(ai); } + static Action* party_command(PlayerbotAI* ai) { return new PartyCommandAction(ai); } + static Action* quest_objective_completed(PlayerbotAI* ai) { return new QuestObjectiveCompletedAction(ai); } + static Action* store_loot(PlayerbotAI* ai) { return new StoreLootAction(ai); } + static Action* tell_out_of_react_range(PlayerbotAI* ai) { return new OutOfReactRangeAction(ai); } + static Action* accept_trade(PlayerbotAI* ai) { return new TradeStatusAction(ai); } + static Action* remember_taxi(PlayerbotAI* ai) { return new RememberTaxiAction(ai); } + static Action* check_mount_state(PlayerbotAI* ai) { return new CheckMountStateAction(ai); } + static Action* area_trigger(PlayerbotAI* ai) { return new AreaTriggerAction(ai); } + static Action* reach_area_trigger(PlayerbotAI* ai) { return new ReachAreaTriggerAction(ai); } + static Action* use_meeting_stone(PlayerbotAI* ai) { return new UseMeetingStoneAction(ai); } + static Action* accept_resurrect(PlayerbotAI* ai) { return new AcceptResurrectAction(ai); } + static Action* revive_from_corpse(PlayerbotAI* ai) { return new ReviveFromCorpseAction(ai); } + static Action* accept_invitation(PlayerbotAI* ai) { return new AcceptInvitationAction(ai); } + static Action* pass_leadership_to_master(PlayerbotAI* ai) { return new PassLeadershipToMasterAction(ai); } + static Action* tell_not_enough_money(PlayerbotAI* ai) { return new TellMasterAction(ai, "Not enough money"); } + static Action* tell_not_enough_reputation(PlayerbotAI* ai) { return new TellMasterAction(ai, "Not enough reputation"); } + static Action* tell_cannot_equip(PlayerbotAI* ai) { return new InventoryChangeFailureAction(ai); } + static Action* turn_in_quest(PlayerbotAI* ai) { return new TalkToQuestGiverAction(ai); } + static Action* accept_quest(PlayerbotAI* ai) { return new AcceptQuestAction(ai); } + static Action* accept_all_quests(PlayerbotAI* ai) { return new AcceptAllQuestsAction(ai); } + static Action* accept_quest_share(PlayerbotAI* ai) { return new AcceptQuestShareAction(ai); } + static Action* loot_roll(PlayerbotAI* ai) { return (QueryItemUsageAction*)new LootRollAction(ai); } + }; + + +}; diff --git a/src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.cpp b/src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.cpp new file mode 100644 index 0000000000..2811c58340 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.cpp @@ -0,0 +1,171 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DruidMultipliers.h" +#include "BearTankDruidStrategy.h" + +using namespace ai; + +class BearTankDruidStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + BearTankDruidStrategyActionNodeFactory() + { + creators["melee"] = &melee; + creators["feral charge - bear"] = &feral_charge_bear; + creators["swipe (bear)"] = &swipe_bear; + creators["faerie fire (feral)"] = &faerie_fire_feral; + creators["bear form"] = &bear_form; + creators["dire bear form"] = &dire_bear_form; + creators["mangle (bear)"] = &mangle_bear; + creators["maul"] = &maul; + creators["bash"] = &bash; + creators["swipe"] = &swipe; + creators["lacerate"] = &lacerate; + creators["demoralizing roar"] = &demoralizing_roar; + } +private: + static ActionNode* melee(PlayerbotAI* ai) + { + return new ActionNode ("melee", + /*P*/ NextAction::array(0, new NextAction("feral charge - bear"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* feral_charge_bear(PlayerbotAI* ai) + { + return new ActionNode ("feral charge - bear", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("reach melee"), NULL), + /*C*/ NULL); + } + static ActionNode* swipe_bear(PlayerbotAI* ai) + { + return new ActionNode ("swipe (bear)", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* faerie_fire_feral(PlayerbotAI* ai) + { + return new ActionNode ("faerie fire (feral)", + /*P*/ NextAction::array(0, new NextAction("feral charge - bear"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* bear_form(PlayerbotAI* ai) + { + return new ActionNode ("bear form", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* dire_bear_form(PlayerbotAI* ai) + { + return new ActionNode ("dire bear form", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("bear form"), NULL), + /*C*/ NULL); + } + static ActionNode* mangle_bear(PlayerbotAI* ai) + { + return new ActionNode ("mangle (bear)", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("lacerate"), NULL), + /*C*/ NULL); + } + static ActionNode* maul(PlayerbotAI* ai) + { + return new ActionNode ("maul", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* bash(PlayerbotAI* ai) + { + return new ActionNode ("bash", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* swipe(PlayerbotAI* ai) + { + return new ActionNode ("swipe", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* lacerate(PlayerbotAI* ai) + { + return new ActionNode ("lacerate", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("maul"), NULL), + /*C*/ NULL); + } + static ActionNode* growl(PlayerbotAI* ai) + { + return new ActionNode ("growl", + /*P*/ NextAction::array(0, new NextAction("reach spell"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* demoralizing_roar(PlayerbotAI* ai) + { + return new ActionNode ("demoralizing roar", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } +}; + +BearTankDruidStrategy::BearTankDruidStrategy(PlayerbotAI* ai) : FeralDruidStrategy(ai) +{ + actionNodeFactories.Add(new BearTankDruidStrategyActionNodeFactory()); +} + +NextAction** BearTankDruidStrategy::getDefaultActions() +{ + return NextAction::array(0, + new NextAction("lacerate", ACTION_NORMAL + 4), + new NextAction("mangle (bear)", ACTION_NORMAL + 3), + new NextAction("maul", ACTION_NORMAL + 2), + new NextAction("faerie fire (feral)", ACTION_NORMAL + 1), + NULL); +} + +void BearTankDruidStrategy::InitTriggers(std::list &triggers) +{ + FeralDruidStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "thorns", + NextAction::array(0, new NextAction("thorns", ACTION_HIGH + 9), NULL))); + + triggers.push_back(new TriggerNode( + "bear form", + NextAction::array(0, new NextAction("dire bear form", ACTION_HIGH + 8), NULL))); + + triggers.push_back(new TriggerNode( + "faerie fire (feral)", + NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_HIGH + 7), NULL))); + + triggers.push_back(new TriggerNode( + "lose aggro", + NextAction::array(0, new NextAction("growl", ACTION_HIGH + 8), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("demoralizing roar", ACTION_HIGH + 6), new NextAction("swipe (bear)", ACTION_HIGH + 6), NULL))); + + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("swipe (bear)", ACTION_HIGH + 5), NULL))); + + triggers.push_back(new TriggerNode( + "bash", + NextAction::array(0, new NextAction("bash", ACTION_INTERRUPT + 2), NULL))); + + triggers.push_back(new TriggerNode( + "bash on enemy healer", + NextAction::array(0, new NextAction("bash on enemy healer", ACTION_INTERRUPT + 1), NULL))); + +} diff --git a/src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.h b/src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.h new file mode 100644 index 0000000000..f5b200a355 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/BearTankDruidStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "FeralDruidStrategy.h" + +namespace ai +{ + class BearTankDruidStrategy : public FeralDruidStrategy + { + public: + BearTankDruidStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bear"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_TANK | STRATEGY_TYPE_MELEE; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.cpp b/src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.cpp new file mode 100644 index 0000000000..b23b9b5a32 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.cpp @@ -0,0 +1,177 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DruidMultipliers.h" +#include "CasterDruidStrategy.h" +#include "FeralDruidStrategy.h" + +using namespace ai; + +class CasterDruidStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + CasterDruidStrategyActionNodeFactory() + { + creators["faerie fire"] = &faerie_fire; + creators["hibernate"] = &hibernate; + creators["entangling roots"] = &entangling_roots; + creators["entangling roots on cc"] = &entangling_roots_on_cc; + creators["wrath"] = &wrath; + creators["starfall"] = &starfall; + creators["insect swarm"] = &insect_swarm; + creators["moonfire"] = &moonfire; + creators["starfire"] = &starfire; + creators["nature's grasp"] = &natures_grasp; + } +private: + static ActionNode* faerie_fire(PlayerbotAI* ai) + { + return new ActionNode ("faerie fire", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* hibernate(PlayerbotAI* ai) + { + return new ActionNode ("hibernate", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NextAction::array(0, new NextAction("entangling roots"), NULL), + /*C*/ NextAction::array(0, new NextAction("flee", 49.0f), NULL)); + } + static ActionNode* entangling_roots(PlayerbotAI* ai) + { + return new ActionNode ("entangling roots", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NextAction::array(0, new NextAction("flee", 49.0f), NULL)); + } + static ActionNode* entangling_roots_on_cc(PlayerbotAI* ai) + { + return new ActionNode ("entangling roots on cc", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* wrath(PlayerbotAI* ai) + { + return new ActionNode ("wrath", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* starfall(PlayerbotAI* ai) + { + return new ActionNode ("starfall", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NextAction::array(0, new NextAction("hurricane"), NULL), + /*C*/ NULL); + } + static ActionNode* insect_swarm(PlayerbotAI* ai) + { + return new ActionNode ("insect swarm", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* moonfire(PlayerbotAI* ai) + { + return new ActionNode ("moonfire", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* starfire(PlayerbotAI* ai) + { + return new ActionNode ("starfire", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* natures_grasp(PlayerbotAI* ai) + { + return new ActionNode ("nature's grasp", + /*P*/ NextAction::array(0, new NextAction("moonkin form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } +}; + +CasterDruidStrategy::CasterDruidStrategy(PlayerbotAI* ai) : GenericDruidStrategy(ai) +{ + actionNodeFactories.Add(new CasterDruidStrategyActionNodeFactory()); + actionNodeFactories.Add(new ShapeshiftDruidStrategyActionNodeFactory()); +} + +NextAction** CasterDruidStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("starfire", ACTION_NORMAL + 2), new NextAction("wrath", ACTION_NORMAL + 1), NULL); +} + +void CasterDruidStrategy::InitTriggers(std::list &triggers) +{ + GenericDruidStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_MOVE), NULL))); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("regrowth", ACTION_MEDIUM_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "almost full health", + NextAction::array(0, new NextAction("rejuvenation", ACTION_LIGHT_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member almost full health", + NextAction::array(0, new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 1), NULL))); + + + triggers.push_back(new TriggerNode( + "insect swarm", + NextAction::array(0, new NextAction("insect swarm", ACTION_NORMAL + 5), NULL))); + + triggers.push_back(new TriggerNode( + "moonfire", + NextAction::array(0, new NextAction("moonfire", ACTION_NORMAL + 4), NULL))); + + triggers.push_back(new TriggerNode( + "eclipse (solar)", + NextAction::array(0, new NextAction("wrath", ACTION_NORMAL + 6), NULL))); + + triggers.push_back(new TriggerNode( + "eclipse (lunar)", + NextAction::array(0, new NextAction("starfire", ACTION_NORMAL + 6), NULL))); + + triggers.push_back(new TriggerNode( + "moonfire", + NextAction::array(0, new NextAction("moonfire", ACTION_NORMAL + 4), NULL))); + + + + triggers.push_back(new TriggerNode( + "nature's grasp", + NextAction::array(0, new NextAction("nature's grasp", ACTION_EMERGENCY), NULL))); + + triggers.push_back(new TriggerNode( + "entangling roots", + NextAction::array(0, new NextAction("entangling roots on cc", ACTION_HIGH + 2), NULL))); +} + +void CasterDruidAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, new NextAction("starfall", ACTION_HIGH + 1), NULL))); +} + +void CasterDruidDebuffStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "faerie fire", + NextAction::array(0, new NextAction("faerie fire", ACTION_HIGH), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.h b/src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.h new file mode 100644 index 0000000000..66ac8386ba --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/CasterDruidStrategy.h @@ -0,0 +1,39 @@ +#pragma once + +#include "GenericDruidStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class CasterDruidStrategy : public GenericDruidStrategy + { + public: + CasterDruidStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "caster"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_RANGED; } + }; + + class CasterDruidAoeStrategy : public CombatStrategy + { + public: + CasterDruidAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "caster aoe"; } + }; + + class CasterDruidDebuffStrategy : public CombatStrategy + { + public: + CasterDruidDebuffStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "caster debuff"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.cpp b/src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.cpp new file mode 100644 index 0000000000..80d9779d1a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.cpp @@ -0,0 +1,139 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DruidMultipliers.h" +#include "CatDpsDruidStrategy.h" + +using namespace ai; + +class CatDpsDruidStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + CatDpsDruidStrategyActionNodeFactory() + { + creators["faerie fire (feral)"] = &faerie_fire_feral; + creators["melee"] = &melee; + creators["feral charge - cat"] = &feral_charge_cat; + creators["cat form"] = &cat_form; + creators["claw"] = &claw; + creators["mangle (cat)"] = &mangle_cat; + creators["rake"] = &rake; + creators["ferocious bite"] = &ferocious_bite; + creators["rip"] = &rip; + } +private: + static ActionNode* faerie_fire_feral(PlayerbotAI* ai) + { + return new ActionNode ("faerie fire (feral)", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* melee(PlayerbotAI* ai) + { + return new ActionNode ("melee", + /*P*/ NextAction::array(0, new NextAction("feral charge - cat"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* feral_charge_cat(PlayerbotAI* ai) + { + return new ActionNode ("feral charge - cat", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("reach melee"), NULL), + /*C*/ NULL); + } + static ActionNode* cat_form(PlayerbotAI* ai) + { + return new ActionNode ("cat form", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* claw(PlayerbotAI* ai) + { + return new ActionNode ("claw", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* mangle_cat(PlayerbotAI* ai) + { + return new ActionNode ("mangle (cat)", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("claw"), NULL), + /*C*/ NULL); + } + static ActionNode* rake(PlayerbotAI* ai) + { + return new ActionNode ("rake", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* ferocious_bite(PlayerbotAI* ai) + { + return new ActionNode ("ferocious bite", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("rip"), NULL), + /*C*/ NULL); + } + static ActionNode* rip(PlayerbotAI* ai) + { + return new ActionNode ("rip", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } +}; + +CatDpsDruidStrategy::CatDpsDruidStrategy(PlayerbotAI* ai) : FeralDruidStrategy(ai) +{ + actionNodeFactories.Add(new CatDpsDruidStrategyActionNodeFactory()); +} + +NextAction** CatDpsDruidStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("mangle (cat)", ACTION_NORMAL + 1), NULL); +} + +void CatDpsDruidStrategy::InitTriggers(std::list &triggers) +{ + FeralDruidStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "cat form", + NextAction::array(0, new NextAction("cat form", ACTION_MOVE + 2), NULL))); + + triggers.push_back(new TriggerNode( + "rake", + NextAction::array(0, new NextAction("rake", ACTION_NORMAL + 5), NULL))); + + triggers.push_back(new TriggerNode( + "combo points available", + NextAction::array(0, new NextAction("ferocious bite", ACTION_NORMAL + 9), NULL))); + + triggers.push_back(new TriggerNode( + "medium threat", + NextAction::array(0, new NextAction("cower", ACTION_EMERGENCY + 1), NULL))); + + triggers.push_back(new TriggerNode( + "faerie fire (feral)", + NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "tiger's fury", + NextAction::array(0, new NextAction("tiger's fury", ACTION_EMERGENCY + 1), NULL))); + + triggers.push_back(new TriggerNode( + "entangling roots", + NextAction::array(0, new NextAction("entangling roots on cc", ACTION_HIGH + 1), NULL))); + +} + +void CatAoeDruidStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 2), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.h b/src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.h new file mode 100644 index 0000000000..397f0b36e6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/CatDpsDruidStrategy.h @@ -0,0 +1,29 @@ +#pragma once + +#include "FeralDruidStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class CatDpsDruidStrategy : public FeralDruidStrategy + { + public: + CatDpsDruidStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "cat"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_MELEE; } + }; + + class CatAoeDruidStrategy : public CombatStrategy + { + public: + CatAoeDruidStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "cat aoe"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidActions.cpp b/src/modules/Bots/playerbot/strategy/druid/DruidActions.cpp new file mode 100644 index 0000000000..4fca07ecaa --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidActions.cpp @@ -0,0 +1,31 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DruidActions.h" + +using namespace ai; + +bool CastCasterFormAction::Execute(Event event) +{ + ai->RemoveShapeshift(); + return true; +} + +NextAction** CastAbolishPoisonAction::getAlternatives() +{ + return NextAction::merge( NextAction::array(0, new NextAction("cure poison"), NULL), CastSpellAction::getPrerequisites()); +} + +NextAction** CastAbolishPoisonOnPartyAction::getAlternatives() +{ + return NextAction::merge( NextAction::array(0, new NextAction("cure poison on party"), NULL), CastSpellAction::getPrerequisites()); +} + +Value* CastEntanglingRootsCcAction::GetTargetValue() +{ + return context->GetValue("cc target", "entangling roots"); +} + +bool CastEntanglingRootsCcAction::Execute(Event event) +{ + return ai->CastSpell("entangling roots", GetTarget()); +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidActions.h b/src/modules/Bots/playerbot/strategy/druid/DruidActions.h new file mode 100644 index 0000000000..d40e355b6d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidActions.h @@ -0,0 +1,184 @@ +#pragma once + +#include "../actions/GenericActions.h" +#include "DruidShapeshiftActions.h" +#include "DruidBearActions.h" +#include "DruidCatActions.h" + +namespace ai +{ + class CastFaerieFireAction : public CastSpellAction + { + public: + CastFaerieFireAction(PlayerbotAI* ai) : CastSpellAction(ai, "faerie fire") {} + }; + + class CastFaerieFireFeralAction : public CastSpellAction + { + public: + CastFaerieFireFeralAction(PlayerbotAI* ai) : CastSpellAction(ai, "faerie fire (feral)") {} + }; + + class CastRejuvenationAction : public CastHealingSpellAction { + public: + CastRejuvenationAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "rejuvenation") {} + }; + + class CastRegrowthAction : public CastHealingSpellAction { + public: + CastRegrowthAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "regrowth") {} + + }; + + class CastHealingTouchAction : public CastHealingSpellAction { + public: + CastHealingTouchAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "healing touch") {} + + }; + + class CastRejuvenationOnPartyAction : public HealPartyMemberAction + { + public: + CastRejuvenationOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "rejuvenation") {} + }; + + class CastRegrowthOnPartyAction : public HealPartyMemberAction + { + public: + CastRegrowthOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "regrowth") {} + }; + + class CastHealingTouchOnPartyAction : public HealPartyMemberAction + { + public: + CastHealingTouchOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "healing touch") {} + }; + + class CastRebirthAction : public ResurrectPartyMemberAction + { + public: + CastRebirthAction(PlayerbotAI* ai) : ResurrectPartyMemberAction(ai, "rebirth") {} + + virtual NextAction** getPrerequisites() { + return NextAction::merge( NextAction::array(0, new NextAction("caster form"), NULL), ResurrectPartyMemberAction::getPrerequisites()); + } + }; + + class CastMarkOfTheWildAction : public CastBuffSpellAction { + public: + CastMarkOfTheWildAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "mark of the wild") {} + }; + + class CastMarkOfTheWildOnPartyAction : public BuffOnPartyAction { + public: + CastMarkOfTheWildOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "mark of the wild") {} + }; + + class CastThornsAction : public CastBuffSpellAction { + public: + CastThornsAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "thorns") {} + }; + + class CastWrathAction : public CastSpellAction + { + public: + CastWrathAction(PlayerbotAI* ai) : CastSpellAction(ai, "wrath") {} + }; + + class CastHurricaneAction : public CastSpellAction + { + public: + CastHurricaneAction(PlayerbotAI* ai) : CastSpellAction(ai, "hurricane") {} + }; + + class CastMoonfireAction : public CastDebuffSpellAction + { + public: + CastMoonfireAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "moonfire") {} + }; + + class CastInsectSwarmAction : public CastDebuffSpellAction + { + public: + CastInsectSwarmAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "insect swarm") {} + }; + + class CastStarfireAction : public CastSpellAction + { + public: + CastStarfireAction(PlayerbotAI* ai) : CastSpellAction(ai, "starfire") {} + }; + + class CastEntanglingRootsAction : public CastSpellAction + { + public: + CastEntanglingRootsAction(PlayerbotAI* ai) : CastSpellAction(ai, "entangling roots") {} + }; + + class CastEntanglingRootsCcAction : public CastSpellAction + { + public: + CastEntanglingRootsCcAction(PlayerbotAI* ai) : CastSpellAction(ai, "entangling roots on cc") {} + virtual Value* GetTargetValue(); + virtual bool Execute(Event event); + }; + + class CastNaturesGraspAction : public CastBuffSpellAction + { + public: + CastNaturesGraspAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "nature's grasp") {} + }; + + class CastHibernateAction : public CastSpellAction + { + public: + CastHibernateAction(PlayerbotAI* ai) : CastSpellAction(ai, "hibernate") {} + }; + + class CastCurePoisonAction : public CastCureSpellAction + { + public: + CastCurePoisonAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "cure poison") {} + }; + + class CastCurePoisonOnPartyAction : public CurePartyMemberAction + { + public: + CastCurePoisonOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "cure poison", DISPEL_POISON) {} + }; + + class CastAbolishPoisonAction : public CastCureSpellAction + { + public: + CastAbolishPoisonAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "abolish poison") {} + virtual NextAction** getAlternatives(); + }; + + class CastAbolishPoisonOnPartyAction : public CurePartyMemberAction + { + public: + CastAbolishPoisonOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "abolish poison", DISPEL_POISON) {} + + virtual NextAction** getAlternatives(); + }; + + class CastBarskinAction : public CastBuffSpellAction + { + public: + CastBarskinAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "barskin") {} + }; + + class CastInnervateAction : public CastSpellAction + { + public: + CastInnervateAction(PlayerbotAI* ai) : CastSpellAction(ai, "innervate") {} + + virtual string GetTargetName() { return "self target"; } + }; + + class CastTranquilityAction : public CastAoeHealSpellAction + { + public: + CastTranquilityAction(PlayerbotAI* ai) : CastAoeHealSpellAction(ai, "tranquility") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.cpp new file mode 100644 index 0000000000..0bde250693 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.cpp @@ -0,0 +1,252 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DruidActions.h" +#include "DruidAiObjectContext.h" +#include "BearTankDruidStrategy.h" +#include "CatDpsDruidStrategy.h" +#include "CasterDruidStrategy.h" +#include "GenericDruidNonCombatStrategy.h" +#include "../NamedObjectContext.h" +#include "DruidTriggers.h" +#include "HealDruidStrategy.h" + +using namespace ai; + +namespace ai +{ + namespace druid + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &druid::StrategyFactoryInternal::nc; + creators["cat aoe"] = &druid::StrategyFactoryInternal::cat_aoe; + creators["caster aoe"] = &druid::StrategyFactoryInternal::caster_aoe; + creators["caster debuff"] = &druid::StrategyFactoryInternal::caster_debuff; + creators["dps debuff"] = &druid::StrategyFactoryInternal::caster_debuff; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new GenericDruidNonCombatStrategy(ai); } + static Strategy* cat_aoe(PlayerbotAI* ai) { return new CatAoeDruidStrategy(ai); } + static Strategy* caster_aoe(PlayerbotAI* ai) { return new CasterDruidAoeStrategy(ai); } + static Strategy* caster_debuff(PlayerbotAI* ai) { return new CasterDruidDebuffStrategy(ai); } + }; + + class DruidStrategyFactoryInternal : public NamedObjectContext + { + public: + DruidStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["bear"] = &druid::DruidStrategyFactoryInternal::bear; + creators["tank"] = &druid::DruidStrategyFactoryInternal::bear; + creators["cat"] = &druid::DruidStrategyFactoryInternal::cat; + creators["caster"] = &druid::DruidStrategyFactoryInternal::caster; + creators["dps"] = &druid::DruidStrategyFactoryInternal::cat; + creators["heal"] = &druid::DruidStrategyFactoryInternal::heal; + } + + private: + static Strategy* bear(PlayerbotAI* ai) { return new BearTankDruidStrategy(ai); } + static Strategy* cat(PlayerbotAI* ai) { return new CatDpsDruidStrategy(ai); } + static Strategy* caster(PlayerbotAI* ai) { return new CasterDruidStrategy(ai); } + static Strategy* heal(PlayerbotAI* ai) { return new HealDruidStrategy(ai); } + }; + }; +}; + +namespace ai +{ + namespace druid + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["thorns"] = &TriggerFactoryInternal::Thorns; + creators["bash"] = &TriggerFactoryInternal::bash; + creators["faerie fire (feral)"] = &TriggerFactoryInternal::faerie_fire_feral; + creators["faerie fire"] = &TriggerFactoryInternal::faerie_fire; + creators["insect swarm"] = &TriggerFactoryInternal::insect_swarm; + creators["moonfire"] = &TriggerFactoryInternal::moonfire; + creators["nature's grasp"] = &TriggerFactoryInternal::natures_grasp; + creators["tiger's fury"] = &TriggerFactoryInternal::tigers_fury; + creators["rake"] = &TriggerFactoryInternal::rake; + creators["mark of the wild"] = &TriggerFactoryInternal::mark_of_the_wild; + creators["mark of the wild on party"] = &TriggerFactoryInternal::mark_of_the_wild_on_party; + creators["cure poison"] = &TriggerFactoryInternal::cure_poison; + creators["party member cure poison"] = &TriggerFactoryInternal::party_member_cure_poison; + creators["entangling roots"] = &TriggerFactoryInternal::entangling_roots; + creators["bear form"] = &TriggerFactoryInternal::bear_form; + creators["cat form"] = &TriggerFactoryInternal::cat_form; + creators["tree form"] = &TriggerFactoryInternal::tree_form; + creators["eclipse (solar)"] = &TriggerFactoryInternal::eclipse_solar; + creators["eclipse (lunar)"] = &TriggerFactoryInternal::eclipse_lunar; + creators["bash on enemy healer"] = &TriggerFactoryInternal::bash_on_enemy_healer; + } + + private: + static Trigger* eclipse_solar(PlayerbotAI* ai) { return new EclipseSolarTrigger(ai); } + static Trigger* eclipse_lunar(PlayerbotAI* ai) { return new EclipseLunarTrigger(ai); } + static Trigger* Thorns(PlayerbotAI* ai) { return new ThornsTrigger(ai); } + static Trigger* bash(PlayerbotAI* ai) { return new BashInterruptSpellTrigger(ai); } + static Trigger* faerie_fire_feral(PlayerbotAI* ai) { return new FaerieFireFeralTrigger(ai); } + static Trigger* insect_swarm(PlayerbotAI* ai) { return new InsectSwarmTrigger(ai); } + static Trigger* moonfire(PlayerbotAI* ai) { return new MoonfireTrigger(ai); } + static Trigger* faerie_fire(PlayerbotAI* ai) { return new FaerieFireTrigger(ai); } + static Trigger* natures_grasp(PlayerbotAI* ai) { return new NaturesGraspTrigger(ai); } + static Trigger* tigers_fury(PlayerbotAI* ai) { return new TigersFuryTrigger(ai); } + static Trigger* rake(PlayerbotAI* ai) { return new RakeTrigger(ai); } + static Trigger* mark_of_the_wild(PlayerbotAI* ai) { return new MarkOfTheWildTrigger(ai); } + static Trigger* mark_of_the_wild_on_party(PlayerbotAI* ai) { return new MarkOfTheWildOnPartyTrigger(ai); } + static Trigger* cure_poison(PlayerbotAI* ai) { return new CurePoisonTrigger(ai); } + static Trigger* party_member_cure_poison(PlayerbotAI* ai) { return new PartyMemberCurePoisonTrigger(ai); } + static Trigger* entangling_roots(PlayerbotAI* ai) { return new EntanglingRootsTrigger(ai); } + static Trigger* bear_form(PlayerbotAI* ai) { return new BearFormTrigger(ai); } + static Trigger* cat_form(PlayerbotAI* ai) { return new CatFormTrigger(ai); } + static Trigger* tree_form(PlayerbotAI* ai) { return new TreeFormTrigger(ai); } + static Trigger* bash_on_enemy_healer(PlayerbotAI* ai) { return new BashInterruptEnemyHealerSpellTrigger(ai); } + }; + }; +}; + +namespace ai +{ + namespace druid + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["feral charge - bear"] = &AiObjectContextInternal::feral_charge_bear; + creators["feral charge - cat"] = &AiObjectContextInternal::feral_charge_cat; + creators["swipe (bear)"] = &AiObjectContextInternal::swipe_bear; + creators["faerie fire (feral)"] = &AiObjectContextInternal::faerie_fire_feral; + creators["faerie fire"] = &AiObjectContextInternal::faerie_fire; + creators["bear form"] = &AiObjectContextInternal::bear_form; + creators["dire bear form"] = &AiObjectContextInternal::dire_bear_form; + creators["moonkin form"] = &AiObjectContextInternal::moonkin_form; + creators["cat form"] = &AiObjectContextInternal::cat_form; + creators["tree form"] = &AiObjectContextInternal::tree_form; + creators["caster form"] = &AiObjectContextInternal::caster_form; + creators["mangle (bear)"] = &AiObjectContextInternal::mangle_bear; + creators["maul"] = &AiObjectContextInternal::maul; + creators["bash"] = &AiObjectContextInternal::bash; + creators["swipe"] = &AiObjectContextInternal::swipe; + creators["growl"] = &AiObjectContextInternal::growl; + creators["demoralizing roar"] = &AiObjectContextInternal::demoralizing_roar; + creators["hibernate"] = &AiObjectContextInternal::hibernate; + creators["entangling roots"] = &AiObjectContextInternal::entangling_roots; + creators["entangling roots on cc"] = &AiObjectContextInternal::entangling_roots_on_cc; + creators["wrath"] = &AiObjectContextInternal::wrath; + creators["insect swarm"] = &AiObjectContextInternal::insect_swarm; + creators["moonfire"] = &AiObjectContextInternal::moonfire; + creators["starfire"] = &AiObjectContextInternal::starfire; + creators["nature's grasp"] = &AiObjectContextInternal::natures_grasp; + creators["claw"] = &AiObjectContextInternal::claw; + creators["mangle (cat)"] = &AiObjectContextInternal::mangle_cat; + creators["swipe (cat)"] = &AiObjectContextInternal::swipe_cat; + creators["rake"] = &AiObjectContextInternal::rake; + creators["ferocious bite"] = &AiObjectContextInternal::ferocious_bite; + creators["rip"] = &AiObjectContextInternal::rip; + creators["cower"] = &AiObjectContextInternal::cower; + creators["thorns"] = &AiObjectContextInternal::thorns; + creators["cure poison"] = &AiObjectContextInternal::cure_poison; + creators["cure poison on party"] = &AiObjectContextInternal::cure_poison_on_party; + creators["abolish poison"] = &AiObjectContextInternal::abolish_poison; + creators["abolish poison on party"] = &AiObjectContextInternal::abolish_poison_on_party; + creators["berserk"] = &AiObjectContextInternal::berserk; + creators["tiger's fury"] = &AiObjectContextInternal::tigers_fury; + creators["mark of the wild"] = &AiObjectContextInternal::mark_of_the_wild; + creators["mark of the wild on party"] = &AiObjectContextInternal::mark_of_the_wild_on_party; + creators["regrowth"] = &AiObjectContextInternal::regrowth; + creators["rejuvenation"] = &AiObjectContextInternal::rejuvenation; + creators["healing touch"] = &AiObjectContextInternal::healing_touch; + creators["regrowth on party"] = &AiObjectContextInternal::regrowth_on_party; + creators["rejuvenation on party"] = &AiObjectContextInternal::rejuvenation_on_party; + creators["healing touch on party"] = &AiObjectContextInternal::healing_touch_on_party; + creators["rebirth"] = &AiObjectContextInternal::rebirth; + creators["barskin"] = &AiObjectContextInternal::barskin; + creators["lacerate"] = &AiObjectContextInternal::lacerate; + creators["hurricane"] = &AiObjectContextInternal::hurricane; + creators["innervate"] = &AiObjectContextInternal::innervate; + creators["tranquility"] = &AiObjectContextInternal::tranquility; + creators["bash on enemy healer"] = &AiObjectContextInternal::bash_on_enemy_healer; + } + + private: + static Action* tranquility(PlayerbotAI* ai) { return new CastTranquilityAction(ai); } + static Action* feral_charge_bear(PlayerbotAI* ai) { return new CastFeralChargeBearAction(ai); } + static Action* feral_charge_cat(PlayerbotAI* ai) { return new CastFeralChargeCatAction(ai); } + static Action* swipe_bear(PlayerbotAI* ai) { return new CastSwipeBearAction(ai); } + static Action* faerie_fire_feral(PlayerbotAI* ai) { return new CastFaerieFireFeralAction(ai); } + static Action* faerie_fire(PlayerbotAI* ai) { return new CastFaerieFireAction(ai); } + static Action* bear_form(PlayerbotAI* ai) { return new CastBearFormAction(ai); } + static Action* dire_bear_form(PlayerbotAI* ai) { return new CastDireBearFormAction(ai); } + static Action* cat_form(PlayerbotAI* ai) { return new CastCatFormAction(ai); } + static Action* tree_form(PlayerbotAI* ai) { return new CastTreeFormAction(ai); } + static Action* caster_form(PlayerbotAI* ai) { return new CastCasterFormAction(ai); } + static Action* mangle_bear(PlayerbotAI* ai) { return new CastMangleBearAction(ai); } + static Action* maul(PlayerbotAI* ai) { return new CastMaulAction(ai); } + static Action* bash(PlayerbotAI* ai) { return new CastBashAction(ai); } + static Action* swipe(PlayerbotAI* ai) { return new CastSwipeAction(ai); } + static Action* growl(PlayerbotAI* ai) { return new CastGrowlAction(ai); } + static Action* demoralizing_roar(PlayerbotAI* ai) { return new CastDemoralizingRoarAction(ai); } + static Action* moonkin_form(PlayerbotAI* ai) { return new CastMoonkinFormAction(ai); } + static Action* hibernate(PlayerbotAI* ai) { return new CastHibernateAction(ai); } + static Action* entangling_roots(PlayerbotAI* ai) { return new CastEntanglingRootsAction(ai); } + static Action* entangling_roots_on_cc(PlayerbotAI* ai) { return new CastEntanglingRootsCcAction(ai); } + static Action* wrath(PlayerbotAI* ai) { return new CastWrathAction(ai); } + static Action* insect_swarm(PlayerbotAI* ai) { return new CastInsectSwarmAction(ai); } + static Action* moonfire(PlayerbotAI* ai) { return new CastMoonfireAction(ai); } + static Action* starfire(PlayerbotAI* ai) { return new CastStarfireAction(ai); } + static Action* natures_grasp(PlayerbotAI* ai) { return new CastNaturesGraspAction(ai); } + static Action* claw(PlayerbotAI* ai) { return new CastClawAction(ai); } + static Action* mangle_cat(PlayerbotAI* ai) { return new CastMangleCatAction(ai); } + static Action* swipe_cat(PlayerbotAI* ai) { return new CastSwipeCatAction(ai); } + static Action* rake(PlayerbotAI* ai) { return new CastRakeAction(ai); } + static Action* ferocious_bite(PlayerbotAI* ai) { return new CastFerociousBiteAction(ai); } + static Action* rip(PlayerbotAI* ai) { return new CastRipAction(ai); } + static Action* cower(PlayerbotAI* ai) { return new CastCowerAction(ai); } + static Action* thorns(PlayerbotAI* ai) { return new CastThornsAction(ai); } + static Action* cure_poison(PlayerbotAI* ai) { return new CastCurePoisonAction(ai); } + static Action* cure_poison_on_party(PlayerbotAI* ai) { return new CastCurePoisonOnPartyAction(ai); } + static Action* abolish_poison(PlayerbotAI* ai) { return new CastAbolishPoisonAction(ai); } + static Action* abolish_poison_on_party(PlayerbotAI* ai) { return new CastAbolishPoisonOnPartyAction(ai); } + static Action* berserk(PlayerbotAI* ai) { return new CastBerserkAction(ai); } + static Action* tigers_fury(PlayerbotAI* ai) { return new CastTigersFuryAction(ai); } + static Action* mark_of_the_wild(PlayerbotAI* ai) { return new CastMarkOfTheWildAction(ai); } + static Action* mark_of_the_wild_on_party(PlayerbotAI* ai) { return new CastMarkOfTheWildOnPartyAction(ai); } + static Action* regrowth(PlayerbotAI* ai) { return new CastRegrowthAction(ai); } + static Action* rejuvenation(PlayerbotAI* ai) { return new CastRejuvenationAction(ai); } + static Action* healing_touch(PlayerbotAI* ai) { return new CastHealingTouchAction(ai); } + static Action* regrowth_on_party(PlayerbotAI* ai) { return new CastRegrowthOnPartyAction(ai); } + static Action* rejuvenation_on_party(PlayerbotAI* ai) { return new CastRejuvenationOnPartyAction(ai); } + static Action* healing_touch_on_party(PlayerbotAI* ai) { return new CastHealingTouchOnPartyAction(ai); } + static Action* rebirth(PlayerbotAI* ai) { return new CastRebirthAction(ai); } + static Action* barskin(PlayerbotAI* ai) { return new CastBarskinAction(ai); } + static Action* lacerate(PlayerbotAI* ai) { return new CastLacerateAction(ai); } + static Action* hurricane(PlayerbotAI* ai) { return new CastHurricaneAction(ai); } + static Action* innervate(PlayerbotAI* ai) { return new CastInnervateAction(ai); } + static Action* bash_on_enemy_healer(PlayerbotAI* ai) { return new CastBashOnEnemyHealerAction(ai); } + }; + }; +}; + +DruidAiObjectContext::DruidAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::druid::StrategyFactoryInternal()); + strategyContexts.Add(new ai::druid::DruidStrategyFactoryInternal()); + actionContexts.Add(new ai::druid::AiObjectContextInternal()); + triggerContexts.Add(new ai::druid::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.h b/src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.h new file mode 100644 index 0000000000..b5d7a2cd12 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class DruidAiObjectContext : public AiObjectContext + { + public: + DruidAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidBearActions.h b/src/modules/Bots/playerbot/strategy/druid/DruidBearActions.h new file mode 100644 index 0000000000..dfb5dde971 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidBearActions.h @@ -0,0 +1,64 @@ +#pragma once + +namespace ai { + class CastFeralChargeBearAction : public CastReachTargetSpellAction + { + public: + CastFeralChargeBearAction(PlayerbotAI* ai) : CastReachTargetSpellAction(ai, "feral charge - bear", 1.5f) {} + }; + + class CastGrowlAction : public CastSpellAction + { + public: + CastGrowlAction(PlayerbotAI* ai) : CastSpellAction(ai, "growl") {} + }; + + class CastMaulAction : public CastMeleeSpellAction + { + public: + CastMaulAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "maul") {} + virtual bool isUseful() { return CastMeleeSpellAction::isUseful() && AI_VALUE2(uint8, "rage", "self target") >= 45; } + }; + + class CastBashAction : public CastMeleeSpellAction + { + public: + CastBashAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "bash") {} + }; + + class CastSwipeAction : public CastMeleeSpellAction + { + public: + CastSwipeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "swipe") {} + }; + + class CastDemoralizingRoarAction : public CastDebuffSpellAction + { + public: + CastDemoralizingRoarAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "demoralizing roar") {} + }; + + class CastMangleBearAction : public CastMeleeSpellAction + { + public: + CastMangleBearAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "mangle (bear)") {} + }; + + class CastSwipeBearAction : public CastMeleeSpellAction + { + public: + CastSwipeBearAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "swipe (bear)") {} + }; + + class CastLacerateAction : public CastMeleeSpellAction + { + public: + CastLacerateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "lacerate") {} + }; + + class CastBashOnEnemyHealerAction : public CastSpellOnEnemyHealerAction + { + public: + CastBashOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "bash") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidCatActions.h b/src/modules/Bots/playerbot/strategy/druid/DruidCatActions.h new file mode 100644 index 0000000000..b15c158c08 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidCatActions.h @@ -0,0 +1,69 @@ +#pragma once + +namespace ai { + class CastFeralChargeCatAction : public CastReachTargetSpellAction + { + public: + CastFeralChargeCatAction(PlayerbotAI* ai) : CastReachTargetSpellAction(ai, "feral charge - cat", 1.5f) {} + }; + + class CastCowerAction : public CastBuffSpellAction + { + public: + CastCowerAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "cower") {} + }; + + + class CastBerserkAction : public CastBuffSpellAction + { + public: + CastBerserkAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "berserk") {} + }; + + class CastTigersFuryAction : public CastBuffSpellAction + { + public: + CastTigersFuryAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "tiger's fury") {} + }; + + class CastRakeAction : public CastDebuffSpellAction + { + public: + CastRakeAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "rake") {} + + virtual NextAction** getPrerequisites() + { + return NextAction::merge( NextAction::array(0, new NextAction("reach melee"), NULL), CastDebuffSpellAction::getPrerequisites()); + } + }; + + + class CastClawAction : public CastMeleeSpellAction { + public: + CastClawAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "claw") {} + }; + + class CastMangleCatAction : public CastMeleeSpellAction { + public: + CastMangleCatAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "mangle (cat)") {} + }; + + class CastSwipeCatAction : public CastMeleeSpellAction { + public: + CastSwipeCatAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "swipe (cat)") {} + }; + + class CastFerociousBiteAction : public CastMeleeSpellAction { + public: + CastFerociousBiteAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "ferocious bite") {} + }; + + + class CastRipAction : public CastMeleeSpellAction { + public: + CastRipAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rip") {} + }; + + + +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.cpp b/src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.cpp new file mode 100644 index 0000000000..f7992c2039 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "DruidMultipliers.h" +//#include "DruidActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.h b/src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidShapeshiftActions.h b/src/modules/Bots/playerbot/strategy/druid/DruidShapeshiftActions.h new file mode 100644 index 0000000000..831b25dbc6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidShapeshiftActions.h @@ -0,0 +1,53 @@ +#pragma once + +namespace ai { + class CastBearFormAction : public CastBuffSpellAction { + public: + CastBearFormAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "bear form") {} + + virtual bool isPossible() { + return CastBuffSpellAction::isPossible() && !ai->HasAura("dire bear form", GetTarget()); + } + virtual bool isUseful() { + return CastBuffSpellAction::isUseful() && !ai->HasAura("dire bear form", GetTarget()); + } + }; + + class CastDireBearFormAction : public CastBuffSpellAction { + public: + CastDireBearFormAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "dire bear form") {} + + virtual NextAction** getAlternatives() { + return NextAction::merge(NextAction::array(0, new NextAction("bear form"), NULL), CastSpellAction::getAlternatives()); + } + }; + + class CastCatFormAction : public CastBuffSpellAction { + public: + CastCatFormAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "cat form") {} + }; + + class CastTreeFormAction : public CastBuffSpellAction { + public: + CastTreeFormAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "tree of life") {} + }; + + class CastMoonkinFormAction : public CastBuffSpellAction { + public: + CastMoonkinFormAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "moonkin form") {} + }; + + class CastCasterFormAction : public CastBuffSpellAction { + public: + CastCasterFormAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "caster form") {} + + virtual bool isUseful() { + return ai->HasAnyAuraOf(GetTarget(), "dire bear form", "bear form", "cat form", "travel form", "aquatic form", + "flight form", "swift flight form", "moonkin form", "tree of life", NULL); + } + virtual bool isPossible() { return true; } + + virtual bool Execute(Event event); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidTriggers.cpp b/src/modules/Bots/playerbot/strategy/druid/DruidTriggers.cpp new file mode 100644 index 0000000000..c41d94d839 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidTriggers.cpp @@ -0,0 +1,7 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "DruidTriggers.h" +//#include "DruidActions.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/druid/DruidTriggers.h b/src/modules/Bots/playerbot/strategy/druid/DruidTriggers.h new file mode 100644 index 0000000000..1c0d4d4661 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/DruidTriggers.h @@ -0,0 +1,127 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai { + class MarkOfTheWildOnPartyTrigger : public BuffOnPartyTrigger + { + public: + MarkOfTheWildOnPartyTrigger(PlayerbotAI* ai) : BuffOnPartyTrigger(ai, "mark of the wild") {} + }; + + class MarkOfTheWildTrigger : public BuffTrigger + { + public: + MarkOfTheWildTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "mark of the wild") {} + }; + + class ThornsTrigger : public BuffTrigger + { + public: + ThornsTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "thorns") {} + }; + + class RakeTrigger : public DebuffTrigger + { + public: + RakeTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "rake") {} + }; + + class InsectSwarmTrigger : public DebuffTrigger + { + public: + InsectSwarmTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "insect swarm") {} + }; + + class MoonfireTrigger : public DebuffTrigger + { + public: + MoonfireTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "moonfire") {} + }; + + class FaerieFireTrigger : public DebuffTrigger + { + public: + FaerieFireTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "faerie fire") {} + }; + + class FaerieFireFeralTrigger : public DebuffTrigger + { + public: + FaerieFireFeralTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "faerie fire (feral)") {} + }; + + class BashInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + BashInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "bash") {} + }; + + class TigersFuryTrigger : public BoostTrigger + { + public: + TigersFuryTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "tiger's fury") {} + }; + + class NaturesGraspTrigger : public BoostTrigger + { + public: + NaturesGraspTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "nature's grasp") {} + }; + + class EntanglingRootsTrigger : public HasCcTargetTrigger + { + public: + EntanglingRootsTrigger(PlayerbotAI* ai) : HasCcTargetTrigger(ai, "entangling roots") {} + }; + + class CurePoisonTrigger : public NeedCureTrigger + { + public: + CurePoisonTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cure poison", DISPEL_POISON) {} + }; + + class PartyMemberCurePoisonTrigger : public PartyMemberNeedCureTrigger + { + public: + PartyMemberCurePoisonTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cure poison", DISPEL_POISON) {} + }; + + class BearFormTrigger : public BuffTrigger + { + public: + BearFormTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "bear form") {} + virtual bool IsActive() { return !ai->HasAnyAuraOf(bot, "bear form", "dire bear form", NULL); } + }; + + class TreeFormTrigger : public BuffTrigger + { + public: + TreeFormTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "tree of life") {} + virtual bool IsActive() { return !ai->HasAura("tree of life", bot); } + }; + + class CatFormTrigger : public BuffTrigger + { + public: + CatFormTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "cat form") {} + virtual bool IsActive() { return !ai->HasAura("cat form", bot); } + }; + + class EclipseSolarTrigger : public HasAuraTrigger + { + public: + EclipseSolarTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "eclipse (solar)") {} + }; + + class EclipseLunarTrigger : public HasAuraTrigger + { + public: + EclipseLunarTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "eclipse (lunar)") {} + }; + + class BashInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger + { + public: + BashInterruptEnemyHealerSpellTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "bash") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.cpp b/src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.cpp new file mode 100644 index 0000000000..f0038834e6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.cpp @@ -0,0 +1,90 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "FeralDruidStrategy.h" + +using namespace ai; + +class FeralDruidStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + FeralDruidStrategyActionNodeFactory() + { + creators["survival instincts"] = &survival_instincts; + creators["thorns"] = þs; + creators["cure poison"] = &cure_poison; + creators["cure poison on party"] = &cure_poison_on_party; + creators["abolish poison"] = &abolish_poison; + creators["abolish poison on party"] = &abolish_poison_on_party; + } +private: + static ActionNode* survival_instincts(PlayerbotAI* ai) + { + return new ActionNode ("survival instincts", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("barskin"), NULL), + /*C*/ NULL); + } + static ActionNode* thorns(PlayerbotAI* ai) + { + return new ActionNode ("thorns", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* cure_poison(PlayerbotAI* ai) + { + return new ActionNode ("cure poison", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* cure_poison_on_party(PlayerbotAI* ai) + { + return new ActionNode ("cure poison on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* abolish_poison(PlayerbotAI* ai) + { + return new ActionNode ("abolish poison", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* abolish_poison_on_party(PlayerbotAI* ai) + { + return new ActionNode ("abolish poison on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } +}; + +FeralDruidStrategy::FeralDruidStrategy(PlayerbotAI* ai) : GenericDruidStrategy(ai) +{ + actionNodeFactories.Add(new FeralDruidStrategyActionNodeFactory()); + actionNodeFactories.Add(new ShapeshiftDruidStrategyActionNodeFactory()); +} + +void FeralDruidStrategy::InitTriggers(std::list &triggers) +{ + GenericDruidStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "not facing target", + NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), NULL))); + + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); + + triggers.push_back(new TriggerNode( + "enemy too close for melee", + NextAction::array(0, new NextAction("move out of enemy contact", ACTION_NORMAL + 8), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("survival instincts", ACTION_EMERGENCY + 1), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.h b/src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.h new file mode 100644 index 0000000000..0ee4a8c077 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/FeralDruidStrategy.h @@ -0,0 +1,75 @@ +#pragma once + +#include "GenericDruidStrategy.h" +#include "DruidAiObjectContext.h" + +namespace ai +{ + class ShapeshiftDruidStrategyActionNodeFactory : public NamedObjectFactory + { + public: + ShapeshiftDruidStrategyActionNodeFactory() + { + creators["rejuvenation"] = &rejuvenation; + creators["regrowth"] = ®rowth; + creators["healing touch"] = &healing_touch; + creators["rejuvenation on party"] = &rejuvenation_on_party; + creators["regrowth on party"] = ®rowth_on_party; + creators["healing touch on party"] = &healing_touch_on_party; + } + private: + static ActionNode* regrowth(PlayerbotAI* ai) + { + return new ActionNode ("regrowth", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NextAction::array(0, new NextAction("healing touch"), NULL), + /*C*/ NextAction::array(0, new NextAction("melee", 10.0f), NULL)); + } + static ActionNode* rejuvenation(PlayerbotAI* ai) + { + return new ActionNode ("rejuvenation", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* healing_touch(PlayerbotAI* ai) + { + return new ActionNode ("healing touch", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* regrowth_on_party(PlayerbotAI* ai) + { + return new ActionNode ("regrowth on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NextAction::array(0, new NextAction("healing touch on party"), NULL), + /*C*/ NextAction::array(0, new NextAction("melee", 10.0f), NULL)); + } + static ActionNode* rejuvenation_on_party(PlayerbotAI* ai) + { + return new ActionNode ("rejuvenation on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* healing_touch_on_party(PlayerbotAI* ai) + { + return new ActionNode ("healing touch on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + }; + + class FeralDruidStrategy : public GenericDruidStrategy + { + protected: + FeralDruidStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_MELEE; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.cpp new file mode 100644 index 0000000000..bc7d8a14e3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.cpp @@ -0,0 +1,73 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DruidMultipliers.h" +#include "GenericDruidNonCombatStrategy.h" + +using namespace ai; + +class GenericDruidNonCombatStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericDruidNonCombatStrategyActionNodeFactory() + { + creators["mark of the wild"] = &mark_of_the_wild; + creators["mark of the wild on party"] = &mark_of_the_wild_on_party; + creators["innervate"] = &innervate; + } +private: + static ActionNode* mark_of_the_wild(PlayerbotAI* ai) + { + return new ActionNode ("mark of the wild", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* mark_of_the_wild_on_party(PlayerbotAI* ai) + { + return new ActionNode ("mark of the wild on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* innervate(PlayerbotAI* ai) + { + return new ActionNode ("innervate", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("drink"), NULL), + /*C*/ NULL); + } +}; + +GenericDruidNonCombatStrategy::GenericDruidNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericDruidNonCombatStrategyActionNodeFactory()); +} + +void GenericDruidNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "mark of the wild", + NextAction::array(0, new NextAction("mark of the wild", 12.0f), NULL))); + + triggers.push_back(new TriggerNode( + "mark of the wild on party", + NextAction::array(0, new NextAction("mark of the wild on party", 11.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cure poison", + NextAction::array(0, new NextAction("abolish poison", 21.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member cure poison", + NextAction::array(0, new NextAction("abolish poison on party", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member dead", + NextAction::array(0, new NextAction("revive", 22.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("innervate", ACTION_EMERGENCY + 5), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.h new file mode 100644 index 0000000000..82cba1587a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/GenericDruidNonCombatStrategy.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericDruidNonCombatStrategy : public NonCombatStrategy + { + public: + GenericDruidNonCombatStrategy(PlayerbotAI* ai); + virtual string getName() { return "nc"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.cpp b/src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.cpp new file mode 100644 index 0000000000..2d580ce848 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.cpp @@ -0,0 +1,132 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GenericDruidStrategy.h" +#include "DruidAiObjectContext.h" + +using namespace ai; + +class GenericDruidStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericDruidStrategyActionNodeFactory() + { + creators["melee"] = &melee; + creators["caster form"] = &caster_form; + creators["cure poison"] = &cure_poison; + creators["cure poison on party"] = &cure_poison_on_party; + creators["abolish poison"] = &abolish_poison; + creators["abolish poison on party"] = &abolish_poison_on_party; + creators["rebirth"] = &rebirth; + creators["entangling roots on cc"] = &entangling_roots_on_cc; + creators["innervate"] = &innervate; + } + +private: + static ActionNode* melee(PlayerbotAI* ai) + { + return new ActionNode ("melee", + /*P*/ NextAction::array(0, new NextAction("reach melee"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* caster_form(PlayerbotAI* ai) + { + return new ActionNode ("caster form", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* cure_poison(PlayerbotAI* ai) + { + return new ActionNode ("cure poison", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* cure_poison_on_party(PlayerbotAI* ai) + { + return new ActionNode ("cure poison on party", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* abolish_poison(PlayerbotAI* ai) + { + return new ActionNode ("abolish poison", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* abolish_poison_on_party(PlayerbotAI* ai) + { + return new ActionNode ("abolish poison on party", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* rebirth(PlayerbotAI* ai) + { + return new ActionNode ("rebirth", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* entangling_roots_on_cc(PlayerbotAI* ai) + { + return new ActionNode ("entangling roots on cc", + /*P*/ NextAction::array(0, new NextAction("caster form"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* innervate(PlayerbotAI* ai) + { + return new ActionNode ("innervate", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mana potion"), NULL), + /*C*/ NULL); + } +}; + +GenericDruidStrategy::GenericDruidStrategy(PlayerbotAI* ai) : CombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericDruidStrategyActionNodeFactory()); +} + +void GenericDruidStrategy::InitTriggers(std::list &triggers) +{ + CombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("regrowth", ACTION_MEDIUM_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1), NULL))); + + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("regrowth", ACTION_CRITICAL_HEAL + 2), new NextAction("healing touch", ACTION_CRITICAL_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member critical health", + NextAction::array(0, new NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 1), new NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 1), NULL))); + + + triggers.push_back(new TriggerNode( + "cure poison", + NextAction::array(0, new NextAction("abolish poison", ACTION_DISPEL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member cure poison", + NextAction::array(0, new NextAction("abolish poison on party", ACTION_DISPEL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "party member dead", + NextAction::array(0, new NextAction("rebirth", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("innervate", ACTION_EMERGENCY + 5), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.h b/src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.h new file mode 100644 index 0000000000..dc12a85d45 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/GenericDruidStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class AiObjectContext; + + class GenericDruidStrategy : public CombatStrategy + { + protected: + GenericDruidStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.cpp b/src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.cpp new file mode 100644 index 0000000000..319a78ceb8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.cpp @@ -0,0 +1,57 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DruidMultipliers.h" +#include "HealDruidStrategy.h" + +using namespace ai; + +class HealDruidStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + HealDruidStrategyActionNodeFactory() + { + } +private: +}; + +HealDruidStrategy::HealDruidStrategy(PlayerbotAI* ai) : GenericDruidStrategy(ai) +{ + actionNodeFactories.Add(new HealDruidStrategyActionNodeFactory()); +} + +void HealDruidStrategy::InitTriggers(std::list &triggers) +{ + GenericDruidStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), NULL))); + + triggers.push_back(new TriggerNode( + "tree form", + NextAction::array(0, new NextAction("tree form", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("regrowth", ACTION_MEDIUM_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "almost full health", + NextAction::array(0, new NextAction("rejuvenation", ACTION_LIGHT_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member almost full health", + NextAction::array(0, new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe heal", + NextAction::array(0, new NextAction("tranquility", ACTION_MEDIUM_HEAL + 3), NULL))); + + triggers.push_back(new TriggerNode( + "entangling roots", + NextAction::array(0, new NextAction("entangling roots on cc", ACTION_HIGH + 1), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.h b/src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.h new file mode 100644 index 0000000000..a0440ba4bf --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/druid/HealDruidStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "GenericDruidStrategy.h" + +namespace ai +{ + class HealDruidStrategy : public GenericDruidStrategy + { + public: + HealDruidStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "heal"; } + virtual int GetType() { return STRATEGY_TYPE_HEAL; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.cpp new file mode 100644 index 0000000000..dc1165595e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.cpp @@ -0,0 +1,13 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AttackEnemyPlayersStrategy.h" + +using namespace ai; + +void AttackEnemyPlayersStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "enemy player is attacking", + NextAction::array(0, new NextAction("attack enemy player", 61.0f), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.h b/src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.h new file mode 100644 index 0000000000..cd9ce7cf96 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/AttackEnemyPlayersStrategy.h @@ -0,0 +1,16 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class AttackEnemyPlayersStrategy : public NonCombatStrategy + { + public: + AttackEnemyPlayersStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "pvp"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.cpp new file mode 100644 index 0000000000..54b00ac743 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.cpp @@ -0,0 +1,14 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AttackRtiStrategy.h" + +using namespace ai; + + +void AttackRtiStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "no attackers", + NextAction::array(0, new NextAction("attack rti target", 60.0f), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.h b/src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.h new file mode 100644 index 0000000000..ad9662afdd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/AttackRtiStrategy.h @@ -0,0 +1,16 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class AttackRtiStrategy : public NonCombatStrategy + { + public: + AttackRtiStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "attack rti"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.cpp new file mode 100644 index 0000000000..485debbd5c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.cpp @@ -0,0 +1,13 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AttackWeakStrategy.h" + +using namespace ai; + +void AttackWeakStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "not least hp target active", + NextAction::array(0, new NextAction("attack least hp target", 60.0f), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.h b/src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.h new file mode 100644 index 0000000000..c6c20c25c2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/AttackWeakStrategy.h @@ -0,0 +1,16 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class AttackWeakStrategy : public NonCombatStrategy + { + public: + AttackWeakStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "attack weak"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.cpp new file mode 100644 index 0000000000..150f3bafd7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.cpp @@ -0,0 +1,42 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CastTimeStrategy.h" +#include "../actions/GenericSpellActions.h" + +using namespace ai; + +float CastTimeMultiplier::GetValue(Action* action) +{ + if (action == NULL) return 1.0f; + + uint8 targetHealth = AI_VALUE2(uint8, "health", "current target"); + string name = action->getName(); + + if (action->GetTarget() != AI_VALUE(Unit*, "current target")) + { + return 1.0f; + } + + if (targetHealth < sPlayerbotAIConfig.lowHealth && dynamic_cast(action)) + { + uint32 spellId = AI_VALUE2(uint32, "spell id", name); + const SpellEntry* const pSpellInfo = sSpellStore.LookupEntry(spellId); + + if (spellId && GetSpellCastTime(pSpellInfo) >= 3000) + { + return 0.0f; + } + else if (spellId && GetSpellCastTime(pSpellInfo) >= 1500) + { + return 0.5f; + } + } + + return 1.0f; +} + + +void CastTimeStrategy::InitMultipliers(std::list &multipliers) +{ + multipliers.push_back(new CastTimeMultiplier(ai)); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.h b/src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.h new file mode 100644 index 0000000000..a483fc0315 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/CastTimeStrategy.h @@ -0,0 +1,26 @@ +#pragma once + +namespace ai +{ + + class CastTimeMultiplier : public Multiplier + { + public: + CastTimeMultiplier(PlayerbotAI* ai) : Multiplier(ai, "cast time") {} + + public: + virtual float GetValue(Action* action); + }; + + class CastTimeStrategy : public Strategy + { + public: + CastTimeStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitMultipliers(std::list &multipliers); + virtual string getName() { return "cast time"; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp new file mode 100644 index 0000000000..efc3d703fd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp @@ -0,0 +1,176 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ChatCommandHandlerStrategy.h" + +using namespace ai; + +class ChatCommandActionNodeFactoryInternal : public NamedObjectFactory +{ +public: + ChatCommandActionNodeFactoryInternal() + { + creators["tank attack chat shortcut"] = &tank_attack_chat_shortcut; + } + +private: + static ActionNode* tank_attack_chat_shortcut(PlayerbotAI* ai) + { + return new ActionNode ("tank attack chat shortcut", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NextAction::array(0, new NextAction("attack my target", 100.0f), NULL)); + } +}; + +void ChatCommandHandlerStrategy::InitTriggers(std::list &triggers) +{ + PassTroughStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "rep", + NextAction::array(0, new NextAction("reputation", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "q", + NextAction::array(0, + new NextAction("query quest", relevance), + new NextAction("query item usage", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "add all loot", + NextAction::array(0, new NextAction("add all loot", relevance), new NextAction("loot", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "u", + NextAction::array(0, new NextAction("use", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "c", + NextAction::array(0, new NextAction("item count", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "e", + NextAction::array(0, new NextAction("equip", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "ue", + NextAction::array(0, new NextAction("unequip", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "t", + NextAction::array(0, new NextAction("trade", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "nt", + NextAction::array(0, new NextAction("trade", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "s", + NextAction::array(0, new NextAction("sell", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "b", + NextAction::array(0, new NextAction("buy", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "r", + NextAction::array(0, new NextAction("reward", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "attack", + NextAction::array(0, new NextAction("attack my target", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "accept", + NextAction::array(0, new NextAction("accept quest", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "follow", + NextAction::array(0, new NextAction("follow chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "stay", + NextAction::array(0, new NextAction("stay chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "flee", + NextAction::array(0, new NextAction("flee chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "tank attack", + NextAction::array(0, new NextAction("tank attack chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "grind", + NextAction::array(0, new NextAction("grind chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "talk", + NextAction::array(0, new NextAction("gossip hello", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "cast", + NextAction::array(0, new NextAction("cast custom spell", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "revive", + NextAction::array(0, new NextAction("spirit healer", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "runaway", + NextAction::array(0, new NextAction("runaway chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "warning", + NextAction::array(0, new NextAction("runaway chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "max dps", + NextAction::array(0, new NextAction("max dps chat shortcut", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "attackers", + NextAction::array(0, new NextAction("tell attackers", relevance), NULL))); +} + + + +ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* ai) : PassTroughStrategy(ai) +{ + actionNodeFactories.Add(new ChatCommandActionNodeFactoryInternal()); + + supported.push_back("quests"); + supported.push_back("stats"); + supported.push_back("leave"); + supported.push_back("reputation"); + supported.push_back("log"); + supported.push_back("los"); + supported.push_back("drop"); + supported.push_back("ll"); + supported.push_back("release"); + supported.push_back("teleport"); + supported.push_back("taxi"); + supported.push_back("repair"); + supported.push_back("talents"); + supported.push_back("spells"); + supported.push_back("co"); + supported.push_back("nc"); + supported.push_back("dead"); + supported.push_back("trainer"); + supported.push_back("chat"); + supported.push_back("home"); + supported.push_back("destroy"); + supported.push_back("reset ai"); + supported.push_back("emote"); + supported.push_back("buff"); + supported.push_back("help"); + supported.push_back("gb"); + supported.push_back("bank"); + supported.push_back("invite"); + supported.push_back("spell"); + supported.push_back("rti"); + supported.push_back("position"); + supported.push_back("summon"); + supported.push_back("who"); + supported.push_back("save mana"); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.h b/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.h new file mode 100644 index 0000000000..c8c93b2f03 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.h @@ -0,0 +1,15 @@ +#pragma once +#include "PassTroughStrategy.h" + +namespace ai +{ + class ChatCommandHandlerStrategy : public PassTroughStrategy + { + public: + ChatCommandHandlerStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "chat"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/CombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/CombatStrategy.cpp new file mode 100644 index 0000000000..bfdd6fb4fd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/CombatStrategy.cpp @@ -0,0 +1,12 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CombatStrategy.h" + +using namespace ai; + +void CombatStrategy::InitTriggers(list &triggers) +{ + triggers.push_back(new TriggerNode( + "invalid target", + NextAction::array(0, new NextAction("drop target", ACTION_HIGH + 9), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/CombatStrategy.h b/src/modules/Bots/playerbot/strategy/generic/CombatStrategy.h new file mode 100644 index 0000000000..475922f680 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/CombatStrategy.h @@ -0,0 +1,13 @@ +#pragma once + +namespace ai +{ + class CombatStrategy : public Strategy + { + public: + CombatStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual void InitTriggers(std::list &triggers); + virtual int GetType() { return STRATEGY_TYPE_COMBAT; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.cpp new file mode 100644 index 0000000000..bbb2e0d273 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.cpp @@ -0,0 +1,116 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ConserveManaStrategy.h" +#include "../../PlayerbotAIConfig.h" +#include "../actions/GenericSpellActions.h" +#include "../values/LastSpellCastValue.h" + +using namespace ai; + +float ConserveManaMultiplier::GetValue(Action* action) +{ + if (action == NULL) return 1.0f; + + uint8 health = AI_VALUE2(uint8, "health", "self target"); + uint8 targetHealth = AI_VALUE2(uint8, "health", "current target"); + uint8 mana = AI_VALUE2(uint8, "mana", "self target"); + bool hasMana = AI_VALUE2(bool, "has mana", "self target"); + bool mediumMana = hasMana && mana < sPlayerbotAIConfig.mediumMana; + + string name = action->getName(); + + if (health < sPlayerbotAIConfig.lowHealth) + { + return 1.0f; + } + + if (name == "melee" || name == "reach melee" || name == "reach spell") + { + return 1.0f; + } + + if (mediumMana && dynamic_cast(action)) + { + return 0.0f; + } + + if (action->GetTarget() != AI_VALUE(Unit*, "current target")) + { + return 1.0f; + } + + if (AI_VALUE(uint8, "balance") <= 50) + { + return 1.0f; + } + + if (targetHealth < sPlayerbotAIConfig.lowHealth && dynamic_cast(action)) + { + return 0.0f; + } + + if (mediumMana && dynamic_cast(action)) + { + return 0.0f; + } + + return 1.0f; +} + +float SaveManaMultiplier::GetValue(Action* action) +{ + if (action == NULL) + { + return 1.0f; + } + + double saveLevel = AI_VALUE(double, "mana save level"); + if (saveLevel <= 1.0) + { + return 1.0f; + } + + CastSpellAction* spellAction = dynamic_cast(action); + if (!spellAction) + { + return 1.0f; + } + + string spell = spellAction->getName(); + uint32 spellId = AI_VALUE2(uint32, "spell id", spell); + const SpellEntry* const spellInfo = sSpellStore.LookupEntry(spellId); + if (!spellInfo || spellInfo->powerType != POWER_MANA) + { + return 1.0f; + } + + int32 cost = spellInfo->manaCost; + if (spellInfo->ManaCostPercentage) + { + cost += spellInfo->ManaCostPercentage * bot->GetCreateMana() / 100; + } + + uint32 mana = bot->GetMaxPower(POWER_MANA); + double percent = (double)cost / (double)mana * 100.0f; + + time_t lastCastTime = AI_VALUE2(time_t, "last spell cast time", spell); + if (!lastCastTime) + { + return 1.0f; + } + + time_t elapsed = time(0) - lastCastTime; + if ((double)elapsed < 10 + pow(saveLevel, sqrt(percent))) + { + return 0.0f; + } + + return 1.0f; +} + + +void ConserveManaStrategy::InitMultipliers(std::list &multipliers) +{ + multipliers.push_back(new ConserveManaMultiplier(ai)); + multipliers.push_back(new SaveManaMultiplier(ai)); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.h b/src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.h new file mode 100644 index 0000000000..a20693420f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/ConserveManaStrategy.h @@ -0,0 +1,32 @@ +#pragma once + +namespace ai +{ + class ConserveManaMultiplier : public Multiplier + { + public: + ConserveManaMultiplier(PlayerbotAI* ai) : Multiplier(ai, "conserve mana") {} + + public: + virtual float GetValue(Action* action); + }; + + class SaveManaMultiplier : public Multiplier + { + public: + SaveManaMultiplier(PlayerbotAI* ai) : Multiplier(ai, "save mana") {} + + public: + virtual float GetValue(Action* action); + }; + + class ConserveManaStrategy : public Strategy + { + public: + ConserveManaStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitMultipliers(std::list &multipliers); + virtual string getName() { return "conserve mana"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/DeadStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/DeadStrategy.cpp new file mode 100644 index 0000000000..b10c636eb1 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DeadStrategy.cpp @@ -0,0 +1,23 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "../Strategy.h" +#include "DeadStrategy.h" + +using namespace ai; + +void DeadStrategy::InitTriggers(std::list &triggers) +{ + PassTroughStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "dead", + NextAction::array(0, new NextAction("revive from corpse", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "resurrect request", + NextAction::array(0, new NextAction("accept resurrect", relevance), NULL))); +} + +DeadStrategy::DeadStrategy(PlayerbotAI* ai) : PassTroughStrategy(ai) +{ +} diff --git a/src/modules/Bots/playerbot/strategy/generic/DeadStrategy.h b/src/modules/Bots/playerbot/strategy/generic/DeadStrategy.h new file mode 100644 index 0000000000..4008570dd6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DeadStrategy.h @@ -0,0 +1,15 @@ +#pragma once +#include "PassTroughStrategy.h" + +namespace ai +{ + class DeadStrategy : public PassTroughStrategy + { + public: + DeadStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "dead"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.cpp new file mode 100644 index 0000000000..6e6bba9cea --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.cpp @@ -0,0 +1,12 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DpsAoeStrategy.h" + +using namespace ai; + +void DpsAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "timer", + NextAction::array(0, new NextAction("dps assist", 50.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.h b/src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.h new file mode 100644 index 0000000000..61ac9b251b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DpsAoeStrategy.h @@ -0,0 +1,18 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class DpsAoeStrategy : public NonCombatStrategy + { + public: + DpsAoeStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "dps aoe"; } + virtual int GetType() { return STRATEGY_TYPE_DPS; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.cpp new file mode 100644 index 0000000000..1e1ffe16fe --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.cpp @@ -0,0 +1,15 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DpsAssistStrategy.h" + +using namespace ai; + +void DpsAssistStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "no attackers", + NextAction::array(0, new NextAction("dps assist", 50.0f), NULL))); +} + + + diff --git a/src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.h b/src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.h new file mode 100644 index 0000000000..213c8694a2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DpsAssistStrategy.h @@ -0,0 +1,16 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class DpsAssistStrategy : public NonCombatStrategy + { + public: + DpsAssistStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "dps assist"; } + virtual int GetType() { return STRATEGY_TYPE_DPS; } + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/DuelStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/DuelStrategy.cpp new file mode 100644 index 0000000000..d1b1cb1f8b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DuelStrategy.cpp @@ -0,0 +1,24 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DuelStrategy.h" + +using namespace ai; + +void DuelStrategy::InitTriggers(std::list &triggers) +{ + PassTroughStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "duel requested", + NextAction::array(0, new NextAction("accept duel", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "no attackers", + NextAction::array(0, new NextAction("attack duel opponent", 70.0f), NULL))); +} + + + +DuelStrategy::DuelStrategy(PlayerbotAI* ai) : PassTroughStrategy(ai) +{ +} diff --git a/src/modules/Bots/playerbot/strategy/generic/DuelStrategy.h b/src/modules/Bots/playerbot/strategy/generic/DuelStrategy.h new file mode 100644 index 0000000000..58284061fb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/DuelStrategy.h @@ -0,0 +1,15 @@ +#pragma once +#include "PassTroughStrategy.h" + +namespace ai +{ + class DuelStrategy : public PassTroughStrategy + { + public: + DuelStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "duel"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.cpp new file mode 100644 index 0000000000..945e353413 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.cpp @@ -0,0 +1,17 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "EmoteStrategy.h" + +using namespace ai; + + +void EmoteStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "random", + NextAction::array(0, new NextAction("emote", 1.0f), NULL))); + + triggers.push_back(new TriggerNode( + "seldom", + NextAction::array(0, new NextAction("suggest what to do", 1.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.h b/src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.h new file mode 100644 index 0000000000..7acbc704b4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/EmoteStrategy.h @@ -0,0 +1,16 @@ +#pragma once + +namespace ai +{ + class EmoteStrategy : public Strategy + { + public: + EmoteStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "emote"; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/FleeStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/FleeStrategy.cpp new file mode 100644 index 0000000000..2ecbc2bb89 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FleeStrategy.cpp @@ -0,0 +1,26 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "FleeStrategy.h" + +using namespace ai; + +void FleeStrategy::InitTriggers(list &triggers) +{ + triggers.push_back(new TriggerNode( + "panic", + NextAction::array(0, new NextAction("flee", ACTION_EMERGENCY + 9), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), NULL)));} + +void FleeFromAddsStrategy::InitTriggers(list &triggers) +{ + triggers.push_back(new TriggerNode( + "has nearest adds", + NextAction::array(0, new NextAction("runaway", 50.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/FleeStrategy.h b/src/modules/Bots/playerbot/strategy/generic/FleeStrategy.h new file mode 100644 index 0000000000..4aa96b9605 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FleeStrategy.h @@ -0,0 +1,21 @@ +#pragma once + +namespace ai +{ + class FleeStrategy : public Strategy + { + public: + FleeStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "flee"; }; + }; + + class FleeFromAddsStrategy : public Strategy + { + public: + FleeFromAddsStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "flee from adds"; }; + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.cpp new file mode 100644 index 0000000000..e406d108df --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +#include "playerbot.h" +#include "FollowLineStrategy.h" + +using namespace ai; + +NextAction** FollowLineStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("follow line", 1.0f), NULL); +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.h b/src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.h new file mode 100644 index 0000000000..79298dbf23 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FollowLineStrategy.h @@ -0,0 +1,13 @@ +#include "NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class FollowLineStrategy : public NonCombatStrategy + { + public: + FollowLineStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "follow line"; } + virtual NextAction** getDefaultActions(); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.cpp new file mode 100644 index 0000000000..8a7f62cc1a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.cpp @@ -0,0 +1,20 @@ +#include "botpch.h" +#include "playerbot.h" +#include "FollowMasterRandomStrategy.h" + +using namespace ai; + +void FollowMasterRandomStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "far from master", + NextAction::array(0, new NextAction("be near", 1.0f), NULL))); + + triggers.push_back(new TriggerNode( + "random", + NextAction::array(0, new NextAction("move random", 2.0f), NULL))); + + triggers.push_back(new TriggerNode( + "target in sight", + NextAction::array(0, new NextAction("stay combat",3.0f), NULL))); +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.h b/src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.h new file mode 100644 index 0000000000..c82dc6e196 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FollowMasterRandomStrategy.h @@ -0,0 +1,14 @@ +#include "NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class FollowMasterRandomStrategy : public NonCombatStrategy + { + public: + FollowMasterRandomStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "be near"; } + virtual void InitTriggers(std::list &triggers); + + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.cpp new file mode 100644 index 0000000000..75d231dc2f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.cpp @@ -0,0 +1,17 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "FollowMasterStrategy.h" + +using namespace ai; + +NextAction** FollowMasterStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("follow master", 1.0f), NULL); +} + +void FollowMasterStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "out of react range", + NextAction::array(0, new NextAction("tell out of react range", 10.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.h b/src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.h new file mode 100644 index 0000000000..80e1e0cc3b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/FollowMasterStrategy.h @@ -0,0 +1,16 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class FollowMasterStrategy : public NonCombatStrategy + { + public: + FollowMasterStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "follow master"; } + virtual NextAction** getDefaultActions(); + virtual void InitTriggers(std::list &triggers); + + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.cpp new file mode 100644 index 0000000000..ed7d374487 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.cpp @@ -0,0 +1,20 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GrindingStrategy.h" + +using namespace ai; + + +NextAction** GrindingStrategy::getDefaultActions() +{ + return NULL; +} + +void GrindingStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "no target", + NextAction::array(0, + new NextAction("attack anything", 5.0f), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.h b/src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.h new file mode 100644 index 0000000000..ce42140701 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/GrindingStrategy.h @@ -0,0 +1,20 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class GrindingStrategy : public NonCombatStrategy + { + public: + GrindingStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "grind"; } + virtual int GetType() { return STRATEGY_TYPE_DPS; } + NextAction** getDefaultActions(); + + public: + virtual void InitTriggers(std::list &triggers); + }; + + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/GuardStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/GuardStrategy.cpp new file mode 100644 index 0000000000..e93b78900f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/GuardStrategy.cpp @@ -0,0 +1,16 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GuardStrategy.h" + +using namespace ai; + + +NextAction** GuardStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("guard", 4.0f), NULL); +} + +void GuardStrategy::InitTriggers(std::list &triggers) +{ +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/GuardStrategy.h b/src/modules/Bots/playerbot/strategy/generic/GuardStrategy.h new file mode 100644 index 0000000000..8705ba3dca --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/GuardStrategy.h @@ -0,0 +1,19 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class GuardStrategy : public NonCombatStrategy + { + public: + GuardStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "guard"; } + NextAction** getDefaultActions(); + + public: + virtual void InitTriggers(std::list &triggers); + }; + + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/KiteStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/KiteStrategy.cpp new file mode 100644 index 0000000000..3370a65f05 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/KiteStrategy.cpp @@ -0,0 +1,16 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "KiteStrategy.h" + +using namespace ai; + +KiteStrategy::KiteStrategy(PlayerbotAI* ai) : Strategy(ai) +{ +} + +void KiteStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "has aggro", + NextAction::array(0, new NextAction("runaway", 51.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/KiteStrategy.h b/src/modules/Bots/playerbot/strategy/generic/KiteStrategy.h new file mode 100644 index 0000000000..e88c7e5634 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/KiteStrategy.h @@ -0,0 +1,15 @@ +#pragma once + +namespace ai +{ + class KiteStrategy : public Strategy + { + public: + KiteStrategy(PlayerbotAI* ai); + virtual string getName() { return "kite"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.cpp new file mode 100644 index 0000000000..48e3385165 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.cpp @@ -0,0 +1,29 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "LootNonCombatStrategy.h" + +using namespace ai; + +void LootNonCombatStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "loot available", + NextAction::array(0, new NextAction("loot", 6.0f), NULL))); + + triggers.push_back(new TriggerNode( + "far from loot target", + NextAction::array(0, new NextAction("move to loot", 7.0f), NULL))); + + triggers.push_back(new TriggerNode( + "can loot", + NextAction::array(0, new NextAction("open loot", 8.0f), NULL))); +} + +void GatherStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "no possible targets", + NextAction::array(0, new NextAction("add gathering loot", 2.0f), NULL))); +} + + diff --git a/src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.h new file mode 100644 index 0000000000..5eecd634db --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/LootNonCombatStrategy.h @@ -0,0 +1,24 @@ +#pragma once + +namespace ai +{ + class LootNonCombatStrategy : public Strategy + { + public: + LootNonCombatStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "loot"; } + }; + + class GatherStrategy : public Strategy + { + public: + GatherStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "gather"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.cpp new file mode 100644 index 0000000000..bd3dc02e22 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.cpp @@ -0,0 +1,23 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MeleeCombatStrategy.h" + +using namespace ai; + + +void MeleeCombatStrategy::InitTriggers(list &triggers) +{ + CombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "not facing target", + NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), NULL))); + + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); + + triggers.push_back(new TriggerNode( + "enemy too close for melee", + NextAction::array(0, new NextAction("move out of enemy contact", ACTION_NORMAL + 8), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.h b/src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.h new file mode 100644 index 0000000000..eeeb90a35b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/MeleeCombatStrategy.h @@ -0,0 +1,16 @@ +#include "CombatStrategy.h" +#include "../generic/CombatStrategy.h" +#pragma once + +namespace ai +{ + class MeleeCombatStrategy : public CombatStrategy + { + public: + MeleeCombatStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + virtual void InitTriggers(std::list &triggers); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_MELEE; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.cpp new file mode 100644 index 0000000000..667a280692 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.cpp @@ -0,0 +1,13 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MoveRandomStrategy.h" + +using namespace ai; + +void MoveRandomStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "random", + NextAction::array(0, new NextAction("move random", 1.0f), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.h b/src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.h new file mode 100644 index 0000000000..ff453bf62c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/MoveRandomStrategy.h @@ -0,0 +1,16 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class MoveRandomStrategy : public NonCombatStrategy + { + public: + MoveRandomStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "move random"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.cpp new file mode 100644 index 0000000000..e0b408c350 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.cpp @@ -0,0 +1,12 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "NonCombatStrategy.h" + +using namespace ai; + +void NonCombatStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "timer", + NextAction::array(0, new NextAction("check mount state", 1.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.h new file mode 100644 index 0000000000..57304fb518 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/NonCombatStrategy.h @@ -0,0 +1,12 @@ +#pragma once + +namespace ai +{ + class NonCombatStrategy : public Strategy + { + public: + NonCombatStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual int GetType() { return STRATEGY_TYPE_NONCOMBAT; } + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h b/src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h new file mode 100644 index 0000000000..14083d48bd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h @@ -0,0 +1,26 @@ +#pragma once + +namespace ai +{ + class PassTroughStrategy : public Strategy + { + public: + PassTroughStrategy(PlayerbotAI* ai, float relevance = 100.0f) : Strategy(ai), relevance(relevance) {} + + virtual void InitTriggers(std::list &triggers) + { + for (list::iterator i = supported.begin(); i != supported.end(); i++) + { + string s = i->c_str(); + + triggers.push_back(new TriggerNode( + s, + NextAction::array(0, new NextAction(s, relevance), NULL))); + } + } + + protected: + list supported; + float relevance; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.cpp new file mode 100644 index 0000000000..90a22791a4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.cpp @@ -0,0 +1,13 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PassiveStrategy.h" +#include "../PassiveMultiplier.h" + +using namespace ai; + + +void PassiveStrategy::InitMultipliers(std::list &multipliers) +{ + multipliers.push_back(new PassiveMultiplier(ai)); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.h b/src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.h new file mode 100644 index 0000000000..8e963885a7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/PassiveStrategy.h @@ -0,0 +1,16 @@ +#pragma once + +namespace ai +{ + class PassiveStrategy : public Strategy + { + public: + PassiveStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitMultipliers(std::list &multipliers); + virtual string getName() { return "passive"; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp new file mode 100644 index 0000000000..6e9a6d1b92 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp @@ -0,0 +1,54 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "../PassiveMultiplier.h" +#include "PullStrategy.h" + +using namespace ai; + +class MagePullMultiplier : public PassiveMultiplier +{ +public: + MagePullMultiplier(PlayerbotAI* ai, string action) : PassiveMultiplier(ai) + { + this->action = action; + } + +public: + virtual float GetValue(Action* action); + +private: + string action; +}; + +float MagePullMultiplier::GetValue(Action* action) +{ + if (!action) + { + return 1.0f; + } + + string name = action->getName(); + if (this->action == name || + name == "reach spell" || + name == "change strategy") + return 1.0f; + + return PassiveMultiplier::GetValue(action); +} + +NextAction** PullStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction(action, 105.0f), new NextAction("follow master", 104.0f), new NextAction("end pull", 103.0f), NULL); +} + +void PullStrategy::InitTriggers(std::list &triggers) +{ + RangedCombatStrategy::InitTriggers(triggers); +} + +void PullStrategy::InitMultipliers(std::list &multipliers) +{ + multipliers.push_back(new MagePullMultiplier(ai, action)); + RangedCombatStrategy::InitMultipliers(multipliers); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/PullStrategy.h b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.h new file mode 100644 index 0000000000..946d47c9f2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.h @@ -0,0 +1,24 @@ +#pragma once + +#include "RangedCombatStrategy.h" + +namespace ai +{ + class PullStrategy : public RangedCombatStrategy + { + public: + PullStrategy(PlayerbotAI* ai, string action) : RangedCombatStrategy(ai) + { + this->action = action; + } + + public: + virtual void InitTriggers(std::list &triggers); + virtual void InitMultipliers(std::list &multipliers); + virtual string getName() { return "pull"; } + virtual NextAction** getDefaultActions(); + + private: + string action; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/QuestStrategies.cpp b/src/modules/Bots/playerbot/strategy/generic/QuestStrategies.cpp new file mode 100644 index 0000000000..a33c6244a6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/QuestStrategies.cpp @@ -0,0 +1,69 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "QuestStrategies.h" + +using namespace ai; + +QuestStrategy::QuestStrategy(PlayerbotAI* ai) : PassTroughStrategy(ai) +{ + supported.push_back("accept quest"); +} + +void QuestStrategy::InitTriggers(std::list &triggers) +{ + PassTroughStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "quest share", + NextAction::array(0, new NextAction("accept quest share", relevance), NULL))); +} + + +void DefaultQuestStrategy::InitTriggers(std::list &triggers) +{ + QuestStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "use game object", + NextAction::array(0, + new NextAction("talk to quest giver", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "gossip hello", + NextAction::array(0, + new NextAction("talk to quest giver", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "complete quest", + NextAction::array(0, new NextAction("talk to quest giver", relevance), NULL))); +} + +DefaultQuestStrategy::DefaultQuestStrategy(PlayerbotAI* ai) : QuestStrategy(ai) +{ +} + + + +void AcceptAllQuestsStrategy::InitTriggers(std::list &triggers) +{ + QuestStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "use game object", + NextAction::array(0, + new NextAction("talk to quest giver", relevance), new NextAction("accept all quests", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "gossip hello", + NextAction::array(0, + new NextAction("talk to quest giver", relevance), new NextAction("accept all quests", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "complete quest", + NextAction::array(0, + new NextAction("talk to quest giver", relevance), new NextAction("accept all quests", relevance), NULL))); +} + +AcceptAllQuestsStrategy::AcceptAllQuestsStrategy(PlayerbotAI* ai) : QuestStrategy(ai) +{ +} diff --git a/src/modules/Bots/playerbot/strategy/generic/QuestStrategies.h b/src/modules/Bots/playerbot/strategy/generic/QuestStrategies.h new file mode 100644 index 0000000000..08423dd492 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/QuestStrategies.h @@ -0,0 +1,34 @@ +#pragma once +#include "PassTroughStrategy.h" + +namespace ai +{ + class QuestStrategy : public PassTroughStrategy + { + public: + QuestStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + }; + + class DefaultQuestStrategy : public QuestStrategy + { + public: + DefaultQuestStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "quest"; } + }; + + class AcceptAllQuestsStrategy : public QuestStrategy + { + public: + AcceptAllQuestsStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "accept all quests"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.cpp new file mode 100644 index 0000000000..640e7cdd0d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.cpp @@ -0,0 +1,39 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RacialsStrategy.h" + +using namespace ai; + + +class RacialsStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + RacialsStrategyActionNodeFactory() + { + creators["lifeblood"] = &lifeblood; + } +private: + static ActionNode* lifeblood(PlayerbotAI* ai) + { + return new ActionNode ("lifeblood", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("gift of the naaru"), NULL), + /*C*/ NULL); + } +}; + +void RacialsStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("lifeblood", 71.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("arcane torrent", ACTION_EMERGENCY + 6), NULL))); +} + +RacialsStrategy::RacialsStrategy(PlayerbotAI* ai) : Strategy(ai) +{ + actionNodeFactories.Add(new RacialsStrategyActionNodeFactory()); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.h b/src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.h new file mode 100644 index 0000000000..6bddf2989e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/RacialsStrategy.h @@ -0,0 +1,15 @@ +#pragma once + +namespace ai +{ + class RacialsStrategy : public Strategy + { + public: + RacialsStrategy(PlayerbotAI* ai); + virtual string getName() { return "racials"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.cpp new file mode 100644 index 0000000000..96ddb809b3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.cpp @@ -0,0 +1,15 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RangedCombatStrategy.h" + +using namespace ai; + + +void RangedCombatStrategy::InitTriggers(list &triggers) +{ + CombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.h b/src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.h new file mode 100644 index 0000000000..a00cbc1c38 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/RangedCombatStrategy.h @@ -0,0 +1,15 @@ +#include "CombatStrategy.h" +#pragma once + +namespace ai +{ + class RangedCombatStrategy : public CombatStrategy + { + public: + RangedCombatStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + virtual void InitTriggers(std::list &triggers); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_RANGED; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.cpp new file mode 100644 index 0000000000..1d235e9594 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.cpp @@ -0,0 +1,18 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RunawayStrategy.h" + +using namespace ai; + + +NextAction** RunawayStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("runaway", 50.0f), NULL); +} + +void RunawayStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "enemy too close for spell", + NextAction::array(0, new NextAction("runaway", 50.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.h b/src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.h new file mode 100644 index 0000000000..d1c3ef50f4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/RunawayStrategy.h @@ -0,0 +1,16 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class RunawayStrategy : public NonCombatStrategy + { + public: + RunawayStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "runaway"; } + virtual NextAction** getDefaultActions(); + virtual void InitTriggers(std::list &triggers); + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.cpp new file mode 100644 index 0000000000..46f9afbd18 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.cpp @@ -0,0 +1,11 @@ +#include "botpch.h" +#include "playerbot.h" +#include "StayCircleStrategy.h" + +using namespace ai; + + +NextAction** StayCircleStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("stay circle", 50.0f), NULL); +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.h b/src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.h new file mode 100644 index 0000000000..95b04f0b57 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayCircleStrategy.h @@ -0,0 +1,14 @@ +#include "NonCombatStrategy.h" +#pragma once + +namespace ai +{ + + class StayCircleStrategy : public NonCombatStrategy + { + public: + StayCircleStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "stay circle"; } + virtual NextAction** getDefaultActions(); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.cpp new file mode 100644 index 0000000000..7688ab4ee6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +#include "playerbot.h" +#include "StayCombatStrategy.h" + +using namespace ai; + +NextAction** StayCombatStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("stay combat", 1.0f), NULL); +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.h b/src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.h new file mode 100644 index 0000000000..d89b8ee4c0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayCombatStrategy.h @@ -0,0 +1,13 @@ +#include "NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class StayCombatStrategy : public NonCombatStrategy + { + public: + StayCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "stay combat"; } + virtual NextAction** getDefaultActions(); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.cpp new file mode 100644 index 0000000000..e2851b9a1e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +#include "playerbot.h" +#include "StayLineStrategy.h" + +using namespace ai; + +NextAction** StayLineStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("stay line", 50.0f), NULL); +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.h b/src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.h new file mode 100644 index 0000000000..5c112b850f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayLineStrategy.h @@ -0,0 +1,14 @@ +#pragma once +#include "PassTroughStrategy.h" +#include "NonCombatStrategy.h" + +namespace ai +{ + class StayLineStrategy : public NonCombatStrategy + { + public: + StayLineStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "stay line"; } + virtual NextAction** getDefaultActions(); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/generic/StayStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/StayStrategy.cpp new file mode 100644 index 0000000000..291b750589 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayStrategy.cpp @@ -0,0 +1,11 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "StayStrategy.h" + +using namespace ai; + +NextAction** StayStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("stay", 1.0f), NULL); +} + diff --git a/src/modules/Bots/playerbot/strategy/generic/StayStrategy.h b/src/modules/Bots/playerbot/strategy/generic/StayStrategy.h new file mode 100644 index 0000000000..d9f4229e53 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/StayStrategy.h @@ -0,0 +1,14 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class StayStrategy : public NonCombatStrategy + { + public: + StayStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "stay"; } + virtual NextAction** getDefaultActions(); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.cpp new file mode 100644 index 0000000000..5a407f73d4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.cpp @@ -0,0 +1,12 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TankAoeStrategy.h" + +using namespace ai; + +void TankAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "tank aoe", + NextAction::array(0, new NextAction("tank assist", 50.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.h b/src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.h new file mode 100644 index 0000000000..f9ed2fb730 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/TankAoeStrategy.h @@ -0,0 +1,18 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class TankAoeStrategy : public NonCombatStrategy + { + public: + TankAoeStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "tank aoe"; } + virtual int GetType() { return STRATEGY_TYPE_TANK; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.cpp new file mode 100644 index 0000000000..7ebac23759 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.cpp @@ -0,0 +1,13 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TankAssistStrategy.h" + +using namespace ai; + + +void TankAssistStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "no attackers", + NextAction::array(0, new NextAction("tank assist", 50.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.h b/src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.h new file mode 100644 index 0000000000..3ecbbb9490 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/TankAssistStrategy.h @@ -0,0 +1,17 @@ +#include "../generic/NonCombatStrategy.h" +#pragma once + +namespace ai +{ + class TankAssistStrategy : public NonCombatStrategy + { + public: + TankAssistStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "tank assist"; } + virtual int GetType() { return STRATEGY_TYPE_TANK; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.cpp new file mode 100644 index 0000000000..32a1e9524f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.cpp @@ -0,0 +1,13 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TellTargetStrategy.h" + +using namespace ai; + + +void TellTargetStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "target changed", + NextAction::array(0, new NextAction("tell target", 51.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.h b/src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.h new file mode 100644 index 0000000000..22b2e2f2e8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/TellTargetStrategy.h @@ -0,0 +1,16 @@ +#pragma once + +namespace ai +{ + class TellTargetStrategy : public Strategy + { + public: + TellTargetStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "TellTarget"; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.cpp new file mode 100644 index 0000000000..4b3554459e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.cpp @@ -0,0 +1,38 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ThreatStrategy.h" +#include "../../PlayerbotAIConfig.h" +#include "../actions/GenericSpellActions.h" + +using namespace ai; + +float ThreatMultiplier::GetValue(Action* action) +{ + if (action == NULL || action->getThreatType() == ACTION_THREAT_NONE) + { + return 1.0f; + } + + if (action->getThreatType() == ACTION_THREAT_AOE) + { + uint8 threat = AI_VALUE2(uint8, "threat", "aoe"); + if (threat >= 90) + { + return 0.0f; + } + } + + uint8 threat = AI_VALUE2(uint8, "threat", "current target"); + + if (threat >= 90) + { + return 0.0f; + } + + return 1.0f; +} + +void ThreatStrategy::InitMultipliers(std::list &multipliers) +{ + multipliers.push_back(new ThreatMultiplier(ai)); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.h b/src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.h new file mode 100644 index 0000000000..406f43320a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/ThreatStrategy.h @@ -0,0 +1,25 @@ +#pragma once + +namespace ai +{ + class ThreatMultiplier : public Multiplier + { + public: + ThreatMultiplier(PlayerbotAI* ai) : Multiplier(ai, "threat") {} + + public: + virtual float GetValue(Action* action); + }; + + class ThreatStrategy : public Strategy + { + public: + ThreatStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitMultipliers(std::list &multipliers); + virtual string getName() { return "threat"; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.cpp new file mode 100644 index 0000000000..081ed1c6ee --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.cpp @@ -0,0 +1,18 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "UseFoodStrategy.h" + +using namespace ai; + +void UseFoodStrategy::InitTriggers(std::list &triggers) +{ + Strategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("food", 2.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("drink", 2.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.h b/src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.h new file mode 100644 index 0000000000..b68ab35e77 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/UseFoodStrategy.h @@ -0,0 +1,15 @@ +#pragma once + +namespace ai +{ + class UseFoodStrategy : public Strategy + { + public: + UseFoodStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "food"; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.cpp new file mode 100644 index 0000000000..4abcf746f8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.cpp @@ -0,0 +1,18 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "UsePotionsStrategy.h" + +using namespace ai; + +void UsePotionsStrategy::InitTriggers(std::list &triggers) +{ + Strategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("healing potion", ACTION_MEDIUM_HEAL), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("mana potion", ACTION_EMERGENCY), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.h b/src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.h new file mode 100644 index 0000000000..b48f89f98d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/UsePotionsStrategy.h @@ -0,0 +1,15 @@ +#pragma once + +namespace ai +{ + class UsePotionsStrategy : public Strategy + { + public: + UsePotionsStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "potions"; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.cpp new file mode 100644 index 0000000000..032c19a7b0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -0,0 +1,116 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WorldPacketHandlerStrategy.h" + +using namespace ai; + +void WorldPacketHandlerStrategy::InitTriggers(std::list &triggers) +{ + PassTroughStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "group invite", + NextAction::array(0, new NextAction("accept invitation", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "group set leader", + NextAction::array(0, new NextAction("leader", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "not enough money", + NextAction::array(0, new NextAction("tell not enough money", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "not enough reputation", + NextAction::array(0, new NextAction("tell not enough reputation", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "cannot equip", + NextAction::array(0, new NextAction("tell cannot equip", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "use game object", + NextAction::array(0, + new NextAction("add loot", relevance), + new NextAction("use meeting stone", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "gossip hello", + NextAction::array(0, + new NextAction("trainer", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "activate taxi", + NextAction::array(0, new NextAction("remember taxi", relevance), new NextAction("taxi", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "taxi done", + NextAction::array(0, new NextAction("taxi", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "trade status", + NextAction::array(0, new NextAction("accept trade", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "area trigger", + NextAction::array(0, new NextAction("reach area trigger", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "within area trigger", + NextAction::array(0, new NextAction("area trigger", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "loot response", + NextAction::array(0, new NextAction("store loot", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "item push result", + NextAction::array(0, new NextAction("query item usage", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "ready check finished", + NextAction::array(0, new NextAction("finish ready check", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "no possible targets", + NextAction::array(0, new NextAction("lfg join", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "seldom", + NextAction::array(0, new NextAction("lfg leave", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "lfg proposal", + NextAction::array(0, new NextAction("lfg accept", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "lfg proposal active", + NextAction::array(0, new NextAction("lfg accept", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "often", + NextAction::array(0, new NextAction("security check", relevance), NULL))); + + triggers.push_back(new TriggerNode( + "guild invite", + NextAction::array(0, new NextAction("guild accept", relevance), NULL))); +} + +WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* ai) : PassTroughStrategy(ai) +{ + 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"); + supported.push_back("lfg role check"); +} + + +void ReadyCheckStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "timer", + NextAction::array(0, new NextAction("ready check", relevance), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.h b/src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.h new file mode 100644 index 0000000000..6a5a44d83e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/generic/WorldPacketHandlerStrategy.h @@ -0,0 +1,25 @@ +#pragma once +#include "PassTroughStrategy.h" + +namespace ai +{ + class WorldPacketHandlerStrategy : public PassTroughStrategy + { + public: + WorldPacketHandlerStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "default"; } + }; + + class ReadyCheckStrategy : public PassTroughStrategy + { + public: + ReadyCheckStrategy(PlayerbotAI* ai) : PassTroughStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "ready check"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.cpp b/src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.cpp new file mode 100644 index 0000000000..4dfb022eb6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.cpp @@ -0,0 +1,118 @@ +#include "botpch.h" +#include "../../playerbot.h" + +#include "HunterMultipliers.h" +#include "DpsHunterStrategy.h" + +using namespace ai; + +class DpsHunterStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + DpsHunterStrategyActionNodeFactory() + { + creators["aimed shot"] = &aimed_shot; + creators["chimera shot"] = &chimera_shot; + creators["explosive shot"] = &explosive_shot; + creators["concussive shot"] = &concussive_shot; + creators["viper sting"] = &viper_sting; + } +private: + static ActionNode* viper_sting(PlayerbotAI* ai) + { + return new ActionNode ("viper sting", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mana potion", 10.0f), NULL), + /*C*/ NULL); + } + static ActionNode* aimed_shot(PlayerbotAI* ai) + { + return new ActionNode ("aimed shot", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("chimera shot", 10.0f), NULL), + /*C*/ NULL); + } + static ActionNode* chimera_shot(PlayerbotAI* ai) + { + return new ActionNode ("chimera shot", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("arcane shot", 10.0f), NULL), + /*C*/ NULL); + } + static ActionNode* explosive_shot(PlayerbotAI* ai) + { + return new ActionNode ("explosive shot", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("aimed shot"), NULL), + /*C*/ NULL); + } + static ActionNode* concussive_shot(PlayerbotAI* ai) + { + return new ActionNode ("concussive shot", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NextAction::array(0, new NextAction("wyvern sting", 11.0f), NULL)); + } + +}; + +DpsHunterStrategy::DpsHunterStrategy(PlayerbotAI* ai) : GenericHunterStrategy(ai) +{ + actionNodeFactories.Add(new DpsHunterStrategyActionNodeFactory()); +} + +NextAction** DpsHunterStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("explosive shot", 11.0f), new NextAction("auto shot", 10.0f), NULL); +} + +void DpsHunterStrategy::InitTriggers(std::list &triggers) +{ + GenericHunterStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "black arrow", + NextAction::array(0, new NextAction("black arrow", 51.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("viper sting", ACTION_EMERGENCY + 5), NULL))); + + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("call pet", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "hunters pet low health", + NextAction::array(0, new NextAction("mend pet", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "hunter's mark", + NextAction::array(0, new NextAction("hunter's mark", 52.0f), NULL))); + + triggers.push_back(new TriggerNode( + "freezing trap", + NextAction::array(0, new NextAction("freezing trap", 83.0f), NULL))); +} + +void DpsAoeHunterStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("multi-shot", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, new NextAction("volley", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "serpent sting on attacker", + NextAction::array(0, new NextAction("serpent sting on attacker", 49.0f), NULL))); +} + +void DpsHunterDebuffStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "no stings", + NextAction::array(0, new NextAction("serpent sting", 50.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.h b/src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.h new file mode 100644 index 0000000000..4992e0e15e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/DpsHunterStrategy.h @@ -0,0 +1,39 @@ +#pragma once + +#include "GenericHunterStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class DpsHunterStrategy : public GenericHunterStrategy + { + public: + DpsHunterStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "dps"; } + virtual NextAction** getDefaultActions(); + + }; + + class DpsAoeHunterStrategy : public CombatStrategy + { + public: + DpsAoeHunterStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "aoe"; } + }; + + class DpsHunterDebuffStrategy : public CombatStrategy + { + public: + DpsHunterDebuffStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "dps debuff"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.cpp new file mode 100644 index 0000000000..0f5dc44852 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.cpp @@ -0,0 +1,58 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "HunterMultipliers.h" +#include "GenericHunterNonCombatStrategy.h" + +using namespace ai; + +class GenericHunterNonCombatStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericHunterNonCombatStrategyActionNodeFactory() + { + creators["rapid fire"] = &rapid_fire; + creators["boost"] = &rapid_fire; + creators["aspect of the pack"] = &aspect_of_the_pack; + } +private: + static ActionNode* rapid_fire(PlayerbotAI* ai) + { + return new ActionNode ("rapid fire", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("readiness"), NULL), + /*C*/ NULL); + } + static ActionNode* aspect_of_the_pack(PlayerbotAI* ai) + { + return new ActionNode ("aspect of the pack", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("aspect of the cheetah"), NULL), + /*C*/ NULL); + } +}; + +GenericHunterNonCombatStrategy::GenericHunterNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericHunterNonCombatStrategyActionNodeFactory()); +} + +void GenericHunterNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "trueshot aura", + NextAction::array(0, new NextAction("trueshot aura", 2.0f), NULL))); + + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("call pet", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "hunters pet dead", + NextAction::array(0, new NextAction("revive pet", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "hunters pet low health", + NextAction::array(0, new NextAction("mend pet", 60.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.h new file mode 100644 index 0000000000..d01486d6d5 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterNonCombatStrategy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericHunterNonCombatStrategy : public NonCombatStrategy + { + public: + GenericHunterNonCombatStrategy(PlayerbotAI* ai); + virtual string getName() { return "nc"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.cpp b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.cpp new file mode 100644 index 0000000000..8c404fc3c8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.cpp @@ -0,0 +1,66 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GenericHunterStrategy.h" +#include "HunterAiObjectContext.h" + +using namespace ai; + +class GenericHunterStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericHunterStrategyActionNodeFactory() + { + creators["rapid fire"] = &rapid_fire; + creators["boost"] = &rapid_fire; + creators["aspect of the pack"] = &aspect_of_the_pack; + creators["feign death"] = &feign_death; + } +private: + static ActionNode* rapid_fire(PlayerbotAI* ai) + { + return new ActionNode ("rapid fire", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("readiness"), NULL), + /*C*/ NULL); + } + static ActionNode* aspect_of_the_pack(PlayerbotAI* ai) + { + return new ActionNode ("aspect of the pack", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("aspect of the cheetah"), NULL), + /*C*/ NULL); + } + static ActionNode* feign_death(PlayerbotAI* ai) + { + return new ActionNode ("feign death", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("flee"), NULL), + /*C*/ NULL); + } +}; + +GenericHunterStrategy::GenericHunterStrategy(PlayerbotAI* ai) : RangedCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericHunterStrategyActionNodeFactory()); +} + +void GenericHunterStrategy::InitTriggers(std::list &triggers) +{ + RangedCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy too close for spell", + NextAction::array(0, new NextAction("wing clip", 50.0f), new NextAction("flee",49.0f), new NextAction("concussive shot", 48.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium threat", + NextAction::array(0, new NextAction("feign death", 52.0f), NULL))); + + triggers.push_back(new TriggerNode( + "hunters pet low health", + NextAction::array(0, new NextAction("mend pet", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "rapid fire", + NextAction::array(0, new NextAction("rapid fire", 55.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.h b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.h new file mode 100644 index 0000000000..f2db28ceab --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/GenericHunterStrategy.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/RangedCombatStrategy.h" + +namespace ai +{ + class AiObjectContext; + + class GenericHunterStrategy : public RangedCombatStrategy + { + public: + GenericHunterStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "hunter"; } + }; +} + diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterActions.cpp b/src/modules/Bots/playerbot/strategy/hunter/HunterActions.cpp new file mode 100644 index 0000000000..5b0e78edf9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterActions.cpp @@ -0,0 +1,26 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "../actions/GenericActions.h" +#include "HunterActions.h" + +using namespace ai; + +bool CastSerpentStingAction::isUseful() +{ + return AI_VALUE2(uint8, "health", "current target") > 50; +} + +bool CastViperStingAction::isUseful() +{ + return AI_VALUE2(uint8, "mana", "self target") < 50 && AI_VALUE2(uint8, "mana", "current target") >= 30; +} + +bool CastAspectOfTheCheetahAction::isUseful() +{ + return !ai->HasAnyAuraOf(GetTarget(), "aspect of the cheetah", "aspect of the pack", NULL); +} + +Value* CastFreezingTrap::GetTargetValue() +{ + return context->GetValue("cc target", "freezing trap"); +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterActions.h b/src/modules/Bots/playerbot/strategy/hunter/HunterActions.h new file mode 100644 index 0000000000..ad4ed659f3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterActions.h @@ -0,0 +1,132 @@ +#pragma once + +#include "../actions/GenericActions.h" + +namespace ai +{ + BEGIN_RANGED_SPELL_ACTION(CastHuntersMarkAction, "hunter's mark") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastAutoShotAction, "auto shot") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastArcaneShotAction, "arcane shot") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastExplosiveShotAction, "explosive shot") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastAimedShotAction, "aimed shot") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastConcussiveShotAction, "concussive shot") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastDistractingShotAction, "distracting shot") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastMultiShotAction, "multi-shot") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastVolleyAction, "volley") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastSerpentStingAction, "serpent sting") + virtual bool isUseful(); + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastWyvernStingAction, "wyvern sting") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastViperStingAction, "viper sting") + virtual bool isUseful(); + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastScorpidStingAction, "scorpid sting") + END_SPELL_ACTION() + + class CastAspectOfTheHawkAction : public CastBuffSpellAction + { + public: + CastAspectOfTheHawkAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "aspect of the hawk") {} + }; + + class CastAspectOfTheWildAction : public CastBuffSpellAction + { + public: + CastAspectOfTheWildAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "aspect of the wild") {} + }; + + class CastAspectOfTheCheetahAction : public CastBuffSpellAction + { + public: + CastAspectOfTheCheetahAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "aspect of the cheetah") {} + virtual bool isUseful(); + }; + + class CastAspectOfThePackAction : public CastBuffSpellAction + { + public: + CastAspectOfThePackAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "aspect of the pack") {} + }; + + class CastCallPetAction : public CastBuffSpellAction + { + public: + CastCallPetAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "call pet") {} + }; + + class CastMendPetAction : public CastAuraSpellAction + { + public: + CastMendPetAction(PlayerbotAI* ai) : CastAuraSpellAction(ai, "mend pet") {} + virtual string GetTargetName() { return "pet target"; } + }; + + class CastRevivePetAction : public CastBuffSpellAction + { + public: + CastRevivePetAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "revive pet") {} + }; + + class CastTrueshotAuraAction : public CastBuffSpellAction + { + public: + CastTrueshotAuraAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "trueshot aura") {} + }; + + class CastFeignDeathAction : public CastBuffSpellAction + { + public: + CastFeignDeathAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "feign death") {} + }; + + class CastRapidFireAction : public CastBuffSpellAction + { + public: + CastRapidFireAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "rapid fire") {} + }; + + class CastFreezingTrap : public CastDebuffSpellAction + { + public: + CastFreezingTrap(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "freezing trap") {} + virtual Value* GetTargetValue(); + }; + + class CastWingClipAction : public CastMeleeSpellAction + { + public: + CastWingClipAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "wing clip") {} + virtual bool isUseful() + { + return CastMeleeSpellAction::isUseful() && !ai->HasAura(spell, GetTarget()); + } + }; + + class CastSerpentStingOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastSerpentStingOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "serpent sting") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.cpp new file mode 100644 index 0000000000..076d1ea101 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.cpp @@ -0,0 +1,183 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "HunterActions.h" +#include "HunterTriggers.h" +#include "HunterAiObjectContext.h" +#include "DpsHunterStrategy.h" +#include "GenericHunterNonCombatStrategy.h" +#include "HunterBuffStrategies.h" +#include "../NamedObjectContext.h" + +using namespace ai; + + +namespace ai +{ + namespace hunter + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["dps"] = &hunter::StrategyFactoryInternal::dps; + creators["nc"] = &hunter::StrategyFactoryInternal::nc; + creators["aoe"] = &hunter::StrategyFactoryInternal::aoe; + creators["dps debuff"] = &hunter::StrategyFactoryInternal::dps_debuff; + } + + private: + static Strategy* aoe(PlayerbotAI* ai) { return new DpsAoeHunterStrategy(ai); } + static Strategy* dps(PlayerbotAI* ai) { return new DpsHunterStrategy(ai); } + static Strategy* nc(PlayerbotAI* ai) { return new GenericHunterNonCombatStrategy(ai); } + static Strategy* dps_debuff(PlayerbotAI* ai) { return new DpsHunterDebuffStrategy(ai); } + }; + + class BuffStrategyFactoryInternal : public NamedObjectContext + { + public: + BuffStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["bspeed"] = &hunter::BuffStrategyFactoryInternal::bspeed; + creators["bdps"] = &hunter::BuffStrategyFactoryInternal::bdps; + creators["bmana"] = &hunter::BuffStrategyFactoryInternal::bmana; + creators["rnature"] = &hunter::BuffStrategyFactoryInternal::rnature; + } + + private: + static Strategy* bspeed(PlayerbotAI* ai) { return new HunterBuffSpeedStrategy(ai); } + static Strategy* bdps(PlayerbotAI* ai) { return new HunterBuffDpsStrategy(ai); } + static Strategy* bmana(PlayerbotAI* ai) { return new HunterBuffManaStrategy(ai); } + static Strategy* rnature(PlayerbotAI* ai) { return new HunterNatureResistanceStrategy(ai); } + }; + }; +}; + + +namespace ai +{ + namespace hunter + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["aspect of the viper"] = &TriggerFactoryInternal::aspect_of_the_viper; + creators["black arrow"] = &TriggerFactoryInternal::black_arrow; + creators["no stings"] = &TriggerFactoryInternal::NoStings; + creators["hunters pet dead"] = &TriggerFactoryInternal::hunters_pet_dead; + creators["hunters pet low health"] = &TriggerFactoryInternal::hunters_pet_low_health; + creators["hunter's mark"] = &TriggerFactoryInternal::hunters_mark; + creators["freezing trap"] = &TriggerFactoryInternal::freezing_trap; + creators["aspect of the pack"] = &TriggerFactoryInternal::aspect_of_the_pack; + creators["rapid fire"] = &TriggerFactoryInternal::rapid_fire; + creators["aspect of the hawk"] = &TriggerFactoryInternal::aspect_of_the_hawk; + creators["aspect of the wild"] = &TriggerFactoryInternal::aspect_of_the_wild; + creators["aspect of the viper"] = &TriggerFactoryInternal::aspect_of_the_viper; + creators["trueshot aura"] = &TriggerFactoryInternal::trueshot_aura; + creators["serpent sting on attacker"] = &TriggerFactoryInternal::serpent_sting_on_attacker; + } + + private: + static Trigger* serpent_sting_on_attacker(PlayerbotAI* ai) { return new SerpentStingOnAttackerTrigger(ai); } + static Trigger* trueshot_aura(PlayerbotAI* ai) { return new TrueshotAuraTrigger(ai); } + static Trigger* aspect_of_the_viper(PlayerbotAI* ai) { return new HunterAspectOfTheViperTrigger(ai); } + static Trigger* black_arrow(PlayerbotAI* ai) { return new BlackArrowTrigger(ai); } + static Trigger* NoStings(PlayerbotAI* ai) { return new HunterNoStingsActiveTrigger(ai); } + static Trigger* hunters_pet_dead(PlayerbotAI* ai) { return new HuntersPetDeadTrigger(ai); } + static Trigger* hunters_pet_low_health(PlayerbotAI* ai) { return new HuntersPetLowHealthTrigger(ai); } + static Trigger* hunters_mark(PlayerbotAI* ai) { return new HuntersMarkTrigger(ai); } + static Trigger* freezing_trap(PlayerbotAI* ai) { return new FreezingTrapTrigger(ai); } + static Trigger* aspect_of_the_pack(PlayerbotAI* ai) { return new HunterAspectOfThePackTrigger(ai); } + static Trigger* rapid_fire(PlayerbotAI* ai) { return new RapidFireTrigger(ai); } + static Trigger* aspect_of_the_hawk(PlayerbotAI* ai) { return new HunterAspectOfTheHawkTrigger(ai); } + static Trigger* aspect_of_the_wild(PlayerbotAI* ai) { return new HunterAspectOfTheWildTrigger(ai); } + }; + }; +}; + + + +namespace ai +{ + namespace hunter + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["auto shot"] = &AiObjectContextInternal::auto_shot; + creators["aimed shot"] = &AiObjectContextInternal::aimed_shot; + creators["explosive shot"] = &AiObjectContextInternal::explosive_shot; + creators["arcane shot"] = &AiObjectContextInternal::arcane_shot; + creators["concussive shot"] = &AiObjectContextInternal::concussive_shot; + creators["distracting shot"] = &AiObjectContextInternal::distracting_shot; + creators["multi-shot"] = &AiObjectContextInternal::multi_shot; + creators["volley"] = &AiObjectContextInternal::volley; + creators["serpent sting"] = &AiObjectContextInternal::serpent_sting; + creators["serpent sting on attacker"] = &AiObjectContextInternal::serpent_sting_on_attacker; + creators["wyvern sting"] = &AiObjectContextInternal::wyvern_sting; + creators["viper sting"] = &AiObjectContextInternal::viper_sting; + creators["scorpid sting"] = &AiObjectContextInternal::scorpid_sting; + creators["hunter's mark"] = &AiObjectContextInternal::hunters_mark; + creators["mend pet"] = &AiObjectContextInternal::mend_pet; + creators["revive pet"] = &AiObjectContextInternal::revive_pet; + creators["call pet"] = &AiObjectContextInternal::call_pet; + creators["freezing trap"] = &AiObjectContextInternal::freezing_trap; + creators["rapid fire"] = &AiObjectContextInternal::rapid_fire; + creators["boost"] = &AiObjectContextInternal::rapid_fire; + creators["aspect of the hawk"] = &AiObjectContextInternal::aspect_of_the_hawk; + creators["aspect of the wild"] = &AiObjectContextInternal::aspect_of_the_wild; + creators["aspect of the pack"] = &AiObjectContextInternal::aspect_of_the_pack; + creators["aspect of the cheetah"] = &AiObjectContextInternal::aspect_of_the_cheetah; + creators["trueshot aura"] = &AiObjectContextInternal::trueshot_aura; + creators["feign death"] = &AiObjectContextInternal::feign_death; + creators["wing clip"] = &AiObjectContextInternal::wing_clip; + } + + private: + static Action* feign_death(PlayerbotAI* ai) { return new CastFeignDeathAction(ai); } + static Action* trueshot_aura(PlayerbotAI* ai) { return new CastTrueshotAuraAction(ai); } + static Action* auto_shot(PlayerbotAI* ai) { return new CastAutoShotAction(ai); } + static Action* aimed_shot(PlayerbotAI* ai) { return new CastAimedShotAction(ai); } + static Action* explosive_shot(PlayerbotAI* ai) { return new CastExplosiveShotAction(ai); } + static Action* arcane_shot(PlayerbotAI* ai) { return new CastArcaneShotAction(ai); } + static Action* concussive_shot(PlayerbotAI* ai) { return new CastConcussiveShotAction(ai); } + static Action* distracting_shot(PlayerbotAI* ai) { return new CastDistractingShotAction(ai); } + static Action* multi_shot(PlayerbotAI* ai) { return new CastMultiShotAction(ai); } + static Action* volley(PlayerbotAI* ai) { return new CastVolleyAction(ai); } + static Action* serpent_sting(PlayerbotAI* ai) { return new CastSerpentStingAction(ai); } + static Action* serpent_sting_on_attacker(PlayerbotAI* ai) { return new CastSerpentStingOnAttackerAction(ai); } + static Action* wyvern_sting(PlayerbotAI* ai) { return new CastWyvernStingAction(ai); } + static Action* viper_sting(PlayerbotAI* ai) { return new CastViperStingAction(ai); } + static Action* scorpid_sting(PlayerbotAI* ai) { return new CastScorpidStingAction(ai); } + static Action* hunters_mark(PlayerbotAI* ai) { return new CastHuntersMarkAction(ai); } + static Action* mend_pet(PlayerbotAI* ai) { return new CastMendPetAction(ai); } + static Action* revive_pet(PlayerbotAI* ai) { return new CastRevivePetAction(ai); } + static Action* call_pet(PlayerbotAI* ai) { return new CastCallPetAction(ai); } + static Action* freezing_trap(PlayerbotAI* ai) { return new CastFreezingTrap(ai); } + static Action* rapid_fire(PlayerbotAI* ai) { return new CastRapidFireAction(ai); } + static Action* aspect_of_the_hawk(PlayerbotAI* ai) { return new CastAspectOfTheHawkAction(ai); } + static Action* aspect_of_the_wild(PlayerbotAI* ai) { return new CastAspectOfTheWildAction(ai); } + static Action* aspect_of_the_pack(PlayerbotAI* ai) { return new CastAspectOfThePackAction(ai); } + static Action* aspect_of_the_cheetah(PlayerbotAI* ai) { return new CastAspectOfTheCheetahAction(ai); } + static Action* wing_clip(PlayerbotAI* ai) { return new CastWingClipAction(ai); } + }; + }; +}; + +HunterAiObjectContext::HunterAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::hunter::StrategyFactoryInternal()); + strategyContexts.Add(new ai::hunter::BuffStrategyFactoryInternal()); + actionContexts.Add(new ai::hunter::AiObjectContextInternal()); + triggerContexts.Add(new ai::hunter::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.h b/src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.h new file mode 100644 index 0000000000..8891a54894 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class HunterAiObjectContext : public AiObjectContext + { + public: + HunterAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.cpp b/src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.cpp new file mode 100644 index 0000000000..970ed690d3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.cpp @@ -0,0 +1,35 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "HunterMultipliers.h" +#include "HunterBuffStrategies.h" + +using namespace ai; + +void HunterBuffDpsStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "aspect of the hawk", + NextAction::array(0, new NextAction("aspect of the hawk", 90.0f), NULL))); +} + +void HunterNatureResistanceStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "aspect of the wild", + NextAction::array(0, new NextAction("aspect of the wild", 90.0f), NULL))); +} + + +void HunterBuffSpeedStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "aspect of the pack", + NextAction::array(0, new NextAction("aspect of the pack", 10.0f), NULL))); +} + +void HunterBuffManaStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "aspect of the viper", + NextAction::array(0, new NextAction("aspect of the viper", 10.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.h b/src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.h new file mode 100644 index 0000000000..7630b12292 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterBuffStrategies.h @@ -0,0 +1,47 @@ +#pragma once + +#include "GenericHunterStrategy.h" +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class HunterBuffSpeedStrategy : public NonCombatStrategy + { + public: + HunterBuffSpeedStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "bspeed"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + + class HunterBuffManaStrategy : public NonCombatStrategy + { + public: + HunterBuffManaStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "bmana"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + + class HunterBuffDpsStrategy : public NonCombatStrategy + { + public: + HunterBuffDpsStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "bdps"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + + class HunterNatureResistanceStrategy : public NonCombatStrategy + { + public: + HunterNatureResistanceStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "rnature"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.cpp b/src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.cpp new file mode 100644 index 0000000000..3efbca9616 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.cpp @@ -0,0 +1,5 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "HunterMultipliers.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.h b/src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.cpp b/src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.cpp new file mode 100644 index 0000000000..21df6ceed2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.cpp @@ -0,0 +1,29 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "HunterTriggers.h" +#include "HunterActions.h" + +using namespace ai; + +bool HunterNoStingsActiveTrigger::IsActive() +{ + Unit* target = AI_VALUE(Unit*, "current target"); + return target && AI_VALUE2(uint8, "health", "current target") > 40 && + !ai->HasAura("serpent sting", target) && + !ai->HasAura("scorpid sting", target) && + !ai->HasAura("viper sting", target); +} + +bool HuntersPetDeadTrigger::IsActive() +{ + Unit* pet = AI_VALUE(Unit*, "pet target"); + return pet && AI_VALUE2(bool, "dead", "pet target") && !AI_VALUE2(bool, "mounted", "self target"); +} + + +bool HuntersPetLowHealthTrigger::IsActive() +{ + Unit* pet = AI_VALUE(Unit*, "pet target"); + return pet && AI_VALUE2(uint8, "health", "pet target") < 40 && + !AI_VALUE2(bool, "dead", "pet target") && !AI_VALUE2(bool, "mounted", "self target"); +} diff --git a/src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.h b/src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.h new file mode 100644 index 0000000000..947426c857 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/hunter/HunterTriggers.h @@ -0,0 +1,86 @@ +#pragma once + +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + BEGIN_TRIGGER(HunterNoStingsActiveTrigger, Trigger) + END_TRIGGER() + + class HunterAspectOfTheHawkTrigger : public BuffTrigger + { + public: + HunterAspectOfTheHawkTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "aspect of the hawk") { + checkInterval = 1; + } + }; + + class HunterAspectOfTheWildTrigger : public BuffTrigger + { + public: + HunterAspectOfTheWildTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "aspect of the wild") { + checkInterval = 1; + } + }; + + class HunterAspectOfTheViperTrigger : public BuffTrigger + { + public: + HunterAspectOfTheViperTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "aspect of the viper") {} + virtual bool IsActive() + { + return SpellTrigger::IsActive() && !ai->HasAura(spell, GetTarget()); + } + }; + + class HunterAspectOfThePackTrigger : public BuffTrigger + { + public: + HunterAspectOfThePackTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "aspect of the pack") {} + virtual bool IsActive() { + return BuffTrigger::IsActive() && !ai->HasAura("aspect of the cheetah", GetTarget()); + }; + }; + + BEGIN_TRIGGER(HuntersPetDeadTrigger, Trigger) + END_TRIGGER() + + BEGIN_TRIGGER(HuntersPetLowHealthTrigger, Trigger) + END_TRIGGER() + + class BlackArrowTrigger : public DebuffTrigger + { + public: + BlackArrowTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "black arrow") {} + }; + + class HuntersMarkTrigger : public DebuffTrigger + { + public: + HuntersMarkTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "hunter's mark") {} + }; + + class FreezingTrapTrigger : public HasCcTargetTrigger + { + public: + FreezingTrapTrigger(PlayerbotAI* ai) : HasCcTargetTrigger(ai, "freezing trap") {} + }; + + class RapidFireTrigger : public BoostTrigger + { + public: + RapidFireTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "rapid fire") {} + }; + + class TrueshotAuraTrigger : public BuffTrigger + { + public: + TrueshotAuraTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "trueshot aura") {} + }; + + class SerpentStingOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + SerpentStingOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "serpent sting") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.cpp b/src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.cpp new file mode 100644 index 0000000000..8a9510cfbc --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.cpp @@ -0,0 +1,64 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MageMultipliers.h" +#include "ArcaneMageStrategy.h" + +using namespace ai; + +class ArcaneMageStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + ArcaneMageStrategyActionNodeFactory() + { + creators["arcane blast"] = &arcane_blast; + creators["arcane barrage"] = &arcane_barrage; + creators["arcane missiles"] = &arcane_missiles; + } +private: + static ActionNode* arcane_blast(PlayerbotAI* ai) + { + return new ActionNode ("arcane blast", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("arcane missiles"), NULL), + /*C*/ NULL); + } + static ActionNode* arcane_barrage(PlayerbotAI* ai) + { + return new ActionNode ("arcane barrage", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("arcane missiles"), NULL), + /*C*/ NULL); + } + static ActionNode* arcane_missiles(PlayerbotAI* ai) + { + return new ActionNode ("arcane missiles", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("shoot"), NULL), + /*C*/ NULL); + } +}; + +ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* ai) : GenericMageStrategy(ai) +{ + actionNodeFactories.Add(new ArcaneMageStrategyActionNodeFactory()); +} + +NextAction** ArcaneMageStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("arcane barrage", 10.0f), NULL); +} + +void ArcaneMageStrategy::InitTriggers(std::list &triggers) +{ + GenericMageStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "arcane blast", + NextAction::array(0, new NextAction("arcane blast", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "missile barrage", + NextAction::array(0, new NextAction("arcane missiles", 15.0f), NULL))); + +} + diff --git a/src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.h b/src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.h new file mode 100644 index 0000000000..ac053a821e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/ArcaneMageStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "GenericMageStrategy.h" + +namespace ai +{ + class ArcaneMageStrategy : public GenericMageStrategy + { + public: + ArcaneMageStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "arcane"; } + virtual NextAction** getDefaultActions(); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.cpp b/src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.cpp new file mode 100644 index 0000000000..8a361326b4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.cpp @@ -0,0 +1,44 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MageMultipliers.h" +#include "FireMageStrategy.h" + +using namespace ai; + +NextAction** FireMageStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("scorch", 7.0f), new NextAction("fireball", 6.0f), new NextAction("fire blast", 5.0f), NULL); +} + +void FireMageStrategy::InitTriggers(std::list &triggers) +{ + GenericMageStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "pyroblast", + NextAction::array(0, new NextAction("pyroblast", 10.0f), NULL))); + + triggers.push_back(new TriggerNode( + "hot streak", + NextAction::array(0, new NextAction("pyroblast", 25.0f), NULL))); + + triggers.push_back(new TriggerNode( + "combustion", + NextAction::array(0, new NextAction("combustion", 50.0f), NULL))); + + triggers.push_back(new TriggerNode( + "enemy too close for spell", + NextAction::array(0, new NextAction("dragon's breath", 70.0f), NULL))); +} + +void FireMageAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("flamestrike", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "living bomb", + NextAction::array(0, new NextAction("living bomb", 25.0f), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.h b/src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.h new file mode 100644 index 0000000000..fc0cd7f856 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/FireMageStrategy.h @@ -0,0 +1,28 @@ +#pragma once + +#include "GenericMageStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class FireMageStrategy : public GenericMageStrategy + { + public: + FireMageStrategy(PlayerbotAI* ai) : GenericMageStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "fire"; } + virtual NextAction** getDefaultActions(); + }; + + class FireMageAoeStrategy : public CombatStrategy + { + public: + FireMageAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "fire aoe"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.cpp b/src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.cpp new file mode 100644 index 0000000000..ed55afb1c0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.cpp @@ -0,0 +1,32 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MageMultipliers.h" +#include "FrostMageStrategy.h" + +using namespace ai; + + +FrostMageStrategy::FrostMageStrategy(PlayerbotAI* ai) : GenericMageStrategy(ai) +{ +} + +NextAction** FrostMageStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("frostbolt", 7.0f), NULL); +} + +void FrostMageStrategy::InitTriggers(std::list &triggers) +{ + GenericMageStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "icy veins", + NextAction::array(0, new NextAction("icy veins", 50.0f), NULL))); +} + +void FrostMageAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, new NextAction("blizzard", 40.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.h b/src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.h new file mode 100644 index 0000000000..15fac2f61c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/FrostMageStrategy.h @@ -0,0 +1,28 @@ +#pragma once + +#include "GenericMageStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class FrostMageStrategy : public GenericMageStrategy + { + public: + FrostMageStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "frost"; } + virtual NextAction** getDefaultActions(); + }; + + class FrostMageAoeStrategy : public CombatStrategy + { + public: + FrostMageAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "frost aoe"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.cpp new file mode 100644 index 0000000000..cec62094be --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.cpp @@ -0,0 +1,87 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MageMultipliers.h" +#include "GenericMageNonCombatStrategy.h" + +using namespace ai; + +class GenericMageNonCombatStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericMageNonCombatStrategyActionNodeFactory() + { + creators["molten armor"] = &molten_armor; + creators["mage armor"] = &mage_armor; + creators["ice armor"] = &ice_armor; + } +private: + static ActionNode* molten_armor(PlayerbotAI* ai) + { + return new ActionNode ("molten armor", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mage armor"), NULL), + /*C*/ NULL); + } + static ActionNode* mage_armor(PlayerbotAI* ai) + { + return new ActionNode ("mage armor", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("ice armor"), NULL), + /*C*/ NULL); + } + static ActionNode* ice_armor(PlayerbotAI* ai) + { + return new ActionNode ("ice armor", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("frost armor"), NULL), + /*C*/ NULL); + } +}; + +GenericMageNonCombatStrategy::GenericMageNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericMageNonCombatStrategyActionNodeFactory()); +} + +void GenericMageNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "arcane intellect", + NextAction::array(0, new NextAction("arcane intellect", 21.0f), NULL))); + + triggers.push_back(new TriggerNode( + "arcane intellect on party", + NextAction::array(0, new NextAction("arcane intellect on party", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "no drink", + NextAction::array(0, new NextAction("conjure water", 16.0f), NULL))); + + triggers.push_back(new TriggerNode( + "no food", + NextAction::array(0, new NextAction("conjure food", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "remove curse", + NextAction::array(0, new NextAction("remove curse", 41.0f), NULL))); + + triggers.push_back(new TriggerNode( + "remove curse on party", + NextAction::array(0, new NextAction("remove curse on party", 40.0f), NULL))); +} + +void MageBuffManaStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "mage armor", + NextAction::array(0, new NextAction("mage armor", 19.0f), NULL))); +} + +void MageBuffDpsStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "mage armor", + NextAction::array(0, new NextAction("molten armor", 19.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.h new file mode 100644 index 0000000000..5319bf9be1 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/GenericMageNonCombatStrategy.h @@ -0,0 +1,37 @@ +#pragma once + +#include "GenericMageStrategy.h" +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericMageNonCombatStrategy : public NonCombatStrategy + { + public: + GenericMageNonCombatStrategy(PlayerbotAI* ai); + virtual string getName() { return "nc"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + + class MageBuffManaStrategy : public Strategy + { + public: + MageBuffManaStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bmana"; } + }; + + class MageBuffDpsStrategy : public Strategy + { + public: + MageBuffDpsStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bdps"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.cpp b/src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.cpp new file mode 100644 index 0000000000..a115b6e9f3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.cpp @@ -0,0 +1,137 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MageMultipliers.h" +#include "GenericMageStrategy.h" + +using namespace ai; + +class GenericMageStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericMageStrategyActionNodeFactory() + { + creators["frostbolt"] = &frostbolt; + creators["fire blast"] = &fire_blast; + creators["scorch"] = &scorch; + creators["frost nova"] = &frost_nova; + creators["icy veins"] = &icy_veins; + creators["combustion"] = &combustion; + creators["evocation"] = &evocation; + creators["dragon's breath"] = &dragons_breath; + creators["blast wave"] = &blast_wave; + } +private: + static ActionNode* frostbolt(PlayerbotAI* ai) + { + return new ActionNode ("frostbolt", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("shoot"), NULL), + /*C*/ NULL); + } + static ActionNode* fire_blast(PlayerbotAI* ai) + { + return new ActionNode ("fire blast", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("scorch"), NULL), + /*C*/ NULL); + } + static ActionNode* scorch(PlayerbotAI* ai) + { + return new ActionNode ("scorch", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("shoot"), NULL), + /*C*/ NULL); + } + static ActionNode* frost_nova(PlayerbotAI* ai) + { + return new ActionNode ("frost nova", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("flee"), NULL), + /*C*/ NextAction::array(0, new NextAction("flee"), NULL)); + } + static ActionNode* icy_veins(PlayerbotAI* ai) + { + return new ActionNode ("icy veins", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* combustion(PlayerbotAI* ai) + { + return new ActionNode ("combustion", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* evocation(PlayerbotAI* ai) + { + return new ActionNode ("evocation", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mana potion"), NULL), + /*C*/ NULL); + } + static ActionNode* dragons_breath(PlayerbotAI* ai) + { + return new ActionNode ("dragon's breath", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("blast wave"), NULL), + /*C*/ NextAction::array(0, new NextAction("flamestrike", 71.0f), NULL)); + } + static ActionNode* blast_wave(PlayerbotAI* ai) + { + return new ActionNode ("blast wave", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("frost nova"), NULL), + /*C*/ NextAction::array(0, new NextAction("flamestrike", 71.0f), NULL)); + } +}; + +GenericMageStrategy::GenericMageStrategy(PlayerbotAI* ai) : RangedCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericMageStrategyActionNodeFactory()); +} + +void GenericMageStrategy::InitTriggers(std::list &triggers) +{ + RangedCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "remove curse", + NextAction::array(0, new NextAction("remove curse", 41.0f), NULL))); + + triggers.push_back(new TriggerNode( + "remove curse on party", + NextAction::array(0, new NextAction("remove curse on party", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "enemy too close for spell", + NextAction::array(0, new NextAction("frost nova", 50.0f), NULL))); + + triggers.push_back(new TriggerNode( + "counterspell", + NextAction::array(0, new NextAction("counterspell", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "counterspell on enemy healer", + NextAction::array(0, new NextAction("counterspell on enemy healer", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("ice block", 80.0f), NULL))); + + triggers.push_back(new TriggerNode( + "polymorph", + NextAction::array(0, new NextAction("polymorph", 30.0f), NULL))); + + triggers.push_back(new TriggerNode( + "spellsteal", + NextAction::array(0, new NextAction("spellsteal", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium threat", + NextAction::array(0, new NextAction("invisibility", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("evocation", ACTION_EMERGENCY + 5), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.h b/src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.h new file mode 100644 index 0000000000..4dcb9d9c0e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/GenericMageStrategy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/RangedCombatStrategy.h" + +namespace ai +{ + class GenericMageStrategy : public RangedCombatStrategy + { + public: + GenericMageStrategy(PlayerbotAI* ai); + virtual string getName() { return "mage"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/mage/MageActions.cpp b/src/modules/Bots/playerbot/strategy/mage/MageActions.cpp new file mode 100644 index 0000000000..4388022199 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageActions.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MageActions.h" + +using namespace ai; + +Value* CastPolymorphAction::GetTargetValue() +{ + return context->GetValue("cc target", getName()); +} diff --git a/src/modules/Bots/playerbot/strategy/mage/MageActions.h b/src/modules/Bots/playerbot/strategy/mage/MageActions.h new file mode 100644 index 0000000000..5282ffa2c1 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageActions.h @@ -0,0 +1,157 @@ +#pragma once + +#include "../actions/GenericActions.h" + +namespace ai +{ + class CastFireballAction : public CastSpellAction + { + public: + CastFireballAction(PlayerbotAI* ai) : CastSpellAction(ai, "fireball") {} + }; + + class CastScorchAction : public CastSpellAction + { + public: + CastScorchAction(PlayerbotAI* ai) : CastSpellAction(ai, "scorch") {} + }; + + class CastFireBlastAction : public CastSpellAction + { + public: + CastFireBlastAction(PlayerbotAI* ai) : CastSpellAction(ai, "fire blast") {} + }; + + class CastArcaneMissilesAction : public CastSpellAction + { + public: + CastArcaneMissilesAction(PlayerbotAI* ai) : CastSpellAction(ai, "arcane missiles") {} + }; + + class CastPyroblastAction : public CastSpellAction + { + public: + CastPyroblastAction(PlayerbotAI* ai) : CastSpellAction(ai, "pyroblast") {} + }; + + class CastFlamestrikeAction : public CastSpellAction + { + public: + CastFlamestrikeAction(PlayerbotAI* ai) : CastSpellAction(ai, "flamestrike") {} + }; + + class CastFrostNovaAction : public CastSpellAction + { + public: + CastFrostNovaAction(PlayerbotAI* ai) : CastSpellAction(ai, "frost nova") {} + virtual bool isUseful() { return AI_VALUE2(float, "distance", GetTargetName()) <= sPlayerbotAIConfig.tooCloseDistance; } + }; + + class CastFrostboltAction : public CastSpellAction + { + public: + CastFrostboltAction(PlayerbotAI* ai) : CastSpellAction(ai, "frostbolt") {} + }; + + class CastBlizzardAction : public CastSpellAction + { + public: + CastBlizzardAction(PlayerbotAI* ai) : CastSpellAction(ai, "blizzard") {} + }; + + class CastArcaneIntellectAction : public CastBuffSpellAction + { + public: + CastArcaneIntellectAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "arcane intellect") {} + }; + + class CastArcaneIntellectOnPartyAction : public BuffOnPartyAction + { + public: + CastArcaneIntellectOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "arcane intellect") {} + }; + + class CastRemoveCurseAction : public CastCureSpellAction + { + public: + CastRemoveCurseAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "remove curse") {} + }; + + class CastCombustionAction : public CastBuffSpellAction + { + public: + CastCombustionAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "combustion") {} + }; + + BEGIN_SPELL_ACTION(CastCounterspellAction, "counterspell") + END_SPELL_ACTION() + + class CastRemoveCurseOnPartyAction : public CurePartyMemberAction + { + public: + CastRemoveCurseOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "remove curse", DISPEL_CURSE) {} + }; + + // Temp disable conjuration + /*class CastConjureFoodAction : public CastBuffSpellAction + { + public: + CastConjureFoodAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "conjure food") {} + }; + + class CastConjureWaterAction : public CastBuffSpellAction + { + public: + CastConjureWaterAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "conjure water") {} + };*/ + + class CastIceBlockAction : public CastBuffSpellAction + { + public: + CastIceBlockAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "ice block") {} + }; + + class CastMageArmorAction : public CastBuffSpellAction + { + public: + CastMageArmorAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "mage armor") {} + }; + + class CastIceArmorAction : public CastBuffSpellAction + { + public: + CastIceArmorAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "ice armor") {} + }; + + class CastFrostArmorAction : public CastBuffSpellAction + { + public: + CastFrostArmorAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "frost armor") {} + }; + + class CastPolymorphAction : public CastBuffSpellAction + { + public: + CastPolymorphAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "polymorph") {} + virtual Value* GetTargetValue(); + }; + + class CastBlastWaveAction : public CastSpellAction + { + public: + CastBlastWaveAction(PlayerbotAI* ai) : CastSpellAction(ai, "blast wave") {} + }; + + class CastEvocationAction : public CastSpellAction + { + public: + CastEvocationAction(PlayerbotAI* ai) : CastSpellAction(ai, "evocation") {} + virtual string GetTargetName() { return "self target"; } + }; + + class CastCounterspellOnEnemyHealerAction : public CastSpellOnEnemyHealerAction + { + public: + CastCounterspellOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "counterspell") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.cpp new file mode 100644 index 0000000000..94dc6f4996 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.cpp @@ -0,0 +1,205 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "../Strategy.h" +#include "MageActions.h" +#include "MageAiObjectContext.h" +#include "FrostMageStrategy.h" +#include "ArcaneMageStrategy.h" +#include "GenericMageNonCombatStrategy.h" +#include "FireMageStrategy.h" +#include "../generic/PullStrategy.h" +#include "MageTriggers.h" +#include "../NamedObjectContext.h" + +using namespace ai; + + +namespace ai +{ + namespace mage + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &mage::StrategyFactoryInternal::nc; + creators["pull"] = &mage::StrategyFactoryInternal::pull; + creators["fire aoe"] = &mage::StrategyFactoryInternal::fire_aoe; + creators["frost aoe"] = &mage::StrategyFactoryInternal::frost_aoe; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new GenericMageNonCombatStrategy(ai); } + static Strategy* pull(PlayerbotAI* ai) { return new PullStrategy(ai, "shoot"); } + static Strategy* fire_aoe(PlayerbotAI* ai) { return new FireMageAoeStrategy(ai); } + static Strategy* frost_aoe(PlayerbotAI* ai) { return new FrostMageAoeStrategy(ai); } + }; + + class MageStrategyFactoryInternal : public NamedObjectContext + { + public: + MageStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["frost"] = &mage::MageStrategyFactoryInternal::frost; + creators["fire"] = &mage::MageStrategyFactoryInternal::fire; + creators["arcane"] = &mage::MageStrategyFactoryInternal::arcane; + } + + private: + static Strategy* frost(PlayerbotAI* ai) { return new FrostMageStrategy(ai); } + static Strategy* fire(PlayerbotAI* ai) { return new FireMageStrategy(ai); } + static Strategy* arcane(PlayerbotAI* ai) { return new ArcaneMageStrategy(ai); } + }; + + class MageBuffStrategyFactoryInternal : public NamedObjectContext + { + public: + MageBuffStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["bmana"] = &mage::MageBuffStrategyFactoryInternal::bmana; + creators["bdps"] = &mage::MageBuffStrategyFactoryInternal::bdps; + } + + private: + static Strategy* bmana(PlayerbotAI* ai) { return new MageBuffManaStrategy(ai); } + static Strategy* bdps(PlayerbotAI* ai) { return new MageBuffDpsStrategy(ai); } + }; + }; +}; + + +namespace ai +{ + namespace mage + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["fireball"] = &TriggerFactoryInternal::fireball; + creators["pyroblast"] = &TriggerFactoryInternal::pyroblast; + creators["combustion"] = &TriggerFactoryInternal::combustion; + creators["icy veins"] = &TriggerFactoryInternal::icy_veins; + creators["arcane intellect"] = &TriggerFactoryInternal::arcane_intellect; + creators["arcane intellect on party"] = &TriggerFactoryInternal::arcane_intellect_on_party; + creators["mage armor"] = &TriggerFactoryInternal::mage_armor; + creators["remove curse"] = &TriggerFactoryInternal::remove_curse; + creators["remove curse on party"] = &TriggerFactoryInternal::remove_curse_on_party; + creators["counterspell"] = &TriggerFactoryInternal::counterspell; + creators["polymorph"] = &TriggerFactoryInternal::polymorph; + creators["spellsteal"] = &TriggerFactoryInternal::spellsteal; + creators["hot streak"] = &TriggerFactoryInternal::hot_streak; + creators["living bomb"] = &TriggerFactoryInternal::living_bomb; + creators["missile barrage"] = &TriggerFactoryInternal::missile_barrage; + creators["arcane blast"] = &TriggerFactoryInternal::arcane_blast; + creators["counterspell on enemy healer"] = &TriggerFactoryInternal::counterspell_enemy_healer; + + } + + private: + static Trigger* hot_streak(PlayerbotAI* ai) { return new HotStreakTrigger(ai); } + static Trigger* fireball(PlayerbotAI* ai) { return new FireballTrigger(ai); } + static Trigger* pyroblast(PlayerbotAI* ai) { return new PyroblastTrigger(ai); } + static Trigger* combustion(PlayerbotAI* ai) { return new CombustionTrigger(ai); } + static Trigger* icy_veins(PlayerbotAI* ai) { return new IcyVeinsTrigger(ai); } + static Trigger* arcane_intellect(PlayerbotAI* ai) { return new ArcaneIntellectTrigger(ai); } + static Trigger* arcane_intellect_on_party(PlayerbotAI* ai) { return new ArcaneIntellectOnPartyTrigger(ai); } + static Trigger* mage_armor(PlayerbotAI* ai) { return new MageArmorTrigger(ai); } + static Trigger* remove_curse(PlayerbotAI* ai) { return new RemoveCurseTrigger(ai); } + static Trigger* remove_curse_on_party(PlayerbotAI* ai) { return new PartyMemberRemoveCurseTrigger(ai); } + static Trigger* counterspell(PlayerbotAI* ai) { return new CounterspellInterruptSpellTrigger(ai); } + static Trigger* polymorph(PlayerbotAI* ai) { return new PolymorphTrigger(ai); } + static Trigger* spellsteal(PlayerbotAI* ai) { return new SpellstealTrigger(ai); } + static Trigger* living_bomb(PlayerbotAI* ai) { return new LivingBombTrigger(ai); } + static Trigger* missile_barrage(PlayerbotAI* ai) { return new MissileBarrageTrigger(ai); } + static Trigger* arcane_blast(PlayerbotAI* ai) { return new ArcaneBlastTrigger(ai); } + static Trigger* counterspell_enemy_healer(PlayerbotAI* ai) { return new CounterspellEnemyHealerTrigger(ai); } + }; + }; +}; + + +namespace ai +{ + namespace mage + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["frostbolt"] = &AiObjectContextInternal::frostbolt; + creators["blizzard"] = &AiObjectContextInternal::blizzard; + creators["frost nova"] = &AiObjectContextInternal::frost_nova; + creators["arcane intellect"] = &AiObjectContextInternal::arcane_intellect; + creators["arcane intellect on party"] = &AiObjectContextInternal::arcane_intellect_on_party; + //creators["conjure water"] = &AiObjectContextInternal::conjure_water; + //creators["conjure food"] = &AiObjectContextInternal::conjure_food; + creators["mage armor"] = &AiObjectContextInternal::mage_armor; + creators["ice armor"] = &AiObjectContextInternal::ice_armor; + creators["frost armor"] = &AiObjectContextInternal::frost_armor; + creators["fireball"] = &AiObjectContextInternal::fireball; + creators["pyroblast"] = &AiObjectContextInternal::pyroblast; + creators["flamestrike"] = &AiObjectContextInternal::flamestrike; + creators["fire blast"] = &AiObjectContextInternal::fire_blast; + creators["scorch"] = &AiObjectContextInternal::scorch; + creators["counterspell"] = &AiObjectContextInternal::counterspell; + creators["remove curse"] = &AiObjectContextInternal::remove_curse; + creators["remove curse on party"] = &AiObjectContextInternal::remove_curse_on_party; + creators["combustion"] = &AiObjectContextInternal::combustion; + creators["ice block"] = &AiObjectContextInternal::ice_block; + creators["polymorph"] = &AiObjectContextInternal::polymorph; + creators["blast wave"] = &AiObjectContextInternal::blast_wave; + creators["evocation"] = &AiObjectContextInternal::evocation; + creators["arcane missiles"] = &AiObjectContextInternal::arcane_missiles; + creators["counterspell on enemy healer"] = &AiObjectContextInternal::counterspell_on_enemy_healer; + } + + private: + static Action* arcane_missiles(PlayerbotAI* ai) { return new CastArcaneMissilesAction(ai); } + static Action* frostbolt(PlayerbotAI* ai) { return new CastFrostboltAction(ai); } + static Action* blizzard(PlayerbotAI* ai) { return new CastBlizzardAction(ai); } + static Action* frost_nova(PlayerbotAI* ai) { return new CastFrostNovaAction(ai); } + static Action* arcane_intellect(PlayerbotAI* ai) { return new CastArcaneIntellectAction(ai); } + static Action* arcane_intellect_on_party(PlayerbotAI* ai) { return new CastArcaneIntellectOnPartyAction(ai); } + //static Action* conjure_water(PlayerbotAI* ai) { return new CastConjureWaterAction(ai); } + //static Action* conjure_food(PlayerbotAI* ai) { return new CastConjureFoodAction(ai); } + static Action* mage_armor(PlayerbotAI* ai) { return new CastMageArmorAction(ai); } + static Action* ice_armor(PlayerbotAI* ai) { return new CastIceArmorAction(ai); } + static Action* frost_armor(PlayerbotAI* ai) { return new CastFrostArmorAction(ai); } + static Action* fireball(PlayerbotAI* ai) { return new CastFireballAction(ai); } + static Action* pyroblast(PlayerbotAI* ai) { return new CastPyroblastAction(ai); } + static Action* flamestrike(PlayerbotAI* ai) { return new CastFlamestrikeAction(ai); } + static Action* fire_blast(PlayerbotAI* ai) { return new CastFireBlastAction(ai); } + static Action* scorch(PlayerbotAI* ai) { return new CastScorchAction(ai); } + static Action* counterspell(PlayerbotAI* ai) { return new CastCounterspellAction(ai); } + static Action* remove_curse(PlayerbotAI* ai) { return new CastRemoveCurseAction(ai); } + static Action* remove_curse_on_party(PlayerbotAI* ai) { return new CastRemoveCurseOnPartyAction(ai); } + static Action* combustion(PlayerbotAI* ai) { return new CastCombustionAction(ai); } + static Action* ice_block(PlayerbotAI* ai) { return new CastIceBlockAction(ai); } + static Action* polymorph(PlayerbotAI* ai) { return new CastPolymorphAction(ai); } + static Action* blast_wave(PlayerbotAI* ai) { return new CastBlastWaveAction(ai); } + static Action* evocation(PlayerbotAI* ai) { return new CastEvocationAction(ai); } + static Action* counterspell_on_enemy_healer(PlayerbotAI* ai) { return new CastCounterspellOnEnemyHealerAction(ai); } + }; + }; +}; + + + +MageAiObjectContext::MageAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::mage::StrategyFactoryInternal()); + strategyContexts.Add(new ai::mage::MageStrategyFactoryInternal()); + strategyContexts.Add(new ai::mage::MageBuffStrategyFactoryInternal()); + actionContexts.Add(new ai::mage::AiObjectContextInternal()); + triggerContexts.Add(new ai::mage::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.h b/src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.h new file mode 100644 index 0000000000..0fe90e2a0d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class MageAiObjectContext : public AiObjectContext + { + public: + MageAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/mage/MageMultipliers.cpp b/src/modules/Bots/playerbot/strategy/mage/MageMultipliers.cpp new file mode 100644 index 0000000000..4bfc60a63e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "MageMultipliers.h" +//#include "MageActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/mage/MageMultipliers.h b/src/modules/Bots/playerbot/strategy/mage/MageMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/mage/MageTriggers.cpp b/src/modules/Bots/playerbot/strategy/mage/MageTriggers.cpp new file mode 100644 index 0000000000..f42c47ec7a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageTriggers.cpp @@ -0,0 +1,15 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "MageTriggers.h" +#include "MageActions.h" + +using namespace ai; + +bool MageArmorTrigger::IsActive() +{ + Unit* target = GetTarget(); + return !ai->HasAura("ice armor", target) && + !ai->HasAura("frost armor", target) && + !ai->HasAura("molten armor", target) && + !ai->HasAura("mage armor", target); +} diff --git a/src/modules/Bots/playerbot/strategy/mage/MageTriggers.h b/src/modules/Bots/playerbot/strategy/mage/MageTriggers.h new file mode 100644 index 0000000000..48bc846513 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/mage/MageTriggers.h @@ -0,0 +1,92 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + BUFF_ON_PARTY_TRIGGER(ArcaneIntellectOnPartyTrigger, "arcane intellect", "arcane intellect on party") + BUFF_TRIGGER(ArcaneIntellectTrigger, "arcane intellect", "arcane intellect") + + class MageArmorTrigger : public BuffTrigger { + public: + MageArmorTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "mage armor") {} + virtual bool IsActive(); + }; + + class LivingBombTrigger : public DebuffTrigger { + public: + LivingBombTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "living bomb") {} + }; + + class FireballTrigger : public DebuffTrigger { + public: + FireballTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "fireball") {} + }; + + class PyroblastTrigger : public DebuffTrigger { + public: + PyroblastTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "pyroblast") {} + }; + + class HotStreakTrigger : public HasAuraTrigger { + public: + HotStreakTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "hot streak") {} + }; + + class MissileBarrageTrigger : public HasAuraTrigger { + public: + MissileBarrageTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "missile barrage") {} + }; + + class ArcaneBlastTrigger : public BuffTrigger { + public: + ArcaneBlastTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "arcane blast") {} + }; + + class CounterspellInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + CounterspellInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "counterspell") {} + }; + + class CombustionTrigger : public BoostTrigger + { + public: + CombustionTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "combustion") {} + }; + + class IcyVeinsTrigger : public BoostTrigger + { + public: + IcyVeinsTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "icy veins") {} + }; + + class PolymorphTrigger : public HasCcTargetTrigger + { + public: + PolymorphTrigger(PlayerbotAI* ai) : HasCcTargetTrigger(ai, "polymorph") {} + }; + + class RemoveCurseTrigger : public NeedCureTrigger + { + public: + RemoveCurseTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "remove curse", DISPEL_CURSE) {} + }; + + class PartyMemberRemoveCurseTrigger : public PartyMemberNeedCureTrigger + { + public: + PartyMemberRemoveCurseTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "remove curse", DISPEL_CURSE) {} + }; + + class SpellstealTrigger : public TargetAuraDispelTrigger + { + public: + SpellstealTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "spellsteal", DISPEL_MAGIC) {} + }; + + class CounterspellEnemyHealerTrigger : public InterruptEnemyHealerTrigger + { + public: + CounterspellEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "counterspell") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.cpp b/src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.cpp new file mode 100644 index 0000000000..45c416b19f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.cpp @@ -0,0 +1,83 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PaladinMultipliers.h" +#include "DpsPaladinStrategy.h" + +using namespace ai; + +class DpsPaladinStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + DpsPaladinStrategyActionNodeFactory() + { + creators["seal of vengeance"] = &seal_of_vengeance; + creators["seal of command"] = &seal_of_command; + creators["blessing of might"] = &blessing_of_might; + creators["crusader strike"] = &crusader_strike; + } + +private: + static ActionNode* seal_of_vengeance(PlayerbotAI* ai) + { + return new ActionNode ("seal of vengeance", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("seal of command"), NULL), + /*C*/ NULL); + } + static ActionNode* seal_of_command(PlayerbotAI* ai) + { + return new ActionNode ("seal of command", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("seal of wisdom"), NULL), + /*C*/ NULL); + } + static ActionNode* blessing_of_might(PlayerbotAI* ai) + { + return new ActionNode ("blessing of might", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("blessing of kings"), NULL), + /*C*/ NULL); + } + static ActionNode* crusader_strike(PlayerbotAI* ai) + { + return new ActionNode ("crusader strike", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } +}; + +DpsPaladinStrategy::DpsPaladinStrategy(PlayerbotAI* ai) : GenericPaladinStrategy(ai) +{ + actionNodeFactories.Add(new DpsPaladinStrategyActionNodeFactory()); +} + +NextAction** DpsPaladinStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("crusader strike", ACTION_NORMAL + 1), NULL); +} + +void DpsPaladinStrategy::InitTriggers(std::list &triggers) +{ + GenericPaladinStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("divine shield", ACTION_CRITICAL_HEAL + 2), new NextAction("holy light", ACTION_CRITICAL_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "judgement of wisdom", + NextAction::array(0, new NextAction("judgement of wisdom", ACTION_NORMAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "blessing", + NextAction::array(0, new NextAction("blessing of might", ACTION_HIGH + 8), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("divine storm", ACTION_HIGH + 1), new NextAction("consecration", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "art of war", + NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 2), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.h b/src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.h new file mode 100644 index 0000000000..cff5fd2242 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/DpsPaladinStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "GenericPaladinStrategy.h" + +namespace ai +{ + class DpsPaladinStrategy : public GenericPaladinStrategy + { + public: + DpsPaladinStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "dps"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.cpp new file mode 100644 index 0000000000..e5ca61623c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.cpp @@ -0,0 +1,65 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PaladinMultipliers.h" +#include "GenericPaladinNonCombatStrategy.h" +#include "GenericPaladinStrategyActionNodeFactory.h" + +using namespace ai; + +GenericPaladinNonCombatStrategy::GenericPaladinNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericPaladinStrategyActionNodeFactory()); +} + +void GenericPaladinNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "blessing of kings on party", + NextAction::array(0, new NextAction("blessing of kings on party", 11.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member dead", + NextAction::array(0, new NextAction("redemption", 30.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("flash of light", 25.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, new NextAction("flash of light on party", 26.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("holy light", 50.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, new NextAction("holy light on party", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse cure disease", + NextAction::array(0, new NextAction("cleanse disease", 41.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse party member cure disease", + NextAction::array(0, new NextAction("cleanse disease on party", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse cure poison", + NextAction::array(0, new NextAction("cleanse poison", 41.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse party member cure poison", + NextAction::array(0, new NextAction("cleanse poison on party", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse cure magic", + NextAction::array(0, new NextAction("cleanse magic", 41.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse party member cure magic", + NextAction::array(0, new NextAction("cleanse magic on party", 40.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.h new file mode 100644 index 0000000000..3bcb4e614c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinNonCombatStrategy.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericPaladinNonCombatStrategy : public NonCombatStrategy + { + public: + GenericPaladinNonCombatStrategy(PlayerbotAI* ai); + virtual string getName() { return "nc"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.cpp b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.cpp new file mode 100644 index 0000000000..7749e080b8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.cpp @@ -0,0 +1,77 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GenericPaladinStrategy.h" +#include "GenericPaladinStrategyActionNodeFactory.h" + +using namespace ai; + + +GenericPaladinStrategy::GenericPaladinStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericPaladinStrategyActionNodeFactory()); +} + +void GenericPaladinStrategy::InitTriggers(std::list &triggers) +{ + MeleeCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("flash of light", ACTION_MEDIUM_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, new NextAction("flash of light on party", ACTION_MEDIUM_HEAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("divine protection", ACTION_CRITICAL_HEAL + 2), new NextAction("holy light", ACTION_CRITICAL_HEAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, new NextAction("holy light on party", ACTION_CRITICAL_HEAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "hammer of justice interrupt", + NextAction::array(0, new NextAction("hammer of justice", ACTION_INTERRUPT), NULL))); + + triggers.push_back(new TriggerNode( + "hammer of justice on enemy healer", + NextAction::array(0, new NextAction("hammer of justice on enemy healer", ACTION_INTERRUPT), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("lay on hands", ACTION_EMERGENCY), NULL))); + + triggers.push_back(new TriggerNode( + "party member critical health", + NextAction::array(0, new NextAction("lay on hands on party", ACTION_EMERGENCY), NULL))); + + triggers.push_back(new TriggerNode( + "target critical health", + NextAction::array(0, new NextAction("hammer of wrath", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse cure disease", + NextAction::array(0, new NextAction("cleanse disease", ACTION_DISPEL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse party member cure disease", + NextAction::array(0, new NextAction("cleanse disease on party", ACTION_DISPEL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse cure poison", + NextAction::array(0, new NextAction("cleanse poison", ACTION_DISPEL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse party member cure poison", + NextAction::array(0, new NextAction("cleanse poison on party", ACTION_DISPEL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse cure magic", + NextAction::array(0, new NextAction("cleanse magic", ACTION_DISPEL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse party member cure magic", + NextAction::array(0, new NextAction("cleanse magic on party", ACTION_DISPEL + 1), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.h b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.h new file mode 100644 index 0000000000..000f785c3d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Strategy.h" +#include "PaladinAiObjectContext.h" +#include "../generic/MeleeCombatStrategy.h" + +namespace ai +{ + class GenericPaladinStrategy : public MeleeCombatStrategy + { + public: + GenericPaladinStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "paladin"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h new file mode 100644 index 0000000000..560784dea9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h @@ -0,0 +1,142 @@ +#pragma once + +namespace ai +{ + class GenericPaladinStrategyActionNodeFactory : public NamedObjectFactory + { + public: + GenericPaladinStrategyActionNodeFactory() + { + creators["seal of light"] = &seal_of_light; + creators["cleanse poison"] = &cleanse_poison; + creators["cleanse disease"] = &cleanse_disease; + creators["cleanse magic"] = &cleanse_magic; + creators["cleanse poison on party"] = &cleanse_poison_on_party; + creators["cleanse disease on party"] = &cleanse_disease_on_party; + creators["seal of wisdom"] = &seal_of_wisdom; + creators["seal of justice"] = &seal_of_justice; + creators["hand of reckoning"] = &hand_of_reckoning; + creators["judgement of wisdom"] = &judgement_of_wisdom; + creators["divine shield"] = &divine_shield; + creators["flash of light"] = &flash_of_light; + creators["flash of light on party"] = &flash_of_light_on_party; + creators["holy wrath"] = &holy_wrath; + creators["lay on hands"] = &lay_on_hands; + creators["lay on hands on party"] = &lay_on_hands_on_party; + } + private: + static ActionNode* lay_on_hands(PlayerbotAI* ai) + { + return new ActionNode ("lay on hands", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("divine shield"), new NextAction("flash of light"), NULL), + /*C*/ NULL); + } + static ActionNode* lay_on_hands_on_party(PlayerbotAI* ai) + { + return new ActionNode ("lay on hands on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("flash of light"), NULL), + /*C*/ NULL); + } + static ActionNode* seal_of_light(PlayerbotAI* ai) + { + return new ActionNode ("seal of light", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("seal of justice"), NULL), + /*C*/ NULL); + } + static ActionNode* cleanse_poison(PlayerbotAI* ai) + { + return new ActionNode ("cleanse poison", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("purify poison"), NULL), + /*C*/ NULL); + } + static ActionNode* cleanse_magic(PlayerbotAI* ai) + { + return new ActionNode ("cleanse magic", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* cleanse_disease(PlayerbotAI* ai) + { + return new ActionNode ("cleanse disease", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("purify disease"), NULL), + /*C*/ NULL); + } + static ActionNode* cleanse_poison_on_party(PlayerbotAI* ai) + { + return new ActionNode ("cleanse poison on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("purify poison on party"), NULL), + /*C*/ NULL); + } + static ActionNode* cleanse_disease_on_party(PlayerbotAI* ai) + { + return new ActionNode ("cleanse disease on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("purify disease on party"), NULL), + /*C*/ NULL); + } + static ActionNode* seal_of_wisdom(PlayerbotAI* ai) + { + return new ActionNode ("seal of wisdom", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("seal of justice"), NULL), + /*C*/ NULL); + } + static ActionNode* seal_of_justice(PlayerbotAI* ai) + { + return new ActionNode ("seal of justice", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("seal of righteousness"), NULL), + /*C*/ NULL); + } + static ActionNode* hand_of_reckoning(PlayerbotAI* ai) + { + return new ActionNode ("hand of reckoning", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("judgement of justice"), NULL), + /*C*/ NULL); + } + static ActionNode* judgement_of_wisdom(PlayerbotAI* ai) + { + return new ActionNode ("judgement of wisdom", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("judgement of light"), NULL), + /*C*/ NULL); + } + static ActionNode* divine_shield(PlayerbotAI* ai) + { + return new ActionNode ("divine shield", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("divine protection"), NULL), + /*C*/ NULL); + } + static ActionNode* flash_of_light(PlayerbotAI* ai) + { + return new ActionNode ("flash of light", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("holy light"), NULL), + /*C*/ NULL); + } + static ActionNode* flash_of_light_on_party(PlayerbotAI* ai) + { + return new ActionNode ("flash of light on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("holy light on party"), NULL), + /*C*/ NULL); + } + static ActionNode* holy_wrath(PlayerbotAI* ai) + { + return new ActionNode ("holy wrath", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("consecration"), NULL), + /*C*/ NULL); + } + }; + +}; diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinActions.cpp b/src/modules/Bots/playerbot/strategy/paladin/PaladinActions.cpp new file mode 100644 index 0000000000..808af419ba --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinActions.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "PaladinActions.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinActions.h b/src/modules/Bots/playerbot/strategy/paladin/PaladinActions.h new file mode 100644 index 0000000000..8b1aa3213d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinActions.h @@ -0,0 +1,325 @@ +#pragma once +#include "../actions/GenericActions.h" + +namespace ai +{ + class CastJudgementOfLightAction : public CastMeleeSpellAction + { + public: + CastJudgementOfLightAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "judgement of light") {} + }; + + class CastJudgementOfWisdomAction : public CastMeleeSpellAction + { + public: + CastJudgementOfWisdomAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "judgement of wisdom") {} + }; + + class CastJudgementOfJusticeAction : public CastMeleeSpellAction + { + public: + CastJudgementOfJusticeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "judgement of justice") {} + }; + + class CastRighteousFuryAction : public CastBuffSpellAction + { + public: + CastRighteousFuryAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "righteous fury") {} + }; + + class CastDevotionAuraAction : public CastBuffSpellAction + { + public: + CastDevotionAuraAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "devotion aura") {} + }; + + class CastRetributionAuraAction : public CastBuffSpellAction + { + public: + CastRetributionAuraAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "retribution aura") {} + }; + + class CastConcentrationAuraAction : public CastBuffSpellAction + { + public: + CastConcentrationAuraAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "concentration aura") {} + }; + + class CastShadowResistanceAuraAction : public CastBuffSpellAction + { + public: + CastShadowResistanceAuraAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shadow resistance aura") {} + }; + + class CastFrostResistanceAuraAction : public CastBuffSpellAction + { + public: + CastFrostResistanceAuraAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "frost resistance aura") {} + }; + + class CastFireResistanceAuraAction : public CastBuffSpellAction + { + public: + CastFireResistanceAuraAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "fire resistance aura") {} + }; + + class CastSealOfRighteousnessAction : public CastBuffSpellAction + { + public: + CastSealOfRighteousnessAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "seal of righteousness") {} + }; + + class CastSealOfJusticeAction : public CastBuffSpellAction + { + public: + CastSealOfJusticeAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "seal of justice") {} + }; + + + class CastSealOfLightAction : public CastBuffSpellAction + { + public: + CastSealOfLightAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "seal of light") {} + }; + + class CastSealOfWisdomAction : public CastBuffSpellAction + { + public: + CastSealOfWisdomAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "seal of wisdom") {} + }; + + class CastSealOfCommandAction : public CastBuffSpellAction + { + public: + CastSealOfCommandAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "seal of command") {} + }; + + class CastBlessingOfMightAction : public CastBuffSpellAction + { + public: + CastBlessingOfMightAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blessing of might") {} + }; + + class CastBlessingOfMightOnPartyAction : public BuffOnPartyAction + { + public: + CastBlessingOfMightOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "blessing of might") {} + virtual string getName() { return "blessing of might on party";} + }; + + class CastBlessingOfWisdomAction : public CastBuffSpellAction + { + public: + CastBlessingOfWisdomAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blessing of wisdom") {} + }; + + class CastBlessingOfWisdomOnPartyAction : public BuffOnPartyAction + { + public: + CastBlessingOfWisdomOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "blessing of wisdom") {} + virtual string getName() { return "blessing of wisdom on party";} + }; + + class CastBlessingOfKingsAction : public CastBuffSpellAction + { + public: + CastBlessingOfKingsAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blessing of kings") {} + }; + + class CastBlessingOfKingsOnPartyAction : public BuffOnPartyAction + { + public: + CastBlessingOfKingsOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "blessing of kings") {} + virtual string getName() { return "blessing of kings on party";} + }; + + class CastBlessingOfSanctuaryAction : public CastBuffSpellAction + { + public: + CastBlessingOfSanctuaryAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blessing of sanctuary") {} + }; + + class CastBlessingOfSanctuaryOnPartyAction : public BuffOnPartyAction + { + public: + CastBlessingOfSanctuaryOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "blessing of sanctuary") {} + virtual string getName() { return "blessing of sanctuary on party";} + }; + + class CastHolyLightAction : public CastHealingSpellAction + { + public: + CastHolyLightAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "holy light") {} + }; + + class CastHolyLightOnPartyAction : public HealPartyMemberAction + { + public: + CastHolyLightOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "holy light") {} + + virtual string getName() { return "holy light on party"; } + }; + + class CastFlashOfLightAction : public CastHealingSpellAction + { + public: + CastFlashOfLightAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "flash of light") {} + }; + + class CastFlashOfLightOnPartyAction : public HealPartyMemberAction + { + public: + CastFlashOfLightOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "flash of light") {} + + virtual string getName() { return "flash of light on party"; } + }; + + class CastLayOnHandsAction : public CastHealingSpellAction + { + public: + CastLayOnHandsAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "lay on hands") {} + }; + + class CastLayOnHandsOnPartyAction : public HealPartyMemberAction + { + public: + CastLayOnHandsOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "lay on hands") {} + + virtual string getName() { return "lay on hands on party"; } + }; + + class CastDivineProtectionAction : public CastBuffSpellAction + { + public: + CastDivineProtectionAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "divine protection") {} + }; + + class CastDivineProtectionOnPartyAction : public HealPartyMemberAction + { + public: + CastDivineProtectionOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "divine protection") {} + + virtual string getName() { return "divine protection on party"; } + }; + + class CastDivineShieldAction: public CastBuffSpellAction + { + public: + CastDivineShieldAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "divine shield") {} + }; + + class CastConsecrationAction : public CastMeleeSpellAction + { + public: + CastConsecrationAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "consecration") {} + }; + + class CastHolyWrathAction : public CastMeleeSpellAction + { + public: + CastHolyWrathAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "holy wrath") {} + }; + + class CastHammerOfJusticeAction : public CastMeleeSpellAction + { + public: + CastHammerOfJusticeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "hammer of justice") {} + }; + + class CastHammerOfWrathAction : public CastMeleeSpellAction + { + public: + CastHammerOfWrathAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "hammer of wrath") {} + }; + + class CastPurifyPoisonAction : public CastCureSpellAction + { + public: + CastPurifyPoisonAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "purify") {} + }; + + class CastPurifyDiseaseAction : public CastCureSpellAction + { + public: + CastPurifyDiseaseAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "purify") {} + }; + + class CastPurifyPoisonOnPartyAction : public CurePartyMemberAction + { + public: + CastPurifyPoisonOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "purify", DISPEL_POISON) {} + + virtual string getName() { return "purify poison on party"; } + }; + + class CastPurifyDiseaseOnPartyAction : public CurePartyMemberAction + { + public: + CastPurifyDiseaseOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "purify", DISPEL_DISEASE) {} + + virtual string getName() { return "purify disease on party"; } + }; + + class CastCleansePoisonAction : public CastCureSpellAction + { + public: + CastCleansePoisonAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "cleanse") {} + }; + + class CastCleanseDiseaseAction : public CastCureSpellAction + { + public: + CastCleanseDiseaseAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "cleanse") {} + }; + + class CastCleanseMagicAction : public CastCureSpellAction + { + public: + CastCleanseMagicAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "cleanse") {} + }; + + class CastCleansePoisonOnPartyAction : public CurePartyMemberAction + { + public: + CastCleansePoisonOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "cleanse", DISPEL_POISON) {} + + virtual string getName() { return "cleanse poison on party"; } + }; + + class CastCleanseDiseaseOnPartyAction : public CurePartyMemberAction + { + public: + CastCleanseDiseaseOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "cleanse", DISPEL_DISEASE) {} + + virtual string getName() { return "cleanse disease on party"; } + }; + + class CastCleanseMagicOnPartyAction : public CurePartyMemberAction + { + public: + CastCleanseMagicOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "cleanse", DISPEL_MAGIC) {} + + virtual string getName() { return "cleanse magic on party"; } + }; + + BEGIN_SPELL_ACTION(CastExorcismAction, "exorcism") + END_SPELL_ACTION() + + class CastHolyShieldAction : public CastBuffSpellAction + { + public: + CastHolyShieldAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "holy shield") {} + }; + + class CastRedemptionAction : public ResurrectPartyMemberAction + { + public: + CastRedemptionAction(PlayerbotAI* ai) : ResurrectPartyMemberAction(ai, "redemption") {} + }; + + class CastHammerOfJusticeOnEnemyHealerAction : public CastSpellOnEnemyHealerAction + { + public: + CastHammerOfJusticeOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "hammer of justice") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.cpp new file mode 100644 index 0000000000..741d734de0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.cpp @@ -0,0 +1,265 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PaladinActions.h" +#include "PaladinTriggers.h" +#include "PaladinAiObjectContext.h" +#include "GenericPaladinNonCombatStrategy.h" +#include "TankPaladinStrategy.h" +#include "DpsPaladinStrategy.h" +#include "PaladinBuffStrategies.h" +#include "../NamedObjectContext.h" + +using namespace ai; + +namespace ai +{ + namespace paladin + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &paladin::StrategyFactoryInternal::nc; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new GenericPaladinNonCombatStrategy(ai); } + }; + + class ResistanceStrategyFactoryInternal : public NamedObjectContext + { + public: + ResistanceStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["rshadow"] = &paladin::ResistanceStrategyFactoryInternal::rshadow; + creators["rfrost"] = &paladin::ResistanceStrategyFactoryInternal::rfrost; + creators["rfire"] = &paladin::ResistanceStrategyFactoryInternal::rfire; + } + + private: + static Strategy* rshadow(PlayerbotAI* ai) { return new PaladinShadowResistanceStrategy(ai); } + static Strategy* rfrost(PlayerbotAI* ai) { return new PaladinFrostResistanceStrategy(ai); } + static Strategy* rfire(PlayerbotAI* ai) { return new PaladinFireResistanceStrategy(ai); } + }; + + class BuffStrategyFactoryInternal : public NamedObjectContext + { + public: + BuffStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["bhealth"] = &paladin::BuffStrategyFactoryInternal::bhealth; + creators["bmana"] = &paladin::BuffStrategyFactoryInternal::bmana; + creators["bdps"] = &paladin::BuffStrategyFactoryInternal::bdps; + creators["barmor"] = &paladin::BuffStrategyFactoryInternal::barmor; + creators["bspeed"] = &paladin::BuffStrategyFactoryInternal::bspeed; + } + + private: + static Strategy* bhealth(PlayerbotAI* ai) { return new PaladinBuffHealthStrategy(ai); } + static Strategy* bmana(PlayerbotAI* ai) { return new PaladinBuffManaStrategy(ai); } + static Strategy* bdps(PlayerbotAI* ai) { return new PaladinBuffDpsStrategy(ai); } + static Strategy* barmor(PlayerbotAI* ai) { return new PaladinBuffArmorStrategy(ai); } + static Strategy* bspeed(PlayerbotAI* ai) { return new PaladinBuffSpeedStrategy(ai); } + }; + + class CombatStrategyFactoryInternal : public NamedObjectContext + { + public: + CombatStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["tank"] = &paladin::CombatStrategyFactoryInternal::tank; + creators["dps"] = &paladin::CombatStrategyFactoryInternal::dps; + } + + private: + static Strategy* tank(PlayerbotAI* ai) { return new TankPaladinStrategy(ai); } + static Strategy* dps(PlayerbotAI* ai) { return new DpsPaladinStrategy(ai); } + }; + }; +}; + +namespace ai +{ + namespace paladin + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["judgement of wisdom"] = &TriggerFactoryInternal::judgement_of_wisdom; + creators["judgement of light"] = &TriggerFactoryInternal::judgement_of_light; + creators["blessing"] = &TriggerFactoryInternal::blessing; + creators["seal"] = &TriggerFactoryInternal::seal; + creators["art of war"] = &TriggerFactoryInternal::art_of_war; + creators["blessing of kings on party"] = &TriggerFactoryInternal::blessing_of_kings_on_party; + creators["crusader aura"] = &TriggerFactoryInternal::crusader_aura; + creators["retribution aura"] = &TriggerFactoryInternal::retribution_aura; + creators["devotion aura"] = &TriggerFactoryInternal::devotion_aura; + creators["shadow resistance aura"] = &TriggerFactoryInternal::shadow_resistance_aura; + creators["frost resistance aura"] = &TriggerFactoryInternal::frost_resistance_aura; + creators["fire resistance aura"] = &TriggerFactoryInternal::fire_resistance_aura; + creators["hammer of justice snare"] = &TriggerFactoryInternal::hammer_of_justice_snare; + creators["hammer of justice interrupt"] = &TriggerFactoryInternal::hammer_of_justice_interrupt; + creators["cleanse cure disease"] = &TriggerFactoryInternal::CleanseCureDisease; + creators["cleanse party member cure disease"] = &TriggerFactoryInternal::CleanseCurePartyMemberDisease; + creators["cleanse cure poison"] = &TriggerFactoryInternal::CleanseCurePoison; + creators["cleanse party member cure poison"] = &TriggerFactoryInternal::CleanseCurePartyMemberPoison; + creators["cleanse cure magic"] = &TriggerFactoryInternal::CleanseCureMagic; + creators["cleanse party member cure magic"] = &TriggerFactoryInternal::CleanseCurePartyMemberMagic; + creators["righteous fury"] = &TriggerFactoryInternal::righteous_fury; + creators["holy shield"] = &TriggerFactoryInternal::holy_shield; + creators["hammer of justice on enemy healer"] = &TriggerFactoryInternal::hammer_of_justice_on_enemy_target; + } + + private: + static Trigger* holy_shield(PlayerbotAI* ai) { return new HolyShieldTrigger(ai); } + static Trigger* righteous_fury(PlayerbotAI* ai) { return new RighteousFuryTrigger(ai); } + static Trigger* judgement_of_wisdom(PlayerbotAI* ai) { return new JudgementOfWisdomTrigger(ai); } + static Trigger* judgement_of_light(PlayerbotAI* ai) { return new JudgementOfLightTrigger(ai); } + static Trigger* blessing(PlayerbotAI* ai) { return new BlessingTrigger(ai); } + static Trigger* seal(PlayerbotAI* ai) { return new SealTrigger(ai); } + static Trigger* art_of_war(PlayerbotAI* ai) { return new ArtOfWarTrigger(ai); } + static Trigger* blessing_of_kings_on_party(PlayerbotAI* ai) { return new BlessingOfKingsOnPartyTrigger(ai); } + static Trigger* crusader_aura(PlayerbotAI* ai) { return new CrusaderAuraTrigger(ai); } + static Trigger* retribution_aura(PlayerbotAI* ai) { return new RetributionAuraTrigger(ai); } + static Trigger* devotion_aura(PlayerbotAI* ai) { return new DevotionAuraTrigger(ai); } + static Trigger* shadow_resistance_aura(PlayerbotAI* ai) { return new ShadowResistanceAuraTrigger(ai); } + static Trigger* frost_resistance_aura(PlayerbotAI* ai) { return new FrostResistanceAuraTrigger(ai); } + static Trigger* fire_resistance_aura(PlayerbotAI* ai) { return new FireResistanceAuraTrigger(ai); } + static Trigger* hammer_of_justice_snare(PlayerbotAI* ai) { return new HammerOfJusticeSnareTrigger(ai); } + static Trigger* hammer_of_justice_interrupt(PlayerbotAI* ai) { return new HammerOfJusticeInterruptSpellTrigger(ai); } + static Trigger* CleanseCureDisease(PlayerbotAI* ai) { return new CleanseCureDiseaseTrigger(ai); } + static Trigger* CleanseCurePartyMemberDisease(PlayerbotAI* ai) { return new CleanseCurePartyMemberDiseaseTrigger(ai); } + static Trigger* CleanseCurePoison(PlayerbotAI* ai) { return new CleanseCurePoisonTrigger(ai); } + static Trigger* CleanseCurePartyMemberPoison(PlayerbotAI* ai) { return new CleanseCurePartyMemberPoisonTrigger(ai); } + static Trigger* CleanseCureMagic(PlayerbotAI* ai) { return new CleanseCureMagicTrigger(ai); } + static Trigger* CleanseCurePartyMemberMagic(PlayerbotAI* ai) { return new CleanseCurePartyMemberMagicTrigger(ai); } + static Trigger* hammer_of_justice_on_enemy_target(PlayerbotAI* ai) { return new HammerOfJusticeEnemyHealerTrigger(ai); } + }; + }; +}; + +namespace ai +{ + namespace paladin + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["seal of command"] = &AiObjectContextInternal::seal_of_command; + creators["blessing of might"] = &AiObjectContextInternal::blessing_of_might; + creators["blessing of kings on party"] = &AiObjectContextInternal::blessing_of_kings_on_party; + creators["redemption"] = &AiObjectContextInternal::redemption; + creators["seal of light"] = &AiObjectContextInternal::seal_of_light; + creators["devotion aura"] = &AiObjectContextInternal::devotion_aura; + creators["holy wrath"] = &AiObjectContextInternal::holy_wrath; + creators["consecration"] = &AiObjectContextInternal::consecration; + creators["cleanse disease"] = &AiObjectContextInternal::cleanse_disease; + creators["cleanse poison"] = &AiObjectContextInternal::cleanse_poison; + creators["cleanse magic"] = &AiObjectContextInternal::cleanse_magic; + creators["purify disease"] = &AiObjectContextInternal::purify_disease; + creators["purify poison"] = &AiObjectContextInternal::purify_poison; + creators["cleanse poison on party"] = &AiObjectContextInternal::cleanse_poison_on_party; + creators["cleanse disease on party"] = &AiObjectContextInternal::cleanse_disease_on_party; + creators["cleanse magic on party"] = &AiObjectContextInternal::cleanse_magic_on_party; + creators["purify poison on party"] = &AiObjectContextInternal::purify_poison_on_party; + creators["purify disease on party"] = &AiObjectContextInternal::purify_disease_on_party; + creators["seal of wisdom"] = &AiObjectContextInternal::seal_of_wisdom; + creators["seal of justice"] = &AiObjectContextInternal::seal_of_justice; + creators["seal of righteousness"] = &AiObjectContextInternal::seal_of_righteousness; + creators["flash of light"] = &AiObjectContextInternal::flash_of_light; + creators["exorcism"] = &AiObjectContextInternal::exorcism; + creators["judgement of light"] = &AiObjectContextInternal::judgement_of_light; + creators["judgement of wisdom"] = &AiObjectContextInternal::judgement_of_wisdom; + creators["divine shield"] = &AiObjectContextInternal::divine_shield; + creators["divine protection"] = &AiObjectContextInternal::divine_protection; + creators["divine protection on party"] =&AiObjectContextInternal::divine_protection_on_party; + creators["hammer of justice"] = &AiObjectContextInternal::hammer_of_justice; + creators["flash of light on party"] = &AiObjectContextInternal::flash_of_light_on_party; + creators["holy light"] = &AiObjectContextInternal::holy_light; + creators["holy light on party"] = &AiObjectContextInternal::holy_light_on_party; + creators["lay on hands"] = &AiObjectContextInternal::lay_on_hands; + creators["lay on hands on party"] = &AiObjectContextInternal::lay_on_hands_on_party; + creators["judgement of justice"] = &AiObjectContextInternal::judgement_of_justice; + creators["hammer of wrath"] = &AiObjectContextInternal::hammer_of_wrath; + creators["holy shield"] = &AiObjectContextInternal::holy_shield; + creators["blessing of kings"] = &AiObjectContextInternal::blessing_of_kings; + creators["retribution aura"] = &AiObjectContextInternal::retribution_aura; + creators["shadow resistance aura"] = &AiObjectContextInternal::shadow_resistance_aura; + creators["frost resistance aura"] = &AiObjectContextInternal::frost_resistance_aura; + creators["fire resistance aura"] = &AiObjectContextInternal::fire_resistance_aura; + creators["righteous fury"] = &AiObjectContextInternal::righteous_fury; + creators["blessing of sanctuary"] = &AiObjectContextInternal::blessing_of_sanctuary; + creators["hammer of justice on enemy healer"] = &AiObjectContextInternal::hammer_of_justice_on_enemy_healer; + } + + private: + static Action* righteous_fury(PlayerbotAI* ai) { return new CastRighteousFuryAction(ai); } + static Action* blessing_of_sanctuary(PlayerbotAI* ai) { return new CastBlessingOfSanctuaryAction(ai); } + static Action* seal_of_command(PlayerbotAI* ai) { return new CastSealOfCommandAction(ai); } + static Action* blessing_of_might(PlayerbotAI* ai) { return new CastBlessingOfMightAction(ai); } + static Action* blessing_of_kings_on_party(PlayerbotAI* ai) { return new CastBlessingOfKingsOnPartyAction(ai); } + static Action* redemption(PlayerbotAI* ai) { return new CastRedemptionAction(ai); } + static Action* seal_of_light(PlayerbotAI* ai) { return new CastSealOfLightAction(ai); } + static Action* devotion_aura(PlayerbotAI* ai) { return new CastDevotionAuraAction(ai); } + static Action* holy_wrath(PlayerbotAI* ai) { return new CastHolyWrathAction(ai); } + static Action* consecration(PlayerbotAI* ai) { return new CastConsecrationAction(ai); } + static Action* cleanse_poison(PlayerbotAI* ai) { return new CastCleansePoisonAction(ai); } + static Action* cleanse_disease(PlayerbotAI* ai) { return new CastCleanseDiseaseAction(ai); } + static Action* cleanse_magic(PlayerbotAI* ai) { return new CastCleanseMagicAction(ai); } + static Action* purify_poison(PlayerbotAI* ai) { return new CastPurifyPoisonAction(ai); } + static Action* purify_disease(PlayerbotAI* ai) { return new CastPurifyDiseaseAction(ai); } + static Action* cleanse_poison_on_party(PlayerbotAI* ai) { return new CastCleansePoisonOnPartyAction(ai); } + static Action* cleanse_disease_on_party(PlayerbotAI* ai) { return new CastCleanseDiseaseOnPartyAction(ai); } + static Action* cleanse_magic_on_party(PlayerbotAI* ai) { return new CastCleanseMagicOnPartyAction(ai); } + static Action* purify_poison_on_party(PlayerbotAI* ai) { return new CastPurifyPoisonOnPartyAction(ai); } + static Action* purify_disease_on_party(PlayerbotAI* ai) { return new CastPurifyDiseaseOnPartyAction(ai); } + static Action* seal_of_wisdom(PlayerbotAI* ai) { return new CastSealOfWisdomAction(ai); } + static Action* seal_of_justice(PlayerbotAI* ai) { return new CastSealOfJusticeAction(ai); } + static Action* seal_of_righteousness(PlayerbotAI* ai) { return new CastSealOfRighteousnessAction(ai); } + static Action* flash_of_light(PlayerbotAI* ai) { return new CastFlashOfLightAction(ai); } + static Action* exorcism(PlayerbotAI* ai) { return new CastExorcismAction(ai); } + static Action* judgement_of_light(PlayerbotAI* ai) { return new CastJudgementOfLightAction(ai); } + static Action* judgement_of_wisdom(PlayerbotAI* ai) { return new CastJudgementOfWisdomAction(ai); } + static Action* divine_shield(PlayerbotAI* ai) { return new CastDivineShieldAction(ai); } + static Action* divine_protection(PlayerbotAI* ai) { return new CastDivineProtectionAction(ai); } + static Action* divine_protection_on_party(PlayerbotAI* ai) { return new CastDivineProtectionOnPartyAction(ai); } + static Action* hammer_of_justice(PlayerbotAI* ai) { return new CastHammerOfJusticeAction(ai); } + static Action* flash_of_light_on_party(PlayerbotAI* ai) { return new CastFlashOfLightOnPartyAction(ai); } + static Action* holy_light(PlayerbotAI* ai) { return new CastHolyLightAction(ai); } + static Action* holy_light_on_party(PlayerbotAI* ai) { return new CastHolyLightOnPartyAction(ai); } + static Action* lay_on_hands(PlayerbotAI* ai) { return new CastLayOnHandsAction(ai); } + static Action* lay_on_hands_on_party(PlayerbotAI* ai) { return new CastLayOnHandsOnPartyAction(ai); } + static Action* judgement_of_justice(PlayerbotAI* ai) { return new CastJudgementOfJusticeAction(ai); } + static Action* hammer_of_wrath(PlayerbotAI* ai) { return new CastHammerOfWrathAction(ai); } + static Action* holy_shield(PlayerbotAI* ai) { return new CastHolyShieldAction(ai); } + static Action* blessing_of_kings(PlayerbotAI* ai) { return new CastBlessingOfKingsAction(ai); } + static Action* retribution_aura(PlayerbotAI* ai) { return new CastRetributionAuraAction(ai); } + static Action* shadow_resistance_aura(PlayerbotAI* ai) { return new CastShadowResistanceAuraAction(ai); } + static Action* frost_resistance_aura(PlayerbotAI* ai) { return new CastFrostResistanceAuraAction(ai); } + static Action* fire_resistance_aura(PlayerbotAI* ai) { return new CastFireResistanceAuraAction(ai); } + static Action* hammer_of_justice_on_enemy_healer(PlayerbotAI* ai) { return new CastHammerOfJusticeOnEnemyHealerAction(ai); } + }; + }; +}; + + +PaladinAiObjectContext::PaladinAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::paladin::StrategyFactoryInternal()); + strategyContexts.Add(new ai::paladin::CombatStrategyFactoryInternal()); + strategyContexts.Add(new ai::paladin::BuffStrategyFactoryInternal()); + strategyContexts.Add(new ai::paladin::ResistanceStrategyFactoryInternal()); + actionContexts.Add(new ai::paladin::AiObjectContextInternal()); + triggerContexts.Add(new ai::paladin::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.h b/src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.h new file mode 100644 index 0000000000..1af334341a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class PaladinAiObjectContext : public AiObjectContext + { + public: + PaladinAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.cpp b/src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.cpp new file mode 100644 index 0000000000..5691e0eec1 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.cpp @@ -0,0 +1,72 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PaladinMultipliers.h" +#include "PaladinBuffStrategies.h" + +using namespace ai; + +void PaladinBuffManaStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "seal", + NextAction::array(0, new NextAction("seal of wisdom", 90.0f), NULL))); +} + +void PaladinBuffHealthStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "seal", + NextAction::array(0, new NextAction("seal of light", 90.0f), NULL))); +} + +void PaladinBuffSpeedStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "crusader aura", + NextAction::array(0, new NextAction("crusader aura", 40.0f), NULL))); +} + +void PaladinBuffDpsStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "seal", + NextAction::array(0, new NextAction("seal of vengeance", 89.0f), NULL))); + + triggers.push_back(new TriggerNode( + "retribution aura", + NextAction::array(0, new NextAction("retribution aura", 90.0f), NULL))); +} + +void PaladinShadowResistanceStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "shadow resistance aura", + NextAction::array(0, new NextAction("shadow resistance aura", 90.0f), NULL))); +} + +void PaladinFrostResistanceStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "frost resistance aura", + NextAction::array(0, new NextAction("frost resistance aura", 90.0f), NULL))); +} + +void PaladinFireResistanceStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "fire resistance aura", + NextAction::array(0, new NextAction("fire resistance aura", 90.0f), NULL))); +} + + +void PaladinBuffArmorStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "seal", + NextAction::array(0, new NextAction("seal of light", 89.0f), NULL))); + + triggers.push_back(new TriggerNode( + "devotion aura", + NextAction::array(0, new NextAction("devotion aura", 90.0f), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.h b/src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.h new file mode 100644 index 0000000000..84e9ecade4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinBuffStrategies.h @@ -0,0 +1,86 @@ +#pragma once + +#include "GenericPaladinStrategy.h" + +namespace ai +{ + class PaladinBuffManaStrategy : public Strategy + { + public: + PaladinBuffManaStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bmana"; } + }; + + class PaladinBuffHealthStrategy : public Strategy + { + public: + PaladinBuffHealthStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bhealth"; } + }; + + class PaladinBuffDpsStrategy : public Strategy + { + public: + PaladinBuffDpsStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bdps"; } + }; + + class PaladinBuffArmorStrategy : public Strategy + { + public: + PaladinBuffArmorStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "barmor"; } + }; + + class PaladinBuffSpeedStrategy : public Strategy + { + public: + PaladinBuffSpeedStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bspeed"; } + }; + + class PaladinShadowResistanceStrategy : public Strategy + { + public: + PaladinShadowResistanceStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "rshadow"; } + }; + + class PaladinFrostResistanceStrategy : public Strategy + { + public: + PaladinFrostResistanceStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "rfrost"; } + }; + + class PaladinFireResistanceStrategy : public Strategy + { + public: + PaladinFireResistanceStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "rfire"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.cpp b/src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.cpp new file mode 100644 index 0000000000..aae071912d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "PaladinMultipliers.h" +//#include "PaladinActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.h b/src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.cpp b/src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.cpp new file mode 100644 index 0000000000..e810fe8108 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.cpp @@ -0,0 +1,23 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PaladinTriggers.h" +#include "PaladinActions.h" + +using namespace ai; + +bool SealTrigger::IsActive() +{ + Unit* target = GetTarget(); + return !ai->HasAura("seal of justice", target) && + !ai->HasAura("seal of command", target) && + !ai->HasAura("seal of vengeance", target) && + !ai->HasAura("seal of righteousness", target) && + !ai->HasAura("seal of light", target) && + !ai->HasAura("seal of wisdom", target); +} + +bool CrusaderAuraTrigger::IsActive() +{ + Unit* target = GetTarget(); + return AI_VALUE2(bool, "mounted", "self target") && !ai->HasAura("crusader aura", target); +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.h b/src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.h new file mode 100644 index 0000000000..a9be3d973f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/PaladinTriggers.h @@ -0,0 +1,114 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + BUFF_TRIGGER(HolyShieldTrigger, "holy shield", "holy shield") + BUFF_TRIGGER(RighteousFuryTrigger, "righteous fury", "righteous fury") + + BUFF_TRIGGER(RetributionAuraTrigger, "retribution aura", "retribution aura") + + class CrusaderAuraTrigger : public BuffTrigger + { + public: + CrusaderAuraTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "crusader aura") {} + virtual bool IsActive(); + }; + + class SealTrigger : public BuffTrigger + { + public: + SealTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "seal of justice") {} + virtual bool IsActive(); + }; + + DEBUFF_TRIGGER(JudgementOfLightTrigger, "judgement of light", "judgement of light") + DEBUFF_TRIGGER(JudgementOfWisdomTrigger, "judgement of wisdom", "judgement of wisdom") + + BUFF_ON_PARTY_TRIGGER(BlessingOfKingsOnPartyTrigger, "blessing of kings", "blessing of kings on party") + BUFF_TRIGGER(BlessingTrigger, "blessing of sanctuary", "blessing of sanctuary") + + class HammerOfJusticeInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + HammerOfJusticeInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "hammer of justice") {} + }; + + class HammerOfJusticeSnareTrigger : public SnareTargetTrigger + { + public: + HammerOfJusticeSnareTrigger(PlayerbotAI* ai) : SnareTargetTrigger(ai, "hammer of justice") {} + }; + + class ArtOfWarTrigger : public HasAuraTrigger + { + public: + ArtOfWarTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "the art of war") {} + }; + + class ShadowResistanceAuraTrigger : public BuffTrigger + { + public: + ShadowResistanceAuraTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "shadow resistance aura") {} + }; + + class FrostResistanceAuraTrigger : public BuffTrigger + { + public: + FrostResistanceAuraTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "frost resistance aura") {} + }; + + class FireResistanceAuraTrigger : public BuffTrigger + { + public: + FireResistanceAuraTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "fire resistance aura") {} + }; + + class DevotionAuraTrigger : public BuffTrigger + { + public: + DevotionAuraTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "devotion aura") {} + }; + + class CleanseCureDiseaseTrigger : public NeedCureTrigger + { + public: + CleanseCureDiseaseTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cleanse", DISPEL_DISEASE) {} + }; + + class CleanseCurePartyMemberDiseaseTrigger : public PartyMemberNeedCureTrigger + { + public: + CleanseCurePartyMemberDiseaseTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cleanse", DISPEL_DISEASE) {} + }; + + class CleanseCurePoisonTrigger : public NeedCureTrigger + { + public: + CleanseCurePoisonTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cleanse", DISPEL_POISON) {} + }; + + class CleanseCurePartyMemberPoisonTrigger : public PartyMemberNeedCureTrigger + { + public: + CleanseCurePartyMemberPoisonTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cleanse", DISPEL_POISON) {} + }; + + class CleanseCureMagicTrigger : public NeedCureTrigger + { + public: + CleanseCureMagicTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cleanse", DISPEL_MAGIC) {} + }; + + class CleanseCurePartyMemberMagicTrigger : public PartyMemberNeedCureTrigger + { + public: + CleanseCurePartyMemberMagicTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cleanse", DISPEL_MAGIC) {} + }; + + class HammerOfJusticeEnemyHealerTrigger : public InterruptEnemyHealerTrigger + { + public: + HammerOfJusticeEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "hammer of justice") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.cpp b/src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.cpp new file mode 100644 index 0000000000..d957713346 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.cpp @@ -0,0 +1,70 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PaladinMultipliers.h" +#include "TankPaladinStrategy.h" + +using namespace ai; + +class TankPaladinStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + TankPaladinStrategyActionNodeFactory() + { + creators["blessing of sanctuary"] = &blessing_of_sanctuary; + } +private: + static ActionNode* blessing_of_sanctuary(PlayerbotAI* ai) + { + return new ActionNode ("blessing of sanctuary", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("blessing of kings"), NULL), + /*C*/ NULL); + } +}; + +TankPaladinStrategy::TankPaladinStrategy(PlayerbotAI* ai) : GenericPaladinStrategy(ai) +{ + actionNodeFactories.Add(new TankPaladinStrategyActionNodeFactory()); +} + +NextAction** TankPaladinStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), NULL); +} + +void TankPaladinStrategy::InitTriggers(std::list &triggers) +{ + GenericPaladinStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "judgement of light", + NextAction::array(0, new NextAction("judgement of light", ACTION_NORMAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "medium mana", + NextAction::array(0, new NextAction("judgement of wisdom", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode( + "righteous fury", + NextAction::array(0, new NextAction("righteous fury", ACTION_HIGH + 8), NULL))); + + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("hammer of the righteous", ACTION_HIGH + 6), new NextAction("avenger's shield", ACTION_HIGH + 6), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 6), NULL))); + + triggers.push_back(new TriggerNode( + "lose aggro", + NextAction::array(0, new NextAction("hand of reckoning", ACTION_HIGH + 7), NULL))); + + triggers.push_back(new TriggerNode( + "holy shield", + NextAction::array(0, new NextAction("holy shield", ACTION_HIGH + 7), NULL))); + + triggers.push_back(new TriggerNode( + "blessing", + NextAction::array(0, new NextAction("blessing of sanctuary", ACTION_HIGH + 9), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.h b/src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.h new file mode 100644 index 0000000000..ca96457ce3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/paladin/TankPaladinStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "GenericPaladinStrategy.h" + +namespace ai +{ + class TankPaladinStrategy : public GenericPaladinStrategy + { + public: + TankPaladinStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "tank"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_TANK | STRATEGY_TYPE_MELEE; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.cpp b/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.cpp new file mode 100644 index 0000000000..c3efea883b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.cpp @@ -0,0 +1,67 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PriestMultipliers.h" +#include "HealPriestStrategy.h" +#include "GenericPriestStrategyActionNodeFactory.h" + +using namespace ai; + +GenericPriestStrategy::GenericPriestStrategy(PlayerbotAI* ai) : CombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericPriestStrategyActionNodeFactory()); +} + +void GenericPriestStrategy::InitTriggers(std::list &triggers) +{ + CombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("flash heal", 25.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, new NextAction("flash heal on party", 20.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("power word: shield", 70.0f), new NextAction("flash heal", 70.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member critical health", + NextAction::array(0, new NextAction("power word: shield on party", 60.0f), new NextAction("flash heal on party", 60.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("power word: shield", 60.0f), new NextAction("greater heal", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, new NextAction("power word: shield on party", 50.0f), new NextAction("greater heal on party", 50.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "dispel magic", + NextAction::array(0, new NextAction("dispel magic", 41.0f), NULL))); + + triggers.push_back(new TriggerNode( + "dispel magic on party", + NextAction::array(0, new NextAction("dispel magic on party", 40.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "cure disease", + NextAction::array(0, new NextAction("abolish disease", 31.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member cure disease", + NextAction::array(0, new NextAction("abolish disease on party", 30.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "medium threat", + NextAction::array(0, new NextAction("psychic scream", 50.0f), NULL))); + +} diff --git a/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.h b/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.h new file mode 100644 index 0000000000..4633e8d087 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class GenericPriestStrategy : public CombatStrategy + { + public: + GenericPriestStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategyActionNodeFactory.h b/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategyActionNodeFactory.h new file mode 100644 index 0000000000..d3ef00b302 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/GenericPriestStrategyActionNodeFactory.h @@ -0,0 +1,173 @@ +#pragma once + +namespace ai +{ + class GenericPriestStrategyActionNodeFactory : public NamedObjectFactory + { + public: + GenericPriestStrategyActionNodeFactory() + { + creators["inner fire"] = &inner_fire; + creators["holy nova"] = &holy_nova; + creators["power word: fortitude"] = &power_word_fortitude; + creators["power word: fortitude on party"] = &power_word_fortitude_on_party; + creators["divine spirit"] = &divine_spirit; + creators["divine spirit on party"] = &divine_spirit_on_party; + creators["power word: shield"] = &power_word_shield; + creators["power word: shield on party"] = &power_word_shield_on_party; + creators["renew"] = &renew; + creators["renew on party"] = &renew_on_party; + creators["greater heal"] = &greater_heal; + creators["greater heal on party"] = &greater_heal_on_party; + creators["heal"] = &heal; + creators["heal on party"] = &heal_on_party; + creators["lesser heal"] = &lesser_heal; + creators["lesser heal on party"] = &lesser_heal_on_party; + creators["flash heal"] = &flash_heal; + creators["flash heal on party"] = &flash_heal_on_party; + creators["psychic scream"] = &psychic_scream; + creators["fade"] = &fade; + } + private: + static ActionNode* inner_fire(PlayerbotAI* ai) + { + return new ActionNode ("inner fire", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* holy_nova(PlayerbotAI* ai) + { + return new ActionNode ("holy nova", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* power_word_fortitude(PlayerbotAI* ai) + { + return new ActionNode ("power word: fortitude", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* power_word_fortitude_on_party(PlayerbotAI* ai) + { + return new ActionNode ("power word: fortitude on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* divine_spirit(PlayerbotAI* ai) + { + return new ActionNode ("divine spirit", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* divine_spirit_on_party(PlayerbotAI* ai) + { + return new ActionNode ("divine spirit on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* power_word_shield(PlayerbotAI* ai) + { + return new ActionNode ("power word: shield", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("renew", 50.0f), NULL), + /*C*/ NULL); + } + static ActionNode* power_word_shield_on_party(PlayerbotAI* ai) + { + return new ActionNode ("power word: shield on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("renew on party", 50.0f), NULL), + /*C*/ NULL); + } + static ActionNode* renew(PlayerbotAI* ai) + { + return new ActionNode ("renew", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* renew_on_party(PlayerbotAI* ai) + { + return new ActionNode ("renew on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* greater_heal(PlayerbotAI* ai) + { + return new ActionNode ("greater heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("heal"), NULL), + /*C*/ NULL); + } + static ActionNode* greater_heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("greater heal on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("heal on party"), NULL), + /*C*/ NULL); + } + static ActionNode* heal(PlayerbotAI* ai) + { + return new ActionNode ("heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("lesser heal"), NULL), + /*C*/ NULL); + } + static ActionNode* heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("heal on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("lesser heal on party"), NULL), + /*C*/ NULL); + } + static ActionNode* lesser_heal(PlayerbotAI* ai) + { + return new ActionNode ("lesser heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* lesser_heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("lesser heal on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* flash_heal(PlayerbotAI* ai) + { + return new ActionNode ("flash heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("greater heal"), NULL), + /*C*/ NULL); + } + static ActionNode* flash_heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("flash heal on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("greater heal on party"), NULL), + /*C*/ NULL); + } + static ActionNode* psychic_scream(PlayerbotAI* ai) + { + return new ActionNode ("psychic scream", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("fade"), NULL), + /*C*/ NULL); + } + static ActionNode* fade(PlayerbotAI* ai) + { + return new ActionNode ("fade", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("flee"), NULL), + /*C*/ NULL); + } + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.cpp b/src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.cpp new file mode 100644 index 0000000000..8433f232d6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.cpp @@ -0,0 +1,36 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PriestMultipliers.h" +#include "HealPriestStrategy.h" + +using namespace ai; + +NextAction** HealPriestStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("shoot", 10.0f), NULL); +} + +void HealPriestStrategy::InitTriggers(std::list &triggers) +{ + GenericPriestStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe heal", + NextAction::array(0, new NextAction("circle of healing", 27.0f), NULL))); + + triggers.push_back(new TriggerNode( + "almost full health", + NextAction::array(0, new NextAction("renew", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member almost full health", + NextAction::array(0, new NextAction("renew on party", 10.0f), NULL))); + + triggers.push_back(new TriggerNode( + "enemy too close for spell", + NextAction::array(0, new NextAction("fade", 50.0f), new NextAction("flee", 49.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.h b/src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.h new file mode 100644 index 0000000000..c4a5fd5f9d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/HealPriestStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "GenericPriestStrategy.h" + +namespace ai +{ + class HealPriestStrategy : public GenericPriestStrategy + { + public: + HealPriestStrategy(PlayerbotAI* ai) : GenericPriestStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual NextAction** getDefaultActions(); + virtual string getName() { return "heal"; } + virtual int GetType() { return STRATEGY_TYPE_HEAL; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.cpp b/src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.cpp new file mode 100644 index 0000000000..cc69cbd85b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.cpp @@ -0,0 +1,46 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PriestMultipliers.h" +#include "HolyPriestStrategy.h" + +namespace ai +{ + class HolyPriestStrategyActionNodeFactory : public NamedObjectFactory + { + public: + HolyPriestStrategyActionNodeFactory() + { + creators["smite"] = &smite; + } + private: + static ActionNode* smite(PlayerbotAI* ai) + { + return new ActionNode ("smite", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("shoot"), NULL), + /*C*/ NULL); + } + }; +}; + +using namespace ai; + +HolyPriestStrategy::HolyPriestStrategy(PlayerbotAI* ai) : HealPriestStrategy(ai) +{ + actionNodeFactories.Add(new HolyPriestStrategyActionNodeFactory()); +} + +NextAction** HolyPriestStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("holy fire", 10.0f), new NextAction("smite", 10.0f), NULL); +} + +void HolyPriestStrategy::InitTriggers(std::list &triggers) +{ + HealPriestStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), NULL))); + +} diff --git a/src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.h b/src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.h new file mode 100644 index 0000000000..c21bcf178e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/HolyPriestStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "HealPriestStrategy.h" + +namespace ai +{ + class HolyPriestStrategy : public HealPriestStrategy + { + public: + HolyPriestStrategy(PlayerbotAI* ai); + + public: + virtual NextAction** getDefaultActions(); + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "holy"; } + virtual int GetType() { return STRATEGY_TYPE_DPS|STRATEGY_TYPE_RANGED; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestActions.cpp b/src/modules/Bots/playerbot/strategy/priest/PriestActions.cpp new file mode 100644 index 0000000000..bcf7ed6432 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestActions.cpp @@ -0,0 +1,17 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PriestActions.h" + +using namespace ai; + + +NextAction** CastAbolishDiseaseAction::getAlternatives() +{ + return NextAction::merge(NextAction::array(0, new NextAction("cure disease"), NULL), CastSpellAction::getAlternatives()); +} + +NextAction** CastAbolishDiseaseOnPartyAction::getAlternatives() +{ + return NextAction::merge(NextAction::array(0, new NextAction("cure disease on party"), NULL), CastSpellAction::getAlternatives()); +} + diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestActions.h b/src/modules/Bots/playerbot/strategy/priest/PriestActions.h new file mode 100644 index 0000000000..abec4a7cec --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestActions.h @@ -0,0 +1,229 @@ +#pragma once + +#include "../actions/GenericActions.h" + +namespace ai +{ + class CastGreaterHealAction : public CastHealingSpellAction { + public: + CastGreaterHealAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "greater heal") {} + }; + + class CastGreaterHealOnPartyAction : public HealPartyMemberAction + { + public: + CastGreaterHealOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "greater heal") {} + + virtual string getName() { return "greater heal on party"; } + }; + + class CastLesserHealAction : public CastHealingSpellAction { + public: + CastLesserHealAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "lesser heal") {} + }; + + class CastLesserHealOnPartyAction : public HealPartyMemberAction + { + public: + CastLesserHealOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "lesser heal") {} + + virtual string getName() { return "lesser heal on party"; } + }; + + class CastFlashHealAction : public CastHealingSpellAction { + public: + CastFlashHealAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "flash heal") {} + }; + + class CastFlashHealOnPartyAction : public HealPartyMemberAction + { + public: + CastFlashHealOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "flash heal") {} + + virtual string getName() { return "flash heal on party"; } + }; + + class CastHealAction : public CastHealingSpellAction { + public: + CastHealAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "heal") {} + }; + + class CastHealOnPartyAction : public HealPartyMemberAction + { + public: + CastHealOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "heal") {} + + virtual string getName() { return "heal on party"; } + }; + + class CastRenewAction : public CastHealingSpellAction { + public: + CastRenewAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "renew") {} + }; + + class CastRenewOnPartyAction : public HealPartyMemberAction + { + public: + CastRenewOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "renew") {} + + virtual string getName() { return "renew on party"; } + }; + + class CastFadeAction : public CastBuffSpellAction { + public: + CastFadeAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "fade") {} + }; + + class CastShadowformAction : public CastBuffSpellAction { + public: + CastShadowformAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shadowform") {} + }; + + class CastRemoveShadowformAction : public Action { + public: + CastRemoveShadowformAction(PlayerbotAI* ai) : Action(ai, "remove shadowform") {} + virtual bool isUseful() { return ai->HasAura("shadowform", AI_VALUE(Unit*, "self target")); } + virtual bool isPossible() { return true; } + virtual bool Execute(Event event) { + ai->RemoveAura("shadowform"); + return true; + } + }; + + class CastVampiricEmbraceAction : public CastBuffSpellAction { + public: + CastVampiricEmbraceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "vampiric embrace") {} + }; + + class CastPowerWordShieldAction : public CastBuffSpellAction { + public: + CastPowerWordShieldAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "power word: shield") {} + }; + + class CastPowerWordShieldOnPartyAction : public HealPartyMemberAction + { + public: + CastPowerWordShieldOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "power word: shield") {} + + virtual string getName() { return "power word: shield on party"; } + }; + + class CastPowerWordFortitudeAction : public CastBuffSpellAction { + public: + CastPowerWordFortitudeAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "power word: fortitude") {} + }; + + class CastDivineSpiritAction : public CastBuffSpellAction { + public: + CastDivineSpiritAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "divine spirit") {} + }; + + class CastInnerFireAction : public CastBuffSpellAction { + public: + CastInnerFireAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "inner fire") {} + }; + + BEGIN_SPELL_ACTION(CastHolyNovaAction, "holy nova") + virtual bool isUseful() { + return !ai->HasAura("shadowform", AI_VALUE(Unit*, "self target")); + } + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastHolyFireAction, "holy fire") + virtual bool isUseful() { + return !ai->HasAura("shadowform", AI_VALUE(Unit*, "self target")); + } + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastSmiteAction, "smite") + virtual bool isUseful() { + return !ai->HasAura("shadowform", AI_VALUE(Unit*, "self target")); + } + END_SPELL_ACTION() + + class CastPowerWordFortitudeOnPartyAction : public BuffOnPartyAction { + public: + CastPowerWordFortitudeOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "power word: fortitude") {} + }; + + class CastDivineSpiritOnPartyAction : public BuffOnPartyAction { + public: + CastDivineSpiritOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "divine spirit") {} + }; + + class CastPowerWordPainAction : public CastDebuffSpellAction + { + public: + CastPowerWordPainAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "shadow word: pain") {} + }; + + class CastPowerWordPainOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastPowerWordPainOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "shadow word: pain") {} + }; + + BEGIN_DEBUFF_ACTION(CastDevouringPlagueAction, "devouring plague") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastMindBlastAction, "mind blast") + END_SPELL_ACTION() + + BEGIN_RANGED_SPELL_ACTION(CastMindFlayAction, "mind flay") + END_SPELL_ACTION() + + class CastCureDiseaseAction : public CastCureSpellAction { + public: + CastCureDiseaseAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "cure disease") {} + }; + + class CastCureDiseaseOnPartyAction : public CurePartyMemberAction + { + public: + CastCureDiseaseOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "cure disease", DISPEL_DISEASE) {} + virtual string getName() { return "cure disease on party"; } + }; + + class CastAbolishDiseaseAction : public CastCureSpellAction { + public: + CastAbolishDiseaseAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "abolish disease") {} + virtual NextAction** getAlternatives(); + }; + + class CastAbolishDiseaseOnPartyAction : public CurePartyMemberAction + { + public: + CastAbolishDiseaseOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "abolish disease", DISPEL_DISEASE) {} + virtual string getName() { return "abolish disease on party"; } + virtual NextAction** getAlternatives(); + }; + + class CastDispelMagicAction : public CastCureSpellAction { + public: + CastDispelMagicAction(PlayerbotAI* ai) : CastCureSpellAction(ai, "dispel magic") {} + }; + + class CastDispelMagicOnTargetAction : public CastSpellAction { + public: + CastDispelMagicOnTargetAction(PlayerbotAI* ai) : CastSpellAction(ai, "dispel magic") {} + }; + + class CastDispelMagicOnPartyAction : public CurePartyMemberAction + { + public: + CastDispelMagicOnPartyAction(PlayerbotAI* ai) : CurePartyMemberAction(ai, "dispel magic", DISPEL_MAGIC) {} + virtual string getName() { return "dispel magic on party"; } + }; + + class CastResurrectionAction : public ResurrectPartyMemberAction + { + public: + CastResurrectionAction(PlayerbotAI* ai) : ResurrectPartyMemberAction(ai, "resurrection") {} + }; + + class CastPsychicScreamAction : public CastSpellAction + { + public: + CastPsychicScreamAction(PlayerbotAI* ai) : CastSpellAction(ai, "psychic scream") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.cpp new file mode 100644 index 0000000000..09276590d9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.cpp @@ -0,0 +1,211 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PriestActions.h" +#include "PriestAiObjectContext.h" +#include "PriestNonCombatStrategy.h" +#include "ShadowPriestStrategy.h" +#include "../generic/PullStrategy.h" +#include "PriestTriggers.h" +#include "../NamedObjectContext.h" +#include "HolyPriestStrategy.h" + +using namespace ai; + + +namespace ai +{ + namespace priest + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &priest::StrategyFactoryInternal::nc; + creators["pull"] = &priest::StrategyFactoryInternal::pull; + creators["aoe"] = &priest::StrategyFactoryInternal::shadow_aoe; + creators["shadow aoe"] = &priest::StrategyFactoryInternal::shadow_aoe; + creators["dps debuff"] = &priest::StrategyFactoryInternal::shadow_debuff; + creators["shadow debuff"] = &priest::StrategyFactoryInternal::shadow_debuff; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new PriestNonCombatStrategy(ai); } + static Strategy* shadow_aoe(PlayerbotAI* ai) { return new ShadowPriestAoeStrategy(ai); } + static Strategy* pull(PlayerbotAI* ai) { return new PullStrategy(ai, "shoot"); } + static Strategy* shadow_debuff(PlayerbotAI* ai) { return new ShadowPriestDebuffStrategy(ai); } + }; + + class CombatStrategyFactoryInternal : public NamedObjectContext + { + public: + CombatStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["heal"] = &priest::CombatStrategyFactoryInternal::heal; + creators["shadow"] = &priest::CombatStrategyFactoryInternal::dps; + creators["dps"] = &priest::CombatStrategyFactoryInternal::dps; + creators["holy"] = &priest::CombatStrategyFactoryInternal::holy; + } + + private: + static Strategy* heal(PlayerbotAI* ai) { return new HealPriestStrategy(ai); } + static Strategy* dps(PlayerbotAI* ai) { return new ShadowPriestStrategy(ai); } + static Strategy* holy(PlayerbotAI* ai) { return new HolyPriestStrategy(ai); } + }; + }; +}; + +namespace ai +{ + namespace priest + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["devouring plague"] = &TriggerFactoryInternal::devouring_plague; + creators["shadow word: pain"] = &TriggerFactoryInternal::shadow_word_pain; + creators["shadow word: pain on attacker"] = &TriggerFactoryInternal::shadow_word_pain_on_attacker; + creators["dispel magic"] = &TriggerFactoryInternal::dispel_magic; + creators["dispel magic on party"] = &TriggerFactoryInternal::dispel_magic_party_member; + creators["cure disease"] = &TriggerFactoryInternal::cure_disease; + creators["party member cure disease"] = &TriggerFactoryInternal::party_member_cure_disease; + creators["power word: fortitude"] = &TriggerFactoryInternal::power_word_fortitude; + creators["power word: fortitude on party"] = &TriggerFactoryInternal::power_word_fortitude_on_party; + creators["divine spirit"] = &TriggerFactoryInternal::divine_spirit; + creators["divine spirit on party"] = &TriggerFactoryInternal::divine_spirit_on_party; + creators["inner fire"] = &TriggerFactoryInternal::inner_fire; + creators["vampiric touch"] = &TriggerFactoryInternal::vampiric_touch; + creators["shadowform"] = &TriggerFactoryInternal::shadowform; + creators["vampiric embrace"] = &TriggerFactoryInternal::vampiric_embrace; + + } + + private: + static Trigger* vampiric_embrace(PlayerbotAI* ai) { return new VampiricEmbraceTrigger(ai); } + static Trigger* shadowform(PlayerbotAI* ai) { return new ShadowformTrigger(ai); } + static Trigger* vampiric_touch(PlayerbotAI* ai) { return new VampiricTouchTrigger(ai); } + static Trigger* devouring_plague(PlayerbotAI* ai) { return new DevouringPlagueTrigger(ai); } + static Trigger* shadow_word_pain(PlayerbotAI* ai) { return new PowerWordPainTrigger(ai); } + static Trigger* shadow_word_pain_on_attacker(PlayerbotAI* ai) { return new PowerWordPainOnAttackerTrigger(ai); } + static Trigger* dispel_magic(PlayerbotAI* ai) { return new DispelMagicTrigger(ai); } + static Trigger* dispel_magic_party_member(PlayerbotAI* ai) { return new DispelMagicPartyMemberTrigger(ai); } + static Trigger* cure_disease(PlayerbotAI* ai) { return new CureDiseaseTrigger(ai); } + static Trigger* party_member_cure_disease(PlayerbotAI* ai) { return new PartyMemberCureDiseaseTrigger(ai); } + static Trigger* power_word_fortitude(PlayerbotAI* ai) { return new PowerWordFortitudeTrigger(ai); } + static Trigger* power_word_fortitude_on_party(PlayerbotAI* ai) { return new PowerWordFortitudeOnPartyTrigger(ai); } + static Trigger* divine_spirit(PlayerbotAI* ai) { return new DivineSpiritTrigger(ai); } + static Trigger* divine_spirit_on_party(PlayerbotAI* ai) { return new DivineSpiritOnPartyTrigger(ai); } + static Trigger* inner_fire(PlayerbotAI* ai) { return new InnerFireTrigger(ai); } + }; + }; +}; + + + +namespace ai +{ + namespace priest + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["shadow word: pain"] = &AiObjectContextInternal::shadow_word_pain; + creators["shadow word: pain on attacker"] = &AiObjectContextInternal::shadow_word_pain_on_attacker; + creators["devouring plague"] = &AiObjectContextInternal::devouring_plague; + creators["mind flay"] = &AiObjectContextInternal::mind_flay; + creators["holy fire"] = &AiObjectContextInternal::holy_fire; + creators["smite"] = &AiObjectContextInternal::smite; + creators["mind blast"] = &AiObjectContextInternal::mind_blast; + creators["shadowform"] = &AiObjectContextInternal::shadowform; + creators["remove shadowform"] = &AiObjectContextInternal::remove_shadowform; + creators["holy nova"] = &AiObjectContextInternal::holy_nova; + creators["power word: fortitude"] = &AiObjectContextInternal::power_word_fortitude; + creators["power word: fortitude on party"] = &AiObjectContextInternal::power_word_fortitude_on_party; + creators["divine spirit"] = &AiObjectContextInternal::divine_spirit; + creators["divine spirit on party"] = &AiObjectContextInternal::divine_spirit_on_party; + creators["power word: shield"] = &AiObjectContextInternal::power_word_shield; + creators["power word: shield on party"] = &AiObjectContextInternal::power_word_shield_on_party; + creators["renew"] = &AiObjectContextInternal::renew; + creators["renew on party"] = &AiObjectContextInternal::renew_on_party; + creators["greater heal"] = &AiObjectContextInternal::greater_heal; + creators["greater heal on party"] = &AiObjectContextInternal::greater_heal_on_party; + creators["heal"] = &AiObjectContextInternal::heal; + creators["heal on party"] = &AiObjectContextInternal::heal_on_party; + creators["lesser heal"] = &AiObjectContextInternal::lesser_heal; + creators["lesser heal on party"] = &AiObjectContextInternal::lesser_heal_on_party; + creators["flash heal"] = &AiObjectContextInternal::flash_heal; + creators["flash heal on party"] = &AiObjectContextInternal::flash_heal_on_party; + creators["dispel magic"] = &AiObjectContextInternal::dispel_magic; + creators["dispel magic on party"] = &AiObjectContextInternal::dispel_magic_on_party; + creators["dispel magic on target"] = &AiObjectContextInternal::dispel_magic_on_target; + creators["cure disease"] = &AiObjectContextInternal::cure_disease; + creators["cure disease on party"] = &AiObjectContextInternal::cure_disease_on_party; + creators["abolish disease"] = &AiObjectContextInternal::abolish_disease; + creators["abolish disease on party"] = &AiObjectContextInternal::abolish_disease_on_party; + creators["fade"] = &AiObjectContextInternal::fade; + creators["inner fire"] = &AiObjectContextInternal::inner_fire; + creators["resurrection"] = &AiObjectContextInternal::resurrection; + creators["psychic scream"] = &AiObjectContextInternal::psychic_scream; + creators["vampiric embrace"] = &AiObjectContextInternal::vampiric_embrace; + } + + private: + static Action* vampiric_embrace(PlayerbotAI* ai) { return new CastVampiricEmbraceAction(ai); } + static Action* psychic_scream(PlayerbotAI* ai) { return new CastPsychicScreamAction(ai); } + static Action* resurrection(PlayerbotAI* ai) { return new CastResurrectionAction(ai); } + static Action* shadow_word_pain(PlayerbotAI* ai) { return new CastPowerWordPainAction(ai); } + static Action* shadow_word_pain_on_attacker(PlayerbotAI* ai) { return new CastPowerWordPainOnAttackerAction(ai); } + static Action* devouring_plague(PlayerbotAI* ai) { return new CastDevouringPlagueAction(ai); } + static Action* mind_flay(PlayerbotAI* ai) { return new CastMindFlayAction(ai); } + static Action* holy_fire(PlayerbotAI* ai) { return new CastHolyFireAction(ai); } + static Action* smite(PlayerbotAI* ai) { return new CastSmiteAction(ai); } + static Action* mind_blast(PlayerbotAI* ai) { return new CastMindBlastAction(ai); } + static Action* shadowform(PlayerbotAI* ai) { return new CastShadowformAction(ai); } + static Action* remove_shadowform(PlayerbotAI* ai) { return new CastRemoveShadowformAction(ai); } + static Action* holy_nova(PlayerbotAI* ai) { return new CastHolyNovaAction(ai); } + static Action* power_word_fortitude(PlayerbotAI* ai) { return new CastPowerWordFortitudeAction(ai); } + static Action* power_word_fortitude_on_party(PlayerbotAI* ai) { return new CastPowerWordFortitudeOnPartyAction(ai); } + static Action* divine_spirit(PlayerbotAI* ai) { return new CastDivineSpiritAction(ai); } + static Action* divine_spirit_on_party(PlayerbotAI* ai) { return new CastDivineSpiritOnPartyAction(ai); } + static Action* power_word_shield(PlayerbotAI* ai) { return new CastPowerWordShieldAction(ai); } + static Action* power_word_shield_on_party(PlayerbotAI* ai) { return new CastPowerWordShieldOnPartyAction(ai); } + static Action* renew(PlayerbotAI* ai) { return new CastRenewAction(ai); } + static Action* renew_on_party(PlayerbotAI* ai) { return new CastRenewOnPartyAction(ai); } + static Action* greater_heal(PlayerbotAI* ai) { return new CastGreaterHealAction(ai); } + static Action* greater_heal_on_party(PlayerbotAI* ai) { return new CastGreaterHealOnPartyAction(ai); } + static Action* heal(PlayerbotAI* ai) { return new CastHealAction(ai); } + static Action* heal_on_party(PlayerbotAI* ai) { return new CastHealOnPartyAction(ai); } + static Action* lesser_heal(PlayerbotAI* ai) { return new CastLesserHealAction(ai); } + static Action* lesser_heal_on_party(PlayerbotAI* ai) { return new CastLesserHealOnPartyAction(ai); } + static Action* flash_heal(PlayerbotAI* ai) { return new CastFlashHealAction(ai); } + static Action* flash_heal_on_party(PlayerbotAI* ai) { return new CastFlashHealOnPartyAction(ai); } + static Action* dispel_magic(PlayerbotAI* ai) { return new CastDispelMagicAction(ai); } + static Action* dispel_magic_on_party(PlayerbotAI* ai) { return new CastDispelMagicOnPartyAction(ai); } + static Action* dispel_magic_on_target(PlayerbotAI* ai) { return new CastDispelMagicOnTargetAction(ai); } + static Action* cure_disease(PlayerbotAI* ai) { return new CastCureDiseaseAction(ai); } + static Action* cure_disease_on_party(PlayerbotAI* ai) { return new CastCureDiseaseOnPartyAction(ai); } + static Action* abolish_disease(PlayerbotAI* ai) { return new CastAbolishDiseaseAction(ai); } + static Action* abolish_disease_on_party(PlayerbotAI* ai) { return new CastAbolishDiseaseOnPartyAction(ai); } + static Action* fade(PlayerbotAI* ai) { return new CastFadeAction(ai); } + static Action* inner_fire(PlayerbotAI* ai) { return new CastInnerFireAction(ai); } + }; + }; +}; + +PriestAiObjectContext::PriestAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::priest::StrategyFactoryInternal()); + strategyContexts.Add(new ai::priest::CombatStrategyFactoryInternal()); + actionContexts.Add(new ai::priest::AiObjectContextInternal()); + triggerContexts.Add(new ai::priest::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.h b/src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.h new file mode 100644 index 0000000000..315c335330 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class PriestAiObjectContext : public AiObjectContext + { + public: + PriestAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.cpp b/src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.cpp new file mode 100644 index 0000000000..8b31c50f44 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "PriestMultipliers.h" +//#include "PriestActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.h b/src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.cpp new file mode 100644 index 0000000000..8c84972efd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.cpp @@ -0,0 +1,82 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PriestMultipliers.h" +#include "PriestNonCombatStrategy.h" +#include "PriestNonCombatStrategyActionNodeFactory.h" + +using namespace ai; + +PriestNonCombatStrategy::PriestNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) +{ + actionNodeFactories.Add(new PriestNonCombatStrategyActionNodeFactory()); +} + +void PriestNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "power word: fortitude", + NextAction::array(0, new NextAction("power word: fortitude", 12.0f), NULL))); + + triggers.push_back(new TriggerNode( + "power word: fortitude on party", + NextAction::array(0, new NextAction("power word: fortitude on party", 11.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "divine spirit", + NextAction::array(0, new NextAction("divine spirit", 14.0f), NULL))); + + triggers.push_back(new TriggerNode( + "divine spirit on party", + NextAction::array(0, new NextAction("divine spirit on party", 13.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "inner fire", + NextAction::array(0, new NextAction("inner fire", 10.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("power word: shield", 70.0f), new NextAction("greater heal", 70.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member critical health", + NextAction::array(0, new NextAction("power word: shield on party", 60.0f), new NextAction("greater heal on party", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("flash heal", 21.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, new NextAction("flash heal on party", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe heal", + NextAction::array(0, new NextAction("circle of healing", 27.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member dead", + NextAction::array(0, new NextAction("resurrection", 30.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "dispel magic", + NextAction::array(0, new NextAction("dispel magic", 41.0f), NULL))); + + triggers.push_back(new TriggerNode( + "dispel magic on party", + NextAction::array(0, new NextAction("dispel magic on party", 40.0f), NULL))); + + + triggers.push_back(new TriggerNode( + "cure disease", + NextAction::array(0, new NextAction("abolish disease", 31.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member cure disease", + NextAction::array(0, new NextAction("abolish disease on party", 30.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.h new file mode 100644 index 0000000000..da82e1ae2f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class PriestNonCombatStrategy : public NonCombatStrategy + { + public: + PriestNonCombatStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "nc"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h b/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h new file mode 100644 index 0000000000..05edd68ebf --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestNonCombatStrategyActionNodeFactory.h @@ -0,0 +1,126 @@ +#pragma once + +namespace ai +{ + class PriestNonCombatStrategyActionNodeFactory : public NamedObjectFactory + { + public: + PriestNonCombatStrategyActionNodeFactory() + { + creators["holy nova"] = &holy_nova; + creators["power word: shield"] = &power_word_shield; + creators["power word: shield on party"] = &power_word_shield_on_party; + creators["renew"] = &renew; + creators["renew on party"] = &renew_on_party; + creators["greater heal"] = &greater_heal; + creators["greater heal on party"] = &greater_heal_on_party; + creators["heal"] = &heal; + creators["heal on party"] = &heal_on_party; + creators["lesser heal"] = &lesser_heal; + creators["lesser heal on party"] = &lesser_heal_on_party; + creators["flash heal"] = &flash_heal; + creators["flash heal on party"] = &flash_heal_on_party; + creators["circle of healing"] = &circle_of_healing; + } + private: + static ActionNode* holy_nova(PlayerbotAI* ai) + { + return new ActionNode ("holy nova", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* power_word_shield(PlayerbotAI* ai) + { + return new ActionNode ("power word: shield", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("renew", 50.0f), NULL), + /*C*/ NULL); + } + static ActionNode* power_word_shield_on_party(PlayerbotAI* ai) + { + return new ActionNode ("power word: shield on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("renew on party", 50.0f), NULL), + /*C*/ NULL); + } + static ActionNode* renew(PlayerbotAI* ai) + { + return new ActionNode ("renew", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* renew_on_party(PlayerbotAI* ai) + { + return new ActionNode ("renew on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* greater_heal(PlayerbotAI* ai) + { + return new ActionNode ("greater heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("heal"), NULL), + /*C*/ NULL); + } + static ActionNode* greater_heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("greater heal on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("heal on party"), NULL), + /*C*/ NULL); + } + static ActionNode* heal(PlayerbotAI* ai) + { + return new ActionNode ("heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("lesser heal"), NULL), + /*C*/ NULL); + } + static ActionNode* heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("heal on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("lesser heal on party"), NULL), + /*C*/ NULL); + } + static ActionNode* lesser_heal(PlayerbotAI* ai) + { + return new ActionNode ("lesser heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* lesser_heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("lesser heal on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* flash_heal(PlayerbotAI* ai) + { + return new ActionNode ("flash heal", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* flash_heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("flash heal on party", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* circle_of_healing(PlayerbotAI* ai) + { + return new ActionNode ("circle of healing", + /*P*/ NextAction::array(0, new NextAction("remove shadowform"), NULL), + /*A*/ NextAction::array(0, new NextAction("flash heal on party"), NULL), + /*C*/ NULL); + } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestTriggers.cpp b/src/modules/Bots/playerbot/strategy/priest/PriestTriggers.cpp new file mode 100644 index 0000000000..b60c0912d7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestTriggers.cpp @@ -0,0 +1,7 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "PriestTriggers.h" +//#include "PriestActions.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/priest/PriestTriggers.h b/src/modules/Bots/playerbot/strategy/priest/PriestTriggers.h new file mode 100644 index 0000000000..83b43c2e93 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/PriestTriggers.h @@ -0,0 +1,54 @@ +#pragma once + +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + BUFF_ON_PARTY_TRIGGER(PowerWordFortitudeOnPartyTrigger, "power word: fortitude", "power word: fortitude on party") + BUFF_TRIGGER(PowerWordFortitudeTrigger, "power word: fortitude", "power word: fortitude") + + BUFF_ON_PARTY_TRIGGER(DivineSpiritOnPartyTrigger, "divine spirit", "divine spirit on party") + BUFF_TRIGGER(DivineSpiritTrigger, "divine spirit", "divine spirit") + BUFF_TRIGGER(InnerFireTrigger, "inner fire", "inner fire") + BUFF_TRIGGER(VampiricEmbraceTrigger, "vampiric embrace", "vampiric embrace") + + class PowerWordPainOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + PowerWordPainOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "shadow word: pain") {} + }; + + DEBUFF_TRIGGER(PowerWordPainTrigger, "shadow word: pain", "shadow word: pain") + DEBUFF_TRIGGER(DevouringPlagueTrigger, "devouring plague", "devouring plague") + DEBUFF_TRIGGER(VampiricTouchTrigger, "vampiric touch", "vampiric touch") + + class DispelMagicTrigger : public NeedCureTrigger + { + public: + DispelMagicTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "dispel magic", DISPEL_MAGIC) {} + }; + + class DispelMagicPartyMemberTrigger : public PartyMemberNeedCureTrigger + { + public: + DispelMagicPartyMemberTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "dispel magic", DISPEL_MAGIC) {} + }; + + class CureDiseaseTrigger : public NeedCureTrigger + { + public: + CureDiseaseTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cure disease", DISPEL_DISEASE) {} + }; + + class PartyMemberCureDiseaseTrigger : public PartyMemberNeedCureTrigger + { + public: + PartyMemberCureDiseaseTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cure disease", DISPEL_DISEASE) {} + }; + + class ShadowformTrigger : public BuffTrigger { + public: + ShadowformTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "shadowform") {} + virtual bool IsActive() { return !ai->HasAura("shadowform", bot); } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.cpp b/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.cpp new file mode 100644 index 0000000000..56ff6deb3d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.cpp @@ -0,0 +1,60 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PriestMultipliers.h" +#include "ShadowPriestStrategy.h" +#include "ShadowPriestStrategyActionNodeFactory.h" + +using namespace ai; + +ShadowPriestStrategy::ShadowPriestStrategy(PlayerbotAI* ai) : GenericPriestStrategy(ai) +{ + actionNodeFactories.Add(new ShadowPriestStrategyActionNodeFactory()); +} + +NextAction** ShadowPriestStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("mind blast", 10.0f), NULL); +} + +void ShadowPriestStrategy::InitTriggers(std::list &triggers) +{ + GenericPriestStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), NULL))); + + triggers.push_back(new TriggerNode( + "shadowform", + NextAction::array(0, new NextAction("shadowform", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("dispersion", ACTION_EMERGENCY + 5), NULL))); + + triggers.push_back(new TriggerNode( + "vampiric embrace", + NextAction::array(0, new NextAction("vampiric embrace", 16.0f), NULL))); +} + +void ShadowPriestAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "shadow word: pain on attacker", + NextAction::array(0, new NextAction("shadow word: pain on attacker", 11.0f), NULL))); +} + +void ShadowPriestDebuffStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "devouring plague", + NextAction::array(0, new NextAction("devouring plague", 13.0f), NULL))); + + triggers.push_back(new TriggerNode( + "vampiric touch", + NextAction::array(0, new NextAction("vampiric touch", 11.0f), NULL))); + + triggers.push_back(new TriggerNode( + "shadow word: pain", + NextAction::array(0, new NextAction("shadow word: pain", 12.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.h b/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.h new file mode 100644 index 0000000000..3097f4ae8f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategy.h @@ -0,0 +1,38 @@ +#pragma once + +#include "HealPriestStrategy.h" + +namespace ai +{ + class ShadowPriestStrategy : public GenericPriestStrategy + { + public: + ShadowPriestStrategy(PlayerbotAI* ai); + + public: + virtual NextAction** getDefaultActions(); + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "shadow"; } + virtual int GetType() { return STRATEGY_TYPE_DPS|STRATEGY_TYPE_RANGED; } + }; + + class ShadowPriestAoeStrategy : public CombatStrategy + { + public: + ShadowPriestAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "shadow aoe"; } + }; + + class ShadowPriestDebuffStrategy : public CombatStrategy + { + public: + ShadowPriestDebuffStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "shadow debuff"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategyActionNodeFactory.h b/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategyActionNodeFactory.h new file mode 100644 index 0000000000..1b9c533b7c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/priest/ShadowPriestStrategyActionNodeFactory.h @@ -0,0 +1,37 @@ +#pragma once + +namespace ai +{ + class ShadowPriestStrategyActionNodeFactory : public NamedObjectFactory + { + public: + ShadowPriestStrategyActionNodeFactory() + { + creators["mind flay"] = &mind_flay; + creators["mind blast"] = &mind_blast; + creators["dispersion"] = &dispersion; + } + private: + static ActionNode* mind_flay(PlayerbotAI* ai) + { + return new ActionNode ("mind flay", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("shoot"), NULL), + /*C*/ NULL); + } + static ActionNode* mind_blast(PlayerbotAI* ai) + { + return new ActionNode ("mind blast", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mind flay"), NULL), + /*C*/ NULL); + } + static ActionNode* dispersion(PlayerbotAI* ai) + { + return new ActionNode ("dispersion", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mana potion"), NULL), + /*C*/ NULL); + } + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.cpp b/src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.cpp new file mode 100644 index 0000000000..68d619d8bf --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.cpp @@ -0,0 +1,110 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RogueMultipliers.h" +#include "DpsRogueStrategy.h" + +using namespace ai; + +class DpsRogueStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + DpsRogueStrategyActionNodeFactory() + { + creators["riposte"] = &riposte; + creators["mutilate"] = &mutilate; + creators["sinister strike"] = &sinister_strike; + creators["kick"] = &kick; + creators["kidney shot"] = &kidney_shot; + creators["rupture"] = &rupture; + creators["backstab"] = &backstab; + } +private: + static ActionNode* riposte(PlayerbotAI* ai) + { + return new ActionNode ("riposte", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mutilate"), NULL), + /*C*/ NULL); + } + static ActionNode* mutilate(PlayerbotAI* ai) + { + return new ActionNode ("mutilate", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("sinister strike"), NULL), + /*C*/ NULL); + } + static ActionNode* sinister_strike(PlayerbotAI* ai) + { + return new ActionNode ("sinister strike", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* kick(PlayerbotAI* ai) + { + return new ActionNode ("kick", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("kidney shot"), NULL), + /*C*/ NULL); + } + static ActionNode* kidney_shot(PlayerbotAI* ai) + { + return new ActionNode ("kidney shot", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* rupture(PlayerbotAI* ai) + { + return new ActionNode ("rupture", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("eviscerate"), NULL), + /*C*/ NULL); + } + static ActionNode* backstab(PlayerbotAI* ai) + { + return new ActionNode ("backstab", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mutilate"), NULL), + /*C*/ NULL); + } +}; + +DpsRogueStrategy::DpsRogueStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai) +{ + actionNodeFactories.Add(new DpsRogueStrategyActionNodeFactory()); +} + +NextAction** DpsRogueStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("riposte", ACTION_NORMAL), NULL); +} + +void DpsRogueStrategy::InitTriggers(std::list &triggers) +{ + MeleeCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "combo points available", + NextAction::array(0, new NextAction("rupture", ACTION_HIGH + 2), NULL))); + + triggers.push_back(new TriggerNode( + "medium threat", + NextAction::array(0, new NextAction("vanish", ACTION_HIGH), NULL))); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("evasion", ACTION_EMERGENCY), new NextAction("feint", ACTION_EMERGENCY), NULL))); + + triggers.push_back(new TriggerNode( + "kick", + NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), NULL))); + + triggers.push_back(new TriggerNode( + "kick on enemy healer", + NextAction::array(0, new NextAction("kick on enemy healer", ACTION_INTERRUPT + 1), NULL))); + + triggers.push_back(new TriggerNode( + "behind target", + NextAction::array(0, new NextAction("backstab", ACTION_NORMAL), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.h b/src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.h new file mode 100644 index 0000000000..77e22495ad --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/DpsRogueStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/MeleeCombatStrategy.h" + +namespace ai +{ + class DpsRogueStrategy : public MeleeCombatStrategy + { + public: + DpsRogueStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "dps"; } + virtual NextAction** getDefaultActions(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp new file mode 100644 index 0000000000..f128c41512 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp @@ -0,0 +1,14 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RogueTriggers.h" +#include "RogueMultipliers.h" +#include "GenericRogueNonCombatStrategy.h" +#include "RogueActions.h" + +using namespace ai; + +void GenericRogueNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.h new file mode 100644 index 0000000000..e2f8145e15 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericRogueNonCombatStrategy : public NonCombatStrategy + { + public: + GenericRogueNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "nc"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueActions.cpp b/src/modules/Bots/playerbot/strategy/rogue/RogueActions.cpp new file mode 100644 index 0000000000..f379d64630 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueActions.cpp @@ -0,0 +1,5 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "RogueActions.h" + +using namespace ai; diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueActions.h b/src/modules/Bots/playerbot/strategy/rogue/RogueActions.h new file mode 100644 index 0000000000..dd3bb25376 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueActions.h @@ -0,0 +1,63 @@ +#pragma once + +#include "../actions/GenericActions.h" +#include "RogueComboActions.h" +#include "RogueOpeningActions.h" +#include "RogueFinishingActions.h" + +namespace ai +{ + class CastEvasionAction : public CastBuffSpellAction + { + public: + CastEvasionAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "evasion") {} + }; + + class CastSprintAction : public CastBuffSpellAction + { + public: + CastSprintAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "sprint") {} + }; + + class CastKickAction : public CastSpellAction + { + public: + CastKickAction(PlayerbotAI* ai) : CastSpellAction(ai, "kick") {} + }; + + class CastFeintAction : public CastBuffSpellAction + { + public: + CastFeintAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "feint") {} + }; + + class CastDistractAction : public CastSpellAction + { + public: + CastDistractAction(PlayerbotAI* ai) : CastSpellAction(ai, "distract") {} + }; + + class CastVanishAction : public CastBuffSpellAction + { + public: + CastVanishAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "vanish") {} + }; + + class CastBlindAction : public CastDebuffSpellAction + { + public: + CastBlindAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "blind") {} + }; + + class CastBladeFlurryAction : public CastBuffSpellAction + { + public: + CastBladeFlurryAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blade flurry") {} + }; + + class CastKickOnEnemyHealerAction : public CastSpellOnEnemyHealerAction + { + public: + CastKickOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "kick") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp new file mode 100644 index 0000000000..6fdea8a4f5 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp @@ -0,0 +1,119 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RogueActions.h" +#include "RogueTriggers.h" +#include "RogueAiObjectContext.h" +#include "DpsRogueStrategy.h" +#include "GenericRogueNonCombatStrategy.h" +#include "../generic/PullStrategy.h" +#include "../NamedObjectContext.h" + +using namespace ai; + + +namespace ai +{ + namespace rogue + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["dps"] = &rogue::StrategyFactoryInternal::dps; + creators["nc"] = &rogue::StrategyFactoryInternal::nc; + creators["pull"] = &rogue::StrategyFactoryInternal::pull; + } + + private: + static Strategy* dps(PlayerbotAI* ai) { return new DpsRogueStrategy(ai); } + static Strategy* nc(PlayerbotAI* ai) { return new GenericRogueNonCombatStrategy(ai); } + static Strategy* pull(PlayerbotAI* ai) { return new PullStrategy(ai, "shoot"); } + }; + }; +}; + +namespace ai +{ + namespace rogue + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["kick"] = &TriggerFactoryInternal::kick; + creators["rupture"] = &TriggerFactoryInternal::rupture; + creators["slice and dice"] = &TriggerFactoryInternal::slice_and_dice; + creators["expose armor"] = &TriggerFactoryInternal::expose_armor; + creators["kick on enemy healer"] = &TriggerFactoryInternal::kick_on_enemy_healer; + + } + + private: + static Trigger* kick(PlayerbotAI* ai) { return new KickInterruptSpellTrigger(ai); } + static Trigger* rupture(PlayerbotAI* ai) { return new RuptureTrigger(ai); } + static Trigger* slice_and_dice(PlayerbotAI* ai) { return new SliceAndDiceTrigger(ai); } + static Trigger* expose_armor(PlayerbotAI* ai) { return new ExposeArmorTrigger(ai); } + static Trigger* kick_on_enemy_healer(PlayerbotAI* ai) { return new KickInterruptEnemyHealerSpellTrigger(ai); } + }; + }; +}; + + +namespace ai +{ + namespace rogue + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["riposte"] = &AiObjectContextInternal::riposte; + creators["mutilate"] = &AiObjectContextInternal::mutilate; + creators["sinister strike"] = &AiObjectContextInternal::sinister_strike; + creators["kidney shot"] = &AiObjectContextInternal::kidney_shot; + creators["rupture"] = &AiObjectContextInternal::rupture; + creators["slice and dice"] = &AiObjectContextInternal::slice_and_dice; + creators["eviscerate"] = &AiObjectContextInternal::eviscerate; + creators["vanish"] = &AiObjectContextInternal::vanish; + creators["evasion"] = &AiObjectContextInternal::evasion; + creators["kick"] = &AiObjectContextInternal::kick; + creators["feint"] = &AiObjectContextInternal::feint; + creators["backstab"] = &AiObjectContextInternal::backstab; + creators["expose armor"] = &AiObjectContextInternal::expose_armor; + creators["kick on enemy healer"] = &AiObjectContextInternal::kick_on_enemy_healer; + } + + private: + static Action* riposte(PlayerbotAI* ai) { return new CastRiposteAction(ai); } + static Action* mutilate(PlayerbotAI* ai) { return new CastMutilateAction(ai); } + static Action* sinister_strike(PlayerbotAI* ai) { return new CastSinisterStrikeAction(ai); } + static Action* kidney_shot(PlayerbotAI* ai) { return new CastKidneyShotAction(ai); } + static Action* rupture(PlayerbotAI* ai) { return new CastRuptureAction(ai); } + static Action* slice_and_dice(PlayerbotAI* ai) { return new CastSliceAndDiceAction(ai); } + static Action* eviscerate(PlayerbotAI* ai) { return new CastEviscerateAction(ai); } + static Action* vanish(PlayerbotAI* ai) { return new CastVanishAction(ai); } + static Action* evasion(PlayerbotAI* ai) { return new CastEvasionAction(ai); } + static Action* kick(PlayerbotAI* ai) { return new CastKickAction(ai); } + static Action* feint(PlayerbotAI* ai) { return new CastFeintAction(ai); } + static Action* backstab(PlayerbotAI* ai) { return new CastBackstabAction(ai); } + static Action* expose_armor(PlayerbotAI* ai) { return new CastExposeArmorAction(ai); } + static Action* kick_on_enemy_healer(PlayerbotAI* ai) { return new CastKickOnEnemyHealerAction(ai); } + }; + }; +}; + +RogueAiObjectContext::RogueAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::rogue::StrategyFactoryInternal()); + actionContexts.Add(new ai::rogue::AiObjectContextInternal()); + triggerContexts.Add(new ai::rogue::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.h b/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.h new file mode 100644 index 0000000000..ba346266cd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class RogueAiObjectContext : public AiObjectContext + { + public: + RogueAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h b/src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h new file mode 100644 index 0000000000..0568847e39 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h @@ -0,0 +1,45 @@ +#pragma once + +namespace ai +{ + class CastComboAction : public CastMeleeSpellAction + { + public: + CastComboAction(PlayerbotAI* ai, string name) : CastMeleeSpellAction(ai, name) {} + + virtual bool isUseful() + { + return CastMeleeSpellAction::isUseful() && AI_VALUE2(uint8, "combo", "self target") < 5; + } + }; + + class CastSinisterStrikeAction : public CastComboAction + { + public: + CastSinisterStrikeAction(PlayerbotAI* ai) : CastComboAction(ai, "sinister strike") {} + }; + + class CastMutilateAction : public CastComboAction + { + public: + CastMutilateAction(PlayerbotAI* ai) : CastComboAction(ai, "mutilate") {} + }; + + class CastRiposteAction : public CastComboAction + { + public: + CastRiposteAction(PlayerbotAI* ai) : CastComboAction(ai, "riposte") {} + }; + + class CastGougeAction : public CastComboAction + { + public: + CastGougeAction(PlayerbotAI* ai) : CastComboAction(ai, "gouge") {} + }; + + class CastBackstabAction : public CastComboAction + { + public: + CastBackstabAction(PlayerbotAI* ai) : CastComboAction(ai, "backstab") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueFinishingActions.h b/src/modules/Bots/playerbot/strategy/rogue/RogueFinishingActions.h new file mode 100644 index 0000000000..3a50517feb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueFinishingActions.h @@ -0,0 +1,35 @@ +#pragma once + +namespace ai +{ + class CastEviscerateAction : public CastMeleeSpellAction + { + public: + CastEviscerateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "eviscerate") {} + }; + + class CastSliceAndDiceAction : public CastMeleeSpellAction + { + public: + CastSliceAndDiceAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "slice and dice") {} + }; + + class CastExposeArmorAction : public CastMeleeSpellAction + { + public: + CastExposeArmorAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "expose armor") {} + }; + + class CastRuptureAction : public CastMeleeSpellAction + { + public: + CastRuptureAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rupture") {} + }; + + class CastKidneyShotAction : public CastMeleeSpellAction + { + public: + CastKidneyShotAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "kidney shot") {} + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.cpp b/src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.cpp new file mode 100644 index 0000000000..04f0970075 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "RogueMultipliers.h" +//#include "RogueActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.h b/src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h b/src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h new file mode 100644 index 0000000000..718efebf25 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h @@ -0,0 +1,24 @@ +#pragma once + +namespace ai +{ + class CastSapAction : public CastMeleeSpellAction + { + public: + CastSapAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "sap") {} + }; + + class CastGarroteAction : public CastMeleeSpellAction + { + public: + CastGarroteAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "garrote") {} + }; + + + class CastCheapShotAction : public CastMeleeSpellAction + { + public: + CastCheapShotAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "cheap shot") {} + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.cpp b/src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.cpp new file mode 100644 index 0000000000..eb68808f4c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.cpp @@ -0,0 +1,7 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "RogueTriggers.h" +//#include "RogueActions.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.h b/src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.h new file mode 100644 index 0000000000..8d20e12b8a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueTriggers.h @@ -0,0 +1,36 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + + class KickInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + KickInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "kick") {} + }; + + class SliceAndDiceTrigger : public BuffTrigger + { + public: + SliceAndDiceTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "slice and dice") {} + }; + + class RuptureTrigger : public DebuffTrigger + { + public: + RuptureTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "rupture") {} + }; + + class ExposeArmorTrigger : public DebuffTrigger + { + public: + ExposeArmorTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "expose armor") {} + }; + + class KickInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger + { + public: + KickInterruptEnemyHealerSpellTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "kick") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.cpp b/src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.cpp new file mode 100644 index 0000000000..cfa027229e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.cpp @@ -0,0 +1,75 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanMultipliers.h" +#include "CasterShamanStrategy.h" + +using namespace ai; + +class CasterShamanStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + CasterShamanStrategyActionNodeFactory() + { + creators["magma totem"] = &magma_totem; + } +private: + static ActionNode* magma_totem(PlayerbotAI* ai) + { + return new ActionNode ("magma totem", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NextAction::array(0, new NextAction("fire nova"), NULL)); + } +}; + +CasterShamanStrategy::CasterShamanStrategy(PlayerbotAI* ai) : GenericShamanStrategy(ai) +{ + actionNodeFactories.Add(new CasterShamanStrategyActionNodeFactory()); +} + +NextAction** CasterShamanStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("lightning bolt", 10.0f), NULL); +} + +void CasterShamanStrategy::InitTriggers(std::list &triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), NULL))); + + triggers.push_back(new TriggerNode( + "shaman weapon", + NextAction::array(0, new NextAction("flametongue weapon", 23.0f), NULL))); + + triggers.push_back(new TriggerNode( + "searing totem", + NextAction::array(0, new NextAction("searing totem", 19.0f), NULL))); + + triggers.push_back(new TriggerNode( + "shock", + NextAction::array(0, new NextAction("earth shock", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "frost shock snare", + NextAction::array(0, new NextAction("frost shock", 21.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("flametongue totem", ACTION_LIGHT_HEAL), NULL))); +} + +void CasterAoeShamanStrategy::InitTriggers(std::list &triggers) +{ + MeleeAoeShamanStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("chain lightning", 25.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("thunderstorm", 26.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.h b/src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.h new file mode 100644 index 0000000000..f9444c6935 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/CasterShamanStrategy.h @@ -0,0 +1,29 @@ +#pragma once + +#include "GenericShamanStrategy.h" +#include "MeleeShamanStrategy.h" + +namespace ai +{ + class CasterShamanStrategy : public GenericShamanStrategy + { + public: + CasterShamanStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual NextAction** getDefaultActions(); + virtual string getName() { return "caster"; } + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_RANGED; } + }; + + class CasterAoeShamanStrategy : public MeleeAoeShamanStrategy + { + public: + CasterAoeShamanStrategy(PlayerbotAI* ai) : MeleeAoeShamanStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "caster aoe"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.cpp b/src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.cpp new file mode 100644 index 0000000000..ce42e286dc --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.cpp @@ -0,0 +1,159 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanMultipliers.h" +#include "HealShamanStrategy.h" + +using namespace ai; + +class GenericShamanStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericShamanStrategyActionNodeFactory() + { + creators["flametongue weapon"] = &flametongue_weapon; + creators["frostbrand weapon"] = &frostbrand_weapon; + creators["windfury weapon"] = &windfury_weapon; + creators["lesser healing wave"] = &lesser_healing_wave; + creators["lesser healing wave on party"] = &lesser_healing_wave_on_party; + creators["chain heal"] = &chain_heal; + creators["riptide"] = &riptide; + creators["chain heal on party"] = &chain_heal_on_party; + creators["riptide on party"] = &riptide_on_party; + creators["earth shock"] = &earth_shock; + } +private: + static ActionNode* earth_shock(PlayerbotAI* ai) + { + return new ActionNode ("earth shock", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("flame shock"), NULL), + /*C*/ NULL); + } + static ActionNode* flametongue_weapon(PlayerbotAI* ai) + { + return new ActionNode ("flametongue weapon", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("frostbrand weapon"), NULL), + /*C*/ NULL); + } + static ActionNode* frostbrand_weapon(PlayerbotAI* ai) + { + return new ActionNode ("frostbrand weapon", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("rockbiter weapon"), NULL), + /*C*/ NULL); + } + static ActionNode* windfury_weapon(PlayerbotAI* ai) + { + return new ActionNode ("windfury weapon", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("rockbiter weapon"), NULL), + /*C*/ NULL); + } + static ActionNode* lesser_healing_wave(PlayerbotAI* ai) + { + return new ActionNode ("lesser healing wave", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("healing wave"), NULL), + /*C*/ NULL); + } + static ActionNode* lesser_healing_wave_on_party(PlayerbotAI* ai) + { + return new ActionNode ("lesser healing wave on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("healing wave on party"), NULL), + /*C*/ NULL); + } + static ActionNode* chain_heal(PlayerbotAI* ai) + { + return new ActionNode ("chain heal", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("lesser healing wave"), NULL), + /*C*/ NULL); + } + static ActionNode* riptide(PlayerbotAI* ai) + { + return new ActionNode ("riptide", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("healing wave"), NULL), + /*C*/ NULL); + } + static ActionNode* chain_heal_on_party(PlayerbotAI* ai) + { + return new ActionNode ("chain heal on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("lesser healing wave on party"), NULL), + /*C*/ NULL); + } + static ActionNode* riptide_on_party(PlayerbotAI* ai) + { + return new ActionNode ("riptide on party", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("healing wave on party"), NULL), + /*C*/ NULL); + } +}; + +GenericShamanStrategy::GenericShamanStrategy(PlayerbotAI* ai) : CombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericShamanStrategyActionNodeFactory()); +} + +void GenericShamanStrategy::InitTriggers(std::list &triggers) +{ + CombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "wind shear", + NextAction::array(0, new NextAction("wind shear", 23.0f), NULL))); + + triggers.push_back(new TriggerNode( + "wind shear on enemy healer", + NextAction::array(0, new NextAction("wind shear on enemy healer", 23.0f), NULL))); + + triggers.push_back(new TriggerNode( + "purge", + NextAction::array(0, new NextAction("purge", 10.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, new NextAction("lesser healing wave on party", 25.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, new NextAction("riptide on party", 25.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe heal", + NextAction::array(0, new NextAction("chain heal", 27.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("lesser healing wave", 26.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("riptide", 26.0f), NULL))); + + triggers.push_back(new TriggerNode( + "heroism", + NextAction::array(0, new NextAction("heroism", 31.0f), NULL))); + + triggers.push_back(new TriggerNode( + "bloodlust", + NextAction::array(0, new NextAction("bloodlust", 30.0f), NULL))); +} + +void ShamanBuffDpsStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "lightning shield", + NextAction::array(0, new NextAction("lightning shield", 22.0f), NULL))); +} + +void ShamanBuffManaStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "water shield", + NextAction::array(0, new NextAction("water shield", 22.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.h b/src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.h new file mode 100644 index 0000000000..fdac460178 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/GenericShamanStrategy.h @@ -0,0 +1,39 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class GenericShamanStrategy : public CombatStrategy + { + public: + GenericShamanStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + + }; + + class ShamanBuffDpsStrategy : public Strategy + { + public: + ShamanBuffDpsStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bdps"; } + + }; + + class ShamanBuffManaStrategy : public Strategy + { + public: + ShamanBuffManaStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bmana"; } + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.cpp b/src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.cpp new file mode 100644 index 0000000000..814a1964be --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.cpp @@ -0,0 +1,82 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanMultipliers.h" +#include "HealShamanStrategy.h" + +using namespace ai; + +class HealShamanStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + HealShamanStrategyActionNodeFactory() + { + creators["earthliving weapon"] = &earthliving_weapon; + creators["mana tide totem"] = &mana_tide_totem; + } +private: + static ActionNode* earthliving_weapon(PlayerbotAI* ai) + { + return new ActionNode ("earthliving weapon", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("flametongue weapon"), NULL), + /*C*/ NULL); + } + static ActionNode* mana_tide_totem(PlayerbotAI* ai) + { + return new ActionNode ("mana tide totem", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mana potion"), NULL), + /*C*/ NULL); + } + +}; + +HealShamanStrategy::HealShamanStrategy(PlayerbotAI* ai) : GenericShamanStrategy(ai) +{ + actionNodeFactories.Add(new HealShamanStrategyActionNodeFactory()); +} + +void HealShamanStrategy::InitTriggers(std::list &triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of spell", + NextAction::array(0, new NextAction("reach spell", ACTION_NORMAL + 9), NULL))); + + triggers.push_back(new TriggerNode( + "shaman weapon", + NextAction::array(0, new NextAction("earthliving weapon", 22.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("mana tide totem", ACTION_EMERGENCY + 5), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse spirit poison", + NextAction::array(0, new NextAction("cleanse spirit", 24.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse spirit curse", + NextAction::array(0, new NextAction("cleanse spirit", 24.0f), NULL))); + + triggers.push_back(new TriggerNode( + "cleanse spirit disease", + NextAction::array(0, new NextAction("cleanse spirit", 24.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member cleanse spirit poison", + NextAction::array(0, new NextAction("cleanse spirit poison on party", 23.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member cleanse spirit curse", + NextAction::array(0, new NextAction("cleanse spirit curse on party", 23.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member cleanse spirit disease", + NextAction::array(0, new NextAction("cleanse spirit disease on party", 23.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("healing stream totem", ACTION_LIGHT_HEAL), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.h b/src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.h new file mode 100644 index 0000000000..56b18b9fe9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/HealShamanStrategy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "GenericShamanStrategy.h" + +namespace ai +{ + class HealShamanStrategy : public GenericShamanStrategy + { + public: + HealShamanStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "heal"; } + virtual int GetType() { return STRATEGY_TYPE_HEAL; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.cpp b/src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.cpp new file mode 100644 index 0000000000..dbdbda28ab --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.cpp @@ -0,0 +1,93 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanMultipliers.h" +#include "MeleeShamanStrategy.h" + +using namespace ai; + +class MeleeShamanStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + MeleeShamanStrategyActionNodeFactory() + { + creators["stormstrike"] = &stormstrike; + creators["lava lash"] = &lava_lash; + creators["magma totem"] = &magma_totem; + } +private: + static ActionNode* stormstrike(PlayerbotAI* ai) + { + return new ActionNode ("stormstrike", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("lava lash"), NULL), + /*C*/ NULL); + } + static ActionNode* lava_lash(PlayerbotAI* ai) + { + return new ActionNode ("lava lash", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* magma_totem(PlayerbotAI* ai) + { + return new ActionNode ("magma totem", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NextAction::array(0, new NextAction("fire nova"), NULL)); + } +}; + +MeleeShamanStrategy::MeleeShamanStrategy(PlayerbotAI* ai) : GenericShamanStrategy(ai) +{ + actionNodeFactories.Add(new MeleeShamanStrategyActionNodeFactory()); +} + +NextAction** MeleeShamanStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("stormstrike", 10.0f), NULL); +} + +void MeleeShamanStrategy::InitTriggers(std::list &triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "shaman weapon", + NextAction::array(0, new NextAction("windfury weapon", 22.0f), NULL))); + + triggers.push_back(new TriggerNode( + "searing totem", + NextAction::array(0, new NextAction("searing totem", 22.0f), NULL))); + + triggers.push_back(new TriggerNode( + "shock", + NextAction::array(0, new NextAction("earth shock", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "not facing target", + NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), NULL))); + + triggers.push_back(new TriggerNode( + "enemy too close for melee", + NextAction::array(0, new NextAction("move out of enemy contact", ACTION_NORMAL + 8), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("strength of earth totem", ACTION_LIGHT_HEAL), NULL))); +} + +void MeleeAoeShamanStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); + + triggers.push_back(new TriggerNode( + "magma totem", + NextAction::array(0, new NextAction("magma totem", 26.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("fire nova", 25.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.h b/src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.h new file mode 100644 index 0000000000..6c18fb6014 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/MeleeShamanStrategy.h @@ -0,0 +1,28 @@ +#pragma once + +#include "GenericShamanStrategy.h" + +namespace ai +{ + class MeleeShamanStrategy : public GenericShamanStrategy + { + public: + MeleeShamanStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual NextAction** getDefaultActions(); + virtual string getName() { return "melee"; } + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } + }; + + class MeleeAoeShamanStrategy : public CombatStrategy + { + public: + MeleeAoeShamanStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "melee aoe"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.cpp b/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.cpp new file mode 100644 index 0000000000..7d23a6cf9c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "ShamanActions.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h b/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h new file mode 100644 index 0000000000..58ac0bcacd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h @@ -0,0 +1,210 @@ +#pragma once + +#include "../actions/GenericActions.h" + +namespace ai +{ + class CastLesserHealingWaveAction : public CastHealingSpellAction { + public: + CastLesserHealingWaveAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "lesser healing wave") {} + }; + + class CastLesserHealingWaveOnPartyAction : public HealPartyMemberAction + { + public: + CastLesserHealingWaveOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "lesser healing wave") {} + }; + + + class CastHealingWaveAction : public CastHealingSpellAction { + public: + CastHealingWaveAction(PlayerbotAI* ai) : CastHealingSpellAction(ai, "healing wave") {} + }; + + class CastHealingWaveOnPartyAction : public HealPartyMemberAction + { + public: + CastHealingWaveOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "healing wave") {} + }; + + class CastChainHealAction : public CastAoeHealSpellAction { + public: + CastChainHealAction(PlayerbotAI* ai) : CastAoeHealSpellAction(ai, "chain heal") {} + }; + + class CastLightningShieldAction : public CastBuffSpellAction { + public: + CastLightningShieldAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "lightning shield") {} + }; + + class CastRockbiterWeaponAction : public CastEnchantItemAction { + public: + CastRockbiterWeaponAction(PlayerbotAI* ai) : CastEnchantItemAction(ai, "rockbiter weapon") {} + }; + + class CastFlametongueWeaponAction : public CastEnchantItemAction { + public: + CastFlametongueWeaponAction(PlayerbotAI* ai) : CastEnchantItemAction(ai, "flametongue weapon") {} + }; + + class CastFrostbrandWeaponAction : public CastEnchantItemAction { + public: + CastFrostbrandWeaponAction(PlayerbotAI* ai) : CastEnchantItemAction(ai, "frostbrand weapon") {} + }; + + class CastWindfuryWeaponAction : public CastEnchantItemAction { + public: + CastWindfuryWeaponAction(PlayerbotAI* ai) : CastEnchantItemAction(ai, "windfury weapon") {} + }; + + class CastTotemAction : public CastBuffSpellAction + { + public: + CastTotemAction(PlayerbotAI* ai, string spell) : CastBuffSpellAction(ai, spell) {} + virtual bool isUseful() { return CastBuffSpellAction::isUseful() && !AI_VALUE2(bool, "has totem", name); } + }; + + class CastStoneskinTotemAction : public CastTotemAction + { + public: + CastStoneskinTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "stoneskin totem") {} + }; + + class CastEarthbindTotemAction : public CastTotemAction + { + public: + CastEarthbindTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "earthbind totem") {} + }; + + class CastStrengthOfEarthTotemAction : public CastTotemAction + { + public: + CastStrengthOfEarthTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "strength of earth totem") {} + }; + + class CastManaSpringTotemAction : public CastTotemAction + { + public: + CastManaSpringTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "mana spring totem") {} + }; + + class CastManaTideTotemAction : public CastTotemAction + { + public: + CastManaTideTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "mana tide totem") {} + virtual string GetTargetName() { return "self target"; } + }; + + class CastHealingStreamTotemAction : public CastTotemAction + { + public: + CastHealingStreamTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "healing stream totem") {} + }; + + class CastCleansingTotemAction : public CastTotemAction + { + public: + CastCleansingTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "cleansing totem") {} + }; + + class CastFlametongueTotemAction : public CastTotemAction + { + public: + CastFlametongueTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "flametongue totem") {} + }; + + class CastWindfuryTotemAction : public CastTotemAction + { + public: + CastWindfuryTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "windfury totem") {} + }; + + class CastSearingTotemAction : public CastTotemAction + { + public: + CastSearingTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "searing totem") {} + virtual string GetTargetName() { return "self target"; } + }; + + class CastMagmaTotemAction : public CastMeleeSpellAction + { + public: + CastMagmaTotemAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "magma totem") {} + virtual string GetTargetName() { return "self target"; } + virtual bool isUseful() { return CastMeleeSpellAction::isUseful() && !AI_VALUE2(bool, "has totem", name); } + }; + + class CastAncestralSpiritAction : public ResurrectPartyMemberAction + { + public: + CastAncestralSpiritAction(PlayerbotAI* ai) : ResurrectPartyMemberAction(ai, "ancestral spirit") {} + }; + + + class CastPurgeAction : public CastSpellAction + { + public: + CastPurgeAction(PlayerbotAI* ai) : CastSpellAction(ai, "purge") {} + }; + + class CastStormstrikeAction : public CastMeleeSpellAction { + public: + CastStormstrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "stormstrike") {} + }; + + class CastWaterBreathingAction : public CastBuffSpellAction { + public: + CastWaterBreathingAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "water breathing") {} + }; + + class CastWaterWalkingAction : public CastBuffSpellAction { + public: + CastWaterWalkingAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "water walking") {} + }; + + class CastWaterBreathingOnPartyAction : public BuffOnPartyAction { + public: + CastWaterBreathingOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "water breathing") {} + }; + + class CastWaterWalkingOnPartyAction : public BuffOnPartyAction { + public: + CastWaterWalkingOnPartyAction(PlayerbotAI* ai) : BuffOnPartyAction(ai, "water walking") {} + }; + + class CastFlameShockAction : public CastDebuffSpellAction + { + public: + CastFlameShockAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "flame shock") {} + }; + + class CastEarthShockAction : public CastDebuffSpellAction + { + public: + CastEarthShockAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "earth shock") {} + }; + + class CastFrostShockAction : public CastDebuffSpellAction + { + public: + CastFrostShockAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "frost shock") {} + }; + + class CastChainLightningAction : public CastSpellAction + { + public: + CastChainLightningAction(PlayerbotAI* ai) : CastSpellAction(ai, "chain lightning") {} + }; + + class CastLightningBoltAction : public CastSpellAction + { + public: + CastLightningBoltAction(PlayerbotAI* ai) : CastSpellAction(ai, "lightning bolt") {} + }; + + class CastBloodlustAction : public CastBuffSpellAction + { + public: + CastBloodlustAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "bloodlust") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.cpp new file mode 100644 index 0000000000..2f35e6703c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.cpp @@ -0,0 +1,236 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanActions.h" +#include "ShamanAiObjectContext.h" +#include "ShamanNonCombatStrategy.h" +#include "HealShamanStrategy.h" +#include "MeleeShamanStrategy.h" +#include "ShamanTriggers.h" +#include "../NamedObjectContext.h" +#include "TotemsShamanStrategy.h" +#include "CasterShamanStrategy.h" + +using namespace ai; + + + +namespace ai +{ + namespace shaman + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &shaman::StrategyFactoryInternal::nc; + creators["totems"] = &shaman::StrategyFactoryInternal::totems; + creators["melee aoe"] = &shaman::StrategyFactoryInternal::melee_aoe; + creators["caster aoe"] = &shaman::StrategyFactoryInternal::caster_aoe; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new ShamanNonCombatStrategy(ai); } + static Strategy* totems(PlayerbotAI* ai) { return new TotemsShamanStrategy(ai); } + static Strategy* melee_aoe(PlayerbotAI* ai) { return new MeleeAoeShamanStrategy(ai); } + static Strategy* caster_aoe(PlayerbotAI* ai) { return new CasterAoeShamanStrategy(ai); } + }; + + class BuffStrategyFactoryInternal : public NamedObjectContext + { + public: + BuffStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["bmana"] = &shaman::BuffStrategyFactoryInternal::bmana; + creators["bdps"] = &shaman::BuffStrategyFactoryInternal::bdps; + } + + private: + static Strategy* bmana(PlayerbotAI* ai) { return new ShamanBuffManaStrategy(ai); } + static Strategy* bdps(PlayerbotAI* ai) { return new ShamanBuffDpsStrategy(ai); } + }; + + class CombatStrategyFactoryInternal : public NamedObjectContext + { + public: + CombatStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["heal"] = &shaman::CombatStrategyFactoryInternal::heal; + creators["melee"] = &shaman::CombatStrategyFactoryInternal::dps; + creators["dps"] = &shaman::CombatStrategyFactoryInternal::dps; + creators["caster"] = &shaman::CombatStrategyFactoryInternal::caster; + } + + private: + static Strategy* heal(PlayerbotAI* ai) { return new HealShamanStrategy(ai); } + static Strategy* dps(PlayerbotAI* ai) { return new MeleeShamanStrategy(ai); } + static Strategy* caster(PlayerbotAI* ai) { return new CasterShamanStrategy(ai); } + }; + }; +}; + +namespace ai +{ + namespace shaman + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["windfury totem"] = &TriggerFactoryInternal::windfury_totem; + creators["mana spring totem"] = &TriggerFactoryInternal::mana_spring_totem; + creators["flametongue totem"] = &TriggerFactoryInternal::flametongue_totem; + creators["strength of earth totem"] = &TriggerFactoryInternal::strength_of_earth_totem; + creators["magma totem"] = &TriggerFactoryInternal::magma_totem; + creators["searing totem"] = &TriggerFactoryInternal::searing_totem; + creators["wind shear"] = &TriggerFactoryInternal::wind_shear; + creators["purge"] = &TriggerFactoryInternal::purge; + creators["shaman weapon"] = &TriggerFactoryInternal::shaman_weapon; + creators["water shield"] = &TriggerFactoryInternal::water_shield; + creators["lightning shield"] = &TriggerFactoryInternal::lightning_shield; + creators["water breathing"] = &TriggerFactoryInternal::water_breathing; + creators["water walking"] = &TriggerFactoryInternal::water_walking; + creators["water breathing on party"] = &TriggerFactoryInternal::water_breathing_on_party; + creators["water walking on party"] = &TriggerFactoryInternal::water_walking_on_party; + creators["cleanse spirit poison"] = &TriggerFactoryInternal::cleanse_poison; + creators["cleanse spirit curse"] = &TriggerFactoryInternal::cleanse_curse; + creators["cleanse spirit disease"] = &TriggerFactoryInternal::cleanse_disease; + creators["party member cleanse spirit poison"] = &TriggerFactoryInternal::party_member_cleanse_poison; + creators["party member cleanse spirit curse"] = &TriggerFactoryInternal::party_member_cleanse_curse; + creators["party member cleanse spirit disease"] = &TriggerFactoryInternal::party_member_cleanse_disease; + creators["shock"] = &TriggerFactoryInternal::shock; + creators["frost shock snare"] = &TriggerFactoryInternal::frost_shock_snare; + creators["heroism"] = &TriggerFactoryInternal::heroism; + creators["bloodlust"] = &TriggerFactoryInternal::bloodlust; + creators["maelstrom weapon"] = &TriggerFactoryInternal::maelstrom_weapon; + creators["wind shear on enemy healer"] = &TriggerFactoryInternal::wind_shear_on_enemy_healer; + } + + private: + static Trigger* maelstrom_weapon(PlayerbotAI* ai) { return new MaelstromWeaponTrigger(ai); } + static Trigger* heroism(PlayerbotAI* ai) { return new HeroismTrigger(ai); } + static Trigger* bloodlust(PlayerbotAI* ai) { return new BloodlustTrigger(ai); } + static Trigger* party_member_cleanse_disease(PlayerbotAI* ai) { return new PartyMemberCleanseSpiritDiseaseTrigger(ai); } + static Trigger* party_member_cleanse_curse(PlayerbotAI* ai) { return new PartyMemberCleanseSpiritCurseTrigger(ai); } + static Trigger* party_member_cleanse_poison(PlayerbotAI* ai) { return new PartyMemberCleanseSpiritPoisonTrigger(ai); } + static Trigger* cleanse_disease(PlayerbotAI* ai) { return new CleanseSpiritDiseaseTrigger(ai); } + static Trigger* cleanse_curse(PlayerbotAI* ai) { return new CleanseSpiritCurseTrigger(ai); } + static Trigger* cleanse_poison(PlayerbotAI* ai) { return new CleanseSpiritPoisonTrigger(ai); } + static Trigger* water_breathing(PlayerbotAI* ai) { return new WaterBreathingTrigger(ai); } + static Trigger* water_walking(PlayerbotAI* ai) { return new WaterWalkingTrigger(ai); } + static Trigger* water_breathing_on_party(PlayerbotAI* ai) { return new WaterBreathingOnPartyTrigger(ai); } + static Trigger* water_walking_on_party(PlayerbotAI* ai) { return new WaterWalkingOnPartyTrigger(ai); } + static Trigger* windfury_totem(PlayerbotAI* ai) { return new WindfuryTotemTrigger(ai); } + static Trigger* mana_spring_totem(PlayerbotAI* ai) { return new ManaSpringTotemTrigger(ai); } + static Trigger* flametongue_totem(PlayerbotAI* ai) { return new FlametongueTotemTrigger(ai); } + static Trigger* strength_of_earth_totem(PlayerbotAI* ai) { return new StrengthOfEarthTotemTrigger(ai); } + static Trigger* magma_totem(PlayerbotAI* ai) { return new MagmaTotemTrigger(ai); } + static Trigger* searing_totem(PlayerbotAI* ai) { return new SearingTotemTrigger(ai); } + static Trigger* wind_shear(PlayerbotAI* ai) { return new WindShearInterruptSpellTrigger(ai); } + static Trigger* purge(PlayerbotAI* ai) { return new PurgeTrigger(ai); } + static Trigger* shaman_weapon(PlayerbotAI* ai) { return new ShamanWeaponTrigger(ai); } + static Trigger* water_shield(PlayerbotAI* ai) { return new WaterShieldTrigger(ai); } + static Trigger* lightning_shield(PlayerbotAI* ai) { return new LightningShieldTrigger(ai); } + static Trigger* shock(PlayerbotAI* ai) { return new ShockTrigger(ai); } + static Trigger* frost_shock_snare(PlayerbotAI* ai) { return new FrostShockSnareTrigger(ai); } + static Trigger* wind_shear_on_enemy_healer(PlayerbotAI* ai) { return new WindShearInterruptEnemyHealerSpellTrigger(ai); } + }; + }; +}; + + +namespace ai +{ + namespace shaman + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["lightning shield"] = &AiObjectContextInternal::lightning_shield; + creators["strength of earth totem"] = &AiObjectContextInternal::strength_of_earth_totem; + creators["flametongue totem"] = &AiObjectContextInternal::flametongue_totem; + creators["searing totem"] = &AiObjectContextInternal::searing_totem; + creators["magma totem"] = &AiObjectContextInternal::magma_totem; + creators["windfury totem"] = &AiObjectContextInternal::windfury_totem; + creators["mana spring totem"] = &AiObjectContextInternal::mana_spring_totem; + creators["mana tide totem"] = &AiObjectContextInternal::mana_tide_totem; + creators["healing stream totem"] = &AiObjectContextInternal::healing_stream_totem; + creators["rockbiter weapon"] = &AiObjectContextInternal::rockbiter_weapon; + creators["flametongue weapon"] = &AiObjectContextInternal::flametongue_weapon; + creators["frostbrand weapon"] = &AiObjectContextInternal::frostbrand_weapon; + creators["windfury weapon"] = &AiObjectContextInternal::windfury_weapon; + creators["purge"] = &AiObjectContextInternal::purge; + creators["healing wave"] = &AiObjectContextInternal::healing_wave; + creators["lesser healing wave"] = &AiObjectContextInternal::lesser_healing_wave; + creators["healing wave on party"] = &AiObjectContextInternal::healing_wave_on_party; + creators["lesser healing wave on party"] = &AiObjectContextInternal::lesser_healing_wave_on_party; + creators["chain heal"] = &AiObjectContextInternal::chain_heal; + creators["stormstrike"] = &AiObjectContextInternal::stormstrike; + creators["ancestral spirit"] = &AiObjectContextInternal::ancestral_spirit; + creators["water walking"] = &AiObjectContextInternal::water_walking; + creators["water breathing"] = &AiObjectContextInternal::water_breathing; + creators["water walking on party"] = &AiObjectContextInternal::water_walking_on_party; + creators["water breathing on party"] = &AiObjectContextInternal::water_breathing_on_party; + creators["flame shock"] = &AiObjectContextInternal::flame_shock; + creators["earth shock"] = &AiObjectContextInternal::earth_shock; + creators["frost shock"] = &AiObjectContextInternal::frost_shock; + creators["chain lightning"] = &AiObjectContextInternal::chain_lightning; + creators["lightning bolt"] = &AiObjectContextInternal::lightning_bolt; + creators["bloodlust"] = &AiObjectContextInternal::bloodlust; + } + + private: + static Action* bloodlust(PlayerbotAI* ai) { return new CastBloodlustAction(ai); } + static Action* lightning_bolt(PlayerbotAI* ai) { return new CastLightningBoltAction(ai); } + static Action* chain_lightning(PlayerbotAI* ai) { return new CastChainLightningAction(ai); } + static Action* frost_shock(PlayerbotAI* ai) { return new CastFrostShockAction(ai); } + static Action* earth_shock(PlayerbotAI* ai) { return new CastEarthShockAction(ai); } + static Action* flame_shock(PlayerbotAI* ai) { return new CastFlameShockAction(ai); } + static Action* water_walking(PlayerbotAI* ai) { return new CastWaterWalkingAction(ai); } + static Action* water_breathing(PlayerbotAI* ai) { return new CastWaterBreathingAction(ai); } + static Action* water_walking_on_party(PlayerbotAI* ai) { return new CastWaterWalkingOnPartyAction(ai); } + static Action* water_breathing_on_party(PlayerbotAI* ai) { return new CastWaterBreathingOnPartyAction(ai); } + static Action* lightning_shield(PlayerbotAI* ai) { return new CastLightningShieldAction(ai); } + static Action* strength_of_earth_totem(PlayerbotAI* ai) { return new CastStrengthOfEarthTotemAction(ai); } + static Action* flametongue_totem(PlayerbotAI* ai) { return new CastFlametongueTotemAction(ai); } + static Action* magma_totem(PlayerbotAI* ai) { return new CastMagmaTotemAction(ai); } + static Action* searing_totem(PlayerbotAI* ai) { return new CastSearingTotemAction(ai); } + static Action* windfury_totem(PlayerbotAI* ai) { return new CastWindfuryTotemAction(ai); } + static Action* mana_spring_totem(PlayerbotAI* ai) { return new CastManaSpringTotemAction(ai); } + static Action* mana_tide_totem(PlayerbotAI* ai) { return new CastManaTideTotemAction(ai); } + static Action* healing_stream_totem(PlayerbotAI* ai) { return new CastHealingStreamTotemAction(ai); } + static Action* rockbiter_weapon(PlayerbotAI* ai) { return new CastRockbiterWeaponAction(ai); } + static Action* flametongue_weapon(PlayerbotAI* ai) { return new CastFlametongueWeaponAction(ai); } + static Action* frostbrand_weapon(PlayerbotAI* ai) { return new CastFrostbrandWeaponAction(ai); } + static Action* windfury_weapon(PlayerbotAI* ai) { return new CastWindfuryWeaponAction(ai); } + static Action* purge(PlayerbotAI* ai) { return new CastPurgeAction(ai); } + static Action* healing_wave(PlayerbotAI* ai) { return new CastHealingWaveAction(ai); } + static Action* lesser_healing_wave(PlayerbotAI* ai) { return new CastLesserHealingWaveAction(ai); } + static Action* healing_wave_on_party(PlayerbotAI* ai) { return new CastHealingWaveOnPartyAction(ai); } + static Action* lesser_healing_wave_on_party(PlayerbotAI* ai) { return new CastLesserHealingWaveOnPartyAction(ai); } + static Action* chain_heal(PlayerbotAI* ai) { return new CastChainHealAction(ai); } + static Action* stormstrike(PlayerbotAI* ai) { return new CastStormstrikeAction(ai); } + static Action* ancestral_spirit(PlayerbotAI* ai) { return new CastAncestralSpiritAction(ai); } + }; + }; +}; + + + +ShamanAiObjectContext::ShamanAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::shaman::StrategyFactoryInternal()); + strategyContexts.Add(new ai::shaman::CombatStrategyFactoryInternal()); + strategyContexts.Add(new ai::shaman::BuffStrategyFactoryInternal()); + actionContexts.Add(new ai::shaman::AiObjectContextInternal()); + triggerContexts.Add(new ai::shaman::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.h b/src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.h new file mode 100644 index 0000000000..718084a6aa --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class ShamanAiObjectContext : public AiObjectContext + { + public: + ShamanAiObjectContext(PlayerbotAI* ai); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.cpp b/src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.cpp new file mode 100644 index 0000000000..4bae6b6e85 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "ShamanMultipliers.h" +//#include "ShamanActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.h b/src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.cpp new file mode 100644 index 0000000000..ae7f9a8b0d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.cpp @@ -0,0 +1,49 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanMultipliers.h" +#include "ShamanNonCombatStrategy.h" + +using namespace ai; + +void ShamanNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "party member dead", + NextAction::array(0, new NextAction("ancestral spirit", 33.0f), NULL))); + + triggers.push_back(new TriggerNode( + "water breathing", + NextAction::array(0, new NextAction("water breathing", 12.0f), NULL))); + + triggers.push_back(new TriggerNode( + "water walking", + NextAction::array(0, new NextAction("water walking", 12.0f), NULL))); + + triggers.push_back(new TriggerNode( + "water breathing on party", + NextAction::array(0, new NextAction("water breathing on party", 11.0f), NULL))); + + triggers.push_back(new TriggerNode( + "water walking on party", + NextAction::array(0, new NextAction("water walking on party", 11.0f), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("healing wave", 70.0f), NULL))); + + triggers.push_back(new TriggerNode( + "party member critical health", + NextAction::array(0, new NextAction("healing wave on party", 60.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe heal", + NextAction::array(0, new NextAction("chain heal", 27.0f), NULL))); +} + +void ShamanNonCombatStrategy::InitMultipliers(std::list &multipliers) +{ + NonCombatStrategy::InitMultipliers(multipliers); +} + diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.h new file mode 100644 index 0000000000..a6859ee711 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanNonCombatStrategy.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class ShamanNonCombatStrategy : public NonCombatStrategy + { + public: + ShamanNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual void InitMultipliers(std::list &multipliers); + virtual string getName() { return "nc"; } + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.cpp b/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.cpp new file mode 100644 index 0000000000..4d719d395e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.cpp @@ -0,0 +1,42 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanTriggers.h" +#include "ShamanActions.h" + +using namespace ai; + +list ShamanWeaponTrigger::spells; + +bool ShamanWeaponTrigger::IsActive() +{ + if (spells.empty()) + { + spells.push_back("frostbrand weapon"); + spells.push_back("rockbiter weapon"); + spells.push_back("flametongue weapon"); + spells.push_back("earthliving weapon"); + spells.push_back("windfury weapon"); + } + + for (list::iterator i = spells.begin(); i != spells.end(); ++i) + { + uint32 spellId = AI_VALUE2(uint32, "spell id", spell); + if (!spellId) + { + continue; + } + + if (AI_VALUE2(Item*, "item for spell", spellId)) + { + return true; + } + } + + return false; +} + +bool ShockTrigger::IsActive() +{ + return SpellTrigger::IsActive() + && !ai->HasAnyAuraOf(GetTarget(), "frost shock", "earth shock", "flame shock", NULL); +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h b/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h new file mode 100644 index 0000000000..96003249d8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h @@ -0,0 +1,197 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + class ShamanWeaponTrigger : public BuffTrigger { + public: + ShamanWeaponTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "rockbiter weapon") {} + virtual bool IsActive(); + private: + static list spells; + }; + + class TotemTrigger : public Trigger { + public: + TotemTrigger(PlayerbotAI* ai, string spell, int attackerCount = 0) : Trigger(ai, spell), attackerCount(attackerCount) {} + + virtual bool IsActive() + { + return AI_VALUE(uint8, "attacker count") >= attackerCount && !AI_VALUE2(bool, "has totem", name); + } + + protected: + int attackerCount; + }; + + class WindfuryTotemTrigger : public TotemTrigger { + public: + WindfuryTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "windfury totem") {} + }; + + class ManaSpringTotemTrigger : public TotemTrigger { + public: + ManaSpringTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "mana spring totem") {} + virtual bool IsActive() + { + return AI_VALUE(uint8, "attacker count") >= attackerCount && + !AI_VALUE2(bool, "has totem", "mana tide totem") && + !AI_VALUE2(bool, "has totem", name); + } + }; + + class FlametongueTotemTrigger : public TotemTrigger { + public: + FlametongueTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "flametongue totem") {} + }; + + class StrengthOfEarthTotemTrigger : public TotemTrigger { + public: + StrengthOfEarthTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "strength of earth totem") {} + }; + + class MagmaTotemTrigger : public TotemTrigger { + public: + MagmaTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "magma totem", 3) {} + }; + + class SearingTotemTrigger : public TotemTrigger { + public: + SearingTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "searing totem", 1) {} + }; + + class WindShearInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + WindShearInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "wind shear") {} + }; + + class WaterShieldTrigger : public BuffTrigger + { + public: + WaterShieldTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "water shield") {} + }; + + class LightningShieldTrigger : public BuffTrigger + { + public: + LightningShieldTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "lightning shield") {} + }; + + class PurgeTrigger : public TargetAuraDispelTrigger + { + public: + PurgeTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "purge", DISPEL_MAGIC) {} + }; + + class WaterWalkingTrigger : public BuffTrigger { + public: + WaterWalkingTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "water walking") {} + + virtual bool IsActive() + { + return BuffTrigger::IsActive() && AI_VALUE2(bool, "swimming", "self target"); + } + }; + + class WaterBreathingTrigger : public BuffTrigger { + public: + WaterBreathingTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "water breathing") {} + + virtual bool IsActive() + { + return BuffTrigger::IsActive() && AI_VALUE2(bool, "swimming", "self target"); + } + }; + + class WaterWalkingOnPartyTrigger : public BuffOnPartyTrigger { + public: + WaterWalkingOnPartyTrigger(PlayerbotAI* ai) : BuffOnPartyTrigger(ai, "water walking on party") {} + + virtual bool IsActive() + { + return BuffOnPartyTrigger::IsActive() && AI_VALUE2(bool, "swimming", "self target"); + } + }; + + class WaterBreathingOnPartyTrigger : public BuffOnPartyTrigger { + public: + WaterBreathingOnPartyTrigger(PlayerbotAI* ai) : BuffOnPartyTrigger(ai, "water breathing on party") {} + + virtual bool IsActive() + { + return BuffOnPartyTrigger::IsActive() && AI_VALUE2(bool, "swimming", "self target"); + } + }; + + class CleanseSpiritPoisonTrigger : public NeedCureTrigger + { + public: + CleanseSpiritPoisonTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cleanse spirit", DISPEL_POISON) {} + }; + + class PartyMemberCleanseSpiritPoisonTrigger : public PartyMemberNeedCureTrigger + { + public: + PartyMemberCleanseSpiritPoisonTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cleanse spirit", DISPEL_POISON) {} + }; + + class CleanseSpiritCurseTrigger : public NeedCureTrigger + { + public: + CleanseSpiritCurseTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cleanse spirit", DISPEL_CURSE) {} + }; + + class PartyMemberCleanseSpiritCurseTrigger : public PartyMemberNeedCureTrigger + { + public: + PartyMemberCleanseSpiritCurseTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cleanse spirit", DISPEL_CURSE) {} + }; + + class CleanseSpiritDiseaseTrigger : public NeedCureTrigger + { + public: + CleanseSpiritDiseaseTrigger(PlayerbotAI* ai) : NeedCureTrigger(ai, "cleanse spirit", DISPEL_DISEASE) {} + }; + + class PartyMemberCleanseSpiritDiseaseTrigger : public PartyMemberNeedCureTrigger + { + public: + PartyMemberCleanseSpiritDiseaseTrigger(PlayerbotAI* ai) : PartyMemberNeedCureTrigger(ai, "cleanse spirit", DISPEL_DISEASE) {} + }; + + class ShockTrigger : public DebuffTrigger { + public: + ShockTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "earth shock") {} + virtual bool IsActive(); + }; + + class FrostShockSnareTrigger : public SnareTargetTrigger { + public: + FrostShockSnareTrigger(PlayerbotAI* ai) : SnareTargetTrigger(ai, "frost shock") {} + }; + + class HeroismTrigger : public BoostTrigger + { + public: + HeroismTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "heroism") {} + }; + + class BloodlustTrigger : public BoostTrigger + { + public: + BloodlustTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "bloodlust") {} + }; + + class MaelstromWeaponTrigger : public HasAuraTrigger + { + public: + MaelstromWeaponTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "maelstrom weapon") {} + }; + + class WindShearInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger + { + public: + WindShearInterruptEnemyHealerSpellTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "wind shear") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.cpp b/src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.cpp new file mode 100644 index 0000000000..0a1b717337 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.cpp @@ -0,0 +1,31 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ShamanMultipliers.h" +#include "TotemsShamanStrategy.h" + +using namespace ai; + +TotemsShamanStrategy::TotemsShamanStrategy(PlayerbotAI* ai) : GenericShamanStrategy(ai) +{ +} + +void TotemsShamanStrategy::InitTriggers(std::list &triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "windfury totem", + NextAction::array(0, new NextAction("windfury totem", 16.0f), NULL))); + + triggers.push_back(new TriggerNode( + "mana spring totem", + NextAction::array(0, new NextAction("mana spring totem", 19.0f), NULL))); + + triggers.push_back(new TriggerNode( + "strength of earth totem", + NextAction::array(0, new NextAction("strength of earth totem", 18.0f), NULL))); + + triggers.push_back(new TriggerNode( + "flametongue totem", + NextAction::array(0, new NextAction("flametongue totem", 17.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.h b/src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.h new file mode 100644 index 0000000000..3205017cbd --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/shaman/TotemsShamanStrategy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "GenericShamanStrategy.h" + +namespace ai +{ + class TotemsShamanStrategy : public GenericShamanStrategy + { + public: + TotemsShamanStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "totems"; } + virtual int GetType() { return STRATEGY_TYPE_HEAL; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h b/src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h new file mode 100644 index 0000000000..019a2f57d8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h @@ -0,0 +1,38 @@ +#pragma once + +#include "../Trigger.h" + +namespace ai +{ + class ChatCommandTrigger : public Trigger { + public: + ChatCommandTrigger(PlayerbotAI* ai, string command) : Trigger(ai, command), triggered(false) {} + + virtual void ExternalEvent(string param, Player* owner = NULL) + { + this->param = param; + this->owner = owner; + triggered = true; + } + + virtual Event Check() + { + if (!triggered) + { + return Event(); + } + + return Event(getName(), param, owner); + } + + virtual void Reset() + { + triggered = false; + } + + private: + string param; + bool triggered; + Player* owner; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h b/src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h new file mode 100644 index 0000000000..4a6397b24a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h @@ -0,0 +1,138 @@ +#pragma once + +#include "ChatCommandTrigger.h" + +namespace ai +{ + class ChatTriggerContext : public NamedObjectContext + { + public: + ChatTriggerContext() + { + creators["quests"] = &ChatTriggerContext::quests; + creators["stats"] = &ChatTriggerContext::stats; + creators["leave"] = &ChatTriggerContext::leave; + creators["rep"] = &ChatTriggerContext::reputation; + creators["reputation"] = &ChatTriggerContext::reputation; + creators["log"] = &ChatTriggerContext::log; + creators["los"] = &ChatTriggerContext::los; + creators["drop"] = &ChatTriggerContext::drop; + creators["q"] = &ChatTriggerContext::q; + creators["ll"] = &ChatTriggerContext::ll; + creators["loot all"] = &ChatTriggerContext::loot_all; + creators["add all loot"] = &ChatTriggerContext::loot_all; + creators["release"] = &ChatTriggerContext::release; + creators["teleport"] = &ChatTriggerContext::teleport; + creators["taxi"] = &ChatTriggerContext::taxi; + creators["repair"] = &ChatTriggerContext::repair; + creators["u"] = &ChatTriggerContext::use; + creators["use"] = &ChatTriggerContext::use; + creators["c"] = &ChatTriggerContext::item_count; + creators["e"] = &ChatTriggerContext::equip; + creators["ue"] = &ChatTriggerContext::uneqip; + creators["s"] = &ChatTriggerContext::sell; + creators["b"] = &ChatTriggerContext::buy; + creators["r"] = &ChatTriggerContext::reward; + creators["t"] = &ChatTriggerContext::trade; + creators["nt"] = &ChatTriggerContext::nontrade; + creators["talents"] = &ChatTriggerContext::talents; + creators["spells"] = &ChatTriggerContext::spells; + creators["co"] = &ChatTriggerContext::co; + creators["nc"] = &ChatTriggerContext::nc; + creators["dead"] = &ChatTriggerContext::dead; + creators["trainer"] = &ChatTriggerContext::trainer; + creators["attack"] = &ChatTriggerContext::attack; + creators["chat"] = &ChatTriggerContext::chat; + creators["accept"] = &ChatTriggerContext::accept; + creators["home"] = &ChatTriggerContext::home; + creators["reset ai"] = &ChatTriggerContext::reset_ai; + creators["destroy"] = &ChatTriggerContext::destroy; + creators["emote"] = &ChatTriggerContext::emote; + creators["buff"] = &ChatTriggerContext::buff; + creators["help"] = &ChatTriggerContext::help; + creators["gb"] = &ChatTriggerContext::gb; + creators["bank"] = &ChatTriggerContext::bank; + creators["follow"] = &ChatTriggerContext::follow; + creators["stay"] = &ChatTriggerContext::stay; + creators["flee"] = &ChatTriggerContext::flee; + creators["grind"] = &ChatTriggerContext::grind; + creators["tank attack"] = &ChatTriggerContext::tank_attack; + creators["talk"] = &ChatTriggerContext::talk; + creators["cast"] = &ChatTriggerContext::talk; + creators["invite"] = &ChatTriggerContext::invite; + creators["spell"] = &ChatTriggerContext::spell; + creators["rti"] = &ChatTriggerContext::rti; + creators["revive"] = &ChatTriggerContext::revive; + creators["runaway"] = &ChatTriggerContext::runaway; + creators["warning"] = &ChatTriggerContext::warning; + creators["position"] = &ChatTriggerContext::position; + creators["summon"] = &ChatTriggerContext::summon; + creators["who"] = &ChatTriggerContext::who; + creators["save mana"] = &ChatTriggerContext::save_mana; + creators["max dps"] = &ChatTriggerContext::max_dps; + creators["attackers"] = &ChatTriggerContext::attackers; + } + + private: + static Trigger* attackers(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "attackers"); } + static Trigger* max_dps(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "max dps"); } + static Trigger* save_mana(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "save mana"); } + static Trigger* who(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "who"); } + static Trigger* summon(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "summon"); } + static Trigger* position(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "position"); } + static Trigger* runaway(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "runaway"); } + static Trigger* warning(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "warning"); } + static Trigger* revive(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "revive"); } + static Trigger* rti(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "rti"); } + static Trigger* invite(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "invite"); } + static Trigger* cast(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "cast"); } + static Trigger* talk(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "talk"); } + static Trigger* flee(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "flee"); } + static Trigger* grind(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "grind"); } + static Trigger* tank_attack(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "tank attack"); } + static Trigger* stay(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "stay"); } + static Trigger* follow(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "follow"); } + static Trigger* gb(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "gb"); } + static Trigger* bank(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "bank"); } + static Trigger* help(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "help"); } + static Trigger* buff(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "buff"); } + static Trigger* emote(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "emote"); } + static Trigger* destroy(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "destroy"); } + static Trigger* home(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "home"); } + static Trigger* accept(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "accept"); } + static Trigger* chat(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "chat"); } + static Trigger* attack(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "attack"); } + static Trigger* trainer(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "trainer"); } + static Trigger* co(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "co"); } + static Trigger* nc(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "nc"); } + static Trigger* dead(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "dead"); } + static Trigger* spells(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "spells"); } + static Trigger* talents(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "talents"); } + static Trigger* equip(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "e"); } + static Trigger* uneqip(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "ue"); } + static Trigger* sell(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "s"); } + static Trigger* buy(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "b"); } + static Trigger* reward(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "r"); } + static Trigger* trade(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "t"); } + static Trigger* nontrade(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "nt"); } + + static Trigger* item_count(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "c"); } + static Trigger* use(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "use"); } + static Trigger* repair(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "repair"); } + static Trigger* taxi(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "taxi"); } + static Trigger* teleport(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "teleport"); } + static Trigger* q(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "q"); } + static Trigger* ll(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "ll"); } + static Trigger* drop(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "drop"); } + static Trigger* quests(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "quests"); } + static Trigger* stats(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "stats"); } + static Trigger* leave(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "leave"); } + static Trigger* reputation(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "reputation"); } + static Trigger* log(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "log"); } + static Trigger* los(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "los"); } + static Trigger* loot_all(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "add all loot"); } + static Trigger* release(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "release"); } + static Trigger* reset_ai(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "reset ai"); } + static Trigger* spell(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "spell"); } + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.cpp b/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.cpp new file mode 100644 index 0000000000..6560658f0e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.cpp @@ -0,0 +1,17 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GenericTriggers.h" +#include "CureTriggers.h" + +using namespace ai; + +bool NeedCureTrigger::IsActive() +{ + Unit* target = GetTarget(); + return target && ai->HasAuraToDispel(target, dispelType); +} + +Value* PartyMemberNeedCureTrigger::GetTargetValue() +{ + return context->GetValue("party member to dispel", dispelType); +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h new file mode 100644 index 0000000000..4cdb151c32 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h @@ -0,0 +1,35 @@ +#pragma once +#include "../Trigger.h" + +namespace ai +{ + class SpellTrigger; + + class NeedCureTrigger : public SpellTrigger { + public: + NeedCureTrigger(PlayerbotAI* ai, string spell, uint32 dispelType) : SpellTrigger(ai, spell) + { + this->dispelType = dispelType; + } + virtual string GetTargetName() { return "self target"; } + virtual bool IsActive(); + + protected: + uint32 dispelType; + }; + + class TargetAuraDispelTrigger : public NeedCureTrigger { + public: + TargetAuraDispelTrigger(PlayerbotAI* ai, string spell, uint32 dispelType) : + NeedCureTrigger(ai, spell, dispelType) {} + virtual string GetTargetName() { return "current target"; } + }; + + class PartyMemberNeedCureTrigger : public NeedCureTrigger { + public: + PartyMemberNeedCureTrigger(PlayerbotAI* ai, string spell, uint32 dispelType) : + NeedCureTrigger(ai, spell, dispelType) {} + + virtual Value* GetTargetValue(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.cpp b/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.cpp new file mode 100644 index 0000000000..815a1b13af --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.cpp @@ -0,0 +1,248 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GenericTriggers.h" +#include "../../LootObjectStack.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool LowManaTrigger::IsActive() +{ + return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana; +} + +bool MediumManaTrigger::IsActive() +{ + return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.mediumMana; +} + + +bool RageAvailable::IsActive() +{ + return AI_VALUE2(uint8, "rage", "self target") >= amount; +} + +bool EnergyAvailable::IsActive() +{ + return AI_VALUE2(uint8, "energy", "self target") >= amount; +} + +bool ComboPointsAvailableTrigger::IsActive() +{ + return AI_VALUE2(uint8, "combo", "current target") >= amount; +} + +bool LoseAggroTrigger::IsActive() +{ + return !AI_VALUE2(bool, "has aggro", "current target"); +} + +bool HasAggroTrigger::IsActive() +{ + return AI_VALUE2(bool, "has aggro", "current target"); +} + +bool PanicTrigger::IsActive() +{ + return AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig.criticalHealth && + (!AI_VALUE2(bool, "has mana", "self target") || AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana); +} + +bool BuffTrigger::IsActive() +{ + Unit* target = GetTarget(); + return SpellTrigger::IsActive() && + !ai->HasAura(spell, target) && + (!AI_VALUE2(bool, "has mana", "self target") || AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.lowMana); +} + +Value* BuffOnPartyTrigger::GetTargetValue() +{ + return context->GetValue("party member without aura", spell); +} + +Value* DebuffOnAttackerTrigger::GetTargetValue() +{ + return context->GetValue("attacker without aura", spell); +} + +bool NoAttackersTrigger::IsActive() +{ + return !AI_VALUE(Unit*, "current target") && AI_VALUE(uint8, "attacker count") > 0; +} + +bool InvalidTargetTrigger::IsActive() +{ + return AI_VALUE2(bool, "invalid target", "current target"); +} + +bool NoTargetTrigger::IsActive() +{ + return !AI_VALUE(Unit*, "current target"); +} + +bool MyAttackerCountTrigger::IsActive() +{ + return AI_VALUE(uint8, "my attacker count") >= amount; +} + +bool AoeTrigger::IsActive() +{ + return AI_VALUE(uint8, "attacker count") >= amount; +} + +bool DebuffTrigger::IsActive() +{ + return BuffTrigger::IsActive() && AI_VALUE2(uint8, "health", "current target") > 25; +} + +bool SpellTrigger::IsActive() +{ + return GetTarget(); +} + +bool SpellCanBeCastTrigger::IsActive() +{ + Unit* target = GetTarget(); + return target && ai->CanCastSpell(spell, target); +} + +bool RandomTrigger::IsActive() +{ + int vl = rand() % (int)(1 + probability * 10 / sPlayerbotAIConfig.randomChangeMultiplier); + return vl == 0; +} + +bool AndTrigger::IsActive() +{ + return ls->IsActive() && rs->IsActive(); +} + +string AndTrigger::getName() +{ + std::string name(ls->getName()); + name = name + " and "; + name = name + rs->getName(); + return name; +} + +bool BoostTrigger::IsActive() +{ + return BuffTrigger::IsActive() && AI_VALUE(uint8, "balance") <= balance; +} + +bool SnareTargetTrigger::IsActive() +{ + Unit* target = GetTarget(); + return DebuffTrigger::IsActive() && AI_VALUE2(bool, "moving", "current target") && !ai->HasAura(spell, target); +} + +bool ItemCountTrigger::IsActive() +{ + return AI_VALUE2(uint8, "item count", item) < count; +} + +bool InterruptSpellTrigger::IsActive() +{ + return SpellTrigger::IsActive() && ai->IsInterruptableSpellCasting(GetTarget(), getName()); +} + +bool HasAuraTrigger::IsActive() +{ + return ai->HasAura(getName(), GetTarget()); +} + +bool TankAoeTrigger::IsActive() +{ + if (!AI_VALUE(uint8, "attacker count")) + { + return false; + } + + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + if (!currentTarget) + { + return true; + } + + Unit* tankTarget = AI_VALUE(Unit*, "tank target"); + if (!tankTarget || currentTarget == tankTarget) + { + return false; + } + + return currentTarget->getVictim() == AI_VALUE(Unit*, "self target"); +} + +bool IsBehindTargetTrigger::IsActive() +{ + Unit* target = AI_VALUE(Unit*, "current target"); + return target && AI_VALUE2(bool, "behind", "current target"); +} + +bool IsNotFacingTargetTrigger::IsActive() +{ + return !AI_VALUE2(bool, "facing", "current target"); +} + +bool HasCcTargetTrigger::IsActive() +{ + return AI_VALUE(uint8, "attacker count") > 2 && AI_VALUE2(Unit*, "cc target", getName()) && + !AI_VALUE2(Unit*, "current cc target", getName()); +} + +bool NoMovementTrigger::IsActive() +{ + return !AI_VALUE2(bool, "moving", "self target"); +} + +bool NoPossibleTargetsTrigger::IsActive() +{ + list targets = AI_VALUE(list, "possible targets"); + return !targets.size(); +} + +bool NotLeastHpTargetActiveTrigger::IsActive() +{ + Unit* leastHp = AI_VALUE(Unit*, "least hp target"); + Unit* target = AI_VALUE(Unit*, "current target"); + return leastHp && target != leastHp; +} + +bool EnemyPlayerIsAttacking::IsActive() +{ + Unit* enemyPlayer = AI_VALUE(Unit*, "enemy player target"); + Unit* target = AI_VALUE(Unit*, "current target"); + return enemyPlayer && target != enemyPlayer; +} + +bool IsSwimmingTrigger::IsActive() +{ + return AI_VALUE2(bool, "swimming", "self target"); +} + +bool HasNearestAddsTrigger::IsActive() +{ + list targets = AI_VALUE(list, "nearest adds"); + return targets.size(); +} + +bool HasItemForSpellTrigger::IsActive() +{ + string spell = getName(); + uint32 spellId = AI_VALUE2(uint32, "spell id", spell); + return spellId && AI_VALUE2(Item*, "item for spell", spellId); +} + + +bool TargetChangedTrigger::IsActive() +{ + Unit* oldTarget = context->GetValue("old target")->Get(); + Unit* target = context->GetValue("current target")->Get(); + return target && oldTarget != target; +} + +Value* InterruptEnemyHealerTrigger::GetTargetValue() +{ + return context->GetValue("enemy healer target", spell); +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h new file mode 100644 index 0000000000..d7a8cc58e4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h @@ -0,0 +1,540 @@ +#pragma once +#include "../Trigger.h" +#include "../../PlayerbotAIConfig.h" + +#define BUFF_TRIGGER(clazz, spell, action) \ + class clazz : public BuffTrigger \ + { \ + public: \ + clazz(PlayerbotAI* ai) : BuffTrigger(ai, spell) {} \ + }; + +#define BUFF_ON_PARTY_TRIGGER(clazz, spell, action) \ + class clazz : public BuffOnPartyTrigger \ + { \ + public: \ + clazz(PlayerbotAI* ai) : BuffOnPartyTrigger(ai, spell) {} \ + }; + +#define DEBUFF_TRIGGER(clazz, spell, action) \ + class clazz : public DebuffTrigger \ + { \ + public: \ + clazz(PlayerbotAI* ai) : DebuffTrigger(ai, spell) {} \ + }; + +namespace ai +{ + class StatAvailable : public Trigger + { + public: + StatAvailable(PlayerbotAI* ai, int amount, string name = "stat available") : Trigger(ai, name) + { + this->amount = amount; + } + + protected: + int amount; + }; + + class RageAvailable : public StatAvailable + { + public: + RageAvailable(PlayerbotAI* ai, int amount) : StatAvailable(ai, amount, "rage available") {} + virtual bool IsActive(); + }; + + class LightRageAvailableTrigger : public RageAvailable + { + public: + LightRageAvailableTrigger(PlayerbotAI* ai) : RageAvailable(ai, 20) {} + }; + + class MediumRageAvailableTrigger : public RageAvailable + { + public: + MediumRageAvailableTrigger(PlayerbotAI* ai) : RageAvailable(ai, 40) {} + }; + + class HighRageAvailableTrigger : public RageAvailable + { + public: + HighRageAvailableTrigger(PlayerbotAI* ai) : RageAvailable(ai, 60) {} + }; + + class EnergyAvailable : public StatAvailable + { + public: + EnergyAvailable(PlayerbotAI* ai, int amount) : StatAvailable(ai, amount, "energy available") {} + virtual bool IsActive(); + }; + + class LightEnergyAvailableTrigger : public EnergyAvailable + { + public: + LightEnergyAvailableTrigger(PlayerbotAI* ai) : EnergyAvailable(ai, 20) {} + }; + + class MediumEnergyAvailableTrigger : public EnergyAvailable + { + public: + MediumEnergyAvailableTrigger(PlayerbotAI* ai) : EnergyAvailable(ai, 40) {} + }; + + class HighEnergyAvailableTrigger : public EnergyAvailable + { + public: + HighEnergyAvailableTrigger(PlayerbotAI* ai) : EnergyAvailable(ai, 60) {} + }; + + class ComboPointsAvailableTrigger : public StatAvailable + { + public: + ComboPointsAvailableTrigger(PlayerbotAI* ai, int amount = 5) : StatAvailable(ai, amount, "combo points available") {} + virtual bool IsActive(); + }; + + class LoseAggroTrigger : public Trigger { + public: + LoseAggroTrigger(PlayerbotAI* ai) : Trigger(ai, "lose aggro") {} + virtual bool IsActive(); + }; + + class HasAggroTrigger : public Trigger { + public: + HasAggroTrigger(PlayerbotAI* ai) : Trigger(ai, "have aggro") {} + virtual bool IsActive(); + }; + + class SpellTrigger : public Trigger + { + public: + SpellTrigger(PlayerbotAI* ai, string spell, int checkInterval = 1) : Trigger(ai, spell, checkInterval) + { + this->spell = spell; + } + + virtual string GetTargetName() { return "current target"; } + virtual string getName() { return spell; } + virtual bool IsActive(); + + protected: + string spell; + }; + + class SpellCanBeCastTrigger : public SpellTrigger + { + public: + SpellCanBeCastTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell) {} + virtual bool IsActive(); + }; + + // TODO: check other targets + class InterruptSpellTrigger : public SpellTrigger + { + public: + InterruptSpellTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell) {} + virtual bool IsActive(); + }; + + + class AttackerCountTrigger : public Trigger + { + public: + AttackerCountTrigger(PlayerbotAI* ai, int amount, float distance = sPlayerbotAIConfig.sightDistance) : Trigger(ai) + { + this->amount = amount; + this->distance = distance; + } + public: + virtual bool IsActive() + { + return AI_VALUE(uint8, "attacker count") >= amount; + } + virtual string getName() { return "attacker count"; } + + protected: + int amount; + float distance; + }; + + class HasAttackersTrigger : public AttackerCountTrigger + { + public: + HasAttackersTrigger(PlayerbotAI* ai) : AttackerCountTrigger(ai, 1) {} + }; + + class MyAttackerCountTrigger : public AttackerCountTrigger + { + public: + MyAttackerCountTrigger(PlayerbotAI* ai, int amount) : AttackerCountTrigger(ai, amount) {} + public: + virtual bool IsActive(); + virtual string getName() { return "my attacker count"; } + }; + + class MediumThreatTrigger : public MyAttackerCountTrigger + { + public: + MediumThreatTrigger(PlayerbotAI* ai) : MyAttackerCountTrigger(ai, 2) {} + }; + + class AoeTrigger : public AttackerCountTrigger + { + public: + AoeTrigger(PlayerbotAI* ai, int amount = 3, float range = 15.0f) : AttackerCountTrigger(ai, amount) + { + this->range = range; + } + public: + virtual bool IsActive(); + virtual string getName() { return "aoe"; } + + private: + float range; + }; + + class NoFoodTrigger : public Trigger { + public: + NoFoodTrigger(PlayerbotAI* ai) : Trigger(ai, "no food trigger") {} + virtual bool IsActive() { return AI_VALUE2(list, "inventory items", "food").empty(); } + }; + + class NoDrinkTrigger : public Trigger { + public: + NoDrinkTrigger(PlayerbotAI* ai) : Trigger(ai, "no drink trigger") {} + virtual bool IsActive() { return AI_VALUE2(list, "inventory items", "drink").empty(); } + }; + + class LightAoeTrigger : public AoeTrigger + { + public: + LightAoeTrigger(PlayerbotAI* ai) : AoeTrigger(ai, 2, 15.0f) {} + }; + + class MediumAoeTrigger : public AoeTrigger + { + public: + MediumAoeTrigger(PlayerbotAI* ai) : AoeTrigger(ai, 3, 17.0f) {} + }; + + class HighAoeTrigger : public AoeTrigger + { + public: + HighAoeTrigger(PlayerbotAI* ai) : AoeTrigger(ai, 4, 20.0f) {} + }; + + class BuffTrigger : public SpellTrigger + { + public: + BuffTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell, 5) {} + public: + virtual string GetTargetName() { return "self target"; } + virtual bool IsActive(); + }; + + class BuffOnPartyTrigger : public BuffTrigger + { + public: + BuffOnPartyTrigger(PlayerbotAI* ai, string spell) : BuffTrigger(ai, spell) {} + public: + virtual Value* GetTargetValue(); + }; + + BEGIN_TRIGGER(NoAttackersTrigger, Trigger) + END_TRIGGER() + + BEGIN_TRIGGER(NoTargetTrigger, Trigger) + END_TRIGGER() + + BEGIN_TRIGGER(InvalidTargetTrigger, Trigger) + END_TRIGGER() + + class TargetInSightTrigger : public Trigger { + public: + TargetInSightTrigger(PlayerbotAI* ai) : Trigger(ai, "target in sight") {} + virtual bool IsActive() { return AI_VALUE(Unit*, "grind target"); } + }; + + class DebuffTrigger : public BuffTrigger + { + public: + DebuffTrigger(PlayerbotAI* ai, string spell) : BuffTrigger(ai, spell) { + checkInterval = 1; + } + public: + virtual string GetTargetName() { return "current target"; } + virtual bool IsActive(); + }; + + class DebuffOnAttackerTrigger : public DebuffTrigger + { + public: + DebuffOnAttackerTrigger(PlayerbotAI* ai, string spell) : DebuffTrigger(ai, spell) {} + public: + virtual Value* GetTargetValue(); + virtual string getName() { return spell + " on attacker"; } + }; + + class BoostTrigger : public BuffTrigger + { + public: + BoostTrigger(PlayerbotAI* ai, string spell, float balance = 50) : BuffTrigger(ai, spell) + { + this->balance = balance; + } + public: + virtual bool IsActive(); + + protected: + float balance; + }; + + class RandomTrigger : public Trigger + { + public: + RandomTrigger(PlayerbotAI* ai, int probability = 200) : Trigger(ai) + { + this->probability = probability; + } + public: + virtual bool IsActive(); + virtual string getName() { return "random"; } + + protected: + int probability; + }; + + class SeldomTrigger : public RandomTrigger + { + public: + SeldomTrigger(PlayerbotAI* ai) : RandomTrigger(ai, 9000) {} + virtual string getName() { return "seldom"; } + }; + + class OftenTrigger : public RandomTrigger + { + public: + OftenTrigger(PlayerbotAI* ai) : RandomTrigger(ai, 50) {} + virtual string getName() { return "often"; } + }; + + class AndTrigger : public Trigger + { + public: + AndTrigger(PlayerbotAI* ai, Trigger* ls, Trigger* rs) : Trigger(ai) + { + this->ls = ls; + this->rs = rs; + } + virtual ~AndTrigger() + { + delete ls; + delete rs; + } + public: + virtual bool IsActive(); + virtual string getName(); + + protected: + Trigger* ls; + Trigger* rs; + }; + + class SnareTargetTrigger : public DebuffTrigger + { + public: + SnareTargetTrigger(PlayerbotAI* ai, string aura) : DebuffTrigger(ai, aura) {} + public: + virtual bool IsActive(); + virtual string getName() { return "target is moving"; } + }; + + class LowManaTrigger : public Trigger + { + public: + LowManaTrigger(PlayerbotAI* ai) : Trigger(ai, "low mana") {} + + virtual bool IsActive(); + }; + + class MediumManaTrigger : public Trigger + { + public: + MediumManaTrigger(PlayerbotAI* ai) : Trigger(ai, "medium mana") {} + + virtual bool IsActive(); + }; + + BEGIN_TRIGGER(PanicTrigger, Trigger) + virtual string getName() { return "panic"; } + END_TRIGGER() + + + class NoPetTrigger : public Trigger + { + public: + NoPetTrigger(PlayerbotAI* ai) : Trigger(ai, "no pet", 5) {} + + virtual bool IsActive() { + return !AI_VALUE(Unit*, "pet target") && !AI_VALUE2(bool, "mounted", "self target"); + } + }; + + class ItemCountTrigger : public Trigger { + public: + ItemCountTrigger(PlayerbotAI* ai, string item, int count) : Trigger(ai, item, 5) { + this->item = item; + this->count = count; + } + public: + virtual bool IsActive(); + virtual string getName() { return "item count"; } + + protected: + string item; + int count; + }; + + class HasAuraTrigger : public Trigger { + public: + HasAuraTrigger(PlayerbotAI* ai, string spell) : Trigger(ai, spell, 5) {} + + virtual string GetTargetName() { return "self target"; } + virtual bool IsActive(); + + }; + + class TimerTrigger : public Trigger + { + public: + TimerTrigger(PlayerbotAI* ai, int checkInterval = 5) : Trigger(ai, "timer", checkInterval) {} + + public: + virtual bool IsActive() { return true; } + }; + + class TankAoeTrigger : public NoAttackersTrigger + { + public: + TankAoeTrigger(PlayerbotAI* ai) : NoAttackersTrigger(ai) {} + + public: + virtual bool IsActive(); + + }; + + class IsBehindTargetTrigger : public Trigger + { + public: + IsBehindTargetTrigger(PlayerbotAI* ai) : Trigger(ai) {} + + public: + virtual bool IsActive(); + }; + + class IsNotFacingTargetTrigger : public Trigger + { + public: + IsNotFacingTargetTrigger(PlayerbotAI* ai) : Trigger(ai) {} + + public: + virtual bool IsActive(); + }; + + class HasCcTargetTrigger : public Trigger + { + public: + HasCcTargetTrigger(PlayerbotAI* ai, string name) : Trigger(ai, name) {} + + public: + virtual bool IsActive(); + }; + + class NoMovementTrigger : public Trigger + { + public: + NoMovementTrigger(PlayerbotAI* ai, string name) : Trigger(ai, name) {} + + public: + virtual bool IsActive(); + }; + + + class NoPossibleTargetsTrigger : public Trigger + { + public: + NoPossibleTargetsTrigger(PlayerbotAI* ai) : Trigger(ai, "no possible targets") {} + + public: + virtual bool IsActive(); + }; + + class NotLeastHpTargetActiveTrigger : public Trigger + { + public: + NotLeastHpTargetActiveTrigger(PlayerbotAI* ai) : Trigger(ai, "not least hp target active") {} + + public: + virtual bool IsActive(); + }; + + class EnemyPlayerIsAttacking : public Trigger + { + public: + EnemyPlayerIsAttacking(PlayerbotAI* ai) : Trigger(ai, "enemy player is attacking") {} + + public: + virtual bool IsActive(); + }; + + class IsSwimmingTrigger : public Trigger + { + public: + IsSwimmingTrigger(PlayerbotAI* ai) : Trigger(ai, "swimming") {} + + public: + virtual bool IsActive(); + }; + + class HasNearestAddsTrigger : public Trigger + { + public: + HasNearestAddsTrigger(PlayerbotAI* ai) : Trigger(ai, "has nearest adds") {} + + public: + virtual bool IsActive(); + }; + + class HasItemForSpellTrigger : public Trigger + { + public: + HasItemForSpellTrigger(PlayerbotAI* ai, string spell) : Trigger(ai, spell) {} + + public: + virtual bool IsActive(); + }; + + class TargetChangedTrigger : public Trigger + { + public: + TargetChangedTrigger(PlayerbotAI* ai) : Trigger(ai, "target changed") {} + + public: + virtual bool IsActive(); + }; + + class InterruptEnemyHealerTrigger : public SpellTrigger + { + public: + InterruptEnemyHealerTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell) {} + public: + virtual Value* GetTargetValue(); + virtual string getName() { return spell + " on enemy healer"; } + }; + +} + +#include "RangeTriggers.h" +#include "HealthTriggers.h" +#include "CureTriggers.h" diff --git a/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.cpp b/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.cpp new file mode 100644 index 0000000000..4072023869 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.cpp @@ -0,0 +1,26 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "HealthTriggers.h" + +using namespace ai; + +float HealthInRangeTrigger::GetValue() +{ + return AI_VALUE2(uint8, "health", GetTargetName()); +} + +bool PartyMemberDeadTrigger::IsActive() +{ + return GetTarget(); +} + +bool DeadTrigger::IsActive() +{ + return AI_VALUE2(bool, "dead", GetTargetName()); +} + +bool AoeHealTrigger::IsActive() +{ + return AI_VALUE2(uint8, "aoe heal", type) >= count; +} + diff --git a/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h new file mode 100644 index 0000000000..1e72eba313 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h @@ -0,0 +1,139 @@ +#pragma once +#include "../Trigger.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class ValueInRangeTrigger : public Trigger + { + public: + ValueInRangeTrigger(PlayerbotAI* ai, string name, float maxValue, float minValue) : Trigger(ai, name) { + this->maxValue = maxValue; + this->minValue = minValue; + } + public: + virtual float GetValue() = 0; + virtual bool IsActive() { + float value = GetValue(); + return value < maxValue && value >= minValue; + } + + protected: + float maxValue, minValue; + }; + + class HealthInRangeTrigger : public ValueInRangeTrigger + { + public: + HealthInRangeTrigger(PlayerbotAI* ai, string name, float maxValue, float minValue = 0) : + ValueInRangeTrigger(ai, name, maxValue, minValue) {} + + virtual bool IsActive() + { + return ValueInRangeTrigger::IsActive() && !AI_VALUE2(bool, "dead", GetTargetName()); + } + + virtual float GetValue(); + }; + + class LowHealthTrigger : public HealthInRangeTrigger + { + public: + LowHealthTrigger(PlayerbotAI* ai, string name = "low health", + float value = sPlayerbotAIConfig.lowHealth, float minValue = sPlayerbotAIConfig.criticalHealth) : + HealthInRangeTrigger(ai, name, value, minValue) {} + + virtual string GetTargetName() { return "self target"; } + }; + + class CriticalHealthTrigger : public LowHealthTrigger + { + public: + CriticalHealthTrigger(PlayerbotAI* ai) : + LowHealthTrigger(ai, "critical health", sPlayerbotAIConfig.criticalHealth, 0) {} + }; + + class MediumHealthTrigger : public LowHealthTrigger + { + public: + MediumHealthTrigger(PlayerbotAI* ai) : + LowHealthTrigger(ai, "medium health", sPlayerbotAIConfig.mediumHealth, sPlayerbotAIConfig.lowHealth) {} + }; + + class AlmostFullHealthTrigger : public LowHealthTrigger + { + public: + AlmostFullHealthTrigger(PlayerbotAI* ai) : + LowHealthTrigger(ai, "almost full health", sPlayerbotAIConfig.almostFullHealth, sPlayerbotAIConfig.mediumHealth) {} + }; + + class PartyMemberLowHealthTrigger : public HealthInRangeTrigger + { + public: + PartyMemberLowHealthTrigger(PlayerbotAI* ai, string name = "party member low health", float value = sPlayerbotAIConfig.lowHealth, float minValue = sPlayerbotAIConfig.criticalHealth) : + HealthInRangeTrigger(ai, name, value, minValue) {} + + virtual string GetTargetName() { return "party member to heal"; } + }; + + class PartyMemberCriticalHealthTrigger : public PartyMemberLowHealthTrigger + { + public: + PartyMemberCriticalHealthTrigger(PlayerbotAI* ai) : + PartyMemberLowHealthTrigger(ai, "party member critical health", sPlayerbotAIConfig.criticalHealth, 0) {} + }; + + class PartyMemberMediumHealthTrigger : public PartyMemberLowHealthTrigger + { + public: + PartyMemberMediumHealthTrigger(PlayerbotAI* ai) : + PartyMemberLowHealthTrigger(ai, "party member medium health", sPlayerbotAIConfig.mediumHealth,sPlayerbotAIConfig.lowHealth) {} + }; + + class PartyMemberAlmostFullHealthTrigger : public PartyMemberLowHealthTrigger + { + public: + PartyMemberAlmostFullHealthTrigger(PlayerbotAI* ai) : + PartyMemberLowHealthTrigger(ai, "party member almost full health", sPlayerbotAIConfig.almostFullHealth,sPlayerbotAIConfig.mediumHealth) {} + }; + + class TargetLowHealthTrigger : public HealthInRangeTrigger { + public: + TargetLowHealthTrigger(PlayerbotAI* ai, float value, float minValue = 0) : + HealthInRangeTrigger(ai, "target low health", value, minValue) {} + virtual string GetTargetName() { return "current target"; } + }; + + class TargetCriticalHealthTrigger : public TargetLowHealthTrigger + { + public: + TargetCriticalHealthTrigger(PlayerbotAI* ai) : TargetLowHealthTrigger(ai, 20) {} + }; + + class PartyMemberDeadTrigger : public Trigger { + public: + PartyMemberDeadTrigger(PlayerbotAI* ai) : Trigger(ai, "resurrect", 10) {} + virtual string GetTargetName() { return "party member to resurrect"; } + virtual bool IsActive(); + }; + + class DeadTrigger : public Trigger { + public: + DeadTrigger(PlayerbotAI* ai) : Trigger(ai, "dead", 10) {} + virtual string GetTargetName() { return "self target"; } + virtual bool IsActive(); + }; + + class AoeHealTrigger : public Trigger { + public: + AoeHealTrigger(PlayerbotAI* ai, string name, string type, int count) : + Trigger(ai, name), type(type), count(count) {} + public: + virtual bool IsActive(); + + protected: + int count; + string type; + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/LfgTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/LfgTriggers.h new file mode 100644 index 0000000000..ec8133e9b3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/LfgTriggers.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../Trigger.h" + +namespace ai +{ +class LfgProposalActiveTrigger : public Trigger +{ +public: + LfgProposalActiveTrigger(PlayerbotAI* ai) : Trigger(ai, "lfg proposal active", 5) {} + + virtual bool IsActive() + { + return AI_VALUE(uint32, "lfg proposal"); + } +}; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/LootTriggers.cpp b/src/modules/Bots/playerbot/strategy/triggers/LootTriggers.cpp new file mode 100644 index 0000000000..ab743622b9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/LootTriggers.cpp @@ -0,0 +1,20 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "LootTriggers.h" + +using namespace ai; + +bool LootAvailableTrigger::IsActive() +{ + return AI_VALUE(bool, "has available loot") && AI_VALUE(uint8, "bag space") < 80; +} + +bool FarFromCurrentLootTrigger::IsActive() +{ + return AI_VALUE2(float, "distance", "loot target") > INTERACTION_DISTANCE; +} + +bool CanLootTrigger::IsActive() +{ + return AI_VALUE(bool, "can loot"); +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/LootTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/LootTriggers.h new file mode 100644 index 0000000000..063456b88d --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/LootTriggers.h @@ -0,0 +1,30 @@ +#pragma once +#include "../Trigger.h" +#include "../values/LastMovementValue.h" + +namespace ai +{ + class LootAvailableTrigger : public Trigger + { + public: + LootAvailableTrigger(PlayerbotAI* ai) : Trigger(ai, "loot available") {} + + virtual bool IsActive(); + }; + + class FarFromCurrentLootTrigger : public Trigger + { + public: + FarFromCurrentLootTrigger(PlayerbotAI* ai) : Trigger(ai, "far from current loot") {} + + virtual bool IsActive(); + }; + + class CanLootTrigger : public Trigger + { + public: + CanLootTrigger(PlayerbotAI* ai) : Trigger(ai, "can loot") {} + + virtual bool IsActive(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h new file mode 100644 index 0000000000..9729877e5b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h @@ -0,0 +1,81 @@ +#pragma once +#include "../Trigger.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class EnemyTooCloseForSpellTrigger : public Trigger { + public: + EnemyTooCloseForSpellTrigger(PlayerbotAI* ai) : Trigger(ai, "enemy too close for spell") {} + virtual bool IsActive() + { + Unit* target = AI_VALUE(Unit*, "current target"); + return target && AI_VALUE2(float, "distance", "current target") <= sPlayerbotAIConfig.spellDistance / 2; + } + }; + + class EnemyTooCloseForMeleeTrigger : public Trigger { + public: + EnemyTooCloseForMeleeTrigger(PlayerbotAI* ai) : Trigger(ai, "enemy too close for melee", 5) {} + virtual bool IsActive() + { + Unit* target = AI_VALUE(Unit*, "current target"); + return target && AI_VALUE2(float, "distance", "current target") <= sPlayerbotAIConfig.contactDistance; + } + }; + + class OutOfRangeTrigger : public Trigger { + public: + OutOfRangeTrigger(PlayerbotAI* ai, string name, float distance) : Trigger(ai, name) + { + this->distance = distance; + } + virtual bool IsActive() + { + Unit* target = AI_VALUE(Unit*, GetTargetName()); + return target && AI_VALUE2(float, "distance", GetTargetName()) > distance; + } + virtual string GetTargetName() { return "current target"; } + + protected: + float distance; + }; + + class EnemyOutOfMeleeTrigger : public OutOfRangeTrigger + { + public: + EnemyOutOfMeleeTrigger(PlayerbotAI* ai) : OutOfRangeTrigger(ai, "enemy out of melee range", sPlayerbotAIConfig.meleeDistance) {} + }; + + class EnemyOutOfSpellRangeTrigger : public OutOfRangeTrigger + { + public: + EnemyOutOfSpellRangeTrigger(PlayerbotAI* ai) : OutOfRangeTrigger(ai, "enemy out of spell range", sPlayerbotAIConfig.spellDistance) {} + }; + + class PartyMemberToHealOutOfSpellRangeTrigger : public OutOfRangeTrigger + { + public: + PartyMemberToHealOutOfSpellRangeTrigger(PlayerbotAI* ai) : OutOfRangeTrigger(ai, "party member to heal out of spell range", sPlayerbotAIConfig.spellDistance) {} + virtual string GetTargetName() { return "party member to heal"; } + }; + + class FarFromMasterTrigger : public Trigger { + public: + FarFromMasterTrigger(PlayerbotAI* ai, string name = "far from master", float distance = 12.0f, int checkInterval = 1) : Trigger(ai, name, checkInterval), distance(distance) {} + + virtual bool IsActive() + { + return AI_VALUE2(float, "distance", "master target") > distance; + } + + private: + float distance; + }; + + class OutOfReactRangeTrigger : public FarFromMasterTrigger + { + public: + OutOfReactRangeTrigger(PlayerbotAI* ai) : FarFromMasterTrigger(ai, "out of react range", sPlayerbotAIConfig.reactDistance / 2, 10) {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/TriggerContext.h b/src/modules/Bots/playerbot/strategy/triggers/TriggerContext.h new file mode 100644 index 0000000000..9906cae02a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/TriggerContext.h @@ -0,0 +1,158 @@ +#pragma once + +#include "HealthTriggers.h" +#include "GenericTriggers.h" +#include "LootTriggers.h" +#include "../triggers/GenericTriggers.h" +#include "LfgTriggers.h" + +namespace ai +{ + + class TriggerContext : public NamedObjectContext + { + public: + TriggerContext() + { + creators["timer"] = &TriggerContext::Timer; + creators["random"] = &TriggerContext::Random; + creators["seldom"] = &TriggerContext::seldom; + creators["often"] = &TriggerContext::often; + + creators["target critical health"] = &TriggerContext::TargetCriticalHealth; + + creators["critical health"] = &TriggerContext::CriticalHealth; + creators["low health"] = &TriggerContext::LowHealth; + creators["medium health"] = &TriggerContext::MediumHealth; + creators["almost full health"] = &TriggerContext::AlmostFullHealth; + + creators["low mana"] = &TriggerContext::LowMana; + creators["medium mana"] = &TriggerContext::MediumMana; + + creators["party member critical health"] = &TriggerContext::PartyMemberCriticalHealth; + creators["party member low health"] = &TriggerContext::PartyMemberLowHealth; + creators["party member medium health"] = &TriggerContext::PartyMemberMediumHealth; + creators["party member almost full health"] = &TriggerContext::PartyMemberAlmostFullHealth; + + creators["light rage available"] = &TriggerContext::LightRageAvailable; + creators["medium rage available"] = &TriggerContext::MediumRageAvailable; + creators["high rage available"] = &TriggerContext::HighRageAvailable; + + creators["light energy available"] = &TriggerContext::LightEnergyAvailable; + creators["medium energy available"] = &TriggerContext::MediumEnergyAvailable; + creators["high energy available"] = &TriggerContext::HighEnergyAvailable; + + creators["loot available"] = &TriggerContext::LootAvailable; + creators["no attackers"] = &TriggerContext::NoAttackers; + creators["no target"] = &TriggerContext::NoTarget; + creators["target in sight"] = &TriggerContext::TargetInSight; + creators["not least hp target active"] = &TriggerContext::not_least_hp_target_active; + creators["has nearest adds"] = &TriggerContext::has_nearest_adds; + creators["enemy player is attacking"] = &TriggerContext::enemy_player_is_attacking; + + creators["tank aoe"] = &TriggerContext::TankAoe; + creators["lose aggro"] = &TriggerContext::LoseAggro; + creators["has aggro"] = &TriggerContext::HasAggro; + + creators["light aoe"] = &TriggerContext::LightAoe; + creators["medium aoe"] = &TriggerContext::MediumAoe; + creators["high aoe"] = &TriggerContext::HighAoe; + + creators["enemy out of melee"] = &TriggerContext::EnemyOutOfMelee; + creators["enemy out of spell"] = &TriggerContext::EnemyOutOfSpell; + creators["enemy too close for spell"] = &TriggerContext::enemy_too_close_for_spell; + creators["enemy too close for melee"] = &TriggerContext::enemy_too_close_for_melee; + + creators["combo points available"] = &TriggerContext::ComboPointsAvailable; + + creators["medium threat"] = &TriggerContext::MediumThreat; + + creators["dead"] = &TriggerContext::Dead; + creators["party member dead"] = &TriggerContext::PartyMemberDead; + creators["no pet"] = &TriggerContext::no_pet; + creators["has attackers"] = &TriggerContext::has_attackers; + creators["no possible targets"] = &TriggerContext::no_possible_targets; + + creators["no drink"] = &TriggerContext::no_drink; + creators["no food"] = &TriggerContext::no_food; + + creators["panic"] = &TriggerContext::panic; + creators["behind target"] = &TriggerContext::behind_target; + creators["not facing target"] = &TriggerContext::not_facing_target; + creators["far from master"] = &TriggerContext::far_from_master; + creators["far from loot target"] = &TriggerContext::far_from_loot_target; + creators["can loot"] = &TriggerContext::can_loot; + creators["swimming"] = &TriggerContext::swimming; + creators["target changed"] = &TriggerContext::target_changed; + + creators["critical aoe heal"] = &TriggerContext::critical_aoe_heal; + creators["low aoe heal"] = &TriggerContext::low_aoe_heal; + creators["medium aoe heal"] = &TriggerContext::medium_aoe_heal; + creators["invalid target"] = &TriggerContext::invalid_target; + creators["lfg proposal active"] = &TriggerContext::lfg_proposal_active; + } + + private: + static Trigger* lfg_proposal_active(PlayerbotAI* ai) { return new LfgProposalActiveTrigger(ai); } + static Trigger* invalid_target(PlayerbotAI* ai) { return new InvalidTargetTrigger(ai); } + static Trigger* critical_aoe_heal(PlayerbotAI* ai) { return new AoeHealTrigger(ai, "critical aoe heal", "critical", 2); } + static Trigger* low_aoe_heal(PlayerbotAI* ai) { return new AoeHealTrigger(ai, "low aoe heal", "low", 2); } + static Trigger* medium_aoe_heal(PlayerbotAI* ai) { return new AoeHealTrigger(ai, "medium aoe heal", "medium", 2); } + static Trigger* target_changed(PlayerbotAI* ai) { return new TargetChangedTrigger(ai); } + static Trigger* swimming(PlayerbotAI* ai) { return new IsSwimmingTrigger(ai); } + static Trigger* no_possible_targets(PlayerbotAI* ai) { return new NoPossibleTargetsTrigger(ai); } + static Trigger* can_loot(PlayerbotAI* ai) { return new CanLootTrigger(ai); } + static Trigger* far_from_loot_target(PlayerbotAI* ai) { return new FarFromCurrentLootTrigger(ai); } + static Trigger* far_from_master(PlayerbotAI* ai) { return new FarFromMasterTrigger(ai); } + static Trigger* behind_target(PlayerbotAI* ai) { return new IsBehindTargetTrigger(ai); } + static Trigger* not_facing_target(PlayerbotAI* ai) { return new IsNotFacingTargetTrigger(ai); } + static Trigger* panic(PlayerbotAI* ai) { return new PanicTrigger(ai); } + static Trigger* no_drink(PlayerbotAI* ai) { return new NoDrinkTrigger(ai); } + static Trigger* no_food(PlayerbotAI* ai) { return new NoFoodTrigger(ai); } + static Trigger* LightAoe(PlayerbotAI* ai) { return new LightAoeTrigger(ai); } + static Trigger* MediumAoe(PlayerbotAI* ai) { return new MediumAoeTrigger(ai); } + static Trigger* HighAoe(PlayerbotAI* ai) { return new HighAoeTrigger(ai); } + static Trigger* LoseAggro(PlayerbotAI* ai) { return new LoseAggroTrigger(ai); } + static Trigger* HasAggro(PlayerbotAI* ai) { return new HasAggroTrigger(ai); } + static Trigger* LowHealth(PlayerbotAI* ai) { return new LowHealthTrigger(ai); } + static Trigger* MediumHealth(PlayerbotAI* ai) { return new MediumHealthTrigger(ai); } + static Trigger* AlmostFullHealth(PlayerbotAI* ai) { return new AlmostFullHealthTrigger(ai); } + static Trigger* CriticalHealth(PlayerbotAI* ai) { return new CriticalHealthTrigger(ai); } + static Trigger* TargetCriticalHealth(PlayerbotAI* ai) { return new TargetCriticalHealthTrigger(ai); } + static Trigger* LowMana(PlayerbotAI* ai) { return new LowManaTrigger(ai); } + static Trigger* MediumMana(PlayerbotAI* ai) { return new MediumManaTrigger(ai); } + static Trigger* LightRageAvailable(PlayerbotAI* ai) { return new LightRageAvailableTrigger(ai); } + static Trigger* MediumRageAvailable(PlayerbotAI* ai) { return new MediumRageAvailableTrigger(ai); } + static Trigger* HighRageAvailable(PlayerbotAI* ai) { return new HighRageAvailableTrigger(ai); } + static Trigger* LightEnergyAvailable(PlayerbotAI* ai) { return new LightEnergyAvailableTrigger(ai); } + static Trigger* MediumEnergyAvailable(PlayerbotAI* ai) { return new MediumEnergyAvailableTrigger(ai); } + static Trigger* HighEnergyAvailable(PlayerbotAI* ai) { return new HighEnergyAvailableTrigger(ai); } + static Trigger* LootAvailable(PlayerbotAI* ai) { return new LootAvailableTrigger(ai); } + static Trigger* NoAttackers(PlayerbotAI* ai) { return new NoAttackersTrigger(ai); } + static Trigger* TankAoe(PlayerbotAI* ai) { return new TankAoeTrigger(ai); } + static Trigger* Timer(PlayerbotAI* ai) { return new TimerTrigger(ai); } + static Trigger* NoTarget(PlayerbotAI* ai) { return new NoTargetTrigger(ai); } + static Trigger* TargetInSight(PlayerbotAI* ai) { return new TargetInSightTrigger(ai); } + static Trigger* not_least_hp_target_active(PlayerbotAI* ai) { return new NotLeastHpTargetActiveTrigger(ai); } + static Trigger* has_nearest_adds(PlayerbotAI* ai) { return new HasNearestAddsTrigger(ai); } + static Trigger* enemy_player_is_attacking(PlayerbotAI* ai) { return new EnemyPlayerIsAttacking(ai); } + static Trigger* Random(PlayerbotAI* ai) { return new RandomTrigger(ai); } + static Trigger* seldom(PlayerbotAI* ai) { return new SeldomTrigger(ai); } + static Trigger* often(PlayerbotAI* ai) { return new OftenTrigger(ai); } + static Trigger* EnemyOutOfMelee(PlayerbotAI* ai) { return new EnemyOutOfMeleeTrigger(ai); } + static Trigger* EnemyOutOfSpell(PlayerbotAI* ai) { return new EnemyOutOfSpellRangeTrigger(ai); } + static Trigger* enemy_too_close_for_spell(PlayerbotAI* ai) { return new EnemyTooCloseForSpellTrigger(ai); } + static Trigger* enemy_too_close_for_melee(PlayerbotAI* ai) { return new EnemyTooCloseForMeleeTrigger(ai); } + static Trigger* ComboPointsAvailable(PlayerbotAI* ai) { return new ComboPointsAvailableTrigger(ai); } + static Trigger* MediumThreat(PlayerbotAI* ai) { return new MediumThreatTrigger(ai); } + static Trigger* Dead(PlayerbotAI* ai) { return new DeadTrigger(ai); } + static Trigger* PartyMemberDead(PlayerbotAI* ai) { return new PartyMemberDeadTrigger(ai); } + static Trigger* PartyMemberLowHealth(PlayerbotAI* ai) { return new PartyMemberLowHealthTrigger(ai); } + static Trigger* PartyMemberMediumHealth(PlayerbotAI* ai) { return new PartyMemberMediumHealthTrigger(ai); } + static Trigger* PartyMemberAlmostFullHealth(PlayerbotAI* ai) { return new PartyMemberAlmostFullHealthTrigger(ai); } + static Trigger* PartyMemberCriticalHealth(PlayerbotAI* ai) { return new PartyMemberCriticalHealthTrigger(ai); } + static Trigger* no_pet(PlayerbotAI* ai) { return new NoPetTrigger(ai); } + static Trigger* has_attackers(PlayerbotAI* ai) { return new HasAttackersTrigger(ai); } + + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/triggers/WithinAreaTrigger.h b/src/modules/Bots/playerbot/strategy/triggers/WithinAreaTrigger.h new file mode 100644 index 0000000000..82a7671b3f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/WithinAreaTrigger.h @@ -0,0 +1,36 @@ +#pragma once +#include "../Trigger.h" +#include "../values/LastMovementValue.h" + +namespace ai +{ + class WithinAreaTrigger : public Trigger { + public: + WithinAreaTrigger(PlayerbotAI* ai) : Trigger(ai, "within area trigger") {} + + virtual bool IsActive() + { + + + LastMovement& movement = context->GetValue("last movement")->Get(); + if (!movement.lastAreaTrigger) + { + return false; + } + + AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(movement.lastAreaTrigger); + if(!atEntry) + { + return false; + } + + AreaTrigger const* at = sObjectMgr.GetAreaTrigger(movement.lastAreaTrigger); + if (!at) + { + return false; + } + + return IsPointInAreaTriggerZone(atEntry, bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), 0.5f); + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h b/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h new file mode 100644 index 0000000000..69a9104482 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h @@ -0,0 +1,38 @@ +#pragma once + +#include "../Trigger.h" + +namespace ai +{ + class WorldPacketTrigger : public Trigger { + public: + WorldPacketTrigger(PlayerbotAI* ai, string command) : Trigger(ai, command), triggered(false) {} + + virtual void ExternalEvent(WorldPacket &packet, Player* owner = NULL) + { + this->packet = packet; + this->owner = owner; + triggered = true; + } + + virtual Event Check() + { + if (!triggered) + { + return Event(); + } + + return Event(getName(), packet, owner); + } + + virtual void Reset() + { + triggered = false; + } + + private: + WorldPacket packet; + bool triggered; + Player* owner; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTriggerContext.h b/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTriggerContext.h new file mode 100644 index 0000000000..80a3376bac --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTriggerContext.h @@ -0,0 +1,83 @@ +#pragma once + +#include "WorldPacketTrigger.h" +#include "WithinAreaTrigger.h" + +namespace ai +{ + class WorldPacketTriggerContext : public NamedObjectContext + { + public: + WorldPacketTriggerContext() + { + creators["gossip hello"] = &WorldPacketTriggerContext::gossip_hello; + creators["group invite"] = &WorldPacketTriggerContext::group_invite; + creators["group set leader"] = &WorldPacketTriggerContext::group_set_leader; + creators["not enough money"] = &WorldPacketTriggerContext::no_money; + 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; + creators["within area trigger"] = &WorldPacketTriggerContext::within_area_trigger; + creators["check mount state"] = &WorldPacketTriggerContext::check_mount_state; + creators["activate taxi"] = &WorldPacketTriggerContext::taxi; + 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; + creators["item push result"] = &WorldPacketTriggerContext::item_push_result; + creators["party command"] = &WorldPacketTriggerContext::party_command; + creators["taxi done"] = &WorldPacketTriggerContext::taxi_done; + creators["cast failed"] = &WorldPacketTriggerContext::cast_failed; + creators["duel requested"] = &WorldPacketTriggerContext::duel_requested; + creators["ready check"] = &WorldPacketTriggerContext::ready_check; + creators["ready check finished"] = &WorldPacketTriggerContext::ready_check_finished; + creators["uninvite"] = &WorldPacketTriggerContext::uninvite; + creators["lfg join"] = &WorldPacketTriggerContext::lfg_update; + creators["lfg proposal"] = &WorldPacketTriggerContext::lfg_proposal; + creators["lfg role check"] = &WorldPacketTriggerContext::lfg_role_check; + creators["lfg leave"] = &WorldPacketTriggerContext::lfg_leave; + creators["guild invite"] = &WorldPacketTriggerContext::guild_invite; + } + + private: + static Trigger* guild_invite(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "guild invite"); } + static Trigger* lfg_leave(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "lfg leave"); } + static Trigger* lfg_proposal(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "lfg proposal"); } + static Trigger* lfg_role_check(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "lfg role check"); } + static Trigger* lfg_update(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "lfg join"); } + static Trigger* uninvite(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "uninvite"); } + static Trigger* ready_check_finished(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "ready check finished"); } + static Trigger* ready_check(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "ready check"); } + static Trigger* duel_requested(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "duel requested"); } + static Trigger* cast_failed(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "cast failed"); } + static Trigger* taxi_done(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "taxi done"); } + static Trigger* party_command(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "party command"); } + static Trigger* item_push_result(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "item push result"); } + static Trigger* quest_objective_completed(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest objective completed"); } + static Trigger* out_of_react_range(PlayerbotAI* ai) { return new OutOfReactRangeTrigger(ai); } + static Trigger* loot_response(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "loot response"); } + static Trigger* trade_status(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "trade status"); } + static Trigger* cannot_equip(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "cannot equip"); } + static Trigger* check_mount_state(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "check mount state"); } + static Trigger* area_trigger(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "area trigger"); } + static Trigger* within_area_trigger(PlayerbotAI* ai) { return new WithinAreaTrigger(ai); } + static Trigger* resurrect_request(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "resurrect request"); } + static Trigger* gossip_hello(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "gossip hello"); } + static Trigger* group_invite(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "group invite"); } + static Trigger* group_set_leader(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "group set leader"); } + static Trigger* no_money(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "not enough money"); } + static Trigger* no_reputation(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "not enough reputation"); } + static Trigger* use_game_object(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "use game object"); } + static Trigger* complete_quest(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "complete quest"); } + static Trigger* accept_quest(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "accept quest"); } + static Trigger* quest_share(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest share"); } + static Trigger* loot_roll(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "loot roll"); } + static Trigger* taxi(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "activate taxi"); } + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/values/AlwaysLootListValue.h b/src/modules/Bots/playerbot/strategy/values/AlwaysLootListValue.h new file mode 100644 index 0000000000..72b6f92ba3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AlwaysLootListValue.h @@ -0,0 +1,14 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class AlwaysLootListValue : public ManualSetValue&> + { + public: + AlwaysLootListValue(PlayerbotAI* ai) : ManualSetValue&>(ai, list) {} + + private: + set list; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/AoeHealValues.cpp b/src/modules/Bots/playerbot/strategy/values/AoeHealValues.cpp new file mode 100644 index 0000000000..303d9ce99e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AoeHealValues.cpp @@ -0,0 +1,49 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AoeHealValues.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +uint8 AoeHealValue::Calculate() +{ + Group* group = bot->GetGroup(); + if (!group) + { + return 0; + } + + float range = 0; + if (qualifier == "low") + { + range = sPlayerbotAIConfig.lowHealth; + } + else if (qualifier == "medium") + { + range = sPlayerbotAIConfig.mediumHealth; + } + else if (qualifier == "critical") + { + range = sPlayerbotAIConfig.criticalHealth; + } + + uint8 count = 0; + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *player = sObjectMgr.GetPlayer(itr->guid); + if( !player || !player->IsAlive()) + { + continue; + } + + float percent = (static_cast (player->GetHealth()) / player->GetMaxHealth()) * 100; + if (percent <= range) + { + count++; + } + } + + return count; +} + diff --git a/src/modules/Bots/playerbot/strategy/values/AoeHealValues.h b/src/modules/Bots/playerbot/strategy/values/AoeHealValues.h new file mode 100644 index 0000000000..1568a931f9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AoeHealValues.h @@ -0,0 +1,14 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class AoeHealValue : public Uint8CalculatedValue, public Qualified + { + public: + AoeHealValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + public: + virtual uint8 Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp b/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp new file mode 100644 index 0000000000..4f4d96b41e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp @@ -0,0 +1,123 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AttackerCountValues.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +uint8 MyAttackerCountValue::Calculate() +{ + return bot->getAttackers().size(); +} + +bool HasAggroValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return true; + } + + HostileReference *ref = bot->GetHostileRefManager().getFirst(); + if (!ref) + { + return true; // simulate as target is not atacking anybody yet + } + + while( ref ) + { + ThreatManager *threatManager = ref->getSource(); + Unit *attacker = threatManager->getOwner(); + Unit *victim = attacker->getVictim(); + if (victim == bot && target == attacker) + { + return true; + } + ref = ref->next(); + } + return false; +} + +uint8 AttackerCountValue::Calculate() +{ + int count = 0; + float range = sPlayerbotAIConfig.sightDistance; + + list attackers = context->GetValue >("attackers")->Get(); + for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + { + Unit* unit = ai->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + + float distance = bot->GetDistance(unit); + if (distance <= range) + { + count++; + } + } + + return count; +} + +uint8 BalancePercentValue::Calculate() +{ + float playerLevel = 0, + attackerLevel = 0; + + Group* group = bot->GetGroup(); + if (group) + { + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *player = sObjectMgr.GetPlayer(itr->guid); + if( !player || !player->IsAlive()) + { + continue; + } + + playerLevel += player->getLevel(); + } + } + + list v = context->GetValue >("attackers")->Get(); + + for (list::iterator i = v.begin(); i!=v.end(); i++) + { + Creature* creature = ai->GetCreature((*i)); + if (!creature || !creature->IsAlive()) + { + continue; + } + + uint32 level = creature->getLevel(); + + switch (creature->GetCreatureInfo()->Rank) { + case CREATURE_ELITE_RARE: + level *= 2; + break; + case CREATURE_ELITE_ELITE: + level *= 3; + break; + case CREATURE_ELITE_RAREELITE: + level *= 3; + break; + case CREATURE_ELITE_WORLDBOSS: + level *= 5; + break; + } + attackerLevel += level; + } + + if (!attackerLevel) + { + return 100; + } + + float percent = playerLevel * 100 / attackerLevel; + return percent <= 200 ? (uint8)percent : 200; +} + diff --git a/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.h b/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.h new file mode 100644 index 0000000000..9c77a3f482 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.h @@ -0,0 +1,59 @@ +#pragma once +#include "StatsValues.h" + +namespace ai +{ + + class AttackerCountValue : public Uint8CalculatedValue, public Qualified + { + public: + AttackerCountValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + + class MyAttackerCountValue : public Uint8CalculatedValue, public Qualified + { + public: + MyAttackerCountValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + + class HasAggroValue : public BoolCalculatedValue, public Qualified + { + public: + HasAggroValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual bool Calculate(); + }; + + class BalancePercentValue : public Uint8CalculatedValue, public Qualified + { + public: + BalancePercentValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.cpp new file mode 100644 index 0000000000..453f048746 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.cpp @@ -0,0 +1,32 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AttackerWithoutAuraTargetValue.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +Unit* AttackerWithoutAuraTargetValue::Calculate() +{ + list attackers = ai->GetAiObjectContext()->GetValue >("attackers")->Get(); + Unit* target = ai->GetAiObjectContext()->GetValue("current target")->Get(); + for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = ai->GetUnit(*i); + if (!unit || unit == target) + { + continue; + } + + if (bot->GetDistance(unit) > sPlayerbotAIConfig.spellDistance) + { + continue; + } + + if (!ai->HasAura(qualifier, unit)) + { + return unit; + } + } + + return NULL; +} diff --git a/src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.h b/src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.h new file mode 100644 index 0000000000..a1ed091e5e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AttackerWithoutAuraTargetValue.h @@ -0,0 +1,15 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class AttackerWithoutAuraTargetValue : public UnitCalculatedValue, public Qualified + { + public: + AttackerWithoutAuraTargetValue(PlayerbotAI* ai) : + UnitCalculatedValue(ai, "attacker without aura") {} + + protected: + virtual Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp b/src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp new file mode 100644 index 0000000000..4b7d12c6db --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp @@ -0,0 +1,99 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "AttackersValue.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +using namespace ai; +using namespace MaNGOS; + +list AttackersValue::Calculate() +{ + set targets; + + AddAttackersOf(bot, targets); + + Group* group = bot->GetGroup(); + if (group) + { + AddAttackersOf(group, targets); + } + + RemoveNonThreating(targets); + + list result; + for (set::iterator i = targets.begin(); i != targets.end(); i++) + { + result.push_back((*i)->GetObjectGuid()); + } + + if (bot->duel && bot->duel->opponent) + { + result.push_back(bot->duel->opponent->GetObjectGuid()); + } + + return result; +} + +void AttackersValue::AddAttackersOf(Group* group, set& targets) +{ + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *member = sObjectMgr.GetPlayer(itr->guid); + if (!member || !member->IsAlive() || member == bot) + { + continue; + } + + AddAttackersOf(member, targets); + } +} + +void AttackersValue::AddAttackersOf(Player* player, set& targets) +{ + if (player->IsBeingTeleported()) + { + return; + } + + list units; + MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(player, sPlayerbotAIConfig.sightDistance); + MaNGOS::UnitListSearcher searcher(units, u_check); + Cell::VisitAllObjects(player, searcher, sPlayerbotAIConfig.sightDistance); + for (list::iterator i = units.begin(); i != units.end(); i++) + { + targets.insert(*i); + } +} + +void AttackersValue::RemoveNonThreating(set& targets) +{ + for(set::iterator tIter = targets.begin(); tIter != targets.end();) + { + Unit* unit = *tIter; + if(!bot->IsWithinLOSInMap(unit) || bot->GetMapId() != unit->GetMapId() || !hasRealThreat(unit)) + { + set::iterator tIter2 = tIter; + ++tIter; + targets.erase(tIter2); + } + else + { + ++tIter; + } + } +} + +bool AttackersValue::hasRealThreat(Unit *attacker) +{ + return attacker && + attacker->IsInWorld() && + attacker->IsAlive() && + !attacker->IsPolymorphed() && + !attacker->IsInRoots() && + !attacker->IsFriendlyTo(bot) && + (attacker->GetThreatManager().getCurrentVictim() || attacker->GetObjectGuid().IsPlayer()); +} diff --git a/src/modules/Bots/playerbot/strategy/values/AttackersValue.h b/src/modules/Bots/playerbot/strategy/values/AttackersValue.h new file mode 100644 index 0000000000..1bae264c3f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AttackersValue.h @@ -0,0 +1,20 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" +#include "NearestUnitsValue.h" + +namespace ai +{ + class AttackersValue : public ObjectGuidListCalculatedValue + { + public: + AttackersValue(PlayerbotAI* ai) : ObjectGuidListCalculatedValue(ai, "attackers", 5) {} + list Calculate(); + + private: + void AddAttackersOf(Group* group, set& targets); + void AddAttackersOf(Player* player, set& targets); + void RemoveNonThreating(set& targets); + bool hasRealThreat(Unit* attacker); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/AvailableLootValue.h b/src/modules/Bots/playerbot/strategy/values/AvailableLootValue.h new file mode 100644 index 0000000000..0089cb45df --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/AvailableLootValue.h @@ -0,0 +1,42 @@ +#pragma once +#include "../Value.h" +#include "../../LootObjectStack.h" + +namespace ai +{ + + class AvailableLootValue : public ManualSetValue + { + public: + AvailableLootValue(PlayerbotAI* ai) : ManualSetValue(ai, NULL) + { + value = new LootObjectStack(ai->GetBot()); + } + + virtual ~AvailableLootValue() + { + if (value) + { + delete value; + } + } + }; + + class LootTargetValue : public ManualSetValue + { + public: + LootTargetValue(PlayerbotAI* ai) : ManualSetValue(ai, LootObject()) {} + }; + + class CanLootValue : public BoolCalculatedValue + { + public: + CanLootValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + virtual bool Calculate() + { + LootObject loot = AI_VALUE(LootObject, "loot target"); + return !loot.IsEmpty() && loot.GetWorldObject(bot) && AI_VALUE2(float, "distance", "loot target") <= INTERACTION_DISTANCE; + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp new file mode 100644 index 0000000000..88506cb5ad --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp @@ -0,0 +1,102 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CcTargetValue.h" +#include "../../PlayerbotAIConfig.h" +#include "../Action.h" + +using namespace ai; + +class FindTargetForCcStrategy : public FindTargetStrategy +{ +public: + FindTargetForCcStrategy(PlayerbotAI* ai, string spell) : FindTargetStrategy(ai) + { + this->spell = spell; + maxDistance = 0; + } + +public: + virtual void CheckAttacker(Unit* creature, ThreatManager* threatManager) + { + Player* bot = ai->GetBot(); + if (*ai->GetAiObjectContext()->GetValue("current target") == creature) + { + return; + } + + uint8 health = creature->GetHealthPercent(); + if (health < sPlayerbotAIConfig.mediumHealth) + { + return; + } + + if (!ai->CanCastSpell(spell, creature)) + { + return; + } + + if (*ai->GetAiObjectContext()->GetValue("rti target") == creature) + { + result = creature; + return; + } + + float minDistance = sPlayerbotAIConfig.spellDistance; + Group* group = bot->GetGroup(); + if (!group) + { + return; + } + + if (group->GetTargetIcon(4) == creature->GetObjectGuid()) + { + result = creature; + return; + } + + int tankCount, dpsCount; + GetPlayerCount(creature, &tankCount, &dpsCount); + if (!tankCount || !dpsCount) + { + result = creature; + return; + } + + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *member = sObjectMgr.GetPlayer(itr->guid); + if( !member || !member->IsAlive() || member == bot) + { + continue; + } + + if (!ai->IsTank(member)) + { + continue; + } + + float distance = member->GetDistance(creature); + if (distance < minDistance) + { + minDistance = distance; + } + } + + if (!result || minDistance > maxDistance) + { + result = creature; + maxDistance = minDistance; + } + } + +private: + string spell; + float maxDistance; +}; + +Unit* CcTargetValue::Calculate() +{ + FindTargetForCcStrategy strategy(ai, qualifier); + return FindTarget(&strategy); +} diff --git a/src/modules/Bots/playerbot/strategy/values/CcTargetValue.h b/src/modules/Bots/playerbot/strategy/values/CcTargetValue.h new file mode 100644 index 0000000000..dcf697a20c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CcTargetValue.h @@ -0,0 +1,16 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class CcTargetValue : public TargetValue, public Qualified + { + public: + CcTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ChatValue.h b/src/modules/Bots/playerbot/strategy/values/ChatValue.h new file mode 100644 index 0000000000..5571b36c28 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ChatValue.h @@ -0,0 +1,11 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class ChatValue : public ManualSetValue + { + public: + ChatValue(PlayerbotAI* ai) : ManualSetValue(ai, CHAT_MSG_WHISPER) {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp new file mode 100644 index 0000000000..5ab1b7bdc7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp @@ -0,0 +1,33 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CurrentCcTargetValue.h" + +using namespace ai; + +class FindCurrentCcTargetStrategy : public FindTargetStrategy +{ +public: + FindCurrentCcTargetStrategy(PlayerbotAI* ai, string spell) : FindTargetStrategy(ai) + { + this->spell = spell; + } + +public: + virtual void CheckAttacker(Unit* attacker, ThreatManager* threatManager) + { + if (ai->HasAura(spell, attacker)) + { + result = attacker; + } + } + +private: + string spell; +}; + + +Unit* CurrentCcTargetValue::Calculate() +{ + FindCurrentCcTargetStrategy strategy(ai, qualifier); + return FindTarget(&strategy); +} diff --git a/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.h b/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.h new file mode 100644 index 0000000000..52c64881b7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.h @@ -0,0 +1,16 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class CurrentCcTargetValue : public TargetValue, public Qualified + { + public: + CurrentCcTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.cpp new file mode 100644 index 0000000000..2ddf95968a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.cpp @@ -0,0 +1,28 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CurrentTargetValue.h" + +using namespace ai; + +Unit* CurrentTargetValue::Get() +{ + + + if (selection.IsEmpty()) + { + return NULL; + } + + Unit* unit = sObjectAccessor.GetUnit(*bot, selection); + if (unit && !bot->IsWithinLOSInMap(unit)) + { + return NULL; + } + + return unit; +} + +void CurrentTargetValue::Set(Unit* target) +{ + selection = target ? target->GetObjectGuid() : ObjectGuid(); +} diff --git a/src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.h b/src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.h new file mode 100644 index 0000000000..18a3cbf498 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CurrentTargetValue.h @@ -0,0 +1,17 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class CurrentTargetValue : public UnitManualSetValue + { + public: + CurrentTargetValue(PlayerbotAI* ai) : UnitManualSetValue(ai, NULL) {} + + virtual Unit* Get(); + virtual void Set(Unit* unit); + + private: + ObjectGuid selection; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/DistanceValue.h b/src/modules/Bots/playerbot/strategy/values/DistanceValue.h new file mode 100644 index 0000000000..c2f86be76c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/DistanceValue.h @@ -0,0 +1,41 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" +#include "../../LootObjectStack.h" + +namespace ai +{ + class DistanceValue : public FloatCalculatedValue, public Qualified + { + public: + DistanceValue(PlayerbotAI* ai) : FloatCalculatedValue(ai) {} + + public: + float Calculate() + { + if (qualifier == "loot target") + { + LootObject loot = AI_VALUE(LootObject, qualifier); + if (loot.IsEmpty()) + { + return 0.0f; + } + + WorldObject* obj = loot.GetWorldObject(bot); + if (!obj) + { + return 0.0f; + } + + return ai->GetBot()->GetDistance(obj); + } + Unit* target = AI_VALUE(Unit*, qualifier); + if (!target || !target->IsInWorld()) + { + return 0.0f; + } + + return ai->GetBot()->GetDistance(target); + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/DpsTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/DpsTargetValue.cpp new file mode 100644 index 0000000000..e6250d1575 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/DpsTargetValue.cpp @@ -0,0 +1,45 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DpsTargetValue.h" + +using namespace ai; + +class FindTargetForDpsStrategy : public FindTargetStrategy +{ +public: + FindTargetForDpsStrategy(PlayerbotAI* ai) : FindTargetStrategy(ai) + { + minThreat = 0; + maxTankCount = 0; + minDpsCount = 0; + } + +public: + virtual void CheckAttacker(Unit* creature, ThreatManager* threatManager) + { + float threat = threatManager->getThreat(ai->GetBot()); + int tankCount, dpsCount; + GetPlayerCount(creature, &tankCount, &dpsCount); + + if (!result || + minThreat >= threat && (maxTankCount <= tankCount || minDpsCount >= dpsCount)) + { + minThreat = threat; + maxTankCount = tankCount; + minDpsCount = dpsCount; + result = creature; + } + } + +protected: + float minThreat; + int maxTankCount; + int minDpsCount; +}; + + +Unit* DpsTargetValue::Calculate() +{ + FindTargetForDpsStrategy strategy(ai); + return FindTarget(&strategy); +} diff --git a/src/modules/Bots/playerbot/strategy/values/DpsTargetValue.h b/src/modules/Bots/playerbot/strategy/values/DpsTargetValue.h new file mode 100644 index 0000000000..c9b8235aeb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/DpsTargetValue.h @@ -0,0 +1,16 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class DpsTargetValue : public TargetValue + { + public: + DpsTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/DuelTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/DuelTargetValue.cpp new file mode 100644 index 0000000000..ea01354843 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/DuelTargetValue.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DuelTargetValue.h" + +using namespace ai; + +Unit* DuelTargetValue::Calculate() +{ + return bot->duel ? bot->duel->opponent : NULL; +} diff --git a/src/modules/Bots/playerbot/strategy/values/DuelTargetValue.h b/src/modules/Bots/playerbot/strategy/values/DuelTargetValue.h new file mode 100644 index 0000000000..606fe0b01c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/DuelTargetValue.h @@ -0,0 +1,15 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + class DuelTargetValue : public TargetValue + { + public: + DuelTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.cpp new file mode 100644 index 0000000000..2ed4db0e21 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.cpp @@ -0,0 +1,46 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "EnemyHealerTargetValue.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +Unit* EnemyHealerTargetValue::Calculate() +{ + string spell = qualifier; + + list attackers = ai->GetAiObjectContext()->GetValue >("attackers")->Get(); + Unit* target = ai->GetAiObjectContext()->GetValue("current target")->Get(); + for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = ai->GetUnit(*i); + if (!unit || unit == target) + { + continue; + } + + if (bot->GetDistance(unit) > sPlayerbotAIConfig.spellDistance) + { + continue; + } + + if (!ai->IsInterruptableSpellCasting(unit, spell)) + { + continue; + } + + Spell* spell = unit->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (spell && IsPositiveSpell(spell->m_spellInfo)) + { + return unit; + } + + spell = unit->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + if (spell && IsPositiveSpell(spell->m_spellInfo)) + { + return unit; + } + } + + return NULL; +} diff --git a/src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.h b/src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.h new file mode 100644 index 0000000000..48f92defaa --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/EnemyHealerTargetValue.h @@ -0,0 +1,15 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class EnemyHealerTargetValue : public UnitCalculatedValue, public Qualified + { + public: + EnemyHealerTargetValue(PlayerbotAI* ai) : + UnitCalculatedValue(ai, "enemy healer target") {} + + protected: + virtual Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.cpp b/src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.cpp new file mode 100644 index 0000000000..b2a9b4b4c3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.cpp @@ -0,0 +1,36 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "EnemyPlayerValue.h" +#include "TargetValue.h" + +using namespace ai; +using namespace std; + +class FindEnemyPlayerStrategy : public FindTargetStrategy +{ +public: + FindEnemyPlayerStrategy(PlayerbotAI* ai) : FindTargetStrategy(ai) + { + } + +public: + virtual void CheckAttacker(Unit* attacker, ThreatManager* threatManager) + { + if (!result) + { + Player* enemy = dynamic_cast(attacker); + if (enemy && ai->IsOpposing(enemy) && enemy->IsPvP()) + { + result = attacker; + } + } + } + +}; + + +Unit* EnemyPlayerValue::Calculate() +{ + FindEnemyPlayerStrategy strategy(ai); + return FindTarget(&strategy); +} diff --git a/src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.h b/src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.h new file mode 100644 index 0000000000..4f124697b6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/EnemyPlayerValue.h @@ -0,0 +1,15 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + class EnemyPlayerValue : public TargetValue + { + public: + EnemyPlayerValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp new file mode 100644 index 0000000000..c41bffa2c8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp @@ -0,0 +1,150 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GrindTargetValue.h" +#include "../../PlayerbotAIConfig.h" +#include "../../RandomPlayerbotMgr.h" + +using namespace ai; + +Unit* GrindTargetValue::Calculate() +{ + uint32 memberCount = 1; + Group* group = bot->GetGroup(); + if (group) + { + memberCount = group->GetMembersCount(); + } + + Unit* target = NULL; + uint32 assistCount = 0; + while (!target && assistCount < memberCount) + { + target = FindTargetForGrinding(assistCount++); + } + + return target; +} + + +Unit* GrindTargetValue::FindTargetForGrinding(int assistCount) +{ + uint32 memberCount = 1; + Group* group = bot->GetGroup(); + Player* master = GetMaster(); + + list attackers = context->GetValue >("attackers")->Get(); + for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + { + Unit* unit = ai->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + + return unit; + } + + list targets = *context->GetValue >("possible targets"); + + if(targets.empty()) + { + return NULL; + } + + float distance = 0; + Unit* result = NULL; + for(list::iterator tIter = targets.begin(); tIter != targets.end(); tIter++) + { + Unit* unit = ai->GetUnit(*tIter); + if (!unit) + { + continue; + } + + if (abs(bot->GetPositionZ() - unit->GetPositionZ()) > sPlayerbotAIConfig.spellDistance) + { + continue; + } + + if (GetTargetingPlayerCount(unit) > assistCount) + { + continue; + } + + if (master && master->GetDistance(unit) >= sPlayerbotAIConfig.grindDistance && !sRandomPlayerbotMgr.IsRandomBot(bot)) + { + continue; + } + + if ((int)unit->getLevel() - (int)bot->getLevel() > 4 && !unit->GetObjectGuid().IsPlayer()) + { + continue; + } + + Creature* creature = dynamic_cast(unit); + if (creature && creature->GetCreatureInfo() && creature->GetCreatureInfo()->Rank > CREATURE_ELITE_NORMAL) + { + continue; + } + + if (group) + { + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *member = sObjectMgr.GetPlayer(itr->guid); + if( !member || !member->IsAlive()) + { + continue; + } + + float d = member->GetDistance(unit); + if (!result || d < distance) + { + distance = d; + result = unit; + } + } + } + else + { + float d = bot->GetDistance(unit); + if (!result || d < distance) + { + distance = d; + result = unit; + } + } + } + + return result; +} + + +int GrindTargetValue::GetTargetingPlayerCount( Unit* unit ) +{ + Group* group = bot->GetGroup(); + if (!group) + { + return 0; + } + + int count = 0; + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *member = sObjectMgr.GetPlayer(itr->guid); + if( !member || !member->IsAlive() || member == bot) + { + continue; + } + + PlayerbotAI* ai = member->GetPlayerbotAI(); + if ((ai && *ai->GetAiObjectContext()->GetValue("current target") == unit) || + (!ai && member->GetSelectionGuid() == unit->GetObjectGuid())) + count++; + } + + return count; +} + diff --git a/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.h b/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.h new file mode 100644 index 0000000000..c3b1ad5b30 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.h @@ -0,0 +1,20 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class GrindTargetValue : public TargetValue + { + public: + GrindTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + + private: + int GetTargetingPlayerCount(Unit* unit); + Unit* FindTargetForGrinding(int assistCount); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/HasAvailableLootValue.h b/src/modules/Bots/playerbot/strategy/values/HasAvailableLootValue.h new file mode 100644 index 0000000000..87a7962275 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/HasAvailableLootValue.h @@ -0,0 +1,20 @@ +#pragma once +#include "../Value.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class HasAvailableLootValue : public BoolCalculatedValue + { + public: + HasAvailableLootValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + public: + virtual bool Calculate() + { + return !AI_VALUE(bool, "can loot") && + AI_VALUE(LootObjectStack*, "available loot")->CanLoot(sPlayerbotAIConfig.lootDistance) && + !bot->IsMounted(); + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/HasTotemValue.h b/src/modules/Bots/playerbot/strategy/values/HasTotemValue.h new file mode 100644 index 0000000000..e9f3f0c179 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/HasTotemValue.h @@ -0,0 +1,40 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" +#include "../../LootObjectStack.h" + +namespace ai +{ + class HasTotemValue : public BoolCalculatedValue, public Qualified + { + public: + HasTotemValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + public: + bool Calculate() + { + list units = *context->GetValue >("nearest npcs"); + for (list::iterator i = units.begin(); i != units.end(); i++) + { + Unit* unit = ai->GetUnit(*i); + if (!unit) + { + continue; + } + + Creature* creature = dynamic_cast(unit); + if (!creature || !creature->IsTotem()) + { + continue; + } + + if (strstri(creature->GetName(), qualifier.c_str()) && bot->GetDistance(creature) <= sPlayerbotAIConfig.spellDistance) + { + return true; + } + } + + return false; + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.cpp new file mode 100644 index 0000000000..c460a28305 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.cpp @@ -0,0 +1,26 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "InvalidTargetValue.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +bool InvalidTargetValue::Calculate() +{ + Unit* target = AI_VALUE(Unit*, qualifier); + if (qualifier == "current target") + { + return !target || + target->GetMapId() != bot->GetMapId() || + target->IsDead() || + target->IsPolymorphed() || + target->IsCharmed() || + target->IsFeared() || + target->hasUnitState(UNIT_STAT_ISOLATED) || + target->IsFriendlyTo(bot) || + !bot->IsWithinDistInMap(target, sPlayerbotAIConfig.sightDistance) || + !bot->IsWithinLOSInMap(target); + } + + return !target; +} diff --git a/src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.h b/src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.h new file mode 100644 index 0000000000..1299257b1e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/InvalidTargetValue.h @@ -0,0 +1,14 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class InvalidTargetValue : public BoolCalculatedValue, public Qualified + { + public: + InvalidTargetValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + public: + virtual bool Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/IsBehindValue.h b/src/modules/Bots/playerbot/strategy/values/IsBehindValue.h new file mode 100644 index 0000000000..714c00b2ed --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/IsBehindValue.h @@ -0,0 +1,27 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class IsBehindValue : public BoolCalculatedValue, public Qualified + { + public: + IsBehindValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + virtual bool Calculate() + { + Unit* target = AI_VALUE(Unit*, qualifier); + if (!target) + { + return false; + } + + + float targetOrientation = target->GetOrientation(); + float orientation = bot->GetOrientation(); + float distance = bot->GetDistance(target); + + return distance <= ATTACK_DISTANCE && abs(targetOrientation - orientation) < M_PI / 2; + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/IsFacingValue.h b/src/modules/Bots/playerbot/strategy/values/IsFacingValue.h new file mode 100644 index 0000000000..e06977161a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/IsFacingValue.h @@ -0,0 +1,22 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class IsFacingValue : public BoolCalculatedValue, public Qualified + { + public: + IsFacingValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + virtual bool Calculate() + { + Unit* target = AI_VALUE(Unit*, qualifier); + if (!target) + { + return false; + } + + return bot->IsInFront(target, sPlayerbotAIConfig.sightDistance, M_PI_F / 3.0f); + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/IsMovingValue.h b/src/modules/Bots/playerbot/strategy/values/IsMovingValue.h new file mode 100644 index 0000000000..dfae5ca1d3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/IsMovingValue.h @@ -0,0 +1,46 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class IsMovingValue : public BoolCalculatedValue, public Qualified + { + public: + IsMovingValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + virtual bool Calculate() + { + Unit* target = AI_VALUE(Unit*, qualifier); + + if (!target) + { + return false; + } + + switch (target->GetMotionMaster()->GetCurrentMovementGeneratorType()) + { + case IDLE_MOTION_TYPE: + return false; + } + return true; + } + }; + + class IsSwimmingValue : public BoolCalculatedValue, public Qualified + { + public: + IsSwimmingValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + virtual bool Calculate() + { + Unit* target = AI_VALUE(Unit*, qualifier); + + if (!target) + { + return false; + } + + return target->IsUnderWater() || target->IsInWater(); + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp b/src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp new file mode 100644 index 0000000000..dec931f994 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp @@ -0,0 +1,39 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ItemCountValue.h" + +using namespace ai; + +list InventoryItemValueBase::Find(string qualifier) +{ + list result; + + Player* bot = InventoryAction::ai->GetBot(); + + list items = InventoryAction::parseItems(qualifier); + for (list::iterator i = items.begin(); i != items.end(); i++) + { + result.push_back(*i); + } + + return result; +} + + +uint8 ItemCountValue::Calculate() +{ + uint8 count = 0; + list items = Find(qualifier); + for (list::iterator i = items.begin(); i != items.end(); ++i) + { + Item* item = *i; + count += item->GetCount(); + } + + return count; +} + +list InventoryItemValue::Calculate() +{ + return Find(qualifier); +} diff --git a/src/modules/Bots/playerbot/strategy/values/ItemCountValue.h b/src/modules/Bots/playerbot/strategy/values/ItemCountValue.h new file mode 100644 index 0000000000..6865482235 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ItemCountValue.h @@ -0,0 +1,35 @@ +#pragma once +#include "../Value.h" +#include "../ItemVisitors.h" +#include "../actions/InventoryAction.h" + +namespace ai +{ + class InventoryItemValueBase : public InventoryAction + { + public: + InventoryItemValueBase(PlayerbotAI* ai) : InventoryAction(ai, "empty") {} + virtual bool Execute(Event event) { return false; } + + protected: + list Find(string qualifier); + }; + + class ItemCountValue : public Uint8CalculatedValue, public Qualified, InventoryItemValueBase + { + public: + ItemCountValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai), InventoryItemValueBase(ai) {} + + public: + virtual uint8 Calculate(); + }; + + class InventoryItemValue : public CalculatedValue >, public Qualified, InventoryItemValueBase + { + public: + InventoryItemValue(PlayerbotAI* ai) : CalculatedValue >(ai), InventoryItemValueBase(ai) {} + + public: + virtual list Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.cpp b/src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.cpp new file mode 100644 index 0000000000..61243eb1da --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.cpp @@ -0,0 +1,90 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ItemForSpellValue.h" + +using namespace ai; + +#ifndef WIN32 +inline int strcmpi(const char* s1, const char* s2) +{ + for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2); + { + return *s1 - *s2; + } +} +#endif + +Item* ItemForSpellValue::Calculate() +{ + uint32 spellid = atoi(qualifier.c_str()); + if (!spellid) + { + return NULL; + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid ); + if (!spellInfo) + { + return NULL; + } + + Item* itemForSpell = NULL; + Player* trader = bot->GetTrader(); + if (trader) + { + itemForSpell = trader->GetTradeData()->GetItem(TRADE_SLOT_NONTRADED); + if (itemForSpell && itemForSpell->IsFitToSpellRequirements(spellInfo)) + { + return itemForSpell; + } + } + + // Workaround as some spells have no item mask (e.g. shaman weapon enhancements) + if (!strcmpi(spellInfo->SpellName[0], "rockbiter weapon") || + !strcmpi(spellInfo->SpellName[0], "flametongue weapon") || + !strcmpi(spellInfo->SpellName[0], "earthliving weapon") || + !strcmpi(spellInfo->SpellName[0], "frostbrand weapon") || + !strcmpi(spellInfo->SpellName[0], "windfury weapon")) + { + itemForSpell = GetItemFitsToSpellRequirements(EQUIPMENT_SLOT_MAINHAND, spellInfo); + if (itemForSpell && itemForSpell->GetProto()->Class == ITEM_CLASS_WEAPON) + { + return itemForSpell; + } + + itemForSpell = GetItemFitsToSpellRequirements(EQUIPMENT_SLOT_OFFHAND, spellInfo); + if (itemForSpell && itemForSpell->GetProto()->Class == ITEM_CLASS_WEAPON) + { + return itemForSpell; + } + + return NULL; + } + + for( uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++ ) { + { + itemForSpell = GetItemFitsToSpellRequirements(slot, spellInfo); + } + if (itemForSpell) + { + return itemForSpell; + } + } + return NULL; +} + +Item* ItemForSpellValue::GetItemFitsToSpellRequirements(uint8 slot, SpellEntry const *spellInfo) +{ + Item* const itemForSpell = bot->GetItemByPos( INVENTORY_SLOT_BAG_0, slot ); + if (!itemForSpell || itemForSpell->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + { + return NULL; + } + + if (itemForSpell->IsFitToSpellRequirements(spellInfo)) + { + return itemForSpell; + } + + return NULL; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.h b/src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.h new file mode 100644 index 0000000000..5c4792abdb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ItemForSpellValue.h @@ -0,0 +1,20 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class ItemForSpellValue : public CalculatedValue, public Qualified + { + public: + ItemForSpellValue(PlayerbotAI* ai) : CalculatedValue(ai) {} + + public: + virtual Item* Calculate(); + + private: + Item* GetItemFitsToSpellRequirements(uint8 slot, SpellEntry const *spellInfo); + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ItemUsageValue.cpp b/src/modules/Bots/playerbot/strategy/values/ItemUsageValue.cpp new file mode 100644 index 0000000000..692c9c159f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ItemUsageValue.cpp @@ -0,0 +1,134 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ItemUsageValue.h" + +using namespace ai; + +ItemUsage ItemUsageValue::Calculate() +{ + uint32 itemId = atoi(qualifier.c_str()); + if (!itemId) + { + return ITEM_USAGE_NONE; + } + + const ItemPrototype* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + return ITEM_USAGE_NONE; + } + + if (IsItemUsefulForSkill(proto)) + { + return ITEM_USAGE_SKILL; + } + + switch (proto->Class) + { + case ITEM_CLASS_KEY: + case ITEM_CLASS_CONSUMABLE: + return ITEM_USAGE_USE; + } + + return QueryItemUsageForEquip(proto); +} + +ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemPrototype const * item) +{ + if (bot->CanUseItem(item) != EQUIP_ERR_OK) + { + return ITEM_USAGE_NONE; + } + + if (item->InventoryType == INVTYPE_NON_EQUIP) + { + return ITEM_USAGE_NONE; + } + + Item *pItem = Item::CreateItem(item->ItemId, 1, bot); + if (!pItem) + { + return ITEM_USAGE_NONE; + } + + uint16 dest; + InventoryResult result = bot->CanEquipItem(NULL_SLOT, dest, pItem, true, false); + pItem->RemoveFromUpdateQueueOf(bot); + delete pItem; + + if( result != EQUIP_ERR_OK ) + { + return ITEM_USAGE_NONE; + } + + Item* existingItem = bot->GetItemByPos(dest); + if (!existingItem) + { + return ITEM_USAGE_EQUIP; + } + + const ItemPrototype* oldItem = existingItem->GetProto(); + if (oldItem->ItemLevel < item->ItemLevel && oldItem->ItemId != item->ItemId) + { + switch (item->Class) + { + case ITEM_CLASS_ARMOR: + if (oldItem->SubClass <= item->SubClass) { + { + return ITEM_USAGE_REPLACE; + } + } + break; + default: + return ITEM_USAGE_EQUIP; + } + } + + return ITEM_USAGE_NONE; +} + +bool ItemUsageValue::IsItemUsefulForSkill(ItemPrototype const * proto) +{ + switch (proto->Class) + { + case ITEM_CLASS_TRADE_GOODS: + switch (proto->SubClass) + { + case ITEM_SUBCLASS_PARTS: + case ITEM_SUBCLASS_EXPLOSIVES: + case ITEM_SUBCLASS_DEVICES: + return bot->HasSkill(SKILL_ENGINEERING); + } + break; + case ITEM_CLASS_RECIPE: + { + if (bot->HasSpell(proto->Spells[2].SpellId)) + { + break; + } + + switch (proto->SubClass) + { + case ITEM_SUBCLASS_LEATHERWORKING_PATTERN: + return bot->HasSkill(SKILL_LEATHERWORKING); + case ITEM_SUBCLASS_TAILORING_PATTERN: + return bot->HasSkill(SKILL_TAILORING); + case ITEM_SUBCLASS_ENGINEERING_SCHEMATIC: + return bot->HasSkill(SKILL_ENGINEERING); + case ITEM_SUBCLASS_BLACKSMITHING: + return bot->HasSkill(SKILL_BLACKSMITHING); + case ITEM_SUBCLASS_COOKING_RECIPE: + return bot->HasSkill(SKILL_COOKING); + case ITEM_SUBCLASS_ALCHEMY_RECIPE: + return bot->HasSkill(SKILL_ALCHEMY); + case ITEM_SUBCLASS_FIRST_AID_MANUAL: + return bot->HasSkill(SKILL_FIRST_AID); + case ITEM_SUBCLASS_ENCHANTING_FORMULA: + return bot->HasSkill(SKILL_ENCHANTING); + case ITEM_SUBCLASS_FISHING_MANUAL: + return bot->HasSkill(SKILL_FISHING); + } + } + } + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ItemUsageValue.h b/src/modules/Bots/playerbot/strategy/values/ItemUsageValue.h new file mode 100644 index 0000000000..b97777d323 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ItemUsageValue.h @@ -0,0 +1,27 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + enum ItemUsage + { + ITEM_USAGE_NONE, + ITEM_USAGE_EQUIP, + ITEM_USAGE_REPLACE, + ITEM_USAGE_SKILL, + ITEM_USAGE_USE + }; + + class ItemUsageValue : public CalculatedValue, public Qualified + { + public: + ItemUsageValue(PlayerbotAI* ai) : CalculatedValue(ai) {} + + public: + virtual ItemUsage Calculate(); + + private: + ItemUsage QueryItemUsageForEquip(ItemPrototype const * proto); + bool IsItemUsefulForSkill(ItemPrototype const * proto); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LastMovementValue.h b/src/modules/Bots/playerbot/strategy/values/LastMovementValue.h new file mode 100644 index 0000000000..8adcb09f01 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LastMovementValue.h @@ -0,0 +1,61 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class LastMovement + { + public: + LastMovement() + { + lastMoveToX = 0; + lastMoveToY = 0; + lastMoveToZ = 0; + lastMoveToOri = 0; + lastFollow = NULL; + } + + LastMovement(LastMovement& other) + { + taxiNodes = other.taxiNodes; + taxiMaster = other.taxiMaster; + lastFollow = other.lastFollow; + lastAreaTrigger = other.lastAreaTrigger; + lastMoveToX = other.lastMoveToX; + lastMoveToY = other.lastMoveToY; + lastMoveToZ = other.lastMoveToZ; + lastMoveToOri = other.lastMoveToOri; + } + + void Set(Unit* lastFollow) + { + Set(0.0f, 0.0f, 0.0f, 0.0f); + this->lastFollow = lastFollow; + } + + void Set(float x, float y, float z, float ori) + { + lastMoveToX = x; + lastMoveToY = y; + lastMoveToZ = z; + lastMoveToOri = ori; + lastFollow = NULL; + } + + public: + vector taxiNodes; + ObjectGuid taxiMaster; + Unit* lastFollow; + uint32 lastAreaTrigger; + float lastMoveToX, lastMoveToY, lastMoveToZ, lastMoveToOri; + }; + + class LastMovementValue : public ManualSetValue + { + public: + LastMovementValue(PlayerbotAI* ai) : ManualSetValue(ai, data) {} + + private: + LastMovement data; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LastSpellCastTimeValue.h b/src/modules/Bots/playerbot/strategy/values/LastSpellCastTimeValue.h new file mode 100644 index 0000000000..4906ee42bb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LastSpellCastTimeValue.h @@ -0,0 +1,11 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class LastSpellCastTimeValue : public ManualSetValue, public Qualified + { + public: + LastSpellCastTimeValue(PlayerbotAI* ai) : ManualSetValue(ai, 0), Qualified() {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LastSpellCastValue.h b/src/modules/Bots/playerbot/strategy/values/LastSpellCastValue.h new file mode 100644 index 0000000000..2c4bcbc5ff --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LastSpellCastValue.h @@ -0,0 +1,39 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class LastSpellCast + { + public: + LastSpellCast() : id(0),time(0) {} + + public: + void Set(uint32 id, ObjectGuid target, time_t time) + { + this->id = id; + this->target = target; + this->time = time; + } + + void Reset() + { + id = 0; + target.Set(0); + time = 0; + } + public: + uint32 id; + ObjectGuid target; + time_t time; + }; + + class LastSpellCastValue : public ManualSetValue + { + public: + LastSpellCastValue(PlayerbotAI* ai) : ManualSetValue(ai, data) {} + + private: + LastSpellCast data; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.cpp new file mode 100644 index 0000000000..bc25ac53f6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.cpp @@ -0,0 +1,35 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "LeastHpTargetValue.h" +#include "TargetValue.h" + +using namespace ai; +using namespace std; + +class FindLeastHpTargetStrategy : public FindTargetStrategy +{ +public: + FindLeastHpTargetStrategy(PlayerbotAI* ai) : FindTargetStrategy(ai) + { + minHealth = 0; + } + +public: + virtual void CheckAttacker(Unit* attacker, ThreatManager* threatManager) + { + if (!result || result->GetHealth() > attacker->GetHealth()) + { + result = attacker; + } + } + +protected: + float minHealth; +}; + + +Unit* LeastHpTargetValue::Calculate() +{ + FindLeastHpTargetStrategy strategy(ai); + return FindTarget(&strategy); +} diff --git a/src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.h b/src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.h new file mode 100644 index 0000000000..c0c6b55049 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LeastHpTargetValue.h @@ -0,0 +1,15 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + class LeastHpTargetValue : public TargetValue + { + public: + LeastHpTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LfgValues.h b/src/modules/Bots/playerbot/strategy/values/LfgValues.h new file mode 100644 index 0000000000..290a4c4302 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LfgValues.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../Value.h" + +namespace ai +{ +class LfgProposalValue : public ManualSetValue +{ +public: + LfgProposalValue(PlayerbotAI* ai) : ManualSetValue(ai, 0, "lfg proposal") {} +}; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LineTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/LineTargetValue.cpp new file mode 100644 index 0000000000..fd9fb40442 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LineTargetValue.cpp @@ -0,0 +1,41 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "LineTargetValue.h" + +using namespace ai; + +Unit* LineTargetValue::Calculate() +{ + Player* master = GetMaster(); + if (!master) + { + return NULL; + } + + Group* group = master->GetGroup(); + if (!group) + { + return NULL; + } + + Player *prev = master; + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *player = sObjectMgr.GetPlayer(itr->guid); + if( !player || !player->IsAlive() || player == master) + { + continue; + } + + if (player == bot) + { + return prev; + } + + prev = player; + } + + return master; +} + diff --git a/src/modules/Bots/playerbot/strategy/values/LineTargetValue.h b/src/modules/Bots/playerbot/strategy/values/LineTargetValue.h new file mode 100644 index 0000000000..3fe5eeb2f7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LineTargetValue.h @@ -0,0 +1,14 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class LineTargetValue : public UnitCalculatedValue + { + public: + LineTargetValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) {} + + public: + virtual Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LogLevelValue.h b/src/modules/Bots/playerbot/strategy/values/LogLevelValue.h new file mode 100644 index 0000000000..cc5c243799 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LogLevelValue.h @@ -0,0 +1,12 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class LogLevelValue : public ManualSetValue + { + public: + LogLevelValue(PlayerbotAI* ai) : + ManualSetValue(ai, LOG_LVL_BASIC) {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/LootStrategyValue.h b/src/modules/Bots/playerbot/strategy/values/LootStrategyValue.h new file mode 100644 index 0000000000..75c0c2b4dc --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/LootStrategyValue.h @@ -0,0 +1,11 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class LootStrategyValue : public ManualSetValue + { + public: + LootStrategyValue(PlayerbotAI* ai) : ManualSetValue(ai, LOOTSTRATEGY_SKILL) {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ManaSaveLevelValue.h b/src/modules/Bots/playerbot/strategy/values/ManaSaveLevelValue.h new file mode 100644 index 0000000000..2c11b06b21 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ManaSaveLevelValue.h @@ -0,0 +1,11 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class ManaSaveLevelValue : public ManualSetValue + { + public: + ManaSaveLevelValue(PlayerbotAI* ai) : ManualSetValue(ai, 1.0, "mana save level") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/MasterTargetValue.h b/src/modules/Bots/playerbot/strategy/values/MasterTargetValue.h new file mode 100644 index 0000000000..49114a09c5 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/MasterTargetValue.h @@ -0,0 +1,13 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class MasterTargetValue : public UnitCalculatedValue + { + public: + MasterTargetValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) {} + + virtual Unit* Calculate() { return ai->GetMaster(); } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestAdsValue.cpp b/src/modules/Bots/playerbot/strategy/values/NearestAdsValue.cpp new file mode 100644 index 0000000000..a7562ea7e1 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestAdsValue.cpp @@ -0,0 +1,11 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "NearestAdsValue.h" + +using namespace ai; + +bool NearestAdsValue::AcceptUnit(Unit* unit) +{ + Unit* target = AI_VALUE(Unit*, "current target"); + return unit != target; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestAdsValue.h b/src/modules/Bots/playerbot/strategy/values/NearestAdsValue.h new file mode 100644 index 0000000000..91687df8ca --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestAdsValue.h @@ -0,0 +1,18 @@ +#pragma once +#include "../Value.h" +#include "NearestUnitsValue.h" +#include "../../PlayerbotAIConfig.h" +#include "PossibleTargetsValue.h" + +namespace ai +{ + class NearestAdsValue : public PossibleTargetsValue + { + public: + NearestAdsValue(PlayerbotAI* ai, float range = sPlayerbotAIConfig.tooCloseDistance) : + PossibleTargetsValue(ai, range) {} + + protected: + bool AcceptUnit(Unit* unit); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.cpp b/src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.cpp new file mode 100644 index 0000000000..52efcb6770 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.cpp @@ -0,0 +1,36 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "NearestCorpsesValue.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +using namespace ai; +using namespace MaNGOS; + +class AnyDeadUnitInObjectRangeCheck +{ +public: + AnyDeadUnitInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} + WorldObject const& GetFocusObject() const { return *i_obj; } + bool operator()(Unit* u) + { + return !u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range); + } +private: + WorldObject const* i_obj; + float i_range; +}; + +void NearestCorpsesValue::FindUnits(list &targets) +{ + AnyDeadUnitInObjectRangeCheck u_check(bot, range); + UnitListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(bot, searcher, range); +} + +bool NearestCorpsesValue::AcceptUnit(Unit* unit) +{ + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.h b/src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.h new file mode 100644 index 0000000000..6e0f113421 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestCorpsesValue.h @@ -0,0 +1,19 @@ +#pragma once +#include "../Value.h" +#include "NearestUnitsValue.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class NearestCorpsesValue : public NearestUnitsValue + { + public: + NearestCorpsesValue(PlayerbotAI* ai, float range = sPlayerbotAIConfig.sightDistance) : + NearestUnitsValue(ai) {} + + protected: + void FindUnits(list &targets); + bool AcceptUnit(Unit* unit); + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestGameObjects.cpp b/src/modules/Bots/playerbot/strategy/values/NearestGameObjects.cpp new file mode 100644 index 0000000000..bd78d33416 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestGameObjects.cpp @@ -0,0 +1,51 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "NearestGameObjects.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +using namespace ai; +using namespace MaNGOS; + +class AnyGameObjectInObjectRangeCheck +{ +public: + AnyGameObjectInObjectRangeCheck(WorldObject const* obj, float range) : i_obj(obj), i_range(range) {} + WorldObject const& GetFocusObject() const { return *i_obj; } + bool operator()(GameObject* u) + { + if (u && i_obj->IsWithinDistInMap(u, i_range) && u->isSpawned() && u->GetGOInfo()) + { + return true; + } + + return false; + } + +private: + WorldObject const* i_obj; + float i_range; +}; + +list NearestGameObjects::Calculate() +{ + list targets; + + AnyGameObjectInObjectRangeCheck u_check(bot, range); + GameObjectListSearcher searcher(targets, u_check); + Cell::VisitAllObjects((const WorldObject*)bot, searcher, range); + + list result; + for(list::iterator tIter = targets.begin(); tIter != targets.end(); ++tIter) + { + GameObject* go = *tIter; + if(bot->IsWithinLOSInMap(go)) + { + result.push_back(go->GetObjectGuid()); + } + } + + return result; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestGameObjects.h b/src/modules/Bots/playerbot/strategy/values/NearestGameObjects.h new file mode 100644 index 0000000000..f163d6e721 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestGameObjects.h @@ -0,0 +1,19 @@ +#pragma once +#include "../Value.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class NearestGameObjects : public ObjectGuidListCalculatedValue + { + public: + NearestGameObjects(PlayerbotAI* ai, float range = sPlayerbotAIConfig.sightDistance) : + ObjectGuidListCalculatedValue(ai), range(range) {} + + protected: + virtual list Calculate(); + + private: + float range; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.cpp b/src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.cpp new file mode 100644 index 0000000000..8a92288edb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.cpp @@ -0,0 +1,22 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "NearestNpcsValue.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +using namespace ai; +using namespace MaNGOS; + +void NearestNpcsValue::FindUnits(list &targets) +{ + AnyFriendlyUnitInObjectRangeCheck u_check(bot, range); + UnitListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(bot, searcher, range); +} + +bool NearestNpcsValue::AcceptUnit(Unit* unit) +{ + return !dynamic_cast(unit); +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.h b/src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.h new file mode 100644 index 0000000000..4b56dd3c71 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestNpcsValue.h @@ -0,0 +1,18 @@ +#pragma once +#include "../Value.h" +#include "NearestUnitsValue.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class NearestNpcsValue : public NearestUnitsValue + { + public: + NearestNpcsValue(PlayerbotAI* ai, float range = sPlayerbotAIConfig.sightDistance) : + NearestUnitsValue(ai) {} + + protected: + void FindUnits(list &targets); + bool AcceptUnit(Unit* unit); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/NearestUnitsValue.h b/src/modules/Bots/playerbot/strategy/values/NearestUnitsValue.h new file mode 100644 index 0000000000..53bef918b3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/NearestUnitsValue.h @@ -0,0 +1,38 @@ +#pragma once +#include "../Value.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class NearestUnitsValue : public ObjectGuidListCalculatedValue + { + public: + NearestUnitsValue(PlayerbotAI* ai, float range = sPlayerbotAIConfig.sightDistance) : + ObjectGuidListCalculatedValue(ai, "nearest units", 5), range(range) {} + + public: + list Calculate() + { + list targets; + FindUnits(targets); + + list results; + for(list::iterator i = targets.begin(); i!= targets.end(); ++i) + { + Unit* unit = *i; + if(bot->IsWithinLOSInMap(unit) && AcceptUnit(unit)) + { + results.push_back(unit->GetObjectGuid()); + } + } + return results; + } + + protected: + virtual void FindUnits(list &targets) = 0; + virtual bool AcceptUnit(Unit* unit) = 0; + + protected: + float range; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.cpp b/src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.cpp new file mode 100644 index 0000000000..ddbb1357de --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.cpp @@ -0,0 +1,35 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PartyMemberToDispel.h" + +using namespace ai; + +class PartyMemberToDispelPredicate : public FindPlayerPredicate, public PlayerbotAIAware +{ +public: + PartyMemberToDispelPredicate(PlayerbotAI* ai, uint32 dispelType) : + PlayerbotAIAware(ai), FindPlayerPredicate(), dispelType(dispelType) {} + +public: + virtual bool Check(Unit* unit) + { + Pet* pet = dynamic_cast(unit); + if (pet && (pet->getPetType() == MINI_PET || pet->getPetType() == SUMMON_PET)) + { + return false; + } + + return unit->IsAlive() && ai->HasAuraToDispel(unit, dispelType); + } + +private: + uint32 dispelType; +}; + +Unit* PartyMemberToDispel::Calculate() +{ + uint32 dispelType = atoi(qualifier.c_str()); + + PartyMemberToDispelPredicate predicate(ai, dispelType); + return FindPartyMember(predicate); +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.h b/src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.h new file mode 100644 index 0000000000..8e2f208413 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberToDispel.h @@ -0,0 +1,16 @@ +#pragma once +#include "../Value.h" +#include "PartyMemberValue.h" + +namespace ai +{ + class PartyMemberToDispel : public PartyMemberValue, Qualified + { + public: + PartyMemberToDispel(PlayerbotAI* ai) : + PartyMemberValue(ai) {} + + protected: + virtual Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.cpp b/src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.cpp new file mode 100644 index 0000000000..e1d4ca73d7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.cpp @@ -0,0 +1,66 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PartyMemberToHeal.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +class IsTargetOfHealingSpell : public SpellEntryPredicate +{ +public: + virtual bool Check(SpellEntry const* spell) { + for (int i=0; i<3; i++) { + if (spell->Effect[i] == SPELL_EFFECT_HEAL || + spell->Effect[i] == SPELL_EFFECT_HEAL_MAX_HEALTH || + spell->Effect[i] == SPELL_EFFECT_HEAL_MECHANICAL) + return true; + } + return false; + } + +}; + +Unit* PartyMemberToHeal::Calculate() +{ + + IsTargetOfHealingSpell predicate; + + Group* group = bot->GetGroup(); + if (!group) + { + return NULL; + } + + bool isRaid = bot->GetGroup()->isRaidGroup(); + MinValueCalculator calc(100); + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->getSource(); + if (!Check(player) || !player->IsAlive()) + { + continue; + } + + uint8 health = player->GetHealthPercent(); + if (isRaid || health < sPlayerbotAIConfig.mediumHealth || !IsTargetOfSpellCast(player, predicate)) + { + calc.probe(health, player); + } + + Pet* pet = player->GetPet(); + if (pet && CanHealPet(pet)) + { + health = pet->GetHealthPercent(); + if (isRaid || health < sPlayerbotAIConfig.mediumHealth || !IsTargetOfSpellCast(player, predicate)) + { + calc.probe(health, player); + } + } + } + return (Unit*)calc.param; +} + +bool PartyMemberToHeal::CanHealPet(Pet* pet) +{ + return MINI_PET != pet->getPetType(); +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.h b/src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.h new file mode 100644 index 0000000000..114b1c45be --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberToHeal.h @@ -0,0 +1,17 @@ +#pragma once +#include "../Value.h" +#include "PartyMemberValue.h" + +namespace ai +{ + class PartyMemberToHeal : public PartyMemberValue + { + public: + PartyMemberToHeal(PlayerbotAI* ai) : + PartyMemberValue(ai) {} + + protected: + virtual Unit* Calculate(); + bool CanHealPet(Pet* pet); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.cpp b/src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.cpp new file mode 100644 index 0000000000..d46343d8df --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.cpp @@ -0,0 +1,44 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PartyMemberToResurrect.h" + +using namespace ai; + +class IsTargetOfResurrectSpell : public SpellEntryPredicate +{ +public: + virtual bool Check(SpellEntry const* spell) + { + for (int i=0; i<3; i++) + { + if (spell->Effect[i] == SPELL_EFFECT_RESURRECT || + spell->Effect[i] == SPELL_EFFECT_RESURRECT_NEW || + spell->Effect[i] == SPELL_EFFECT_SELF_RESURRECT) + return true; + } + return false; + } + +}; + +class FindDeadPlayer : public FindPlayerPredicate +{ +public: + FindDeadPlayer(PartyMemberValue* value) : value(value) {} + + virtual bool Check(Unit* unit) + { + Player* player = dynamic_cast(unit); + return player && player->GetDeathState() == CORPSE && !value->IsTargetOfSpellCast(player, predicate); + } + +private: + PartyMemberValue* value; + IsTargetOfResurrectSpell predicate; +}; + +Unit* PartyMemberToResurrect::Calculate() +{ + FindDeadPlayer finder(this); + return FindPartyMember(finder); +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.h b/src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.h new file mode 100644 index 0000000000..d6da5a6774 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberToResurrect.h @@ -0,0 +1,16 @@ +#pragma once +#include "../Value.h" +#include "PartyMemberValue.h" + +namespace ai +{ + class PartyMemberToResurrect : public PartyMemberValue + { + public: + PartyMemberToResurrect(PlayerbotAI* ai) : + PartyMemberValue(ai) {} + + protected: + virtual Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberValue.cpp b/src/modules/Bots/playerbot/strategy/values/PartyMemberValue.cpp new file mode 100644 index 0000000000..e8a479c069 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberValue.cpp @@ -0,0 +1,131 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PartyMemberValue.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; +using namespace std; + +Unit* PartyMemberValue::FindPartyMember(list* party, FindPlayerPredicate &predicate) +{ + for (list::iterator i = party->begin(); i != party->end(); ++i) + { + Player* player = *i; + + if (!player) + { + continue; + } + + if (Check(player) && predicate.Check(player)) + { + return player; + } + + Pet* pet = player->GetPet(); + if (pet && Check(pet) && predicate.Check(pet)) + { + return pet; + } + } + + return NULL; +} + +Unit* PartyMemberValue::FindPartyMember(FindPlayerPredicate &predicate) +{ + Player* master = GetMaster(); + Group* group = bot->GetGroup(); + if (!group) + { + return NULL; + } + + list healers, tanks, others, masters; + masters.push_back(master); + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->getSource(); + + if (ai->IsHeal(player)) + { + healers.push_back(player); + } + else if (ai->IsTank(player)) + { + tanks.push_back(player); + } + else if (player != master) + { + others.push_back(player); + } + } + + list* > lists; + lists.push_back(&healers); + lists.push_back(&tanks); + lists.push_back(&masters); + lists.push_back(&others); + + for (list* >::iterator i = lists.begin(); i != lists.end(); ++i) + { + list* party = *i; + Unit* target = FindPartyMember(party, predicate); + if (target) + { + return target; + } + } + + return NULL; +} + +bool PartyMemberValue::Check(Unit* player) +{ + + + return player && player != bot && player->GetMapId() == bot->GetMapId() && + bot->GetDistance(player) < sPlayerbotAIConfig.spellDistance && + bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); +} + +bool PartyMemberValue::IsTargetOfSpellCast(Player* target, SpellEntryPredicate &predicate) +{ + + Group* group = bot->GetGroup(); + ObjectGuid targetGuid = target ? target->GetObjectGuid() : bot->GetObjectGuid(); + ObjectGuid corpseGuid = target && target->GetCorpse() ? target->GetCorpse()->GetObjectGuid() : ObjectGuid(); + + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* player = gref->getSource(); + if (player == bot) + { + continue; + } + + if (player->IsNonMeleeSpellCasted(true)) + { + for (int type = CURRENT_GENERIC_SPELL; type < CURRENT_MAX_SPELL; type++) + { + Spell* spell = player->GetCurrentSpell((CurrentSpellTypes)type); + if (spell && predicate.Check(spell->m_spellInfo)) + { + ObjectGuid unitTarget = spell->m_targets.getUnitTargetGuid(); + if (unitTarget == targetGuid) + { + return true; + } + + ObjectGuid corpseTarget = spell->m_targets.getCorpseTargetGuid(); + if (corpseTarget == corpseGuid) + { + return true; + } + } + } + } + } + + return false; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberValue.h b/src/modules/Bots/playerbot/strategy/values/PartyMemberValue.h new file mode 100644 index 0000000000..bf31211890 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberValue.h @@ -0,0 +1,31 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class FindPlayerPredicate + { + public: + virtual bool Check(Unit*) = 0; + }; + + class SpellEntryPredicate + { + public: + virtual bool Check(SpellEntry const*) = 0; + }; + + class PartyMemberValue : public UnitCalculatedValue + { + public: + PartyMemberValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) {} + + public: + bool IsTargetOfSpellCast(Player* target, SpellEntryPredicate &predicate); + + protected: + Unit* FindPartyMember(FindPlayerPredicate &predicate); + Unit* FindPartyMember(list* party, FindPlayerPredicate &predicate); + bool Check(Unit* player); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp b/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp new file mode 100644 index 0000000000..f2ab8aa1c4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp @@ -0,0 +1,33 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PartyMemberWithoutAuraValue.h" + +using namespace ai; + +class PlayerWithoutAuraPredicate : public FindPlayerPredicate, public PlayerbotAIAware +{ +public: + PlayerWithoutAuraPredicate(PlayerbotAI* ai, string aura) : + PlayerbotAIAware(ai), FindPlayerPredicate(), aura(aura) {} + +public: + virtual bool Check(Unit* unit) + { + Pet* pet = dynamic_cast(unit); + if (pet && (pet->getPetType() == MINI_PET || pet->getPetType() == SUMMON_PET)) + { + return false; + } + + return unit->IsAlive() && !ai->HasAura(aura, unit); + } + +private: + string aura; +}; + +Unit* PartyMemberWithoutAuraValue::Calculate() +{ + PlayerWithoutAuraPredicate predicate(ai, qualifier); + return FindPartyMember(predicate); +} diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.h b/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.h new file mode 100644 index 0000000000..ba2755fa1a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.h @@ -0,0 +1,17 @@ +#pragma once +#include "../Value.h" +#include "PartyMemberValue.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class PartyMemberWithoutAuraValue : public PartyMemberValue, public Qualified + { + public: + PartyMemberWithoutAuraValue(PlayerbotAI* ai, float range = sPlayerbotAIConfig.sightDistance) : + PartyMemberValue(ai) {} + + protected: + virtual Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PetTargetValue.h b/src/modules/Bots/playerbot/strategy/values/PetTargetValue.h new file mode 100644 index 0000000000..69c20478d7 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PetTargetValue.h @@ -0,0 +1,13 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class PetTargetValue : public UnitCalculatedValue + { + public: + PetTargetValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) {} + + virtual Unit* Calculate() { return ai->GetBot()->GetPet(); } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PositionValue.cpp b/src/modules/Bots/playerbot/strategy/values/PositionValue.cpp new file mode 100644 index 0000000000..6d58f3fcda --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PositionValue.cpp @@ -0,0 +1,10 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PositionValue.h" + +using namespace ai; + +PositionValue::PositionValue(PlayerbotAI* ai) + : ManualSetValue(ai, position), Qualified() +{ +} diff --git a/src/modules/Bots/playerbot/strategy/values/PositionValue.h b/src/modules/Bots/playerbot/strategy/values/PositionValue.h new file mode 100644 index 0000000000..07fb0f73d8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PositionValue.h @@ -0,0 +1,26 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class Position + { + public: + Position() : valueSet(false) {} + void Set(double x, double y, double z) { this->x = x; this->y = y; this->z = z; this->valueSet = true; } + void Reset() { valueSet = false; } + bool isSet() { return valueSet; } + + double x, y, z; + bool valueSet; + }; + + class PositionValue : public ManualSetValue, public Qualified + { + public: + PositionValue(PlayerbotAI* ai); + + private: + Position position; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.cpp b/src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.cpp new file mode 100644 index 0000000000..48538f91f9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.cpp @@ -0,0 +1,23 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "PossibleTargetsValue.h" + +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +using namespace ai; +using namespace MaNGOS; + +void PossibleTargetsValue::FindUnits(list &targets) +{ + MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(bot, range); + MaNGOS::UnitListSearcher searcher(targets, u_check); + Cell::VisitAllObjects(bot, searcher, range); +} + +bool PossibleTargetsValue::AcceptUnit(Unit* unit) +{ + return !unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) && + (unit->IsHostileTo(bot) || (unit->getLevel() > 1 && !unit->IsFriendlyTo(bot))); +} diff --git a/src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.h b/src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.h new file mode 100644 index 0000000000..372db1698f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/PossibleTargetsValue.h @@ -0,0 +1,19 @@ +#pragma once +#include "../Value.h" +#include "NearestUnitsValue.h" +#include "../../PlayerbotAIConfig.h" + +namespace ai +{ + class PossibleTargetsValue : public NearestUnitsValue + { + public: + PossibleTargetsValue(PlayerbotAI* ai, float range = sPlayerbotAIConfig.sightDistance) : + NearestUnitsValue(ai) {} + + protected: + virtual void FindUnits(list &targets); + virtual bool AcceptUnit(Unit* unit); + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h b/src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h new file mode 100644 index 0000000000..855717f5c2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h @@ -0,0 +1,82 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class RtiTargetValue : public UnitCalculatedValue + { + public: + RtiTargetValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) + {} + + public: + static int GetRtiIndex(string rti) + { + int index = -1; + if(rti == "star") + { + index = 0; + } + else if(rti == "circle") + { + index = 1; + } + else if(rti == "diamond") + { + index = 2; + } + else if(rti == "triangle") + { + index = 3; + } + else if(rti == "moon") + { + index = 4; + } + else if(rti == "square") + { + index = 5; + } + else if(rti == "cross") + { + index = 6; + } + else if(rti == "skull") + { + index = 7; + } + return index; + } + + Unit *Calculate() + { + Group *group = bot->GetGroup(); + if(!group) + { + return NULL; + } + + string rti = AI_VALUE(string, "rti"); + int index = GetRtiIndex(rti); + + if (index == -1) + { + return NULL; + } + + ObjectGuid guid = group->GetTargetIcon(index); + if (!guid) + { + return NULL; + } + + Unit* unit = ai->GetUnit(guid); + if (!unit || unit->IsDead()) + { + return NULL; + } + + return unit; + } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/RtiValue.cpp b/src/modules/Bots/playerbot/strategy/values/RtiValue.cpp new file mode 100644 index 0000000000..3c9eea1498 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/RtiValue.cpp @@ -0,0 +1,37 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "RtiValue.h" + +using namespace ai; +using namespace MaNGOS; + +RtiValue::RtiValue(PlayerbotAI* ai) + : ManualSetValue(ai, "none") +{ + switch (ai->GetBot()->getClass()) + { + case CLASS_DRUID: + value = "circle"; + break; + case CLASS_ROGUE: + value = "star"; + break; + case CLASS_SHAMAN: + value = "square"; + break; + case CLASS_HUNTER: + value = "triangle"; + break; + case CLASS_WARLOCK: + case CLASS_PALADIN: + value = "diamond"; + break; + case CLASS_PRIEST: + case CLASS_MAGE: + value = "moon"; + break; + default: + value = "skull"; + break; + } +} diff --git a/src/modules/Bots/playerbot/strategy/values/RtiValue.h b/src/modules/Bots/playerbot/strategy/values/RtiValue.h new file mode 100644 index 0000000000..396e020968 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/RtiValue.h @@ -0,0 +1,11 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class RtiValue : public ManualSetValue + { + public: + RtiValue(PlayerbotAI* ai); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/SelfTargetValue.h b/src/modules/Bots/playerbot/strategy/values/SelfTargetValue.h new file mode 100644 index 0000000000..a562023d7a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/SelfTargetValue.h @@ -0,0 +1,13 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class SelfTargetValue : public UnitCalculatedValue + { + public: + SelfTargetValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) {} + + virtual Unit* Calculate() { return ai->GetBot(); } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.cpp b/src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.cpp new file mode 100644 index 0000000000..73e8e03d63 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.cpp @@ -0,0 +1,54 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "SpellCastUsefulValue.h" +#include "LastSpellCastValue.h" + +using namespace ai; + +bool SpellCastUsefulValue::Calculate() +{ + uint32 spellid = AI_VALUE2(uint32, "spell id", qualifier); + if (!spellid) + { + return true; // there can be known alternatives + } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); + if (!spellInfo) + { + return true; // there can be known alternatives + } + + if (spellInfo->Attributes & SPELL_ATTR_ON_NEXT_SWING_1 || + spellInfo->Attributes & SPELL_ATTR_ON_NEXT_SWING_2) + { + Spell* spell = bot->GetCurrentSpell(CURRENT_MELEE_SPELL); + if (spell && spell->m_spellInfo->Id == spellid && spell->IsNextMeleeSwingSpell()) + { + return false; + } + } + + uint32 lastSpellId = AI_VALUE(LastSpellCast&, "last spell cast").id; + if (spellid == lastSpellId) + { + Spell* const pSpell = bot->FindCurrentSpellBySpellId(lastSpellId); + if (pSpell) + { + return false; + } + } + + // TODO: workaround + if (qualifier == "windfury weapon" || qualifier == "flametongue weapon" || qualifier == "frostbrand weapon" || + qualifier == "rockbiter weapon" || qualifier == "earthliving weapon" || qualifier == "spellstone") + { + Item *item = AI_VALUE2(Item*, "item for spell", spellid); + if (item && item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT)) + { + return false; + } + } + + return true; +} diff --git a/src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.h b/src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.h new file mode 100644 index 0000000000..5454f0c5d3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/SpellCastUsefulValue.h @@ -0,0 +1,17 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class SpellCastUsefulValue : public BoolCalculatedValue, public Qualified + { + public: + SpellCastUsefulValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + public: + virtual bool Calculate(); + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/SpellIdValue.cpp b/src/modules/Bots/playerbot/strategy/values/SpellIdValue.cpp new file mode 100644 index 0000000000..f0162e5175 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/SpellIdValue.cpp @@ -0,0 +1,117 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "SpellIdValue.h" +#include "../../PlayerbotAIConfig.h" + +using namespace ai; + +SpellIdValue::SpellIdValue(PlayerbotAI* ai) : + CalculatedValue(ai, "spell id", 5) +{ +} + +uint32 SpellIdValue::Calculate() +{ + string namepart = qualifier; + wstring wnamepart; + + if (!Utf8toWStr(namepart, wnamepart)) + { + return 0; + } + + wstrToLower(wnamepart); + char firstSymbol = tolower(qualifier[0]); + int spellLength = wnamepart.length(); + + int loc = bot->GetSession()->GetSessionDbcLocale(); + + uint32 foundSpellId = 0; + bool foundMatchUsesNoReagents = false; + + for (PlayerSpellMap::iterator itr = bot->GetSpellMap().begin(); itr != bot->GetSpellMap().end(); ++itr) + { + uint32 spellId = itr->first; + + if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled || IsPassiveSpell(spellId)) + { + continue; + } + + const SpellEntry* pSpellInfo = sSpellStore.LookupEntry(spellId); + if (!pSpellInfo) + { + continue; + } + + if (pSpellInfo->Effect[0] == SPELL_EFFECT_LEARN_SPELL) + { + continue; + } + + char* spellName = pSpellInfo->SpellName[loc]; + if (tolower(spellName[0]) != firstSymbol || strlen(spellName) != spellLength || !Utf8FitTo(spellName, wnamepart)) + { + continue; + } + + bool usesNoReagents = (pSpellInfo->Reagent[0] <= 0); + + // if we already found a spell + bool useThisSpell = true; + if (foundSpellId > 0) { + if (usesNoReagents && !foundMatchUsesNoReagents) + { + + } + else if (spellId > foundSpellId) + { + + } + else + { + useThisSpell = false; + } + } + if (useThisSpell) { + { + foundSpellId = spellId; + } + foundMatchUsesNoReagents = usesNoReagents; + } + } + + Pet* pet = bot->GetPet(); + if (!foundSpellId && pet) + { + for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr) + { + if(itr->second.state == PETSPELL_REMOVED) + { + continue; + } + + uint32 spellId = itr->first; + const SpellEntry* pSpellInfo = sSpellStore.LookupEntry(spellId); + if (!pSpellInfo) + { + continue; + } + + if (pSpellInfo->Effect[0] == SPELL_EFFECT_LEARN_SPELL) + { + continue; + } + + char* spellName = pSpellInfo->SpellName[loc]; + if (tolower(spellName[0]) != firstSymbol || strlen(spellName) != spellLength || !Utf8FitTo(spellName, wnamepart)) + { + continue; + } + + foundSpellId = spellId; + } + } + + return foundSpellId; +} diff --git a/src/modules/Bots/playerbot/strategy/values/SpellIdValue.h b/src/modules/Bots/playerbot/strategy/values/SpellIdValue.h new file mode 100644 index 0000000000..06e88c56c5 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/SpellIdValue.h @@ -0,0 +1,17 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class SpellIdValue : public CalculatedValue, public Qualified + { + public: + SpellIdValue(PlayerbotAI* ai); + + public: + virtual uint32 Calculate(); + + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/StatsValues.cpp b/src/modules/Bots/playerbot/strategy/values/StatsValues.cpp new file mode 100644 index 0000000000..af394d6001 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/StatsValues.cpp @@ -0,0 +1,131 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "StatsValues.h" + +using namespace ai; + +uint8 HealthValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return 100; + } + return (static_cast (target->GetHealth()) / target->GetMaxHealth()) * 100; +} + +bool IsDeadValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return false; + } + return target->GetDeathState() != ALIVE; +} + + +uint8 RageValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return 0; + } + return (static_cast (target->GetPower(POWER_RAGE))); +} + +uint8 EnergyValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return 0; + } + return (static_cast (target->GetPower(POWER_ENERGY))); +} + +uint8 ManaValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return 100; + } + return (static_cast (target->GetPower(POWER_MANA)) / target->GetMaxPower(POWER_MANA)) * 100; +} + +bool HasManaValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return false; + } + return target->GetPower(POWER_MANA); +} + + +uint8 ComboPointsValue::Calculate() +{ + Unit *target = GetTarget(); + if (!target || target->GetObjectGuid() != bot->GetComboTargetGuid()) + { + return 0; + } + + return bot->GetComboPoints(); +} + +bool IsMountedValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return false; + } + + return target->IsMounted(); +} + + +bool IsInCombatValue::Calculate() +{ + Unit* target = GetTarget(); + if (!target) + { + return false; + } + + return target->IsInCombat(); +} + +uint8 BagSpaceValue::Calculate() +{ + uint32 totalused = 0, total = 16; + for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++) + { + if (bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + { + totalused++; + } + } + + uint32 totalfree = 16 - totalused; + for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag) + { + const Bag* const pBag = (Bag*) bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag); + if (pBag) + { + ItemPrototype const* pBagProto = pBag->GetProto(); + if (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER) + { + total += pBag->GetBagSize(); + totalfree += pBag->GetFreeSlots(); + } + } + + } + + return (static_cast (totalused) / total) * 100; +} diff --git a/src/modules/Bots/playerbot/strategy/values/StatsValues.h b/src/modules/Bots/playerbot/strategy/values/StatsValues.h new file mode 100644 index 0000000000..4fcdbaf2bb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/StatsValues.h @@ -0,0 +1,133 @@ +#pragma once +#include "../Value.h" + +class Unit; + +namespace ai +{ + class HealthValue : public Uint8CalculatedValue, public Qualified + { + public: + HealthValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + + class IsDeadValue : public BoolCalculatedValue, public Qualified + { + public: + IsDeadValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual bool Calculate(); + }; + + class RageValue : public Uint8CalculatedValue, public Qualified + { + public: + RageValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + + class EnergyValue : public Uint8CalculatedValue, public Qualified + { + public: + EnergyValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + + class ManaValue : public Uint8CalculatedValue, public Qualified + { + public: + ManaValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + + class HasManaValue : public BoolCalculatedValue, public Qualified + { + public: + HasManaValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual bool Calculate(); + }; + + class ComboPointsValue : public Uint8CalculatedValue, public Qualified + { + public: + ComboPointsValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual uint8 Calculate(); + }; + + class IsMountedValue : public BoolCalculatedValue, public Qualified + { + public: + IsMountedValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual bool Calculate(); + }; + + class IsInCombatValue : public BoolCalculatedValue, public Qualified + { + public: + IsInCombatValue(PlayerbotAI* ai) : BoolCalculatedValue(ai) {} + + Unit* GetTarget() + { + AiObjectContext* ctx = AiObject::context; + return ctx->GetValue(qualifier)->Get(); + } + virtual bool Calculate() ; + }; + + class BagSpaceValue : public Uint8CalculatedValue + { + public: + BagSpaceValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + virtual uint8 Calculate(); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/values/TankTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/TankTargetValue.cpp new file mode 100644 index 0000000000..b1d443d666 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/TankTargetValue.cpp @@ -0,0 +1,47 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TankTargetValue.h" + +using namespace ai; + +class FindTargetForTankStrategy : public FindTargetStrategy +{ +public: + FindTargetForTankStrategy(PlayerbotAI* ai) : FindTargetStrategy(ai) + { + minThreat = 0; + minTankCount = 0; + maxDpsCount = 0; + } + +public: + virtual void CheckAttacker(Unit* creature, ThreatManager* threatManager) + { + Player* bot = ai->GetBot(); + float threat = threatManager->getThreat(bot); + int tankCount, dpsCount; + GetPlayerCount(creature, &tankCount, &dpsCount); + + if (!result || + (minThreat >= threat && + (minTankCount >= tankCount || maxDpsCount <= dpsCount))) + { + minThreat = threat; + minTankCount = tankCount; + maxDpsCount = dpsCount; + result = creature; + } + } + +protected: + float minThreat; + int minTankCount; + int maxDpsCount; +}; + + +Unit* TankTargetValue::Calculate() +{ + FindTargetForTankStrategy strategy(ai); + return FindTarget(&strategy); +} diff --git a/src/modules/Bots/playerbot/strategy/values/TankTargetValue.h b/src/modules/Bots/playerbot/strategy/values/TankTargetValue.h new file mode 100644 index 0000000000..2eaf57709c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/TankTargetValue.h @@ -0,0 +1,16 @@ +#pragma once +#include "../Value.h" +#include "TargetValue.h" + +namespace ai +{ + + class TankTargetValue : public TargetValue + { + public: + TankTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + + public: + Unit* Calculate(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/TargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/TargetValue.cpp new file mode 100644 index 0000000000..0fdc4a3c2c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/TargetValue.cpp @@ -0,0 +1,66 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "TargetValue.h" +#include "Unit.h" + +using namespace ai; + +Unit* TargetValue::FindTarget(FindTargetStrategy* strategy) +{ + list attackers = ai->GetAiObjectContext()->GetValue >("attackers")->Get(); + for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = ai->GetUnit(*i); + if (!unit) + { + continue; + } + + ThreatManager &threatManager = unit->GetThreatManager(); + strategy->CheckAttacker(unit, &threatManager); + } + + return strategy->GetResult(); +} + +void FindTargetStrategy::GetPlayerCount(Unit* creature, int* tankCount, int* dpsCount) +{ + Player* bot = ai->GetBot(); + if (tankCountCache.find(creature) != tankCountCache.end()) + { + *tankCount = tankCountCache[creature]; + *dpsCount = dpsCountCache[creature]; + return; + } + + *tankCount = 0; + *dpsCount = 0; + + Unit::AttackerSet attackers(creature->getAttackers()); + for (set::const_iterator i = attackers.begin(); i != attackers.end(); i++) + { + Unit* attacker = *i; + if (!attacker || !attacker->IsAlive() || attacker == bot) + { + continue; + } + + Player* player = dynamic_cast(attacker); + if (!player) + { + continue; + } + + if (ai->IsTank(player)) + { + (*tankCount)++; + } + else + { + (*dpsCount)++; + } + } + + tankCountCache[creature] = *tankCount; + dpsCountCache[creature] = *dpsCount; +} diff --git a/src/modules/Bots/playerbot/strategy/values/TargetValue.h b/src/modules/Bots/playerbot/strategy/values/TargetValue.h new file mode 100644 index 0000000000..f02c194b09 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/TargetValue.h @@ -0,0 +1,39 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class FindTargetStrategy + { + public: + FindTargetStrategy(PlayerbotAI* ai) + { + result = NULL; + this->ai = ai; + } + + public: + Unit* GetResult() { return result; } + + public: + virtual void CheckAttacker(Unit* attacker, ThreatManager* threatManager) = 0; + void GetPlayerCount(Unit* creature, int* tankCount, int* dpsCount); + + protected: + Unit* result; + PlayerbotAI* ai; + + protected: + map tankCountCache; + map dpsCountCache; + }; + + class TargetValue : public UnitCalculatedValue + { + public: + TargetValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) {} + + protected: + Unit* FindTarget(FindTargetStrategy* strategy); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp b/src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp new file mode 100644 index 0000000000..09ff3820ef --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp @@ -0,0 +1,79 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "ThreatValues.h" +#include "ThreatManager.h" + +using namespace ai; + +uint8 ThreatValue::Calculate() +{ + if (qualifier == "aoe") + { + uint8 maxThreat = 0; + list attackers = context->GetValue >("attackers")->Get(); + for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + { + Unit* unit = ai->GetUnit(*i); + if (!unit || !unit->IsAlive()) + { + continue; + } + + uint8 threat = Calculate(unit); + if (!maxThreat || threat > maxThreat) + { + maxThreat = threat; + } + } + + return maxThreat; + } + + Unit* target = AI_VALUE(Unit*, qualifier); + return Calculate(target); +} + +uint8 ThreatValue::Calculate(Unit* target) +{ + if (!target) + { + return 0; + } + + if (target->GetObjectGuid().IsPlayer()) + { + return 0; + } + + Group* group = bot->GetGroup(); + if (!group) + { + return 0; + } + + float botThreat = target->GetThreatManager().getThreat(bot); + float maxThreat = 0; + + Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); + for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) + { + Player *player = sObjectMgr.GetPlayer(itr->guid); + if( !player || !player->IsAlive() || player == bot) + { + continue; + } + + float threat = target->GetThreatManager().getThreat(player); + if (maxThreat < threat) + { + maxThreat = threat; + } + } + + if (maxThreat <= 0) + { + return 0; + } + + return botThreat * 100 / maxThreat; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ThreatValues.h b/src/modules/Bots/playerbot/strategy/values/ThreatValues.h new file mode 100644 index 0000000000..6ce721065a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ThreatValues.h @@ -0,0 +1,17 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class ThreatValue : public Uint8CalculatedValue, public Qualified + { + public: + ThreatValue(PlayerbotAI* ai) : Uint8CalculatedValue(ai) {} + + public: + virtual uint8 Calculate(); + + protected: + uint8 Calculate(Unit* target); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ValueContext.h b/src/modules/Bots/playerbot/strategy/values/ValueContext.h new file mode 100644 index 0000000000..eae61e3dfb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/ValueContext.h @@ -0,0 +1,222 @@ +#pragma once + +#include "NearestGameObjects.h" +#include "LogLevelValue.h" +#include "NearestNpcsValue.h" +#include "PossibleTargetsValue.h" +#include "NearestAdsValue.h" +#include "NearestCorpsesValue.h" +#include "PartyMemberWithoutAuraValue.h" +#include "PartyMemberToHeal.h" +#include "PartyMemberToResurrect.h" +#include "CurrentTargetValue.h" +#include "SelfTargetValue.h" +#include "MasterTargetValue.h" +#include "LineTargetValue.h" +#include "TankTargetValue.h" +#include "DpsTargetValue.h" +#include "CcTargetValue.h" +#include "CurrentCcTargetValue.h" +#include "PetTargetValue.h" +#include "GrindTargetValue.h" +#include "RtiTargetValue.h" +#include "PartyMemberToDispel.h" +#include "StatsValues.h" +#include "AttackerCountValues.h" +#include "AttackersValue.h" +#include "AvailableLootValue.h" +#include "AlwaysLootListValue.h" +#include "LootStrategyValue.h" +#include "HasAvailableLootValue.h" +#include "LastMovementValue.h" +#include "DistanceValue.h" +#include "IsMovingValue.h" +#include "IsBehindValue.h" +#include "IsFacingValue.h" +#include "ItemCountValue.h" +#include "SpellIdValue.h" +#include "ItemForSpellValue.h" +#include "SpellCastUsefulValue.h" +#include "LastSpellCastValue.h" +#include "ChatValue.h" +#include "HasTotemValue.h" +#include "LeastHpTargetValue.h" +#include "AoeHealValues.h" +#include "RtiValue.h" +#include "PositionValue.h" +#include "ThreatValues.h" +#include "DuelTargetValue.h" +#include "InvalidTargetValue.h" +#include "EnemyPlayerValue.h" +#include "AttackerWithoutAuraTargetValue.h" +#include "LastSpellCastTimeValue.h" +#include "ManaSaveLevelValue.h" +#include "LfgValues.h" +#include "EnemyHealerTargetValue.h" +#include "ItemUsageValue.h" + +namespace ai +{ + class ValueContext : public NamedObjectContext + { + public: + ValueContext() + { + creators["nearest game objects"] = &ValueContext::nearest_game_objects; + creators["nearest npcs"] = &ValueContext::nearest_npcs; + creators["possible targets"] = &ValueContext::possible_targets; + creators["nearest adds"] = &ValueContext::nearest_adds; + creators["nearest corpses"] = &ValueContext::nearest_corpses; + creators["log level"] = &ValueContext::log_level; + creators["party member without aura"] = &ValueContext::party_member_without_aura; + creators["attacker without aura"] = &ValueContext::attacker_without_aura; + creators["party member to heal"] = &ValueContext::party_member_to_heal; + creators["party member to resurrect"] = &ValueContext::party_member_to_resurrect; + creators["current target"] = &ValueContext::current_target; + creators["self target"] = &ValueContext::self_target; + creators["master target"] = &ValueContext::master; + creators["line target"] = &ValueContext::line_target; + creators["tank target"] = &ValueContext::tank_target; + creators["dps target"] = &ValueContext::dps_target; + creators["least hp target"] = &ValueContext::least_hp_target; + creators["enemy player target"] = &ValueContext::enemy_player_target; + creators["cc target"] = &ValueContext::cc_target; + creators["current cc target"] = &ValueContext::current_cc_target; + creators["pet target"] = &ValueContext::pet_target; + creators["old target"] = &ValueContext::old_target; + creators["grind target"] = &ValueContext::grind_target; + creators["rti target"] = &ValueContext::rti_target; + creators["duel target"] = &ValueContext::duel_target; + creators["party member to dispel"] = &ValueContext::party_member_to_dispel; + creators["health"] = &ValueContext::health; + creators["rage"] = &ValueContext::rage; + creators["energy"] = &ValueContext::energy; + creators["mana"] = &ValueContext::mana; + creators["combo"] = &ValueContext::combo; + creators["dead"] = &ValueContext::dead; + creators["has mana"] = &ValueContext::has_mana; + creators["attacker count"] = &ValueContext::attacker_count; + creators["my attacker count"] = &ValueContext::my_attacker_count; + creators["has aggro"] = &ValueContext::has_aggro; + creators["mounted"] = &ValueContext::mounted; + + creators["can loot"] = &ValueContext::can_loot; + creators["loot target"] = &ValueContext::loot_target; + creators["available loot"] = &ValueContext::available_loot; + creators["has available loot"] = &ValueContext::has_available_loot; + creators["always loot list"] = &ValueContext::always_loot_list; + creators["loot strategy"] = &ValueContext::loot_strategy; + creators["last movement"] = &ValueContext::last_movement; + creators["distance"] = &ValueContext::distance; + creators["moving"] = &ValueContext::moving; + creators["swimming"] = &ValueContext::swimming; + creators["behind"] = &ValueContext::behind; + creators["facing"] = &ValueContext::facing; + + creators["item count"] = &ValueContext::item_count; + creators["inventory items"] = &ValueContext::inventory_item; + + creators["spell id"] = &ValueContext::spell_id; + creators["item for spell"] = &ValueContext::item_for_spell; + creators["spell cast useful"] = &ValueContext::spell_cast_useful; + creators["last spell cast"] = &ValueContext::last_spell_cast; + creators["last spell cast time"] = &ValueContext::last_spell_cast_time; + creators["chat"] = &ValueContext::chat; + creators["has totem"] = &ValueContext::has_totem; + + creators["aoe heal"] = &ValueContext::aoe_heal; + + creators["rti"] = &ValueContext::rti; + creators["position"] = &ValueContext::position; + creators["threat"] = &ValueContext::threat; + + creators["balance"] = &ValueContext::balance; + creators["attackers"] = &ValueContext::attackers; + creators["invalid target"] = &ValueContext::invalid_target; + creators["mana save level"] = &ValueContext::mana_save_level; + creators["combat"] = &ValueContext::combat; + creators["lfg proposal"] = &ValueContext::lfg_proposal; + creators["bag space"] = &ValueContext::bag_space; + creators["enemy healer target"] = &ValueContext::enemy_healer_target; + creators["item usage"] = &ValueContext::item_usage; + } + + private: + static UntypedValue* item_usage(PlayerbotAI* ai) { return new ItemUsageValue(ai); } + static UntypedValue* mana_save_level(PlayerbotAI* ai) { return new ManaSaveLevelValue(ai); } + static UntypedValue* invalid_target(PlayerbotAI* ai) { return new InvalidTargetValue(ai); } + static UntypedValue* balance(PlayerbotAI* ai) { return new BalancePercentValue(ai); } + static UntypedValue* attackers(PlayerbotAI* ai) { return new AttackersValue(ai); } + + static UntypedValue* position(PlayerbotAI* ai) { return new PositionValue(ai); } + static UntypedValue* rti(PlayerbotAI* ai) { return new RtiValue(ai); } + + static UntypedValue* aoe_heal(PlayerbotAI* ai) { return new AoeHealValue(ai); } + + static UntypedValue* chat(PlayerbotAI* ai) { return new ChatValue(ai); } + static UntypedValue* last_spell_cast(PlayerbotAI* ai) { return new LastSpellCastValue(ai); } + static UntypedValue* last_spell_cast_time(PlayerbotAI* ai) { return new LastSpellCastTimeValue(ai); } + static UntypedValue* spell_cast_useful(PlayerbotAI* ai) { return new SpellCastUsefulValue(ai); } + static UntypedValue* item_for_spell(PlayerbotAI* ai) { return new ItemForSpellValue(ai); } + static UntypedValue* spell_id(PlayerbotAI* ai) { return new SpellIdValue(ai); } + static UntypedValue* inventory_item(PlayerbotAI* ai) { return new InventoryItemValue(ai); } + static UntypedValue* item_count(PlayerbotAI* ai) { return new ItemCountValue(ai); } + static UntypedValue* behind(PlayerbotAI* ai) { return new IsBehindValue(ai); } + static UntypedValue* facing(PlayerbotAI* ai) { return new IsFacingValue(ai); } + static UntypedValue* moving(PlayerbotAI* ai) { return new IsMovingValue(ai); } + static UntypedValue* swimming(PlayerbotAI* ai) { return new IsSwimmingValue(ai); } + static UntypedValue* distance(PlayerbotAI* ai) { return new DistanceValue(ai); } + static UntypedValue* last_movement(PlayerbotAI* ai) { return new LastMovementValue(ai); } + + static UntypedValue* can_loot(PlayerbotAI* ai) { return new CanLootValue(ai); } + static UntypedValue* available_loot(PlayerbotAI* ai) { return new AvailableLootValue(ai); } + static UntypedValue* loot_target(PlayerbotAI* ai) { return new LootTargetValue(ai); } + static UntypedValue* has_available_loot(PlayerbotAI* ai) { return new HasAvailableLootValue(ai); } + static UntypedValue* always_loot_list(PlayerbotAI* ai) { return new AlwaysLootListValue(ai); } + static UntypedValue* loot_strategy(PlayerbotAI* ai) { return new LootStrategyValue(ai); } + + static UntypedValue* attacker_count(PlayerbotAI* ai) { return new AttackerCountValue(ai); } + static UntypedValue* my_attacker_count(PlayerbotAI* ai) { return new MyAttackerCountValue(ai); } + static UntypedValue* has_aggro(PlayerbotAI* ai) { return new HasAggroValue(ai); } + static UntypedValue* mounted(PlayerbotAI* ai) { return new IsMountedValue(ai); } + static UntypedValue* health(PlayerbotAI* ai) { return new HealthValue(ai); } + static UntypedValue* rage(PlayerbotAI* ai) { return new RageValue(ai); } + static UntypedValue* energy(PlayerbotAI* ai) { return new EnergyValue(ai); } + static UntypedValue* mana(PlayerbotAI* ai) { return new ManaValue(ai); } + static UntypedValue* combo(PlayerbotAI* ai) { return new ComboPointsValue(ai); } + static UntypedValue* dead(PlayerbotAI* ai) { return new IsDeadValue(ai); } + static UntypedValue* has_mana(PlayerbotAI* ai) { return new HasManaValue(ai); } + static UntypedValue* nearest_game_objects(PlayerbotAI* ai) { return new NearestGameObjects(ai); } + static UntypedValue* log_level(PlayerbotAI* ai) { return new LogLevelValue(ai); } + static UntypedValue* nearest_npcs(PlayerbotAI* ai) { return new NearestNpcsValue(ai); } + static UntypedValue* nearest_corpses(PlayerbotAI* ai) { return new NearestCorpsesValue(ai); } + static UntypedValue* possible_targets(PlayerbotAI* ai) { return new PossibleTargetsValue(ai); } + static UntypedValue* nearest_adds(PlayerbotAI* ai) { return new NearestAdsValue(ai); } + static UntypedValue* party_member_without_aura(PlayerbotAI* ai) { return new PartyMemberWithoutAuraValue(ai); } + static UntypedValue* attacker_without_aura(PlayerbotAI* ai) { return new AttackerWithoutAuraTargetValue(ai); } + static UntypedValue* party_member_to_heal(PlayerbotAI* ai) { return new PartyMemberToHeal(ai); } + static UntypedValue* party_member_to_resurrect(PlayerbotAI* ai) { return new PartyMemberToResurrect(ai); } + static UntypedValue* party_member_to_dispel(PlayerbotAI* ai) { return new PartyMemberToDispel(ai); } + static UntypedValue* current_target(PlayerbotAI* ai) { return new CurrentTargetValue(ai); } + static UntypedValue* old_target(PlayerbotAI* ai) { return new CurrentTargetValue(ai); } + static UntypedValue* self_target(PlayerbotAI* ai) { return new SelfTargetValue(ai); } + static UntypedValue* master(PlayerbotAI* ai) { return new MasterTargetValue(ai); } + static UntypedValue* line_target(PlayerbotAI* ai) { return new LineTargetValue(ai); } + static UntypedValue* tank_target(PlayerbotAI* ai) { return new TankTargetValue(ai); } + static UntypedValue* dps_target(PlayerbotAI* ai) { return new DpsTargetValue(ai); } + static UntypedValue* least_hp_target(PlayerbotAI* ai) { return new LeastHpTargetValue(ai); } + static UntypedValue* enemy_player_target(PlayerbotAI* ai) { return new EnemyPlayerValue(ai); } + static UntypedValue* cc_target(PlayerbotAI* ai) { return new CcTargetValue(ai); } + static UntypedValue* current_cc_target(PlayerbotAI* ai) { return new CurrentCcTargetValue(ai); } + static UntypedValue* pet_target(PlayerbotAI* ai) { return new PetTargetValue(ai); } + static UntypedValue* grind_target(PlayerbotAI* ai) { return new GrindTargetValue(ai); } + static UntypedValue* rti_target(PlayerbotAI* ai) { return new RtiTargetValue(ai); } + static UntypedValue* duel_target(PlayerbotAI* ai) { return new DuelTargetValue(ai); } + static UntypedValue* has_totem(PlayerbotAI* ai) { return new HasTotemValue(ai); } + static UntypedValue* threat(PlayerbotAI* ai) { return new ThreatValue(ai); } + static UntypedValue* combat(PlayerbotAI* ai) { return new IsInCombatValue(ai); } + static UntypedValue* lfg_proposal(PlayerbotAI* ai) { return new LfgProposalValue(ai); } + static UntypedValue* bag_space(PlayerbotAI* ai) { return new BagSpaceValue(ai); } + static UntypedValue* enemy_healer_target(PlayerbotAI* ai) { return new EnemyHealerTargetValue(ai); } + }; +}; diff --git a/src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.cpp b/src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.cpp new file mode 100644 index 0000000000..5651a27a59 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.cpp @@ -0,0 +1,76 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarlockTriggers.h" +#include "WarlockMultipliers.h" +#include "DpsWarlockStrategy.h" +#include "WarlockActions.h" + +using namespace ai; + +class DpsWarlockStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + DpsWarlockStrategyActionNodeFactory() + { + creators["shadow bolt"] = &shadow_bolt; + } +private: + static ActionNode* shadow_bolt(PlayerbotAI* ai) + { + return new ActionNode ("shadow bolt", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("shoot"), NULL), + /*C*/ NULL); + } +}; + +DpsWarlockStrategy::DpsWarlockStrategy(PlayerbotAI* ai) : GenericWarlockStrategy(ai) +{ + actionNodeFactories.Add(new DpsWarlockStrategyActionNodeFactory()); +} + + +NextAction** DpsWarlockStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("incinirate", 10.0f), new NextAction("shadow bolt", 10.0f), NULL); +} + +void DpsWarlockStrategy::InitTriggers(std::list &triggers) +{ + GenericWarlockStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "shadow trance", + NextAction::array(0, new NextAction("shadow bolt", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "backlash", + NextAction::array(0, new NextAction("shadow bolt", 20.0f), NULL))); +} + +void DpsAoeWarlockStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, new NextAction("rain of fire", 30.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("seed of corruption", 31.0f), NULL))); + + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("shadowfury", 29.0f), NULL))); + + triggers.push_back(new TriggerNode( + "corruption on attacker", + NextAction::array(0, new NextAction("corruption on attacker", 28.0f), NULL))); + +} + +void DpsWarlockDebuffStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "corruption", + NextAction::array(0, new NextAction("corruption", 12.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.h b/src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.h new file mode 100644 index 0000000000..846f9df36a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/DpsWarlockStrategy.h @@ -0,0 +1,39 @@ +#pragma once + +#include "GenericWarlockStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class DpsWarlockStrategy : public GenericWarlockStrategy + { + public: + DpsWarlockStrategy(PlayerbotAI* ai); + virtual string getName() { return "dps"; } + + public: + virtual void InitTriggers(std::list &triggers); + virtual NextAction** getDefaultActions(); + }; + + class DpsAoeWarlockStrategy : public CombatStrategy + { + public: + DpsAoeWarlockStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "aoe"; } + }; + + class DpsWarlockDebuffStrategy : public CombatStrategy + { + public: + DpsWarlockDebuffStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "dps debuff"; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.cpp new file mode 100644 index 0000000000..0835ea416e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.cpp @@ -0,0 +1,65 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarlockMultipliers.h" +#include "GenericWarlockNonCombatStrategy.h" + +using namespace ai; + +class GenericWarlockNonCombatStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericWarlockNonCombatStrategyActionNodeFactory() + { + creators["fel armor"] = &fel_armor; + creators["demon armor"] = &demon_armor; + } +private: + static ActionNode* fel_armor(PlayerbotAI* ai) + { + return new ActionNode ("fel armor", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("demon armor"), NULL), + /*C*/ NULL); + } + static ActionNode* demon_armor(PlayerbotAI* ai) + { + return new ActionNode ("demon armor", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("demon skin"), NULL), + /*C*/ NULL); + } +}; + +GenericWarlockNonCombatStrategy::GenericWarlockNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericWarlockNonCombatStrategyActionNodeFactory()); +} + +void GenericWarlockNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "demon armor", + NextAction::array(0, new NextAction("fel armor", 21.0f), NULL))); + + triggers.push_back(new TriggerNode( + "no healthstone", + NextAction::array(0, new NextAction("create healthstone", 15.0f), NULL))); + + triggers.push_back(new TriggerNode( + "no firestone", + NextAction::array(0, new NextAction("create firestone", 14.0f), NULL))); + + triggers.push_back(new TriggerNode( + "no spellstone", + NextAction::array(0, new NextAction("create spellstone", 13.0f), NULL))); + + triggers.push_back(new TriggerNode( + "spellstone", + NextAction::array(0, new NextAction("spellstone", 13.0f), NULL))); + + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("summon imp", 10.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.h new file mode 100644 index 0000000000..c5e483f8a0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockNonCombatStrategy.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericWarlockNonCombatStrategy : public NonCombatStrategy + { + public: + GenericWarlockNonCombatStrategy(PlayerbotAI* ai); + virtual string getName() { return "nc"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.cpp b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.cpp new file mode 100644 index 0000000000..b498b5ae3c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.cpp @@ -0,0 +1,74 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarlockMultipliers.h" +#include "GenericWarlockStrategy.h" + +using namespace ai; + +class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericWarlockStrategyActionNodeFactory() + { + creators["summon voidwalker"] = &summon_voidwalker; + creators["banish"] = &banish; + } +private: + static ActionNode* summon_voidwalker(PlayerbotAI* ai) + { + return new ActionNode ("summon voidwalker", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("drain soul"), NULL), + /*C*/ NULL); + } + static ActionNode* banish(PlayerbotAI* ai) + { + return new ActionNode ("banish", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("fear"), NULL), + /*C*/ NULL); + } +}; + +GenericWarlockStrategy::GenericWarlockStrategy(PlayerbotAI* ai) : RangedCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory()); +} + +NextAction** GenericWarlockStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("shoot", 10.0f), NULL); +} + +void GenericWarlockStrategy::InitTriggers(std::list &triggers) +{ + RangedCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "curse of agony", + NextAction::array(0, new NextAction("curse of agony", 11.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("drain life", 40.0f), NULL))); + + triggers.push_back(new TriggerNode( + "low mana", + NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), NULL))); + + triggers.push_back(new TriggerNode( + "target critical health", + NextAction::array(0, new NextAction("drain soul", 30.0f), NULL))); + + triggers.push_back(new TriggerNode( + "banish", + NextAction::array(0, new NextAction("banish", 21.0f), NULL))); + + triggers.push_back(new TriggerNode( + "fear", + NextAction::array(0, new NextAction("fear on cc", 20.0f), NULL))); + + triggers.push_back(new TriggerNode( + "immolate", + NextAction::array(0, new NextAction("immolate", 19.0f), new NextAction("conflagrate", 19.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.h b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.h new file mode 100644 index 0000000000..473da59030 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/GenericWarlockStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/RangedCombatStrategy.h" + +namespace ai +{ + class GenericWarlockStrategy : public RangedCombatStrategy + { + public: + GenericWarlockStrategy(PlayerbotAI* ai); + virtual string getName() { return "warlock"; } + + public: + virtual void InitTriggers(std::list &triggers); + virtual NextAction** getDefaultActions(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.cpp b/src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.cpp new file mode 100644 index 0000000000..f037d45eb4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.cpp @@ -0,0 +1,51 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarlockMultipliers.h" +#include "TankWarlockStrategy.h" + +using namespace ai; + +class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericWarlockStrategyActionNodeFactory() + { + creators["summon voidwalker"] = &summon_voidwalker; + creators["summon felguard"] = &summon_felguard; + } +private: + static ActionNode* summon_voidwalker(PlayerbotAI* ai) + { + return new ActionNode ("summon voidwalker", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("drain soul"), NULL), + /*C*/ NULL); + } + static ActionNode* summon_felguard(PlayerbotAI* ai) + { + return new ActionNode ("summon felguard", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("summon voidwalker"), NULL), + /*C*/ NULL); + } +}; + +TankWarlockStrategy::TankWarlockStrategy(PlayerbotAI* ai) : GenericWarlockStrategy(ai) +{ + actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory()); +} + +NextAction** TankWarlockStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("shoot", 10.0f), NULL); +} + +void TankWarlockStrategy::InitTriggers(std::list &triggers) +{ + GenericWarlockStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("summon felguard", 50.0f), NULL))); + +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.h b/src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.h new file mode 100644 index 0000000000..9cdd6e62fe --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/TankWarlockStrategy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "GenericWarlockStrategy.h" + +namespace ai +{ + class TankWarlockStrategy : public GenericWarlockStrategy + { + public: + TankWarlockStrategy(PlayerbotAI* ai); + virtual string getName() { return "tank"; } + + public: + virtual void InitTriggers(std::list &triggers); + virtual NextAction** getDefaultActions(); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockActions.cpp b/src/modules/Bots/playerbot/strategy/warlock/WarlockActions.cpp new file mode 100644 index 0000000000..46e9370bbc --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockActions.cpp @@ -0,0 +1,5 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "WarlockActions.h" + +using namespace ai; diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockActions.h b/src/modules/Bots/playerbot/strategy/warlock/WarlockActions.h new file mode 100644 index 0000000000..253c67c3cf --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockActions.h @@ -0,0 +1,146 @@ +#pragma once + +#include "../actions/GenericActions.h" + +namespace ai +{ + class CastDemonSkinAction : public CastBuffSpellAction { + public: + CastDemonSkinAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demon skin") {} + }; + + class CastDemonArmorAction : public CastBuffSpellAction + { + public: + CastDemonArmorAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demon armor") {} + }; + + BEGIN_RANGED_SPELL_ACTION(CastShadowBoltAction, "shadow bolt") + END_SPELL_ACTION() + + class CastDrainSoulAction : public CastSpellAction + { + public: + CastDrainSoulAction(PlayerbotAI* ai) : CastSpellAction(ai, "drain soul") {} + virtual bool isUseful() + { + return AI_VALUE2(uint8, "item count", "soul shard") < 2; + } + }; + + class CastDrainManaAction : public CastSpellAction + { + public: + CastDrainManaAction(PlayerbotAI* ai) : CastSpellAction(ai, "drain mana") {} + }; + + class CastDrainLifeAction : public CastSpellAction + { + public: + CastDrainLifeAction(PlayerbotAI* ai) : CastSpellAction(ai, "drain life") {} + }; + + class CastCurseOfAgonyAction : public CastDebuffSpellAction + { + public: + CastCurseOfAgonyAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "curse of agony") {} + }; + + class CastCurseOfWeaknessAction : public CastDebuffSpellAction + { + public: + CastCurseOfWeaknessAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "curse of weakness") {} + }; + + class CastCorruptionAction : public CastDebuffSpellAction + { + public: + CastCorruptionAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "corruption") {} + }; + + class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastCorruptionOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "corruption") {} + }; + + + class CastSummonVoidwalkerAction : public CastBuffSpellAction + { + public: + CastSummonVoidwalkerAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "summon voidwalker") {} + }; + + class CastSummonImpAction : public CastBuffSpellAction + { + public: + CastSummonImpAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "summon imp") {} + }; + + class CastCreateHealthstoneAction : public CastBuffSpellAction + { + public: + CastCreateHealthstoneAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "create healthstone") {} + }; + + class CastCreateFirestoneAction : public CastBuffSpellAction + { + public: + CastCreateFirestoneAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "create firestone") {} + }; + + class CastCreateSpellstoneAction : public CastBuffSpellAction + { + public: + CastCreateSpellstoneAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "create spellstone") {} + }; + + class CastBanishAction : public CastBuffSpellAction + { + public: + CastBanishAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "banish on cc") {} + virtual Value* GetTargetValue() { return context->GetValue("cc target", "banish"); } + virtual bool Execute(Event event) { return ai->CastSpell("banish", GetTarget()); } + }; + + class CastRainOfFireAction : public CastSpellAction + { + public: + CastRainOfFireAction(PlayerbotAI* ai) : CastSpellAction(ai, "rain of fire") {} + }; + + class CastImmolateAction : public CastDebuffSpellAction + { + public: + CastImmolateAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "immolate") {} + }; + + class CastConflagrateAction : public CastSpellAction + { + public: + CastConflagrateAction(PlayerbotAI* ai) : CastSpellAction(ai, "conflagrate") {} + }; + + class CastFearAction : public CastDebuffSpellAction + { + public: + CastFearAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "fear") {} + }; + + class CastFearOnCcAction : public CastBuffSpellAction + { + public: + CastFearOnCcAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "fear on cc") {} + virtual Value* GetTargetValue() { return context->GetValue("cc target", "fear"); } + virtual bool Execute(Event event) { return ai->CastSpell("fear", GetTarget()); } + }; + + class CastLifeTapAction: public CastSpellAction + { + public: + CastLifeTapAction(PlayerbotAI* ai) : CastSpellAction(ai, "life tap") {} + virtual string GetTargetName() { return "self target"; } + virtual bool isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig.lowHealth; } + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.cpp new file mode 100644 index 0000000000..c5a63336d8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.cpp @@ -0,0 +1,173 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarlockActions.h" +#include "WarlockAiObjectContext.h" +#include "DpsWarlockStrategy.h" +#include "GenericWarlockNonCombatStrategy.h" +#include "TankWarlockStrategy.h" +#include "../generic/PullStrategy.h" +#include "WarlockTriggers.h" +#include "../NamedObjectContext.h" +#include "../actions/UseItemAction.h" + +using namespace ai; + +namespace ai +{ + namespace warlock + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &warlock::StrategyFactoryInternal::nc; + creators["pull"] = &warlock::StrategyFactoryInternal::pull; + creators["aoe"] = &warlock::StrategyFactoryInternal::aoe; + creators["dps debuff"] = &warlock::StrategyFactoryInternal::dps_debuff; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new GenericWarlockNonCombatStrategy(ai); } + static Strategy* aoe(PlayerbotAI* ai) { return new DpsAoeWarlockStrategy(ai); } + static Strategy* dps_debuff(PlayerbotAI* ai) { return new DpsWarlockDebuffStrategy(ai); } + static Strategy* pull(PlayerbotAI* ai) { return new PullStrategy(ai, "shoot"); } + }; + + class CombatStrategyFactoryInternal : public NamedObjectContext + { + public: + CombatStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["dps"] = &warlock::CombatStrategyFactoryInternal::dps; + creators["tank"] = &warlock::CombatStrategyFactoryInternal::tank; + } + + private: + static Strategy* tank(PlayerbotAI* ai) { return new TankWarlockStrategy(ai); } + static Strategy* dps(PlayerbotAI* ai) { return new DpsWarlockStrategy(ai); } + }; + }; +}; + +namespace ai +{ + namespace warlock + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["shadow trance"] = &TriggerFactoryInternal::shadow_trance; + creators["demon armor"] = &TriggerFactoryInternal::demon_armor; + creators["no healthstone"] = &TriggerFactoryInternal::HasHealthstone; + creators["no firestone"] = &TriggerFactoryInternal::HasFirestone; + creators["no spellstone"] = &TriggerFactoryInternal::HasSpellstone; + creators["corruption"] = &TriggerFactoryInternal::corruption; + creators["corruption on attacker"] = &TriggerFactoryInternal::corruption_on_attacker; + creators["curse of agony"] = &TriggerFactoryInternal::curse_of_agony; + creators["banish"] = &TriggerFactoryInternal::banish; + creators["spellstone"] = &TriggerFactoryInternal::spellstone; + creators["backlash"] = &TriggerFactoryInternal::backlash; + creators["fear"] = &TriggerFactoryInternal::fear; + creators["immolate"] = &TriggerFactoryInternal::immolate; + + + } + + private: + static Trigger* shadow_trance(PlayerbotAI* ai) { return new ShadowTranceTrigger(ai); } + static Trigger* demon_armor(PlayerbotAI* ai) { return new DemonArmorTrigger(ai); } + static Trigger* HasHealthstone(PlayerbotAI* ai) { return new HasHealthstoneTrigger(ai); } + static Trigger* HasFirestone(PlayerbotAI* ai) { return new HasFirestoneTrigger(ai); } + static Trigger* HasSpellstone(PlayerbotAI* ai) { return new HasSpellstoneTrigger(ai); } + static Trigger* corruption(PlayerbotAI* ai) { return new CorruptionTrigger(ai); } + static Trigger* corruption_on_attacker(PlayerbotAI* ai) { return new CorruptionOnAttackerTrigger(ai); } + static Trigger* curse_of_agony(PlayerbotAI* ai) { return new CurseOfAgonyTrigger(ai); } + static Trigger* banish(PlayerbotAI* ai) { return new BanishTrigger(ai); } + static Trigger* spellstone(PlayerbotAI* ai) { return new SpellstoneTrigger(ai); } + static Trigger* backlash(PlayerbotAI* ai) { return new BacklashTrigger(ai); } + static Trigger* fear(PlayerbotAI* ai) { return new FearTrigger(ai); } + static Trigger* immolate(PlayerbotAI* ai) { return new ImmolateTrigger(ai); } + + }; + }; +}; + +namespace ai +{ + namespace warlock + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["summon imp"] = &AiObjectContextInternal::summon_imp; + creators["demon armor"] = &AiObjectContextInternal::demon_armor; + creators["demon skin"] = &AiObjectContextInternal::demon_skin; + creators["create healthstone"] = &AiObjectContextInternal::create_healthstone; + creators["create firestone"] = &AiObjectContextInternal::create_firestone; + creators["create spellstone"] = &AiObjectContextInternal::create_spellstone; + creators["spellstone"] = &AiObjectContextInternal::spellstone; + creators["summon voidwalker"] = &AiObjectContextInternal::summon_voidwalker; + creators["immolate"] = &AiObjectContextInternal::immolate; + creators["corruption"] = &AiObjectContextInternal::corruption; + creators["corruption on attacker"] = &AiObjectContextInternal::corruption_on_attacker; + creators["curse of agony"] = &AiObjectContextInternal::curse_of_agony; + creators["shadow bolt"] = &AiObjectContextInternal::shadow_bolt; + creators["drain soul"] = &AiObjectContextInternal::drain_soul; + creators["drain mana"] = &AiObjectContextInternal::drain_mana; + creators["drain life"] = &AiObjectContextInternal::drain_life; + creators["banish"] = &AiObjectContextInternal::banish; + creators["rain of fire"] = &AiObjectContextInternal::rain_of_fire; + creators["life tap"] = &AiObjectContextInternal::life_tap; + creators["fear"] = &AiObjectContextInternal::fear; + creators["fear on cc"] = &AiObjectContextInternal::fear_on_cc; + creators["conflagrate"] = &AiObjectContextInternal::conflagrate; + } + + private: + static Action* conflagrate(PlayerbotAI* ai) { return new CastConflagrateAction(ai); } + static Action* fear_on_cc(PlayerbotAI* ai) { return new CastFearOnCcAction(ai); } + static Action* fear(PlayerbotAI* ai) { return new CastFearAction(ai); } + static Action* immolate(PlayerbotAI* ai) { return new CastImmolateAction(ai); } + static Action* summon_imp(PlayerbotAI* ai) { return new CastSummonImpAction(ai); } + static Action* demon_armor(PlayerbotAI* ai) { return new CastDemonArmorAction(ai); } + static Action* demon_skin(PlayerbotAI* ai) { return new CastDemonSkinAction(ai); } + static Action* create_healthstone(PlayerbotAI* ai) { return new CastCreateHealthstoneAction(ai); } + static Action* create_firestone(PlayerbotAI* ai) { return new CastCreateFirestoneAction(ai); } + static Action* create_spellstone(PlayerbotAI* ai) { return new CastCreateSpellstoneAction(ai); } + static Action* spellstone(PlayerbotAI* ai) { return new UseSpellItemAction(ai, "spellstone", true); } + static Action* summon_voidwalker(PlayerbotAI* ai) { return new CastSummonVoidwalkerAction(ai); } + static Action* corruption(PlayerbotAI* ai) { return new CastCorruptionAction(ai); } + static Action* corruption_on_attacker(PlayerbotAI* ai) { return new CastCorruptionOnAttackerAction(ai); } + static Action* curse_of_agony(PlayerbotAI* ai) { return new CastCurseOfAgonyAction(ai); } + static Action* shadow_bolt(PlayerbotAI* ai) { return new CastShadowBoltAction(ai); } + static Action* drain_soul(PlayerbotAI* ai) { return new CastDrainSoulAction(ai); } + static Action* drain_mana(PlayerbotAI* ai) { return new CastDrainManaAction(ai); } + static Action* drain_life(PlayerbotAI* ai) { return new CastDrainLifeAction(ai); } + static Action* banish(PlayerbotAI* ai) { return new CastBanishAction(ai); } + static Action* rain_of_fire(PlayerbotAI* ai) { return new CastRainOfFireAction(ai); } + static Action* life_tap(PlayerbotAI* ai) { return new CastLifeTapAction(ai); } + + }; + }; +}; + + + +WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::warlock::StrategyFactoryInternal()); + strategyContexts.Add(new ai::warlock::CombatStrategyFactoryInternal()); + actionContexts.Add(new ai::warlock::AiObjectContextInternal()); + triggerContexts.Add(new ai::warlock::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.h b/src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.h new file mode 100644 index 0000000000..0d3fa27f36 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class WarlockAiObjectContext : public AiObjectContext + { + public: + WarlockAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.cpp b/src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.cpp new file mode 100644 index 0000000000..d4894976d8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "WarlockMultipliers.h" +//#include "WarlockActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.h b/src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.cpp b/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.cpp new file mode 100644 index 0000000000..65fbabac60 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.cpp @@ -0,0 +1,19 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarlockTriggers.h" +#include "WarlockActions.h" + +using namespace ai; + +bool DemonArmorTrigger::IsActive() +{ + Unit* target = GetTarget(); + return !ai->HasAura("demon skin", target) && + !ai->HasAura("demon armor", target) && + !ai->HasAura("fel armor", target); +} + +bool SpellstoneTrigger::IsActive() +{ + return BuffTrigger::IsActive() && AI_VALUE2(uint8, "item count", getName()) > 0; +} diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h b/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h new file mode 100644 index 0000000000..227c39889c --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h @@ -0,0 +1,81 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + class DemonArmorTrigger : public BuffTrigger + { + public: + DemonArmorTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "demon armor") {} + virtual bool IsActive(); + }; + + class SpellstoneTrigger : public BuffTrigger + { + public: + SpellstoneTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "spellstone") {} + virtual bool IsActive(); + }; + + DEBUFF_TRIGGER(CurseOfAgonyTrigger, "curse of agony", "curse of agony"); + DEBUFF_TRIGGER(CorruptionTrigger, "corruption", "corruption"); + + class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + CorruptionOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "corruption") {} + }; + + DEBUFF_TRIGGER(ImmolateTrigger, "immolate", "immolate"); + + class ShadowTranceTrigger : public HasAuraTrigger + { + public: + ShadowTranceTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "shadow trance") {} + }; + + class BacklashTrigger : public HasAuraTrigger + { + public: + BacklashTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "backlash") {} + }; + + class BanishTrigger : public HasCcTargetTrigger + { + public: + BanishTrigger(PlayerbotAI* ai) : HasCcTargetTrigger(ai, "banish") {} + }; + + class WarlockConjuredItemTrigger : public ItemCountTrigger + { + public: + WarlockConjuredItemTrigger(PlayerbotAI* ai, string item) : ItemCountTrigger(ai, item, 1) {} + + virtual bool IsActive() { return ItemCountTrigger::IsActive() && AI_VALUE2(uint8, "item count", "soul shard") > 0; } + }; + + class HasSpellstoneTrigger : public WarlockConjuredItemTrigger + { + public: + HasSpellstoneTrigger(PlayerbotAI* ai) : WarlockConjuredItemTrigger(ai, "spellstone") {} + }; + + class HasFirestoneTrigger : public WarlockConjuredItemTrigger + { + public: + HasFirestoneTrigger(PlayerbotAI* ai) : WarlockConjuredItemTrigger(ai, "firestone") {} + }; + + class HasHealthstoneTrigger : public WarlockConjuredItemTrigger + { + public: + HasHealthstoneTrigger(PlayerbotAI* ai) : WarlockConjuredItemTrigger(ai, "healthstone") {} + }; + + class FearTrigger : public HasCcTargetTrigger + { + public: + FearTrigger(PlayerbotAI* ai) : HasCcTargetTrigger(ai, "fear") {} + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.cpp b/src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.cpp new file mode 100644 index 0000000000..25e4539011 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.cpp @@ -0,0 +1,130 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarriorMultipliers.h" +#include "DpsWarriorStrategy.h" + +using namespace ai; + +class DpsWarriorStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + DpsWarriorStrategyActionNodeFactory() + { + creators["overpower"] = &overpower; + creators["melee"] = &melee; + creators["charge"] = &charge; + creators["bloodthirst"] = &bloodthirst; + creators["rend"] = &rend; + creators["mocking blow"] = &mocking_blow; + creators["death wish"] = &death_wish; + creators["execute"] = &execute; + } +private: + static ActionNode* overpower(PlayerbotAI* ai) + { + return new ActionNode ("overpower", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* melee(PlayerbotAI* ai) + { + return new ActionNode ("melee", + /*P*/ NextAction::array(0, new NextAction("charge"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* charge(PlayerbotAI* ai) + { + return new ActionNode ("charge", + /*P*/ NextAction::array(0, new NextAction("battle stance"), NULL), + /*A*/ NextAction::array(0, new NextAction("reach melee"), NULL), + /*C*/ NULL); + } + static ActionNode* bloodthirst(PlayerbotAI* ai) + { + return new ActionNode ("bloodthirst", + /*P*/ NextAction::array(0, new NextAction("battle stance"), NULL), + /*A*/ NextAction::array(0, new NextAction("heroic strike"), NULL), + /*C*/ NULL); + } + static ActionNode* rend(PlayerbotAI* ai) + { + return new ActionNode ("rend", + /*P*/ NextAction::array(0, new NextAction("battle stance"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* mocking_blow(PlayerbotAI* ai) + { + return new ActionNode ("mocking blow", + /*P*/ NextAction::array(0, new NextAction("battle stance"), NULL), + /*A*/ NextAction::array(0, NULL), + /*C*/ NULL); + } + static ActionNode* death_wish(PlayerbotAI* ai) + { + return new ActionNode ("death wish", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("berserker rage"), NULL), + /*C*/ NULL); + } + static ActionNode* execute(PlayerbotAI* ai) + { + return new ActionNode ("execute", + /*P*/ NextAction::array(0, new NextAction("battle stance"), NULL), + /*A*/ NextAction::array(0, new NextAction("heroic strike"), NULL), + /*C*/ NULL); + } +}; + +DpsWarriorStrategy::DpsWarriorStrategy(PlayerbotAI* ai) : GenericWarriorStrategy(ai) +{ + actionNodeFactories.Add(new DpsWarriorStrategyActionNodeFactory()); +} + +NextAction** DpsWarriorStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("bloodthirst", ACTION_NORMAL + 1), NULL); +} + +void DpsWarriorStrategy::InitTriggers(std::list &triggers) +{ + GenericWarriorStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("charge", ACTION_NORMAL + 9), NULL))); + + triggers.push_back(new TriggerNode( + "target critical health", + NextAction::array(0, new NextAction("execute", ACTION_HIGH + 4), NULL))); + + triggers.push_back(new TriggerNode( + "hamstring", + NextAction::array(0, new NextAction("hamstring", ACTION_INTERRUPT), NULL))); + + triggers.push_back(new TriggerNode( + "victory rush", + NextAction::array(0, new NextAction("victory rush", ACTION_HIGH + 3), NULL))); + + triggers.push_back(new TriggerNode( + "death wish", + NextAction::array(0, new NextAction("death wish", ACTION_HIGH + 2), NULL))); +} + + +void DpsWarrirorAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "rend on attacker", + NextAction::array(0, new NextAction("rend on attacker", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 2), new NextAction("demoralizing shout", ACTION_HIGH + 2), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("cleave", ACTION_HIGH + 3), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.h b/src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.h new file mode 100644 index 0000000000..3ef29c3354 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/DpsWarriorStrategy.h @@ -0,0 +1,28 @@ +#pragma once + +#include "GenericWarriorStrategy.h" + +namespace ai +{ + class DpsWarriorStrategy : public GenericWarriorStrategy + { + public: + DpsWarriorStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "dps"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } + }; + + class DpsWarrirorAoeStrategy : public CombatStrategy + { + public: + DpsWarrirorAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "aoe"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.cpp new file mode 100644 index 0000000000..7ac6cb79a8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.cpp @@ -0,0 +1,7 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarriorMultipliers.h" +#include "GenericWarriorNonCombatStrategy.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.h new file mode 100644 index 0000000000..1041a2eeb2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorNonCombatStrategy.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericWarriorNonCombatStrategy : public NonCombatStrategy + { + public: + GenericWarriorNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {} + virtual string getName() { return "nc"; } + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.cpp b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.cpp new file mode 100644 index 0000000000..c8898ec784 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.cpp @@ -0,0 +1,73 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "GenericWarriorStrategy.h" +#include "WarriorAiObjectContext.h" + +using namespace ai; + +class GenericWarriorStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericWarriorStrategyActionNodeFactory() + { + creators["hamstring"] = &hamstring; + creators["heroic strike"] = &heroic_strike; + creators["battle shout"] = &battle_shout; + } +private: + static ActionNode* hamstring(PlayerbotAI* ai) + { + return new ActionNode ("hamstring", + /*P*/ NextAction::array(0, new NextAction("battle stance"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* heroic_strike(PlayerbotAI* ai) + { + return new ActionNode ("heroic strike", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* battle_shout(PlayerbotAI* ai) + { + return new ActionNode ("battle shout", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } +}; + +GenericWarriorStrategy::GenericWarriorStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericWarriorStrategyActionNodeFactory()); +} + +void GenericWarriorStrategy::InitTriggers(std::list &triggers) +{ + MeleeCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "battle shout", + NextAction::array(0, new NextAction("battle shout", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "rend", + NextAction::array(0, new NextAction("rend", ACTION_NORMAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "bloodrage", + NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "shield bash", + NextAction::array(0, new NextAction("shield bash", ACTION_INTERRUPT + 4), NULL))); + + triggers.push_back(new TriggerNode( + "shield bash on enemy healer", + NextAction::array(0, new NextAction("shield bash on enemy healer", ACTION_INTERRUPT + 3), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.h b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.h new file mode 100644 index 0000000000..0ef2dcf8f5 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/GenericWarriorStrategy.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/MeleeCombatStrategy.h" + +namespace ai +{ + class AiObjectContext; + + class GenericWarriorStrategy : public MeleeCombatStrategy + { + public: + GenericWarriorStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "warrior"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.cpp b/src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.cpp new file mode 100644 index 0000000000..ba6159986f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.cpp @@ -0,0 +1,126 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarriorMultipliers.h" +#include "TankWarriorStrategy.h" + +using namespace ai; + +class TankWarriorStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + TankWarriorStrategyActionNodeFactory() + { + creators["melee"] = &melee; + creators["shield wall"] = &shield_wall; + creators["rend"] = &rend; + creators["revenge"] = &revenge; + creators["devastate"] = &devastate; + creators["shockwave"] = &shockwave; + creators["taunt"] = &taunt; + } +private: + static ActionNode* melee(PlayerbotAI* ai) + { + return new ActionNode ("melee", + /*P*/ NextAction::array(0, new NextAction("defensive stance"), new NextAction("reach melee"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* shield_wall(PlayerbotAI* ai) + { + return new ActionNode ("shield wall", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("shield block"), NULL), + /*C*/ NULL); + } + static ActionNode* rend(PlayerbotAI* ai) + { + return new ActionNode ("rend", + /*P*/ NextAction::array(0, new NextAction("defensive stance"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* revenge(PlayerbotAI* ai) + { + return new ActionNode ("revenge", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* devastate(PlayerbotAI* ai) + { + return new ActionNode ("devastate", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("sunder armor"), NULL), + /*C*/ NULL); + } + static ActionNode* shockwave(PlayerbotAI* ai) + { + return new ActionNode ("shockwave", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("cleave"), NULL), + /*C*/ NULL); + } + static ActionNode* taunt(PlayerbotAI* ai) + { + return new ActionNode ("taunt", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("mocking blow"), NULL), + /*C*/ NULL); + } +}; + +TankWarriorStrategy::TankWarriorStrategy(PlayerbotAI* ai) : GenericWarriorStrategy(ai) +{ + actionNodeFactories.Add(new TankWarriorStrategyActionNodeFactory()); +} + +NextAction** TankWarriorStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("devastate", ACTION_NORMAL + 1), new NextAction("revenge", ACTION_NORMAL + 1), NULL); +} + +void TankWarriorStrategy::InitTriggers(std::list &triggers) +{ + GenericWarriorStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "medium rage available", + NextAction::array(0, new NextAction("shield slam", ACTION_NORMAL + 2), new NextAction("heroic strike", ACTION_NORMAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "disarm", + NextAction::array(0, new NextAction("disarm", ACTION_NORMAL), NULL))); + + triggers.push_back(new TriggerNode( + "lose aggro", + NextAction::array(0, new NextAction("taunt", ACTION_HIGH + 9), NULL))); + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("shield wall", ACTION_MEDIUM_HEAL), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("last stand", ACTION_EMERGENCY + 3), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("shockwave", ACTION_HIGH + 2), NULL))); + + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 2), new NextAction("demoralizing shout", ACTION_HIGH + 2), new NextAction("cleave", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, new NextAction("challenging shout", ACTION_HIGH + 3), NULL))); + + triggers.push_back(new TriggerNode( + "concussion blow", + NextAction::array(0, new NextAction("concussion blow", ACTION_INTERRUPT), NULL))); + + triggers.push_back(new TriggerNode( + "sword and board", + NextAction::array(0, new NextAction("shield slam", ACTION_HIGH + 3), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.h b/src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.h new file mode 100644 index 0000000000..0f989460a8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/TankWarriorStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "GenericWarriorStrategy.h" + +namespace ai +{ + class TankWarriorStrategy : public GenericWarriorStrategy + { + public: + TankWarriorStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "tank"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_TANK | STRATEGY_TYPE_MELEE; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.cpp b/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.cpp new file mode 100644 index 0000000000..4dd0e1d430 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.cpp @@ -0,0 +1,30 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarriorActions.h" + +using namespace ai; + +NextAction** CastRendAction::getPrerequisites() +{ + return NextAction::merge( NextAction::array(0, new NextAction("reach melee"), NULL), CastDebuffSpellAction::getPrerequisites()); +} + +NextAction** CastRendOnAttackerAction::getPrerequisites() +{ + return NextAction::merge( NextAction::array(0, new NextAction("reach melee"), NULL), CastDebuffSpellOnAttackerAction::getPrerequisites()); +} + +NextAction** CastDisarmAction::getPrerequisites() +{ + return NextAction::merge( NextAction::array(0, new NextAction("reach melee"), new NextAction("defensive stance"), NULL), CastDebuffSpellAction::getPrerequisites()); +} + +NextAction** CastSunderArmorAction::getPrerequisites() +{ + return NextAction::merge( NextAction::array(0, new NextAction("reach melee"), NULL), CastDebuffSpellAction::getPrerequisites()); +} + +NextAction** CastRevengeAction::getPrerequisites() +{ + return NextAction::merge( NextAction::array(0, new NextAction("defensive stance"), NULL), CastMeleeSpellAction::getPrerequisites()); +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h b/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h new file mode 100644 index 0000000000..9cc7d342a3 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h @@ -0,0 +1,195 @@ +#pragma once +#include "../actions/GenericActions.h" + +namespace ai +{ + // battle + class CastBattleMeleeSpellAction : public CastMeleeSpellAction { + public: + CastBattleMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge( NextAction::array(0, new NextAction("battle stance"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + + // defensive + class CastDefensiveMeleeSpellAction : public CastMeleeSpellAction { + public: + CastDefensiveMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge( NextAction::array(0, new NextAction("defensive stance"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + + // all + class CastHeroicStrikeAction : public CastMeleeSpellAction { + public: + CastHeroicStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "heroic strike") {} + }; + + // all + class CastCleaveAction : public CastMeleeSpellAction { + public: + CastCleaveAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "cleave") {} + }; + + // battle, berserker + class CastMockingBlowAction : public CastMeleeSpellAction { + public: + CastMockingBlowAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "mocking blow") {} + }; + + class CastBloodthirstAction : public CastMeleeSpellAction { + public: + CastBloodthirstAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "bloodthirst") {} + }; + + // battle, berserker + class CastExecuteAction : public CastMeleeSpellAction { + public: + CastExecuteAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "execute") {} + }; + + // battle + class CastOverpowerAction : public CastBattleMeleeSpellAction { + public: + CastOverpowerAction(PlayerbotAI* ai) : CastBattleMeleeSpellAction(ai, "overpower") {} + }; + + // battle, berserker + class CastHamstringAction : public CastMeleeSpellAction { + public: + CastHamstringAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "hamstring") {} + }; + + // defensive + class CastTauntAction : public CastSpellAction { + public: + CastTauntAction(PlayerbotAI* ai) : CastSpellAction(ai, "taunt") {} + virtual NextAction** getPrerequisites() { + return NextAction::merge( NextAction::array(0, new NextAction("defensive stance"), NULL), CastSpellAction::getPrerequisites()); + } + }; + + // defensive + class CastShieldBlockAction : public CastBuffSpellAction { + public: + CastShieldBlockAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shield block") {} + virtual NextAction** getPrerequisites() { + return NextAction::merge( NextAction::array(0, new NextAction("defensive stance"), NULL), CastSpellAction::getPrerequisites()); + } + }; + + // defensive + class CastShieldWallAction : public CastDefensiveMeleeSpellAction { + public: + CastShieldWallAction(PlayerbotAI* ai) : CastDefensiveMeleeSpellAction(ai, "shield wall") {} + }; + + class CastBloodrageAction : public CastBuffSpellAction { + public: + CastBloodrageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "bloodrage") {} + }; + + // all + class CastSlamAction : public CastMeleeSpellAction { + public: + CastSlamAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "slam") {} + }; + + // all + class CastShieldSlamAction : public CastMeleeSpellAction { + public: + CastShieldSlamAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "shield slam") {} + }; + + // after dodge + BEGIN_MELEE_SPELL_ACTION(CastRevengeAction, "revenge") + virtual NextAction** getPrerequisites(); + END_SPELL_ACTION() + + + //debuffs + BEGIN_DEBUFF_ACTION(CastRendAction, "rend") + virtual NextAction** getPrerequisites(); + END_SPELL_ACTION() + + class CastRendOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastRendOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "rend") {} + virtual NextAction** getPrerequisites(); + }; + + BEGIN_DEBUFF_ACTION(CastDisarmAction, "disarm") + virtual NextAction** getPrerequisites(); + END_SPELL_ACTION() + + BEGIN_DEBUFF_ACTION(CastSunderArmorAction, "sunder armor") // 5 times + virtual NextAction** getPrerequisites(); + END_SPELL_ACTION() + + class CastDemoralizingShoutAction : public CastDebuffSpellAction { + public: + CastDemoralizingShoutAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "demoralizing shout") {} + }; + + BEGIN_MELEE_SPELL_ACTION(CastChallengingShoutAction, "challenging shout") + END_SPELL_ACTION() + + // stuns + BEGIN_MELEE_SPELL_ACTION(CastShieldBashAction, "shield bash") + END_SPELL_ACTION() + + BEGIN_MELEE_SPELL_ACTION(CastIntimidatingShoutAction, "intimidating shout") + END_SPELL_ACTION() + + BEGIN_MELEE_SPELL_ACTION(CastThunderClapAction, "thunder clap") + END_SPELL_ACTION() + + // buffs + class CastBattleShoutAction : public CastBuffSpellAction { + public: + CastBattleShoutAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "battle shout") {} + }; + + class CastDefensiveStanceAction : public CastBuffSpellAction { + public: + CastDefensiveStanceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "defensive stance") {} + }; + + class CastBattleStanceAction : public CastBuffSpellAction { + public: + CastBattleStanceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "battle stance") {} + }; + + BEGIN_RANGED_SPELL_ACTION(CastChargeAction, "charge") + END_SPELL_ACTION() + + class CastDeathWishAction : public CastBuffSpellAction { + public: + CastDeathWishAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "death wish") {} + }; + + class CastBerserkerRageAction : public CastBuffSpellAction { + public: + CastBerserkerRageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "berserker rage") {} + }; + + class CastLastStandAction : public CastBuffSpellAction { + public: + CastLastStandAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "last stand") {} + }; + + // defensive + class CastConcussionBlowAction : public CastDefensiveMeleeSpellAction { + public: + CastConcussionBlowAction(PlayerbotAI* ai) : CastDefensiveMeleeSpellAction(ai, "concussion blow") {} + }; + + class CastShieldBashOnEnemyHealerAction : public CastSpellOnEnemyHealerAction + { + public: + CastShieldBashOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "shield bash") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.cpp new file mode 100644 index 0000000000..0cd612c1f0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.cpp @@ -0,0 +1,186 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "WarriorActions.h" +#include "WarriorAiObjectContext.h" +#include "GenericWarriorNonCombatStrategy.h" +#include "TankWarriorStrategy.h" +#include "DpsWarriorStrategy.h" +#include "../generic/PullStrategy.h" +#include "WarriorTriggers.h" +#include "../NamedObjectContext.h" + +using namespace ai; + + +namespace ai +{ + namespace warrior + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &warrior::StrategyFactoryInternal::nc; + creators["pull"] = &warrior::StrategyFactoryInternal::pull; + creators["aoe"] = &warrior::StrategyFactoryInternal::aoe; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new GenericWarriorNonCombatStrategy(ai); } + static Strategy* aoe(PlayerbotAI* ai) { return new DpsWarrirorAoeStrategy(ai); } + static Strategy* pull(PlayerbotAI* ai) { return new PullStrategy(ai, "shoot"); } + }; + + class CombatStrategyFactoryInternal : public NamedObjectContext + { + public: + CombatStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["tank"] = &warrior::CombatStrategyFactoryInternal::tank; + creators["dps"] = &warrior::CombatStrategyFactoryInternal::dps; + } + + private: + static Strategy* tank(PlayerbotAI* ai) { return new TankWarriorStrategy(ai); } + static Strategy* dps(PlayerbotAI* ai) { return new DpsWarriorStrategy(ai); } + }; + }; +}; + +namespace ai +{ + namespace warrior + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["hamstring"] = &TriggerFactoryInternal::hamstring; + creators["victory rush"] = &TriggerFactoryInternal::victory_rush; + creators["death wish"] = &TriggerFactoryInternal::death_wish; + creators["battle shout"] = &TriggerFactoryInternal::battle_shout; + creators["rend"] = &TriggerFactoryInternal::rend; + creators["rend on attacker"] = &TriggerFactoryInternal::rend_on_attacker; + creators["bloodrage"] = &TriggerFactoryInternal::bloodrage; + creators["shield bash"] = &TriggerFactoryInternal::shield_bash; + creators["disarm"] = &TriggerFactoryInternal::disarm; + creators["concussion blow"] = &TriggerFactoryInternal::concussion_blow; + creators["sword and board"] = &TriggerFactoryInternal::SwordAndBoard; + creators["shield bash on enemy healer"] = &TriggerFactoryInternal::shield_bash_on_enemy_healer; + + } + + private: + static Trigger* hamstring(PlayerbotAI* ai) { return new HamstringTrigger(ai); } + static Trigger* victory_rush(PlayerbotAI* ai) { return new VictoryRushTrigger(ai); } + static Trigger* death_wish(PlayerbotAI* ai) { return new DeathWishTrigger(ai); } + static Trigger* battle_shout(PlayerbotAI* ai) { return new BattleShoutTrigger(ai); } + static Trigger* rend(PlayerbotAI* ai) { return new RendDebuffTrigger(ai); } + static Trigger* rend_on_attacker(PlayerbotAI* ai) { return new RendDebuffOnAttackerTrigger(ai); } + static Trigger* bloodrage(PlayerbotAI* ai) { return new BloodrageDebuffTrigger(ai); } + static Trigger* shield_bash(PlayerbotAI* ai) { return new ShieldBashInterruptSpellTrigger(ai); } + static Trigger* disarm(PlayerbotAI* ai) { return new DisarmDebuffTrigger(ai); } + static Trigger* concussion_blow(PlayerbotAI* ai) { return new ConcussionBlowTrigger(ai); } + static Trigger* SwordAndBoard(PlayerbotAI* ai) { return new SwordAndBoardTrigger(ai); } + static Trigger* shield_bash_on_enemy_healer(PlayerbotAI* ai) { return new ShieldBashInterruptEnemyHealerSpellTrigger(ai); } + }; + }; +}; + + +namespace ai +{ + namespace warrior + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + creators["overpower"] = &AiObjectContextInternal::overpower; + creators["charge"] = &AiObjectContextInternal::charge; + creators["bloodthirst"] = &AiObjectContextInternal::bloodthirst; + creators["rend"] = &AiObjectContextInternal::rend; + creators["rend on attacker"] = &AiObjectContextInternal::rend_on_attacker; + creators["mocking blow"] = &AiObjectContextInternal::mocking_blow; + creators["death wish"] = &AiObjectContextInternal::death_wish; + creators["berserker rage"] = &AiObjectContextInternal::berserker_rage; + creators["execute"] = &AiObjectContextInternal::execute; + creators["defensive stance"] = &AiObjectContextInternal::defensive_stance; + creators["hamstring"] = &AiObjectContextInternal::hamstring; + creators["shield bash"] = &AiObjectContextInternal::shield_bash; + creators["shield block"] = &AiObjectContextInternal::shield_block; + creators["bloodrage"] = &AiObjectContextInternal::bloodrage; + creators["battle stance"] = &AiObjectContextInternal::battle_stance; + creators["heroic strike"] = &AiObjectContextInternal::heroic_strike; + creators["intimidating shout"] = &AiObjectContextInternal::intimidating_shout; + creators["demoralizing shout"] = &AiObjectContextInternal::demoralizing_shout; + creators["challenging shout"] = &AiObjectContextInternal::challenging_shout; + creators["shield wall"] = &AiObjectContextInternal::shield_wall; + creators["battle shout"] = &AiObjectContextInternal::battle_shout; + creators["thunder clap"] = &AiObjectContextInternal::thunder_clap; + creators["taunt"] = &AiObjectContextInternal::taunt; + creators["revenge"] = &AiObjectContextInternal::revenge; + creators["slam"] = &AiObjectContextInternal::slam; + creators["shield slam"] = &AiObjectContextInternal::shield_slam; + creators["disarm"] = &AiObjectContextInternal::disarm; + creators["sunder armor"] = &AiObjectContextInternal::sunder_armor; + creators["last stand"] = &AiObjectContextInternal::last_stand; + creators["cleave"] = &AiObjectContextInternal::cleave; + creators["concussion blow"] = &AiObjectContextInternal::concussion_blow; + creators["shield bash on enemy healer"] = &AiObjectContextInternal::shield_bash_on_enemy_healer; + } + + private: + static Action* last_stand(PlayerbotAI* ai) { return new CastLastStandAction(ai); } + static Action* cleave(PlayerbotAI* ai) { return new CastCleaveAction(ai); } + static Action* concussion_blow(PlayerbotAI* ai) { return new CastConcussionBlowAction(ai); } + static Action* taunt(PlayerbotAI* ai) { return new CastTauntAction(ai); } + static Action* revenge(PlayerbotAI* ai) { return new CastRevengeAction(ai); } + static Action* slam(PlayerbotAI* ai) { return new CastSlamAction(ai); } + static Action* shield_slam(PlayerbotAI* ai) { return new CastShieldSlamAction(ai); } + static Action* disarm(PlayerbotAI* ai) { return new CastDisarmAction(ai); } + static Action* sunder_armor(PlayerbotAI* ai) { return new CastSunderArmorAction(ai); } + static Action* overpower(PlayerbotAI* ai) { return new CastOverpowerAction(ai); } + static Action* charge(PlayerbotAI* ai) { return new CastChargeAction(ai); } + static Action* bloodthirst(PlayerbotAI* ai) { return new CastBloodthirstAction(ai); } + static Action* rend(PlayerbotAI* ai) { return new CastRendAction(ai); } + static Action* rend_on_attacker(PlayerbotAI* ai) { return new CastRendOnAttackerAction(ai); } + static Action* mocking_blow(PlayerbotAI* ai) { return new CastMockingBlowAction(ai); } + static Action* death_wish(PlayerbotAI* ai) { return new CastDeathWishAction(ai); } + static Action* berserker_rage(PlayerbotAI* ai) { return new CastBerserkerRageAction(ai); } + static Action* execute(PlayerbotAI* ai) { return new CastExecuteAction(ai); } + static Action* defensive_stance(PlayerbotAI* ai) { return new CastDefensiveStanceAction(ai); } + static Action* hamstring(PlayerbotAI* ai) { return new CastHamstringAction(ai); } + static Action* shield_bash(PlayerbotAI* ai) { return new CastShieldBashAction(ai); } + static Action* shield_block(PlayerbotAI* ai) { return new CastShieldBlockAction(ai); } + static Action* bloodrage(PlayerbotAI* ai) { return new CastBloodrageAction(ai); } + static Action* battle_stance(PlayerbotAI* ai) { return new CastBattleStanceAction(ai); } + static Action* heroic_strike(PlayerbotAI* ai) { return new CastHeroicStrikeAction(ai); } + static Action* intimidating_shout(PlayerbotAI* ai) { return new CastIntimidatingShoutAction(ai); } + static Action* demoralizing_shout(PlayerbotAI* ai) { return new CastDemoralizingShoutAction(ai); } + static Action* challenging_shout(PlayerbotAI* ai) { return new CastChallengingShoutAction(ai); } + static Action* shield_wall(PlayerbotAI* ai) { return new CastShieldWallAction(ai); } + static Action* battle_shout(PlayerbotAI* ai) { return new CastBattleShoutAction(ai); } + static Action* thunder_clap(PlayerbotAI* ai) { return new CastThunderClapAction(ai); } + static Action* shield_bash_on_enemy_healer(PlayerbotAI* ai) { return new CastShieldBashOnEnemyHealerAction(ai); } + + }; + }; +}; + +WarriorAiObjectContext::WarriorAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::warrior::StrategyFactoryInternal()); + strategyContexts.Add(new ai::warrior::CombatStrategyFactoryInternal()); + actionContexts.Add(new ai::warrior::AiObjectContextInternal()); + triggerContexts.Add(new ai::warrior::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.h b/src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.h new file mode 100644 index 0000000000..bc1b5d49a2 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class WarriorAiObjectContext : public AiObjectContext + { + public: + WarriorAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.cpp b/src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.cpp new file mode 100644 index 0000000000..7f521513b4 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "WarriorMultipliers.h" +//#include "WarriorActions.h" + +using namespace ai; \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.h b/src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.h new file mode 100644 index 0000000000..a244824476 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.cpp b/src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.cpp new file mode 100644 index 0000000000..cd6b206fa6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.cpp @@ -0,0 +1,7 @@ +#include "botpch.h" +//#include "../../playerbot.h" +//#include "WarriorTriggers.h" +//#include "WarriorActions.h" + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.h b/src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.h new file mode 100644 index 0000000000..1396bd627e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorTriggers.h @@ -0,0 +1,78 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + BUFF_TRIGGER(BattleShoutTrigger, "battle shout", "battle shout") + + DEBUFF_TRIGGER(RendDebuffTrigger, "rend", "rend") + DEBUFF_TRIGGER(DisarmDebuffTrigger, "disarm", "disarm") + DEBUFF_TRIGGER(SunderArmorDebuffTrigger, "sunder armor", "sunder armor") + + class RendDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + RendDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "rend") {} + }; + + class RevengeAvailableTrigger : public SpellCanBeCastTrigger + { + public: + RevengeAvailableTrigger(PlayerbotAI* ai) : SpellCanBeCastTrigger(ai, "revenge") {} + }; + + class BloodrageDebuffTrigger : public DebuffTrigger + { + public: + BloodrageDebuffTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "bloodrage") {} + virtual bool IsActive() + { + return DebuffTrigger::IsActive() && + AI_VALUE2(uint8, "health", "self target") >= 75 && + AI_VALUE2(uint8, "rage", "self target") < 20; + } + }; + + class ShieldBashInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + ShieldBashInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "shield bash") {} + }; + + class VictoryRushTrigger : public HasAuraTrigger + { + public: + VictoryRushTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "victory rush") {} + }; + + class SwordAndBoardTrigger : public HasAuraTrigger + { + public: + SwordAndBoardTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "sword and board") {} + }; + + class ConcussionBlowTrigger : public SnareTargetTrigger + { + public: + ConcussionBlowTrigger(PlayerbotAI* ai) : SnareTargetTrigger(ai, "concussion blow") {} + }; + + class HamstringTrigger : public SnareTargetTrigger + { + public: + HamstringTrigger(PlayerbotAI* ai) : SnareTargetTrigger(ai, "hamstring") {} + }; + + class DeathWishTrigger : public BoostTrigger + { + public: + DeathWishTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "death wish") {} + }; + + class ShieldBashInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger + { + public: + ShieldBashInterruptEnemyHealerSpellTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "shield bash") {} + }; + +} From 2ba85b1ce0f7d3ba03caaa3bf92d65f2986f7d30 Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Wed, 23 Mar 2022 09:38:55 -0400 Subject: [PATCH 2/9] Adjust BuyAction for MangosTwo Whitespace and buffer overflow fix (PR checks) --- src/game/Object/Player.h | 2 +- src/modules/Bots/playerbot/strategy/Engine.cpp | 5 ++++- src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/game/Object/Player.h b/src/game/Object/Player.h index de4e6ef6ff..cdacd4315b 100644 --- a/src/game/Object/Player.h +++ b/src/game/Object/Player.h @@ -2575,7 +2575,7 @@ class Player : public Unit MapReference& GetMapRef() { return m_mapRef; } bool isAllowedToLoot(Creature* creature); - + #ifdef ENABLE_PLAYERBOTS //EquipmentSets& GetEquipmentSets() { return m_EquipmentSets; } void SetPlayerbotAI(PlayerbotAI* ai) { assert(!m_playerbotAI && !m_playerbotMgr); m_playerbotAI = ai; } diff --git a/src/modules/Bots/playerbot/strategy/Engine.cpp b/src/modules/Bots/playerbot/strategy/Engine.cpp index 5cc25d633f..cd68defe43 100644 --- a/src/modules/Bots/playerbot/strategy/Engine.cpp +++ b/src/modules/Bots/playerbot/strategy/Engine.cpp @@ -513,7 +513,10 @@ void Engine::LogAction(const char* format, ...) va_list ap; va_start(ap, format); - vsprintf(buf, format, ap); + if (sizeof(buf) <= 1024) + { + vsprintf(buf, format, ap); + } va_end(ap); lastAction = buf; diff --git a/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp b/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp index f2977a9927..214dcddb74 100644 --- a/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp @@ -49,12 +49,12 @@ bool BuyAction::Execute(Event event) { if (tItems->GetItem(slot)->item == *i) { - bot->BuyItemFromVendor(vendorguid, *i, 1, NULL_BAG, NULL_SLOT); + // bot->BuyItemFromVendor(vendorguid, *i, 1, NULL_BAG, NULL_SLOT); + bot->BuyItemFromVendorSlot(vendorguid, slot, *i, 1, NULL_BAG, NULL_SLOT); ai->TellMaster("Bought item"); } } } -BuyAction.cpp:(.text+0x247): undefined reference to `Player::BuyItemFromVendor(ObjectGuid, unsigned int, unsigned char, unsigned char, unsigned char)' return true; } From c7d8052f1cf363c3c242e14e7f030938a6159537 Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Thu, 24 Mar 2022 14:26:55 -0400 Subject: [PATCH 3/9] Update playerbot from https://github.com/celguar/mangosbot-bots Pull in some of the updates from Celguar's playerbot repo. --- src/game/WorldHandlers/CharacterHandler.cpp | 2 +- src/modules/Bots/CMakeLists.txt | 18 ++ src/modules/Bots/ahbot/AhBotConfig.cpp | 8 +- src/modules/Bots/playerbot/AiFactory.cpp | 20 ++ src/modules/Bots/playerbot/ChatFilter.cpp | 2 +- src/modules/Bots/playerbot/ChatHelper.cpp | 7 + src/modules/Bots/playerbot/PlayerbotAI.cpp | 7 +- .../Bots/playerbot/PlayerbotAIConfig.cpp | 144 ++++----- .../Bots/playerbot/PlayerbotFactory.cpp | 18 +- src/modules/Bots/playerbot/PlayerbotMgr.cpp | 12 +- .../Bots/playerbot/RandomPlayerbotFactory.cpp | 23 ++ .../Bots/playerbot/RandomPlayerbotMgr.cpp | 10 + .../strategy/deathknight/BloodDKStrategy.cpp | 100 ++++++ .../strategy/deathknight/BloodDKStrategy.h | 20 ++ .../strategy/deathknight/DKActions.cpp | 7 + .../strategy/deathknight/DKActions.h | 301 ++++++++++++++++++ .../deathknight/DKAiObjectContext.cpp | 266 ++++++++++++++++ .../strategy/deathknight/DKAiObjectContext.h | 12 + .../strategy/deathknight/DKMultipliers.cpp | 6 + .../strategy/deathknight/DKMultipliers.h | 6 + .../strategy/deathknight/DKTriggers.cpp | 14 + .../strategy/deathknight/DKTriggers.h | 102 ++++++ .../strategy/deathknight/FrostDKStrategy.cpp | 91 ++++++ .../strategy/deathknight/FrostDKStrategy.h | 29 ++ .../GenericDKNonCombatStrategy.cpp | 62 ++++ .../deathknight/GenericDKNonCombatStrategy.h | 27 ++ .../deathknight/GenericDKStrategy.cpp | 239 ++++++++++++++ .../strategy/deathknight/GenericDKStrategy.h | 18 ++ .../strategy/deathknight/UnholyDKStrategy.cpp | 88 +++++ .../strategy/deathknight/UnholyDKStrategy.h | 29 ++ 30 files changed, 1607 insertions(+), 81 deletions(-) create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKActions.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.h create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp create mode 100644 src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h diff --git a/src/game/WorldHandlers/CharacterHandler.cpp b/src/game/WorldHandlers/CharacterHandler.cpp index e999aa4a4f..ec1c658cce 100644 --- a/src/game/WorldHandlers/CharacterHandler.cpp +++ b/src/game/WorldHandlers/CharacterHandler.cpp @@ -207,7 +207,7 @@ class CharacterHandler // The bot's WorldSession is owned by the bot's Player object // The bot's WorldSession is deleted by PlayerbotMgr::LogoutPlayerBot uint32 botAccountId = lqh->GetAccountId(); - WorldSession *botSession = new WorldSession(botAccountId, NULL, SEC_PLAYER, masterSession->Expansion(), 0, LOCALE_enUS); + WorldSession *botSession = new WorldSession(botAccountId, NULL, SEC_PLAYER, 2, 0, LOCALE_enUS); botSession->m_Address = "bot"; botSession->HandlePlayerLogin(lqh); // will delete lqh Player* bot = botSession->GetPlayer(); diff --git a/src/modules/Bots/CMakeLists.txt b/src/modules/Bots/CMakeLists.txt index cf9330ab0c..80c28b1dc8 100644 --- a/src/modules/Bots/CMakeLists.txt +++ b/src/modules/Bots/CMakeLists.txt @@ -581,6 +581,24 @@ set(BOT_SRCS playerbot/strategy/warrior/WarriorMultipliers.h playerbot/strategy/warrior/WarriorTriggers.cpp playerbot/strategy/warrior/WarriorTriggers.h + playerbot/strategy/deathknight/BloodDKStrategy.cpp + playerbot/strategy/deathknight/BloodDKStrategy.h + playerbot/strategy/deathknight/DKActions.cpp + playerbot/strategy/deathknight/DKActions.h + playerbot/strategy/deathknight/DKAiObjectContext.cpp + playerbot/strategy/deathknight/DKAiObjectContext.h + playerbot/strategy/deathknight/DKMultipliers.cpp + playerbot/strategy/deathknight/DKMultipliers.h + playerbot/strategy/deathknight/DKTriggers.cpp + playerbot/strategy/deathknight/DKTriggers.h + playerbot/strategy/deathknight/FrostDKStrategy.cpp + playerbot/strategy/deathknight/FrostDKStrategy.h + playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp + playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h + playerbot/strategy/deathknight/GenericDKStrategy.cpp + playerbot/strategy/deathknight/GenericDKStrategy.h + playerbot/strategy/deathknight/UnholyDKStrategy.cpp + playerbot/strategy/deathknight/UnholyDKStrategy.h ) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/playerbot FILES ${BOT_SRCS}) diff --git a/src/modules/Bots/ahbot/AhBotConfig.cpp b/src/modules/Bots/ahbot/AhBotConfig.cpp index 5ad07a36b4..44046169d9 100644 --- a/src/modules/Bots/ahbot/AhBotConfig.cpp +++ b/src/modules/Bots/ahbot/AhBotConfig.cpp @@ -29,9 +29,13 @@ void LoadSet(string value, T &res) bool AhBotConfig::Initialize() { - if (!config.SetSource(AUCTIONHOUSEBOT_CONFIG_NAME)) + sLog.outString("Initializing AhBot by ike3, based on the original Playerbot by blueboy"); + + const char* cfg_file = SYSCONFDIR"ahbot.conf"; + + if (!config.SetSource(cfg_file)) { - sLog.outString("AhBot is Disabled. Unable to open configuration file ahbot.conf"); + sLog.outString("AhBot is Disabled in %s", cfg_file); return false; } diff --git a/src/modules/Bots/playerbot/AiFactory.cpp b/src/modules/Bots/playerbot/AiFactory.cpp index 8c36faa14b..bebe984eab 100644 --- a/src/modules/Bots/playerbot/AiFactory.cpp +++ b/src/modules/Bots/playerbot/AiFactory.cpp @@ -12,6 +12,7 @@ #include "strategy/druid/DruidAiObjectContext.h" #include "strategy/hunter/HunterAiObjectContext.h" #include "strategy/rogue/RogueAiObjectContext.h" +#include "strategy/deathknight/DKAiObjectContext.h" #include "Player.h" #include "PlayerbotAIConfig.h" #include "RandomPlayerbotMgr.h" @@ -48,6 +49,10 @@ AiObjectContext* AiFactory::createAiObjectContext(Player* player, PlayerbotAI* a case CLASS_ROGUE: return new RogueAiObjectContext(ai); break; + /* TODO: Implement DK AI */ + // case CLASS_DEATH_KNIGHT: + // return new DKAiObjectContext(ai); + // break; } return new AiObjectContext(ai); } @@ -235,6 +240,21 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategy("flee"); break; + case CLASS_DEATH_KNIGHT: + if (tab == 0) + { + engine->addStrategies("blood", NULL); + } + else if (tab == 1) + { + engine->addStrategies("frost", "frost aoe", "dps assist", "threat", NULL); + } + else + { + engine->addStrategies("frost", "frost aoe", "dps assist", "threat", NULL); + } + engine->addStrategies("dps assist", "flee", "close", "cc", NULL); + break; } if (sRandomPlayerbotMgr.IsRandomBot(player) && !player->GetGroup()) diff --git a/src/modules/Bots/playerbot/ChatFilter.cpp b/src/modules/Bots/playerbot/ChatFilter.cpp index 24547890e9..0a2d7cb6b6 100644 --- a/src/modules/Bots/playerbot/ChatFilter.cpp +++ b/src/modules/Bots/playerbot/ChatFilter.cpp @@ -230,7 +230,7 @@ class ClassChatFilter : public ChatFilter public: ClassChatFilter(PlayerbotAI* ai) : ChatFilter(ai) { - //classNames["@death_knight"] = CLASS_DEATH_KNIGHT; + classNames["@death_knight"] = CLASS_DEATH_KNIGHT; classNames["@druid"] = CLASS_DRUID; classNames["@hunter"] = CLASS_HUNTER; classNames["@mage"] = CLASS_MAGE; diff --git a/src/modules/Bots/playerbot/ChatHelper.cpp b/src/modules/Bots/playerbot/ChatHelper.cpp index 37da50c6aa..f724155abf 100644 --- a/src/modules/Bots/playerbot/ChatHelper.cpp +++ b/src/modules/Bots/playerbot/ChatHelper.cpp @@ -139,6 +139,11 @@ ChatHelper::ChatHelper(PlayerbotAI* ai) : PlayerbotAIAware(ai) specs[CLASS_WARRIOR][1] = "fury"; specs[CLASS_WARRIOR][2] = "protection"; + classes[CLASS_DEATH_KNIGHT] = "dk"; + specs[CLASS_DEATH_KNIGHT][0] = "blood"; + specs[CLASS_DEATH_KNIGHT][1] = "frost"; + specs[CLASS_DEATH_KNIGHT][2] = "unholy"; + races[RACE_DWARF] = "Dwarf"; races[RACE_GNOME] = "Gnome"; races[RACE_HUMAN] = "Human"; @@ -147,6 +152,8 @@ ChatHelper::ChatHelper(PlayerbotAI* ai) : PlayerbotAIAware(ai) races[RACE_TAUREN] = "Tauren"; races[RACE_TROLL] = "Troll"; races[RACE_UNDEAD] = "Undead"; + races[RACE_BLOODELF] = "Blood Elf"; + races[RACE_DRAENEI] = "Draenei"; } string ChatHelper::formatMoney(uint32 copper) diff --git a/src/modules/Bots/playerbot/PlayerbotAI.cpp b/src/modules/Bots/playerbot/PlayerbotAI.cpp index 47e23f2399..5a705f4b91 100644 --- a/src/modules/Bots/playerbot/PlayerbotAI.cpp +++ b/src/modules/Bots/playerbot/PlayerbotAI.cpp @@ -189,7 +189,7 @@ void PlayerbotAI::HandleTeleportAck() if (bot->IsBeingTeleportedNear()) { WorldPacket p = WorldPacket(MSG_MOVE_TELEPORT_ACK, 8 + 4 + 4); - p << bot->GetObjectGuid(); + p << bot->GetObjectGuid().WriteAsPacked(); p << (uint32)0; // supposed to be flags? not used currently p << (uint32)time(0); // time - not currently used bot->GetSession()->HandleMoveTeleportAckOpcode(p); @@ -583,7 +583,7 @@ bool PlayerbotAI::IsRanged(Player* player) switch (player->getClass()) { - //case CLASS_DEATH_KNIGHT: + case CLASS_DEATH_KNIGHT: case CLASS_PALADIN: case CLASS_WARRIOR: case CLASS_ROGUE: @@ -604,7 +604,7 @@ bool PlayerbotAI::IsTank(Player* player) switch (player->getClass()) { - //case CLASS_DEATH_KNIGHT: + case CLASS_DEATH_KNIGHT: case CLASS_PALADIN: case CLASS_WARRIOR: return true; @@ -1166,7 +1166,6 @@ void PlayerbotAI::InterruptSpell() SpellInterrupted(lastSpell.id); } - void PlayerbotAI::RemoveAura(string name) { uint32 spellid = aiObjectContext->GetValue("spell id", name)->Get(); diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp index a7744047a4..7a44be874e 100644 --- a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp @@ -33,95 +33,97 @@ bool PlayerbotAIConfig::Initialize() { sLog.outString("Initializing AI Playerbot by ike3, based on the original Playerbot by blueboy"); - if (!config.SetSource(SYSCONFDIR"aiplayerbot.conf")) + const char* cfg_file = SYSCONFDIR"aiplayerbot.conf"; + if (!sConfig.SetSource(cfg_file)) { - sLog.outString("AI Playerbot is Disabled. Unable to open configuration file aiplayerbot.conf"); + sLog.outError("AI Playerbot is Disabled. Could not find configuration file %s.", cfg_file); + Log::WaitBeforeContinueIfNeed(); return false; } - enabled = config.GetBoolDefault("AiPlayerbot.Enabled", true); + enabled = sConfig.GetBoolDefault("AiPlayerbot.Enabled", true); if (!enabled) { - sLog.outString("AI Playerbot is Disabled in aiplayerbot.conf"); + sLog.outString("AI Playerbot is Disabled in %s", cfg_file); return false; } - globalCoolDown = (uint32) config.GetIntDefault("AiPlayerbot.GlobalCooldown", 500); - maxWaitForMove = config.GetIntDefault("AiPlayerbot.MaxWaitForMove", 3000); - reactDelay = (uint32) config.GetIntDefault("AiPlayerbot.ReactDelay", 100); + globalCoolDown = (uint32) sConfig.GetIntDefault("AiPlayerbot.GlobalCooldown", 500); + maxWaitForMove = sConfig.GetIntDefault("AiPlayerbot.MaxWaitForMove", 3000); + reactDelay = (uint32) sConfig.GetIntDefault("AiPlayerbot.ReactDelay", 100); - sightDistance = config.GetFloatDefault("AiPlayerbot.SightDistance", 50.0f); - spellDistance = config.GetFloatDefault("AiPlayerbot.SpellDistance", 30.0f); - reactDistance = config.GetFloatDefault("AiPlayerbot.ReactDistance", 150.0f); - grindDistance = config.GetFloatDefault("AiPlayerbot.GrindDistance", 100.0f); - lootDistance = config.GetFloatDefault("AiPlayerbot.LootDistance", 20.0f); - fleeDistance = config.GetFloatDefault("AiPlayerbot.FleeDistance", 20.0f); - tooCloseDistance = config.GetFloatDefault("AiPlayerbot.TooCloseDistance", 7.0f); - meleeDistance = config.GetFloatDefault("AiPlayerbot.MeleeDistance", 1.5f); - followDistance = config.GetFloatDefault("AiPlayerbot.FollowDistance", 1.5f); - whisperDistance = config.GetFloatDefault("AiPlayerbot.WhisperDistance", 6000.0f); - contactDistance = config.GetFloatDefault("AiPlayerbot.ContactDistance", 0.5f); + sightDistance = sConfig.GetFloatDefault("AiPlayerbot.SightDistance", 50.0f); + spellDistance = sConfig.GetFloatDefault("AiPlayerbot.SpellDistance", 30.0f); + reactDistance = sConfig.GetFloatDefault("AiPlayerbot.ReactDistance", 150.0f); + grindDistance = sConfig.GetFloatDefault("AiPlayerbot.GrindDistance", 100.0f); + lootDistance = sConfig.GetFloatDefault("AiPlayerbot.LootDistance", 20.0f); + fleeDistance = sConfig.GetFloatDefault("AiPlayerbot.FleeDistance", 20.0f); + tooCloseDistance = sConfig.GetFloatDefault("AiPlayerbot.TooCloseDistance", 7.0f); + meleeDistance = sConfig.GetFloatDefault("AiPlayerbot.MeleeDistance", 1.5f); + followDistance = sConfig.GetFloatDefault("AiPlayerbot.FollowDistance", 1.5f); + whisperDistance = sConfig.GetFloatDefault("AiPlayerbot.WhisperDistance", 6000.0f); + contactDistance = sConfig.GetFloatDefault("AiPlayerbot.ContactDistance", 0.5f); - criticalHealth = config.GetIntDefault("AiPlayerbot.CriticalHealth", 20); - lowHealth = config.GetIntDefault("AiPlayerbot.LowHealth", 50); - mediumHealth = config.GetIntDefault("AiPlayerbot.MediumHealth", 70); - almostFullHealth = config.GetIntDefault("AiPlayerbot.AlmostFullHealth", 85); - lowMana = config.GetIntDefault("AiPlayerbot.LowMana", 15); - mediumMana = config.GetIntDefault("AiPlayerbot.MediumMana", 40); + criticalHealth = sConfig.GetIntDefault("AiPlayerbot.CriticalHealth", 20); + lowHealth = sConfig.GetIntDefault("AiPlayerbot.LowHealth", 50); + mediumHealth = sConfig.GetIntDefault("AiPlayerbot.MediumHealth", 70); + almostFullHealth = sConfig.GetIntDefault("AiPlayerbot.AlmostFullHealth", 85); + lowMana = sConfig.GetIntDefault("AiPlayerbot.LowMana", 15); + mediumMana = sConfig.GetIntDefault("AiPlayerbot.MediumMana", 40); - randomGearLoweringChance = config.GetFloatDefault("AiPlayerbot.RandomGearLoweringChance", 0.15f); - randomBotMaxLevelChance = config.GetFloatDefault("AiPlayerbot.RandomBotMaxLevelChance", 0.4f); + randomGearLoweringChance = sConfig.GetFloatDefault("AiPlayerbot.RandomGearLoweringChance", 0.15f); + randomBotMaxLevelChance = sConfig.GetFloatDefault("AiPlayerbot.RandomBotMaxLevelChance", 0.4f); - iterationsPerTick = config.GetIntDefault("AiPlayerbot.IterationsPerTick", 4); + iterationsPerTick = sConfig.GetIntDefault("AiPlayerbot.IterationsPerTick", 4); - allowGuildBots = config.GetBoolDefault("AiPlayerbot.AllowGuildBots", true); + allowGuildBots = sConfig.GetBoolDefault("AiPlayerbot.AllowGuildBots", true); - randomBotMapsAsString = config.GetStringDefault("AiPlayerbot.RandomBotMaps", "0,1,530,571"); + randomBotMapsAsString = sConfig.GetStringDefault("AiPlayerbot.RandomBotMaps", "0,1,530,571"); LoadList >(randomBotMapsAsString, randomBotMaps); - LoadList >(config.GetStringDefault("AiPlayerbot.RandomBotQuestItems", "6948,5175,5176,5177,5178"), randomBotQuestItems); - LoadList >(config.GetStringDefault("AiPlayerbot.RandomBotSpellIds", "54197"), randomBotSpellIds); - - randomBotAutologin = config.GetBoolDefault("AiPlayerbot.RandomBotAutologin", true); - minRandomBots = config.GetIntDefault("AiPlayerbot.MinRandomBots", 50); - maxRandomBots = config.GetIntDefault("AiPlayerbot.MaxRandomBots", 200); - randomBotUpdateInterval = config.GetIntDefault("AiPlayerbot.RandomBotUpdateInterval", 60); - randomBotCountChangeMinInterval = config.GetIntDefault("AiPlayerbot.RandomBotCountChangeMinInterval", 24 * 3600); - randomBotCountChangeMaxInterval = config.GetIntDefault("AiPlayerbot.RandomBotCountChangeMaxInterval", 3 * 24 * 3600); - minRandomBotInWorldTime = config.GetIntDefault("AiPlayerbot.MinRandomBotInWorldTime", 2 * 3600); - maxRandomBotInWorldTime = config.GetIntDefault("AiPlayerbot.MaxRandomBotInWorldTime", 14 * 24 * 3600); - minRandomBotRandomizeTime = config.GetIntDefault("AiPlayerbot.MinRandomBotRandomizeTime", 2 * 3600); - maxRandomBotRandomizeTime = config.GetIntDefault("AiPlayerbot.MaxRandomRandomizeTime", 14 * 24 * 3600); - minRandomBotReviveTime = config.GetIntDefault("AiPlayerbot.MinRandomBotReviveTime", 60); - maxRandomBotReviveTime = config.GetIntDefault("AiPlayerbot.MaxRandomReviveTime", 300); - randomBotTeleportDistance = config.GetIntDefault("AiPlayerbot.RandomBotTeleportDistance", 1000); - minRandomBotsPerInterval = config.GetIntDefault("AiPlayerbot.MinRandomBotsPerInterval", 50); - maxRandomBotsPerInterval = config.GetIntDefault("AiPlayerbot.MaxRandomBotsPerInterval", 100); - minRandomBotsPriceChangeInterval = config.GetIntDefault("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * 3600); - maxRandomBotsPriceChangeInterval = config.GetIntDefault("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * 3600); - randomBotJoinLfg = config.GetBoolDefault("AiPlayerbot.RandomBotJoinLfg", true); - logInGroupOnly = config.GetBoolDefault("AiPlayerbot.LogInGroupOnly", true); - logValuesPerTick = config.GetBoolDefault("AiPlayerbot.LogValuesPerTick", false); - fleeingEnabled = config.GetBoolDefault("AiPlayerbot.FleeingEnabled", true); - randomBotMinLevel = config.GetIntDefault("AiPlayerbot.RandomBotMinLevel", 1); - randomBotMaxLevel = config.GetIntDefault("AiPlayerbot.RandomBotMaxLevel", 255); - randomBotLoginAtStartup = config.GetBoolDefault("AiPlayerbot.RandomBotLoginAtStartup", true); - randomBotTeleLevel = config.GetIntDefault("AiPlayerbot.RandomBotTeleLevel", 3); - - randomChangeMultiplier = config.GetFloatDefault("AiPlayerbot.RandomChangeMultiplier", 1.0); - - randomBotCombatStrategies = config.GetStringDefault("AiPlayerbot.RandomBotCombatStrategies", "+dps,+attack weak"); - randomBotNonCombatStrategies = config.GetStringDefault("AiPlayerbot.RandomBotNonCombatStrategies", "+grind,+move random,+loot"); - - commandPrefix = config.GetStringDefault("AiPlayerbot.CommandPrefix", ""); - - commandServerPort = config.GetIntDefault("AiPlayerbot.CommandServerPort", 0); + LoadList >(sConfig.GetStringDefault("AiPlayerbot.RandomBotQuestItems", "6948,5175,5176,5177,5178"), randomBotQuestItems); + LoadList >(sConfig.GetStringDefault("AiPlayerbot.RandomBotSpellIds", "54197"), randomBotSpellIds); + + randomBotAutologin = sConfig.GetBoolDefault("AiPlayerbot.RandomBotAutologin", true); + minRandomBots = sConfig.GetIntDefault("AiPlayerbot.MinRandomBots", 50); + maxRandomBots = sConfig.GetIntDefault("AiPlayerbot.MaxRandomBots", 200); + randomBotUpdateInterval = sConfig.GetIntDefault("AiPlayerbot.RandomBotUpdateInterval", 60); + randomBotCountChangeMinInterval = sConfig.GetIntDefault("AiPlayerbot.RandomBotCountChangeMinInterval", 24 * 3600); + randomBotCountChangeMaxInterval = sConfig.GetIntDefault("AiPlayerbot.RandomBotCountChangeMaxInterval", 3 * 24 * 3600); + minRandomBotInWorldTime = sConfig.GetIntDefault("AiPlayerbot.MinRandomBotInWorldTime", 2 * 3600); + maxRandomBotInWorldTime = sConfig.GetIntDefault("AiPlayerbot.MaxRandomBotInWorldTime", 14 * 24 * 3600); + minRandomBotRandomizeTime = sConfig.GetIntDefault("AiPlayerbot.MinRandomBotRandomizeTime", 2 * 3600); + maxRandomBotRandomizeTime = sConfig.GetIntDefault("AiPlayerbot.MaxRandomRandomizeTime", 14 * 24 * 3600); + minRandomBotReviveTime = sConfig.GetIntDefault("AiPlayerbot.MinRandomBotReviveTime", 60); + maxRandomBotReviveTime = sConfig.GetIntDefault("AiPlayerbot.MaxRandomReviveTime", 300); + randomBotTeleportDistance = sConfig.GetIntDefault("AiPlayerbot.RandomBotTeleportDistance", 1000); + minRandomBotsPerInterval = sConfig.GetIntDefault("AiPlayerbot.MinRandomBotsPerInterval", 50); + maxRandomBotsPerInterval = sConfig.GetIntDefault("AiPlayerbot.MaxRandomBotsPerInterval", 100); + minRandomBotsPriceChangeInterval = sConfig.GetIntDefault("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * 3600); + maxRandomBotsPriceChangeInterval = sConfig.GetIntDefault("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * 3600); + randomBotJoinLfg = sConfig.GetBoolDefault("AiPlayerbot.RandomBotJoinLfg", true); + logInGroupOnly = sConfig.GetBoolDefault("AiPlayerbot.LogInGroupOnly", true); + logValuesPerTick = sConfig.GetBoolDefault("AiPlayerbot.LogValuesPerTick", false); + fleeingEnabled = sConfig.GetBoolDefault("AiPlayerbot.FleeingEnabled", true); + randomBotMinLevel = sConfig.GetIntDefault("AiPlayerbot.RandomBotMinLevel", 1); + randomBotMaxLevel = sConfig.GetIntDefault("AiPlayerbot.RandomBotMaxLevel", 255); + randomBotLoginAtStartup = sConfig.GetBoolDefault("AiPlayerbot.RandomBotLoginAtStartup", true); + randomBotTeleLevel = sConfig.GetIntDefault("AiPlayerbot.RandomBotTeleLevel", 3); + + randomChangeMultiplier = sConfig.GetFloatDefault("AiPlayerbot.RandomChangeMultiplier", 1.0); + + randomBotCombatStrategies = sConfig.GetStringDefault("AiPlayerbot.RandomBotCombatStrategies", "+dps,+attack weak"); + randomBotNonCombatStrategies = sConfig.GetStringDefault("AiPlayerbot.RandomBotNonCombatStrategies", "+grind,+move random,+loot"); + + commandPrefix = sConfig.GetStringDefault("AiPlayerbot.CommandPrefix", ""); + + commandServerPort = sConfig.GetIntDefault("AiPlayerbot.CommandServerPort", 0); for (uint32 cls = 0; cls < MAX_CLASSES; ++cls) { for (uint32 spec = 0; spec < 3; ++spec) { ostringstream os; os << "AiPlayerbot.RandomClassSpecProbability." << cls << "." << spec; - specProbability[cls][spec] = config.GetIntDefault(os.str().c_str(), 33); + specProbability[cls][spec] = sConfig.GetIntDefault(os.str().c_str(), 33); } } @@ -277,10 +279,10 @@ void PlayerbotAIConfig::SetValue(string name, string value) void PlayerbotAIConfig::CreateRandomBots() { - string randomBotAccountPrefix = config.GetStringDefault("AiPlayerbot.RandomBotAccountPrefix", "rndbot"); - int32 randomBotAccountCount = config.GetIntDefault("AiPlayerbot.RandomBotAccountCount", 50); + string randomBotAccountPrefix = sConfig.GetStringDefault("AiPlayerbot.RandomBotAccountPrefix", "rndbot"); + int32 randomBotAccountCount = sConfig.GetIntDefault("AiPlayerbot.RandomBotAccountCount", 50); - if (config.GetBoolDefault("AiPlayerbot.DeleteRandomBotAccounts", false)) + if (sConfig.GetBoolDefault("AiPlayerbot.DeleteRandomBotAccounts", false)) { sLog.outBasic("Deleting random bot accounts..."); QueryResult *results = LoginDatabase.PQuery("SELECT `id` FROM `account` WHERE `username` LIKE '%s%%'", randomBotAccountPrefix.c_str()); @@ -320,7 +322,7 @@ void PlayerbotAIConfig::CreateRandomBots() sLog.outDetail("Account %s created for random bots", accountName.c_str()); } - LoginDatabase.PExecute("UPDATE `account` SET `expansion` = '%u', `playerbot` = %u WHERE `username` LIKE '%s%%'", 0,true, randomBotAccountPrefix.c_str()); + LoginDatabase.PExecute("UPDATE `account` SET `expansion` = '%u', `playerbot` = %u WHERE `username` LIKE '%s%%'", 2,true, randomBotAccountPrefix.c_str()); int totalRandomBotChars = 0; for (int accountNumber = 0; accountNumber < randomBotAccountCount; ++accountNumber) diff --git a/src/modules/Bots/playerbot/PlayerbotFactory.cpp b/src/modules/Bots/playerbot/PlayerbotFactory.cpp index 646483ad94..a8d4811bd0 100644 --- a/src/modules/Bots/playerbot/PlayerbotFactory.cpp +++ b/src/modules/Bots/playerbot/PlayerbotFactory.cpp @@ -400,6 +400,12 @@ bool PlayerbotFactory::CheckItemStats(uint8 sp, uint8 ap, uint8 tank) return false; } break; + case CLASS_DEATH_KNIGHT: + if((!ap && !tank) || sp > ap || sp > tank) + { + return false; + } + break; } return sp || ap || tank; @@ -548,6 +554,15 @@ bool PlayerbotFactory::CanEquipWeapon(ItemPrototype const* proto) proto->SubClass != ITEM_SUBCLASS_WEAPON_THROWN) return false; break; + case CLASS_DEATH_KNIGHT: + if (proto->SubClass != ITEM_SUBCLASS_WEAPON_MACE2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_POLEARM && + proto->SubClass != ITEM_SUBCLASS_WEAPON_SWORD2 && + proto->SubClass != ITEM_SUBCLASS_WEAPON_AXE2) + { + return false; + } + break; } return true; @@ -1052,6 +1067,7 @@ void PlayerbotFactory::InitTradeSkills() { case CLASS_WARRIOR: case CLASS_PALADIN: + case CLASS_DEATH_KNIGHT: firstSkills.push_back(SKILL_MINING); secondSkills.push_back(SKILL_BLACKSMITHING); secondSkills.push_back(SKILL_ENGINEERING); @@ -1148,7 +1164,7 @@ void PlayerbotFactory::InitSkills() uint32 skillLevel = bot->getLevel() < 40 ? 0 : 1; switch (bot->getClass()) { - //case CLASS_DEATH_KNIGHT: + case CLASS_DEATH_KNIGHT: case CLASS_WARRIOR: case CLASS_PALADIN: bot->SetSkill(SKILL_PLATE_MAIL, skillLevel, skillLevel); diff --git a/src/modules/Bots/playerbot/PlayerbotMgr.cpp b/src/modules/Bots/playerbot/PlayerbotMgr.cpp index 25c03dad31..bbf94c61c0 100644 --- a/src/modules/Bots/playerbot/PlayerbotMgr.cpp +++ b/src/modules/Bots/playerbot/PlayerbotMgr.cpp @@ -127,8 +127,18 @@ void PlayerbotHolder::OnBotLogin(Player * const bot) bool PlayerbotHolder::ProcessBotCommand(string cmd, ObjectGuid guid, bool admin, uint32 masterAccountId) { - if (!sPlayerbotAIConfig.enabled || guid.IsEmpty()) + // if (!sPlayerbotAIConfig.enabled || guid.IsEmpty()) + // { + // return false; + // } + if (!sPlayerbotAIConfig.enabled) + { + sLog.outError("AI Config is not enabled."); + return false; + } + if (guid.IsEmpty()) { + sLog.outError("gUID is empty."); return false; } diff --git a/src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp b/src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp index 724cdbf590..32a8385b4e 100644 --- a/src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp +++ b/src/modules/Bots/playerbot/RandomPlayerbotFactory.cpp @@ -23,9 +23,12 @@ RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(acc availableRaces[CLASS_WARRIOR].push_back(RACE_UNDEAD); availableRaces[CLASS_WARRIOR].push_back(RACE_TAUREN); availableRaces[CLASS_WARRIOR].push_back(RACE_TROLL); + availableRaces[CLASS_WARRIOR].push_back(RACE_DRAENEI); availableRaces[CLASS_PALADIN].push_back(RACE_HUMAN); availableRaces[CLASS_PALADIN].push_back(RACE_DWARF); + availableRaces[CLASS_PALADIN].push_back(RACE_DRAENEI); + availableRaces[CLASS_PALADIN].push_back(RACE_BLOODELF); availableRaces[CLASS_ROGUE].push_back(RACE_HUMAN); availableRaces[CLASS_ROGUE].push_back(RACE_DWARF); @@ -33,35 +36,55 @@ RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(acc availableRaces[CLASS_ROGUE].push_back(RACE_GNOME); availableRaces[CLASS_ROGUE].push_back(RACE_ORC); availableRaces[CLASS_ROGUE].push_back(RACE_TROLL); + availableRaces[CLASS_ROGUE].push_back(RACE_BLOODELF); availableRaces[CLASS_PRIEST].push_back(RACE_HUMAN); availableRaces[CLASS_PRIEST].push_back(RACE_DWARF); availableRaces[CLASS_PRIEST].push_back(RACE_NIGHTELF); availableRaces[CLASS_PRIEST].push_back(RACE_TROLL); availableRaces[CLASS_PRIEST].push_back(RACE_UNDEAD); + availableRaces[CLASS_PRIEST].push_back(RACE_DRAENEI); + availableRaces[CLASS_PRIEST].push_back(RACE_BLOODELF); availableRaces[CLASS_MAGE].push_back(RACE_HUMAN); availableRaces[CLASS_MAGE].push_back(RACE_GNOME); availableRaces[CLASS_MAGE].push_back(RACE_UNDEAD); availableRaces[CLASS_MAGE].push_back(RACE_TROLL); + availableRaces[CLASS_MAGE].push_back(RACE_DRAENEI); + availableRaces[CLASS_MAGE].push_back(RACE_BLOODELF); availableRaces[CLASS_WARLOCK].push_back(RACE_HUMAN); availableRaces[CLASS_WARLOCK].push_back(RACE_GNOME); availableRaces[CLASS_WARLOCK].push_back(RACE_UNDEAD); availableRaces[CLASS_WARLOCK].push_back(RACE_ORC); + availableRaces[CLASS_WARLOCK].push_back(RACE_BLOODELF); availableRaces[CLASS_SHAMAN].push_back(RACE_ORC); availableRaces[CLASS_SHAMAN].push_back(RACE_TAUREN); availableRaces[CLASS_SHAMAN].push_back(RACE_TROLL); + availableRaces[CLASS_SHAMAN].push_back(RACE_DRAENEI); availableRaces[CLASS_HUNTER].push_back(RACE_DWARF); availableRaces[CLASS_HUNTER].push_back(RACE_NIGHTELF); availableRaces[CLASS_HUNTER].push_back(RACE_ORC); availableRaces[CLASS_HUNTER].push_back(RACE_TAUREN); availableRaces[CLASS_HUNTER].push_back(RACE_TROLL); + availableRaces[CLASS_HUNTER].push_back(RACE_DRAENEI); + availableRaces[CLASS_HUNTER].push_back(RACE_BLOODELF); availableRaces[CLASS_DRUID].push_back(RACE_NIGHTELF); availableRaces[CLASS_DRUID].push_back(RACE_TAUREN); + + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_NIGHTELF); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_TAUREN); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_HUMAN); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_ORC); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_UNDEAD); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_TROLL); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_GNOME); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_DWARF); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_BLOODELF); + availableRaces[CLASS_DEATH_KNIGHT].push_back(RACE_DRAENEI); } bool RandomPlayerbotFactory::CreateRandomBot(uint8 cls) diff --git a/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp index 82984536d8..071bb925dc 100644 --- a/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp +++ b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp @@ -875,6 +875,16 @@ void RandomPlayerbotMgr::PrintStats() dps++; } break; + case CLASS_DEATH_KNIGHT: + if (spec == 0) + { + tank++; + } + else + { + dps++; + } + break; default: dps++; break; diff --git a/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp new file mode 100644 index 0000000000..540f404f67 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp @@ -0,0 +1,100 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKMultipliers.h" +#include "BloodDKStrategy.h" + +using namespace ai; + +class BloodDKStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + BloodDKStrategyActionNodeFactory() + { + //creators["melee"] = &melee; + //creators["blood strike"] = &blood_strike; + creators["rune strike"] = &rune_strike; + creators["heart strike"] = &heart_strike; + creators["death strike"] = &death_strike; + //creators["death grip"] = &death_grip; + //creators["plague strike"] = &plague_strike; + //creators["pestilence"] = &pestilence; + //creators["icy touch"] = &icy_touch; + //creators["obliterate"] = &obliterate; + //creators["blood boil"] = &blood_boil; + //creators["mark of_blood"] = &mark_of_blood; + //creators["blood presence"] = &blood_presence; + //creators["rune tap"] = &rune_tap; + //creators["vampiric blood"] = &vampiric_blood; + //creators["death pact"] = &death_pact; + //creators["death rune_mastery"] = &death_rune_mastery; + //creators["hysteria"] = &hysteria; + //creators["dancing weapon"] = &dancing_weapon; + //creators["dark command"] = &dark_command; + } +private: + static ActionNode* rune_strike(PlayerbotAI* ai) + { + return new ActionNode("rune strike", + /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("death coil"), NULL), + /*C*/ NULL); + } + static ActionNode* heart_strike(PlayerbotAI* ai) + { + return new ActionNode ("heart strike", + /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), + /*C*/ NULL); + } + static ActionNode* death_strike(PlayerbotAI* ai) + { + return new ActionNode("death strike", + /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + +}; + +BloodDKStrategy::BloodDKStrategy(PlayerbotAI* ai) : GenericDKStrategy(ai) +{ + actionNodeFactories.Add(new BloodDKStrategyActionNodeFactory()); +} + +NextAction** BloodDKStrategy::getDefaultActions() +{ + return NextAction::array(0, + new NextAction("melee", ACTION_NORMAL + 2), + new NextAction("heart strike", ACTION_NORMAL + 5), + new NextAction("death strike", ACTION_NORMAL + 4), + new NextAction("rune strike", ACTION_NORMAL + 3), NULL); +} + +void BloodDKStrategy::InitTriggers(std::list &triggers) +{ + GenericDKStrategy::InitTriggers(triggers); + +triggers.push_back(new TriggerNode( + "rune strike", + NextAction::array(0, new NextAction("rune strike", ACTION_NORMAL + 3), NULL))); + +triggers.push_back(new TriggerNode( + "blood tap", + NextAction::array(0, new NextAction("blood tap", ACTION_HIGH + 5), NULL))); + + +triggers.push_back(new TriggerNode( + "lose aggro", + NextAction::array(0, new NextAction("dark command", ACTION_HIGH + 3), NULL))); + + +triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, + new NextAction("blood tap", ACTION_HIGH + 5), + new NextAction("vampiric blood", ACTION_HIGH + 3), + new NextAction("death strike", ACTION_HIGH + 4), NULL))); + + + +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h new file mode 100644 index 0000000000..d7e1cb35a6 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h @@ -0,0 +1,20 @@ +#pragma once + +#include "GenericDKStrategy.h" + +namespace ai +{ + class BloodDKStrategy : public GenericDKStrategy + { + public: + BloodDKStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "blood"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_TANK | STRATEGY_TYPE_MELEE; } + }; + + +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp new file mode 100644 index 0000000000..1caff14f38 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp @@ -0,0 +1,7 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKActions.h" + + +using namespace ai; + diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h new file mode 100644 index 0000000000..2f6720170b --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h @@ -0,0 +1,301 @@ +#pragma once + +#include "../actions/GenericActions.h" + +namespace ai +{ + class CastBloodPresenceAction : public CastBuffSpellAction { + public: + CastBloodPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blood presence") {} + }; + + class CastFrostPresenceAction : public CastBuffSpellAction { + public: + CastFrostPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "frost presence") {} + }; + + class CastUnholyPresenceAction : public CastBuffSpellAction { + public: + CastUnholyPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unholy presence") {} + }; + + class CastDeathchillAction : public CastBuffSpellAction { + public: + CastDeathchillAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "deathchill") {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("frost presence"), NULL), CastSpellAction::getPrerequisites()); + } + }; + + class CastDarkCommandAction : public CastBuffSpellAction { + public: + CastDarkCommandAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "dark command") {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), NULL), CastSpellAction::getPrerequisites()); + } + }; + + BEGIN_RANGED_SPELL_ACTION(CastDeathGripAction, "death grip") + END_SPELL_ACTION() + + // Unholy presence + class CastUnholyMeleeSpellAction : public CastMeleeSpellAction { + public: + CastUnholyMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("unholy presence"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + + + // Frost presence + class CastFrostMeleeSpellAction : public CastMeleeSpellAction { + public: + CastFrostMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("frost presence"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + + // Blood presence + class CastBloodMeleeSpellAction : public CastMeleeSpellAction { + public: + CastBloodMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + // a + class CastRuneStrikeAction : public CastMeleeSpellAction { + public: + CastRuneStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rune strike") {} + }; + //debuff + BEGIN_DEBUFF_ACTION(CastPestilenceAction, "pestilence") + END_SPELL_ACTION() + + //debuff + BEGIN_DEBUFF_ACTION(CastHowlingBlastAction, "howling blast") + END_SPELL_ACTION() + + //debuff it + BEGIN_DEBUFF_ACTION(CastIcyTouchAction, "icy touch") + END_SPELL_ACTION() + + + class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastIcyTouchOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "icy touch") {} + }; + + //debuff ps + BEGIN_DEBUFF_ACTION(CastPlagueStrikeAction, "plague strike") + END_SPELL_ACTION() + + + class CastPlagueStrikeOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastPlagueStrikeOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "plague strike") {} + }; + + //debuff + BEGIN_DEBUFF_ACTION(CastMarkOfBloodAction, "mark of blood") + END_SPELL_ACTION() + + class CastMarkOfBloodOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastMarkOfBloodOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "mark of blood") {} + }; + + class CastUnholyBlightAction : public CastBuffSpellAction + { + public: + CastUnholyBlightAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unholy blight") {} + }; + + class CastSummonGargoyleAction : public CastBuffSpellAction + { + public: + CastSummonGargoyleAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "summon gargoyle") {} + }; + + class CastGhoulFrenzyAction : public CastBuffSpellAction + { + public: + CastGhoulFrenzyAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "ghoul frenzy") {} + }; + + BEGIN_MELEE_SPELL_ACTION(CastCorpseExplosionAction, "corpse explosion") + END_SPELL_ACTION() + + BEGIN_MELEE_SPELL_ACTION(CastAntiMagicShellAction, "anti magic shell") + END_SPELL_ACTION() + + + BEGIN_MELEE_SPELL_ACTION(CastAntiMagicZoneAction, "anti magic zone") + END_SPELL_ACTION() + + + class CastChainsOfIceAction : public CastSpellAction { + public: + CastChainsOfIceAction(PlayerbotAI* ai) : CastSpellAction(ai, "chains of ice") {} + }; + + class CastHungeringColdAction : public CastMeleeSpellAction { + public: + CastHungeringColdAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "hungering cold") {} + }; + + class CastHeartStrikeAction : public CastMeleeSpellAction { + public: + CastHeartStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "heart strike") {} + }; + + class CastBloodStrikeAction : public CastMeleeSpellAction { + public: + CastBloodStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "blood strike") {} + }; + + class CastFrostStrikeAction : public CastMeleeSpellAction { + public: + CastFrostStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "frost strike") {} + }; + + class CastObliterateAction : public CastMeleeSpellAction { + public: + CastObliterateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "obliterate") {} + }; + + class CastDeathStrikeAction : public CastMeleeSpellAction { + public: + CastDeathStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "death strike") {} + }; + + class CastScourgeStrikeAction : public CastMeleeSpellAction { + public: + CastScourgeStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "scorgue strike") {} + }; + + class CastDeathCoilAction : public CastSpellAction { + public: + CastDeathCoilAction(PlayerbotAI* ai) : CastSpellAction(ai, "death coill") {} + }; + + class CastBloodBoilAction : public CastBuffSpellAction { + public: + CastBloodBoilAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blood boil") {} + }; + + class CastDeathAndDecayAction : public CastSpellAction { + public: + CastDeathAndDecayAction(PlayerbotAI* ai) : CastSpellAction(ai, "death and decay") {} + }; + + class CastHornOfWinterAction : public CastBuffSpellAction + { + public: + CastHornOfWinterAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "horn of winter") {} + }; + + class CastImprovedIcyTalonsAction : public CastBuffSpellAction + { + public: + CastImprovedIcyTalonsAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "improved icy talons") {} + }; + + class CastBoneShieldAction : public CastBuffSpellAction + { + public: + CastBoneShieldAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "bone shield") {} + }; + + class CastDeathPactAction : public CastBuffSpellAction + { + public: + CastDeathPactAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "death pact") {} + }; + + class CastDeathRuneMasteryAction : public CastBuffSpellAction + { + public: + CastDeathRuneMasteryAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "death rune mastery") {} + }; + + class CastDancingWeaponAction : public CastBuffSpellAction + { + public: + CastDancingWeaponAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "dancing weapon") {} + }; + + class CastEmpowerRuneWeaponAction : public CastBuffSpellAction + { + public: + CastEmpowerRuneWeaponAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "empower rune weapon") {} + }; + + class CastArmyOfTheDeadAction : public CastBuffSpellAction + { + public: + CastArmyOfTheDeadAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "army of the dead") {} + }; + + + class CastRaiseDeadAction : public CastBuffSpellAction + { + public: + CastRaiseDeadAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "raise dead") {} + }; + + class CastKillingMachineAction : public CastBuffSpellAction + { + public: + CastKillingMachineAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "killing machine") {} + }; + + class CastIceboundFortitudeAction : public CastBuffSpellAction + { + public: + CastIceboundFortitudeAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "icebound fortitude") {} + }; + + class CastUnbreakableArmorAction : public CastBuffSpellAction + { + public: + CastUnbreakableArmorAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unbreakable armor") {} + }; + + class CastVampiricBloodAction : public CastBuffSpellAction + { + public: + CastVampiricBloodAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "vampiric blood") {} + }; + + class CastMindFreezeAction : public CastMeleeSpellAction { + public: + CastMindFreezeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "mind freeze") {} + }; + + class CastStrangulateAction : public CastMeleeSpellAction { + public: + CastStrangulateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "strangulate") {} + }; + + class CastMindFreezeOnEnemyHealerAction : public CastSpellOnEnemyHealerAction + { + public: + CastMindFreezeOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "mind freeze") {} + }; + + class CastRuneTapAction : public CastMeleeSpellAction { + public: + CastRuneTapAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rune tap") {} + + }; + class CastBloodTapAction : public CastMeleeSpellAction { + public: + CastBloodTapAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "blood tap") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp new file mode 100644 index 0000000000..9f7b837523 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp @@ -0,0 +1,266 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "../Strategy.h" +#include "DKActions.h" +#include "DKAiObjectContext.h" +#include "FrostDKStrategy.h" +#include "BloodDKStrategy.h" +#include "GenericDKNonCombatStrategy.h" +#include "UnholyDKStrategy.h" +#include "../generic/PullStrategy.h" +#include "DKTriggers.h" +#include "../NamedObjectContext.h" + +using namespace ai; + + +namespace ai +{ + namespace DK + { + using namespace ai; + + class StrategyFactoryInternal : public NamedObjectContext + { + public: + StrategyFactoryInternal() + { + creators["nc"] = &DK::StrategyFactoryInternal::nc; + creators["pull"] = &DK::StrategyFactoryInternal::pull; + creators["frost aoe"] = &DK::StrategyFactoryInternal::frost_aoe; + creators["unholy aoe"] = &DK::StrategyFactoryInternal::unholy_aoe; + } + + private: + static Strategy* nc(PlayerbotAI* ai) { return new GenericDKNonCombatStrategy(ai); } + static Strategy* pull(PlayerbotAI* ai) { return new PullStrategy(ai, "icy touch"); } + static Strategy* frost_aoe(PlayerbotAI* ai) { return new FrostDKAoeStrategy(ai); } + static Strategy* unholy_aoe(PlayerbotAI* ai) { return new UnholyDKAoeStrategy(ai); } + }; + + class CombatStrategyFactoryInternal : public NamedObjectContext + { + public: + CombatStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["tank"] = &DK::CombatStrategyFactoryInternal::blood; + creators["blood"] = &DK::CombatStrategyFactoryInternal::blood; + creators["frost"] = &DK::CombatStrategyFactoryInternal::frost_dps; + creators["unholy"] = &DK::CombatStrategyFactoryInternal::unholy_dps; + } + + private: + static Strategy* frost_dps(PlayerbotAI* ai) { return new FrostDKStrategy(ai); } + static Strategy* unholy_dps(PlayerbotAI* ai) { return new UnholyDKStrategy(ai); } + static Strategy* tank(PlayerbotAI* ai) { return new BloodDKStrategy(ai); } + static Strategy* blood(PlayerbotAI* ai) { return new BloodDKStrategy(ai); } + }; + + class DKBuffStrategyFactoryInternal : public NamedObjectContext + { + public: + DKBuffStrategyFactoryInternal() : NamedObjectContext(false, true) + { + + creators["bdps"] = &DK::DKBuffStrategyFactoryInternal::bdps; + } + + private: + static Strategy* bdps(PlayerbotAI* ai) { return new DKBuffDpsStrategy(ai); } + }; + }; +}; + + +namespace ai +{ + namespace DK + { + using namespace ai; + + class TriggerFactoryInternal : public NamedObjectContext + { + public: + TriggerFactoryInternal() + { + creators["bone shield"] = &TriggerFactoryInternal::bone_shield; + creators["pestilence"] = &TriggerFactoryInternal::pestilence; + creators["blood strike"] = &TriggerFactoryInternal::blood_strike; + creators["plague strike"] = &TriggerFactoryInternal::plague_strike; + creators["plague strike on attacker"] = &TriggerFactoryInternal::plague_strike_on_attacker; + creators["icy touch"] = &TriggerFactoryInternal::icy_touch; + creators["death coil"] = &TriggerFactoryInternal::death_coil; + creators["icy touch on attacker"] = &TriggerFactoryInternal::icy_touch_on_attacker; + creators["improved icy talons"] = &TriggerFactoryInternal::improved_icy_talons; + creators["plague strike"] = &TriggerFactoryInternal::plague_strike; + creators["horn of winter"] = &TriggerFactoryInternal::horn_of_winter; + creators["mind freeze"] = &TriggerFactoryInternal::mind_freeze; + creators["mind freeze on enemy healer"] = &TriggerFactoryInternal::mind_freeze_on_enemy_healer; + creators["strangulate"] = &TriggerFactoryInternal::strangulate; + creators["strangulate on enemy healer"] = &TriggerFactoryInternal::strangulate_on_enemy_healer; + creators["blood tap"] = &TriggerFactoryInternal::blood_tap; + creators["raise dead"] = &TriggerFactoryInternal::raise_dead; + creators["chains of ice"] = &TriggerFactoryInternal::chains_of_ice; + } + + private: + static Trigger* bone_shield(PlayerbotAI* ai) { return new BoneShieldTrigger(ai); } + static Trigger* pestilence(PlayerbotAI* ai) { return new PestilenceTrigger(ai); } + static Trigger* blood_strike(PlayerbotAI* ai) { return new BloodStrikeTrigger(ai); } + static Trigger* plague_strike(PlayerbotAI* ai) { return new PlagueStrikeDebuffTrigger(ai); } + static Trigger* plague_strike_on_attacker(PlayerbotAI* ai) { return new PlagueStrikeDebuffOnAttackerTrigger(ai); } + static Trigger* icy_touch(PlayerbotAI* ai) { return new IcyTouchDebuffTrigger(ai); } + static Trigger* death_coil(PlayerbotAI* ai) { return new DeathCoilTrigger(ai); } + static Trigger* icy_touch_on_attacker(PlayerbotAI* ai) { return new IcyTouchDebuffOnAttackerTrigger(ai); } + static Trigger* improved_icy_talons(PlayerbotAI* ai) { return new ImprovedIcyTalonsTrigger(ai); } + static Trigger* horn_of_winter(PlayerbotAI* ai) { return new HornOfWinterTrigger(ai); } + static Trigger* mind_freeze(PlayerbotAI* ai) { return new MindFreezeInterruptSpellTrigger(ai); } + static Trigger* mind_freeze_on_enemy_healer(PlayerbotAI* ai) { return new MindFreezeOnEnemyHealerTrigger(ai); } + static Trigger* strangulate(PlayerbotAI* ai) { return new StrangulateInterruptSpellTrigger(ai); } + static Trigger* strangulate_on_enemy_healer(PlayerbotAI* ai) { return new StrangulateOnEnemyHealerTrigger(ai); } + static Trigger* blood_tap(PlayerbotAI* ai) { return new BloodTapTrigger(ai); } + static Trigger* raise_dead(PlayerbotAI* ai) { return new RaiseDeadTrigger(ai); } + static Trigger* chains_of_ice(PlayerbotAI* ai) { return new ChainsOfIceSnareTrigger(ai); } + + + }; + }; +}; + + +namespace ai +{ + namespace DK + { + using namespace ai; + + class AiObjectContextInternal : public NamedObjectContext + { + public: + AiObjectContextInternal() + { + + // Unholy + creators["bone shield"] = &AiObjectContextInternal::bone_shield; + creators["plague strike"] = &AiObjectContextInternal::plague_strike; + creators["plague strike on attacker"] = &AiObjectContextInternal::plague_strike_on_attacker; + creators["death grip"] = &AiObjectContextInternal::death_grip; + creators["death coil"] = &AiObjectContextInternal::death_coil; + creators["death strike"] = &AiObjectContextInternal::death_strike; + creators["unholy blight"] = &AiObjectContextInternal::unholy_blight; + creators["scourge strike"] = &AiObjectContextInternal::scourge_strike; + creators["death and decay"] = &AiObjectContextInternal::death_and_decay; + creators["unholy pressence"] = &AiObjectContextInternal::unholy_pressence; + creators["raise dead"] = &AiObjectContextInternal::raise_dead; + creators["army of the dead"] = &AiObjectContextInternal::army_of_the_dead; + creators["summon gargoyle"] = &AiObjectContextInternal::summon_gargoyle; + creators["anti magic shell"] = &AiObjectContextInternal::anti_magic_shell; + creators["anti magic zone"] = &AiObjectContextInternal::anti_magic_zone; + creators["ghoul frenzy"] = &AiObjectContextInternal::ghoul_frenzy; + creators["corpse explosion"] = &AiObjectContextInternal::corpse_explosion; + // Frost + creators["icy touch"] = &AiObjectContextInternal::icy_touch; + creators["icy touch on attacker"] = &AiObjectContextInternal::icy_touch_on_attacker; + creators["obliterate"] = &AiObjectContextInternal::obliterate; + creators["howling blast"] = &AiObjectContextInternal::howling_blast; + creators["frost strike"] = &AiObjectContextInternal::frost_strike; + creators["chains of ice"] = &AiObjectContextInternal::chains_of_ice; + creators["rune strike"] = &AiObjectContextInternal::rune_strike; + //creators["icy clutch"] = &AiObjectContextInternal::icy_clutch; + creators["horn of winter"] = &AiObjectContextInternal::horn_of_winter; + creators["killing machine"] = &AiObjectContextInternal::killing_machine; + creators["frost presence"] = &AiObjectContextInternal::frost_presence; + creators["deathchill"] = &AiObjectContextInternal::deathchill; + creators["icebound fortitude"] = &AiObjectContextInternal::icebound_fortitude; + creators["mind freeze"] = &AiObjectContextInternal::mind_freeze; + creators["empower rune weapon"] = &AiObjectContextInternal::empower_rune_weapon; + creators["hungering cold"] = &AiObjectContextInternal::hungering_cold; + creators["unbreakable armor"] = &AiObjectContextInternal::unbreakable_armor; + creators["improved icy talons"] = &AiObjectContextInternal::improved_icy_talons; + // blood + creators["blood strike"] = &AiObjectContextInternal::blood_strike; + creators["blood tap"] = &AiObjectContextInternal::blood_tap; + creators["pestilence"] = &AiObjectContextInternal::pestilence; + creators["strangulate"] = &AiObjectContextInternal::strangulate; + creators["blood boil"] = &AiObjectContextInternal::blood_boil; + creators["heart strike"] = &AiObjectContextInternal::heart_strike; + creators["mark of_blood"] = &AiObjectContextInternal::mark_of_blood; + creators["blood presence"] = &AiObjectContextInternal::blood_presence; + creators["rune tap"] = &AiObjectContextInternal::rune_tap; + creators["vampiric blood"] = &AiObjectContextInternal::vampiric_blood; + creators["death pact"] = &AiObjectContextInternal::death_pact; + creators["death rune_mastery"] = &AiObjectContextInternal::death_rune_mastery; + //creators["hysteria"] = &AiObjectContextInternal::hysteria; + creators["dancing weapon"] = &AiObjectContextInternal::dancing_weapon; + creators["dark command"] = &AiObjectContextInternal::dark_command; + } + + private: + + // Unholy + static Action* bone_shield(PlayerbotAI* ai) { return new CastBoneShieldAction(ai); } + static Action* plague_strike(PlayerbotAI* ai) { return new CastPlagueStrikeAction(ai); } + static Action* plague_strike_on_attacker(PlayerbotAI* ai) { return new CastPlagueStrikeOnAttackerAction(ai); } + static Action* death_grip(PlayerbotAI* ai) { return new CastDeathGripAction(ai); } + static Action* death_coil(PlayerbotAI* ai) { return new CastDeathCoilAction(ai); } + static Action* death_strike(PlayerbotAI* ai) { return new CastDeathStrikeAction(ai); } + static Action* unholy_blight(PlayerbotAI* ai) { return new CastUnholyBlightAction(ai); } + static Action* scourge_strike(PlayerbotAI* ai) { return new CastScourgeStrikeAction(ai); } + static Action* death_and_decay(PlayerbotAI* ai) { return new CastDeathAndDecayAction(ai); } + static Action* unholy_pressence(PlayerbotAI* ai) { return new CastUnholyPresenceAction(ai); } + static Action* raise_dead(PlayerbotAI* ai) { return new CastRaiseDeadAction(ai); } + static Action* army_of_the_dead(PlayerbotAI* ai) { return new CastArmyOfTheDeadAction(ai); } + static Action* summon_gargoyle(PlayerbotAI* ai) { return new CastSummonGargoyleAction(ai); } + static Action* anti_magic_shell(PlayerbotAI* ai) { return new CastAntiMagicShellAction(ai); } + static Action* anti_magic_zone(PlayerbotAI* ai) { return new CastAntiMagicZoneAction(ai); } + static Action* ghoul_frenzy(PlayerbotAI* ai) { return new CastGhoulFrenzyAction(ai); } + static Action* corpse_explosion(PlayerbotAI* ai) { return new CastCorpseExplosionAction(ai); } + // Frost + static Action* icy_touch(PlayerbotAI* ai) { return new CastIcyTouchAction(ai); } + static Action* icy_touch_on_attacker(PlayerbotAI* ai) { return new CastIcyTouchOnAttackerAction(ai); } + static Action* obliterate(PlayerbotAI* ai) { return new CastObliterateAction(ai); } + static Action* howling_blast(PlayerbotAI* ai) { return new CastHowlingBlastAction(ai); } + static Action* frost_strike(PlayerbotAI* ai) { return new CastFrostStrikeAction(ai); } + static Action* chains_of_ice(PlayerbotAI* ai) { return new CastChainsOfIceAction(ai); } + static Action* rune_strike(PlayerbotAI* ai) { return new CastRuneStrikeAction(ai); } + //static Action* icy_clutch(PlayerbotAI* ai) { return new CastIcyClutchAction(ai); } + static Action* horn_of_winter(PlayerbotAI* ai) { return new CastHornOfWinterAction(ai); } + static Action* killing_machine(PlayerbotAI* ai) { return new CastKillingMachineAction(ai); } + static Action* frost_presence(PlayerbotAI* ai) { return new CastFrostPresenceAction(ai); } + static Action* deathchill(PlayerbotAI* ai) { return new CastDeathchillAction(ai); } + static Action* icebound_fortitude(PlayerbotAI* ai) { return new CastIceboundFortitudeAction(ai); } + static Action* mind_freeze(PlayerbotAI* ai) { return new CastMindFreezeAction(ai); } + static Action* empower_rune_weapon(PlayerbotAI* ai) { return new CastEmpowerRuneWeaponAction(ai); } + static Action* hungering_cold(PlayerbotAI* ai) { return new CastHungeringColdAction(ai); } + static Action* unbreakable_armor(PlayerbotAI* ai) { return new CastUnbreakableArmorAction(ai); } + static Action* improved_icy_talons(PlayerbotAI* ai) { return new CastImprovedIcyTalonsAction(ai); } + // blood + static Action* blood_strike(PlayerbotAI* ai) { return new CastBloodStrikeAction(ai); } + static Action* blood_tap(PlayerbotAI* ai) { return new CastBloodTapAction(ai); } + static Action* pestilence(PlayerbotAI* ai) { return new CastPestilenceAction(ai); } + static Action* strangulate(PlayerbotAI* ai) { return new CastStrangulateAction(ai); } + static Action* blood_boil(PlayerbotAI* ai) { return new CastBloodBoilAction(ai); } + static Action* heart_strike(PlayerbotAI* ai) { return new CastHeartStrikeAction(ai); } + static Action* mark_of_blood(PlayerbotAI* ai) { return new CastMarkOfBloodAction(ai); } + static Action* blood_presence(PlayerbotAI* ai) { return new CastBloodPresenceAction(ai); } + static Action* rune_tap(PlayerbotAI* ai) { return new CastRuneTapAction(ai); } + static Action* vampiric_blood(PlayerbotAI* ai) { return new CastVampiricBloodAction(ai); } + static Action* death_pact(PlayerbotAI* ai) { return new CastDeathPactAction(ai); } + static Action* death_rune_mastery(PlayerbotAI* ai) { return new CastDeathRuneMasteryAction(ai); } + //static Action* hysteria(PlayerbotAI* ai) { return new CastHysteriaAction(ai); } + static Action* dancing_weapon(PlayerbotAI* ai) { return new CastDancingWeaponAction(ai); } + static Action* dark_command(PlayerbotAI* ai) { return new CastDarkCommandAction(ai); } + static Action* mind_freeze_on_enemy_healer(PlayerbotAI* ai) { return new CastMindFreezeOnEnemyHealerAction(ai); } + + }; + }; +}; + +DKAiObjectContext::DKAiObjectContext(PlayerbotAI* ai) : AiObjectContext(ai) +{ + strategyContexts.Add(new ai::DK::StrategyFactoryInternal()); + strategyContexts.Add(new ai::DK::CombatStrategyFactoryInternal()); + strategyContexts.Add(new ai::DK::DKBuffStrategyFactoryInternal()); + actionContexts.Add(new ai::DK::AiObjectContextInternal()); + triggerContexts.Add(new ai::DK::TriggerFactoryInternal()); +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h new file mode 100644 index 0000000000..b5b86ca7c9 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h @@ -0,0 +1,12 @@ +#pragma once + +#include "../AiObjectContext.h" + +namespace ai +{ + class DKAiObjectContext : public AiObjectContext + { + public: + DKAiObjectContext(PlayerbotAI* ai); + }; +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.cpp b/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.cpp new file mode 100644 index 0000000000..b1d573ab2f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.cpp @@ -0,0 +1,6 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKMultipliers.h" +#include "DKActions.h" + +using namespace ai; diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h b/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h new file mode 100644 index 0000000000..7cfbdd46e8 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ai +{ + +} \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.cpp b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.cpp new file mode 100644 index 0000000000..bf096ea27a --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.cpp @@ -0,0 +1,14 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKTriggers.h" +#include "DKActions.h" + +using namespace ai; + +bool DKPresenceTrigger::IsActive() +{ + Unit* target = GetTarget(); + return !ai->HasAura("blood presence", target) && + !ai->HasAura("unholy presence", target) && + !ai->HasAura("frost presence", target); +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h new file mode 100644 index 0000000000..816f0e3d8f --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h @@ -0,0 +1,102 @@ +#pragma once +#include "../triggers/GenericTriggers.h" + +namespace ai +{ + + BUFF_TRIGGER(HornOfWinterTrigger, "horn of winter"); + BUFF_TRIGGER(BoneShieldTrigger, "bone shield"); + BUFF_TRIGGER(ImprovedIcyTalonsTrigger, "improved icy talons"); + DEBUFF_TRIGGER(PlagueStrikeDebuffTrigger, "plague strike"); + DEBUFF_TRIGGER(IcyTouchDebuffTrigger, "icy touch"); + + class PlagueStrikeDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + PlagueStrikeDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "plague strike") {} + }; + class IcyTouchDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + IcyTouchDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "icy touch") {} + }; + + class DKPresenceTrigger : public BuffTrigger { + public: + DKPresenceTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "blood presence") {} + virtual bool IsActive(); + }; + + class BloodTapTrigger : public BuffTrigger { + public: + BloodTapTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "blood tap") {} + }; + + class RaiseDeadTrigger : public BuffTrigger { + public: + RaiseDeadTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "raise dead") {} + }; + + + class RuneStrikeTrigger : public SpellCanBeCastTrigger { + public: + RuneStrikeTrigger(PlayerbotAI* ai) : SpellCanBeCastTrigger(ai, "rune strike") {} + }; + + class DeathCoilTrigger : public SpellCanBeCastTrigger { + public: + DeathCoilTrigger(PlayerbotAI* ai) : SpellCanBeCastTrigger(ai, "death coil") {} + }; + + class PestilenceTrigger : public DebuffTrigger { + public: + PestilenceTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "pestilence") {} + }; + + class BloodStrikeTrigger : public DebuffTrigger { + public: + BloodStrikeTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "blood strike") {} + }; + + + class HowlingBlastTrigger : public DebuffTrigger { + public: + HowlingBlastTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "howling blast") {} + }; + + class MindFreezeInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + MindFreezeInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "mind freeze") {} + }; + + class StrangulateInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + StrangulateInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "strangulate") {} + }; + + class KillingMachineTrigger : public BoostTrigger + { + public: + KillingMachineTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "killing machine") {} + }; + + class MindFreezeOnEnemyHealerTrigger : public InterruptEnemyHealerTrigger + { + public: + MindFreezeOnEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "mind freeze") {} + }; + + class ChainsOfIceSnareTrigger : public SnareTargetTrigger + { + public: + ChainsOfIceSnareTrigger(PlayerbotAI* ai) : SnareTargetTrigger(ai, "chains of ice") {} + }; + + class StrangulateOnEnemyHealerTrigger : public InterruptEnemyHealerTrigger + { + public: + StrangulateOnEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "strangulate") {} + }; +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp new file mode 100644 index 0000000000..b3736b5300 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp @@ -0,0 +1,91 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKMultipliers.h" +#include "FrostDKStrategy.h" + +using namespace ai; + +class FrostDKStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + FrostDKStrategyActionNodeFactory() + { + //creators["icy touch"] = &icy_touch; + creators["obliterate"] = &obliterate; + creators["howling blast"] = &howling_blast; + creators["frost strike"] = &frost_strike; + //creators["chains of ice"] = &chains_of_ice; + creators["rune strike"] = &rune_strike; + //creators["icy clutch"] = &icy_clutch; + //creators["horn of winter"] = &horn_of_winter; + //creators["killing machine"] = &killing_machine; + //creators["frost presence"] = &frost_presence; + //creators["deathchill"] = &deathchill; + //creators["icebound fortitude"] = &icebound_fortitude; + //creators["mind freeze"] = &mind_freeze; + //creators["empower weapon"] = &empower_weapon; + //creators["hungering cold"] = &hungering_cold; + //creators["unbreakable armor"] = &unbreakable_armor; + //creators["improved icy talons"] = &improved_icy_talons; + } + + private: + + + static ActionNode* obliterate(PlayerbotAI* ai) + { + return new ActionNode("obliterate", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("frost strike"), NULL), + /*C*/ NULL); + } + static ActionNode* rune_strike(PlayerbotAI* ai) + { + return new ActionNode("rune strike", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* frost_strike(PlayerbotAI* ai) + { + return new ActionNode("frost strike", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* howling_blast(PlayerbotAI* ai) + { + return new ActionNode("howling blast", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("icy touch"), NULL), + /*C*/ NULL); + } +}; + + FrostDKStrategy::FrostDKStrategy(PlayerbotAI* ai) : GenericDKStrategy(ai) + { + actionNodeFactories.Add(new FrostDKStrategyActionNodeFactory()); + } + + + NextAction** FrostDKStrategy::getDefaultActions() + { + return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), new NextAction("frost strike", ACTION_NORMAL + 5), + new NextAction("obliterate", ACTION_NORMAL + 4), NULL); + } + +void FrostDKStrategy::InitTriggers(std::list &triggers) +{ + GenericDKStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "empower weapon", + NextAction::array(0, new NextAction("empower weapon", ACTION_NORMAL + 4), NULL))); +} + +void FrostDKAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("howling blast", ACTION_NORMAL + 4), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h new file mode 100644 index 0000000000..0f33cbe437 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h @@ -0,0 +1,29 @@ +#pragma once + +#include "GenericDKStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class FrostDKStrategy : public GenericDKStrategy + { + public: + FrostDKStrategy(PlayerbotAI* ai); + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "frost"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } + }; + + class FrostDKAoeStrategy : public CombatStrategy + { + public: + FrostDKAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "frost aoe"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp new file mode 100644 index 0000000000..414789a586 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp @@ -0,0 +1,62 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKMultipliers.h" +#include "GenericDKNonCombatStrategy.h" + +using namespace ai; + +class GenericDKNonCombatStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericDKNonCombatStrategyActionNodeFactory() + { + creators["bone shield"] = &bone_shield; + creators["horn of winter"] = &horn_of_winter; + } +private: + static ActionNode* bone_shield(PlayerbotAI* ai) + { + return new ActionNode ("bone shield", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* horn_of_winter(PlayerbotAI* ai) + { + return new ActionNode ("horn of winter", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } +}; + +GenericDKNonCombatStrategy::GenericDKNonCombatStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericDKNonCombatStrategyActionNodeFactory()); +} + +void GenericDKNonCombatStrategy::InitTriggers(std::list &triggers) +{ + NonCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "raise dead", + NextAction::array(0, new NextAction("raise dead", ACTION_NORMAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "horn of winter", + NextAction::array(0, new NextAction("horn of winter", 21.0f), NULL))); + + triggers.push_back(new TriggerNode( + "bone shield", + NextAction::array(0, new NextAction("bone shield", 21.0f), NULL))); + +} + + +void DKBuffDpsStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "improved icy talons", + NextAction::array(0, new NextAction("improved icy talons", 19.0f), NULL))); +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h new file mode 100644 index 0000000000..4ea0cd4ddb --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h @@ -0,0 +1,27 @@ +#pragma once + +#include "GenericDKStrategy.h" +#include "../generic/NonCombatStrategy.h" + +namespace ai +{ + class GenericDKNonCombatStrategy : public NonCombatStrategy + { + public: + GenericDKNonCombatStrategy(PlayerbotAI* ai); + virtual string getName() { return "nc"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + + class DKBuffDpsStrategy : public Strategy + { + public: + DKBuffDpsStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "bdps"; } + }; +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp new file mode 100644 index 0000000000..8ddd906f18 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp @@ -0,0 +1,239 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKMultipliers.h" +#include "GenericDKStrategy.h" +#include "DKAiObjectContext.h" + +using namespace ai; + +class GenericDKStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + GenericDKStrategyActionNodeFactory() + { + //blood + //creators["rune tap"] = &rune_tap; cd + //creators["vampiric blood"] = &vampiric_blood; + //creators["death pact"] = &death_pact; + //creators["hysteria"] = &hysteria; boost party + //creators["dancing rune weapon"] = &dancing_rune_weapon; //cd + //creators["dark command"] = &dark_command; taunt + + //frost + //creators["chains of ice"] = &chains_of_ice; + //creators["icy clutch"] = &icy_clutch; + creators["horn of winter"] = &horn_of_winter; + creators["killing machine"] = &killing_machine; // buff + //creators["deathchill"] = &deathchill; //boost + creators["icebound fortitude"] = &icebound_fortitude; + //creators["mind freeze"] = &mind_freeze; interrupt + //creators["empower rune weapon"] = &empower_rune_weapon; boost + //creators["hungering cold"] = &hungering_cold; snare + //creators["unbreakable armor"] = &unbreakable_armor; boost +cd + //creators["improved icy talons"] = &improved_icy_talons; boost party + + //unholy + //creators["death and decay"] = &death_and_decay; + //creators["raise dead"] = &raise_dead; + //creators["army of the dead"] = &army of the dead; + //creators["summon gargoyle"] = &army of the dead; + //creators["anti magic shell"] = &anti_magic_shell; cd + creators["anti magic zone"] = &anti_magic_zone; + //creators["ghoul frenzy"] = &ghoul_frenzy; + creators["corpse explosion"] = &corpse_explosion; + creators["bone shield"] = &bone_shield; + creators["heart strike"] = &heart_strike; + creators["death grip"] = &death_grip; + creators["plague strike"] = &plague_strike; + creators["pestilence"] = &pestilence; + creators["icy touch"] = &icy_touch; + + } +private: + static ActionNode* death_coil(PlayerbotAI* ai) + { + return new ActionNode("death coil", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), + /*C*/ NULL); + } + static ActionNode* death_grip(PlayerbotAI* ai) + { + return new ActionNode("death grip", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("icy touch"), NULL), + /*C*/ NULL); + } + static ActionNode* plague_strike(PlayerbotAI* ai) + { + return new ActionNode("plague strike", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* icy_touch(PlayerbotAI* ai) + { + return new ActionNode("icy touch", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* heart_strike(PlayerbotAI* ai) + { + return new ActionNode("heart strike", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("blood strike"), NULL), + /*C*/ NULL); + } + static ActionNode* pestilence(PlayerbotAI* ai) + { + return new ActionNode("pestilence", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* horn_of_winter(PlayerbotAI* ai) + { + return new ActionNode ("horn of winter", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* bone_shield(PlayerbotAI* ai) + { + return new ActionNode ("bone shield", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* killing_machine(PlayerbotAI* ai) + { + return new ActionNode ("killing machine", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("improved icy talons"), NULL), + /*C*/ NULL); + } + static ActionNode* corpse_explosion(PlayerbotAI* ai) + { + return new ActionNode ("corpse explosion", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* anti_magic_zone(PlayerbotAI* ai) + { + return new ActionNode ("anti magic zone", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("anti magic shell"), NULL), + /*C*/ NULL); + } + static ActionNode* icebound_fortitude(PlayerbotAI* ai) + { + return new ActionNode ("icebound fortitude", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + + } +}; + +GenericDKStrategy::GenericDKStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai) +{ + actionNodeFactories.Add(new GenericDKStrategyActionNodeFactory()); +} + +void GenericDKStrategy::InitTriggers(std::list &triggers) +{ + MeleeCombatStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, + new NextAction("anti magic shell", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode( + "death coil", + NextAction::array(0, new NextAction("death coil", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode( + "critical aoe heal", + NextAction::array(0, new NextAction("anti magic zone", ACTION_EMERGENCY + 1), NULL))); + + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("raise dead", ACTION_NORMAL + 5), NULL))); + + triggers.push_back(new TriggerNode( + "mind freeze", + NextAction::array(0, new NextAction("mind freeze", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "bone shield", + NextAction::array(0, new NextAction("bone shield", ACTION_NORMAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "horn of winter", + NextAction::array(0, new NextAction("horn of winter", ACTION_NORMAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "mind freeze on enemy healer", + NextAction::array(0, new NextAction("mind freeze on enemy healer", ACTION_HIGH + 1), NULL))); + + + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("icy touch", ACTION_NORMAL + 9), + new NextAction("death grip", ACTION_NORMAL + 9), + new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("icebound fortitude", ACTION_HIGH + 5), + new NextAction("rune tap", ACTION_HIGH + 4), NULL))); + + + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("rune tap", ACTION_NORMAL + 4), + new NextAction("death strike", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode( + "icy touch on attacker", + NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "icy touch", + NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "plague strike", + NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "plague strike on attacker", + NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, + new NextAction("unholy blight", ACTION_NORMAL + 6), + new NextAction("death and decay", ACTION_NORMAL + 5), + new NextAction("pestilence", ACTION_NORMAL + 4), + new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, + new NextAction("death and decay", ACTION_NORMAL + 5), + new NextAction("pestilence", ACTION_NORMAL + 4), + new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode("light aoe", + NextAction::array(0, + new NextAction("howling blast", ACTION_NORMAL + 5), + new NextAction("pestilence", ACTION_NORMAL + 4), + new NextAction("hearth strike", ACTION_NORMAL + 3), + new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); + + +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.h new file mode 100644 index 0000000000..eb00bf8719 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.h @@ -0,0 +1,18 @@ +#pragma once + +#include "../Strategy.h" +#include "../generic/MeleeCombatStrategy.h" + +namespace ai +{ + class GenericDKStrategy : public MeleeCombatStrategy + { + public: + GenericDKStrategy(PlayerbotAI* ai); + virtual string getName() { return "DK"; } + + public: + virtual void InitTriggers(std::list &triggers); + }; + +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp new file mode 100644 index 0000000000..d69bfe7193 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp @@ -0,0 +1,88 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "DKMultipliers.h" +#include "UnholyDKStrategy.h" + +using namespace ai; + +class UnholyDKStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + UnholyDKStrategyActionNodeFactory() + { + // Unholy + //creators["bone shield"] = &bone_shield; + //creators["plague strike"] = &plague_strike; + //creators["death grip"] = &death_grip; + //creators["death coil"] = &death_coil; + creators["death strike"] = &death_strike; + //creators["unholy blight"] = &unholy_blight; + creators["scourge strike"] = &scourge_strike; + //creators["death and decay"] = &death_and_decay; + //creators["unholy pressence"] = &unholy_pressence; + //creators["raise dead"] = &raise_dead; + //creators["army of the dead"] = &army of the dead; + //creators["summon gargoyle"] = &army of the dead; + //creators["anti magic shell"] = &anti_magic_shell; + //creators["anti magic zone"] = &anti_magic_zone; + //creators["ghoul frenzy"] = &ghoul_frenzy; + creators["corpse explosion"] = &corpse_explosion; + } +private: + + + static ActionNode* death_strike(PlayerbotAI* ai) + { + return new ActionNode("death strike", + /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* corpse_explosion(PlayerbotAI* ai) + { + return new ActionNode("corpse explosion", + /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* scourge_strike(PlayerbotAI* ai) + { + return new ActionNode("scourge strike", + /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), + /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), + /*C*/ NULL); + } +}; + + + NextAction** UnholyDKStrategy::getDefaultActions() + { + return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), new NextAction("scourge strike" , ACTION_NORMAL + 3), NULL); + } + +void UnholyDKStrategy::InitTriggers(std::list &triggers) +{ + GenericDKStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode( + "often", + NextAction::array(0, new NextAction("ghoul frenzy", ACTION_NORMAL + 2), NULL))); + + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("death pact", ACTION_EMERGENCY + 1), NULL))); +} + + +void UnholyDKAoeStrategy::InitTriggers(std::list &triggers) +{ + triggers.push_back(new TriggerNode( + "loot available", + NextAction::array(0, new NextAction("corpse explosion", ACTION_NORMAL + 1), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("death and decay", ACTION_NORMAL + 3), + new NextAction("corpse explosion", ACTION_NORMAL + 3), NULL))); +} + diff --git a/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h new file mode 100644 index 0000000000..c02075194e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h @@ -0,0 +1,29 @@ +#pragma once + +#include "GenericDKStrategy.h" +#include "../generic/CombatStrategy.h" + +namespace ai +{ + class UnholyDKStrategy : public GenericDKStrategy + { + public: + UnholyDKStrategy(PlayerbotAI* ai) : GenericDKStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "unholy"; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } + }; + + class UnholyDKAoeStrategy : public CombatStrategy + { + public: + UnholyDKAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + + public: + virtual void InitTriggers(std::list &triggers); + virtual string getName() { return "unholy aoe"; } + }; +} From 3617ca99f52338e6ba64b165812bc867ed740a57 Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Sat, 26 Mar 2022 07:38:19 -0400 Subject: [PATCH 4/9] Code compliance fixes - whitespace --- .../strategy/deathknight/BloodDKStrategy.cpp | 104 ++- .../strategy/deathknight/BloodDKStrategy.h | 6 +- .../strategy/deathknight/DKActions.cpp | 2 - .../strategy/deathknight/DKActions.h | 596 +++++++++--------- .../deathknight/DKAiObjectContext.cpp | 275 ++++---- .../strategy/deathknight/DKAiObjectContext.h | 2 +- .../strategy/deathknight/DKMultipliers.h | 4 +- .../strategy/deathknight/DKTriggers.h | 113 ++-- .../strategy/deathknight/FrostDKStrategy.cpp | 122 ++-- .../strategy/deathknight/FrostDKStrategy.h | 2 +- .../GenericDKNonCombatStrategy.cpp | 12 +- .../deathknight/GenericDKNonCombatStrategy.h | 2 + .../deathknight/GenericDKStrategy.cpp | 298 +++++---- .../strategy/deathknight/UnholyDKStrategy.cpp | 113 ++-- .../strategy/deathknight/UnholyDKStrategy.h | 4 +- 15 files changed, 824 insertions(+), 831 deletions(-) diff --git a/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp index 540f404f67..d1f01f71a6 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.cpp @@ -11,49 +11,48 @@ class BloodDKStrategyActionNodeFactory : public NamedObjectFactory BloodDKStrategyActionNodeFactory() { //creators["melee"] = &melee; - //creators["blood strike"] = &blood_strike; - creators["rune strike"] = &rune_strike; - creators["heart strike"] = &heart_strike; - creators["death strike"] = &death_strike; - //creators["death grip"] = &death_grip; - //creators["plague strike"] = &plague_strike; - //creators["pestilence"] = &pestilence; - //creators["icy touch"] = &icy_touch; - //creators["obliterate"] = &obliterate; - //creators["blood boil"] = &blood_boil; - //creators["mark of_blood"] = &mark_of_blood; - //creators["blood presence"] = &blood_presence; - //creators["rune tap"] = &rune_tap; - //creators["vampiric blood"] = &vampiric_blood; - //creators["death pact"] = &death_pact; - //creators["death rune_mastery"] = &death_rune_mastery; - //creators["hysteria"] = &hysteria; - //creators["dancing weapon"] = &dancing_weapon; - //creators["dark command"] = &dark_command; + //creators["blood strike"] = &blood_strike; + creators["rune strike"] = &rune_strike; + creators["heart strike"] = &heart_strike; + creators["death strike"] = &death_strike; + //creators["death grip"] = &death_grip; + //creators["plague strike"] = &plague_strike; + //creators["pestilence"] = &pestilence; + //creators["icy touch"] = &icy_touch; + //creators["obliterate"] = &obliterate; + //creators["blood boil"] = &blood_boil; + //creators["mark of_blood"] = &mark_of_blood; + //creators["blood presence"] = &blood_presence; + //creators["rune tap"] = &rune_tap; + //creators["vampiric blood"] = &vampiric_blood; + //creators["death pact"] = &death_pact; + //creators["death rune_mastery"] = &death_rune_mastery; + //creators["hysteria"] = &hysteria; + //creators["dancing weapon"] = &dancing_weapon; + //creators["dark command"] = &dark_command; } private: - static ActionNode* rune_strike(PlayerbotAI* ai) - { - return new ActionNode("rune strike", - /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), - /*A*/ NextAction::array(0, new NextAction("death coil"), NULL), - /*C*/ NULL); - } - static ActionNode* heart_strike(PlayerbotAI* ai) + static ActionNode* rune_strike(PlayerbotAI* ai) + { + return new ActionNode("rune strike", + /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("death coil"), NULL), + /*C*/ NULL); + } + static ActionNode* heart_strike(PlayerbotAI* ai) { return new ActionNode ("heart strike", /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), /*C*/ NULL); - } - static ActionNode* death_strike(PlayerbotAI* ai) - { - return new ActionNode("death strike", - /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), - /*A*/ NULL, - /*C*/ NULL); - } - + } + static ActionNode* death_strike(PlayerbotAI* ai) + { + return new ActionNode("death strike", + /*P*/ NextAction::array(0, new NextAction("frost presence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } }; BloodDKStrategy::BloodDKStrategy(PlayerbotAI* ai) : GenericDKStrategy(ai) @@ -63,11 +62,11 @@ BloodDKStrategy::BloodDKStrategy(PlayerbotAI* ai) : GenericDKStrategy(ai) NextAction** BloodDKStrategy::getDefaultActions() { - return NextAction::array(0, + return NextAction::array(0, new NextAction("melee", ACTION_NORMAL + 2), - new NextAction("heart strike", ACTION_NORMAL + 5), - new NextAction("death strike", ACTION_NORMAL + 4), - new NextAction("rune strike", ACTION_NORMAL + 3), NULL); + new NextAction("heart strike", ACTION_NORMAL + 5), + new NextAction("death strike", ACTION_NORMAL + 4), + new NextAction("rune strike", ACTION_NORMAL + 3), NULL); } void BloodDKStrategy::InitTriggers(std::list &triggers) @@ -75,26 +74,23 @@ void BloodDKStrategy::InitTriggers(std::list &triggers) GenericDKStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode( - "rune strike", - NextAction::array(0, new NextAction("rune strike", ACTION_NORMAL + 3), NULL))); + "rune strike", + NextAction::array(0, new NextAction("rune strike", ACTION_NORMAL + 3), NULL))); triggers.push_back(new TriggerNode( - "blood tap", - NextAction::array(0, new NextAction("blood tap", ACTION_HIGH + 5), NULL))); + "blood tap", + NextAction::array(0, new NextAction("blood tap", ACTION_HIGH + 5), NULL))); triggers.push_back(new TriggerNode( - "lose aggro", - NextAction::array(0, new NextAction("dark command", ACTION_HIGH + 3), NULL))); + "lose aggro", + NextAction::array(0, new NextAction("dark command", ACTION_HIGH + 3), NULL))); triggers.push_back(new TriggerNode( - "low health", - NextAction::array(0, - new NextAction("blood tap", ACTION_HIGH + 5), - new NextAction("vampiric blood", ACTION_HIGH + 3), - new NextAction("death strike", ACTION_HIGH + 4), NULL))); - - - + "low health", + NextAction::array(0, + new NextAction("blood tap", ACTION_HIGH + 5), + new NextAction("vampiric blood", ACTION_HIGH + 3), + new NextAction("death strike", ACTION_HIGH + 4), NULL))); } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h index d7e1cb35a6..8336bdfdd6 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/BloodDKStrategy.h @@ -13,8 +13,6 @@ namespace ai virtual void InitTriggers(std::list &triggers); virtual string getName() { return "blood"; } virtual NextAction** getDefaultActions(); - virtual int GetType() { return STRATEGY_TYPE_TANK | STRATEGY_TYPE_MELEE; } - }; - - + virtual int GetType() { return STRATEGY_TYPE_TANK | STRATEGY_TYPE_MELEE; } + }; } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp index 1caff14f38..b9699b938e 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.cpp @@ -2,6 +2,4 @@ #include "../../playerbot.h" #include "DKActions.h" - using namespace ai; - diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h index 2f6720170b..6a0378d05d 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h @@ -4,298 +4,320 @@ namespace ai { - class CastBloodPresenceAction : public CastBuffSpellAction { - public: - CastBloodPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blood presence") {} - }; - - class CastFrostPresenceAction : public CastBuffSpellAction { - public: - CastFrostPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "frost presence") {} - }; - - class CastUnholyPresenceAction : public CastBuffSpellAction { - public: - CastUnholyPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unholy presence") {} - }; - - class CastDeathchillAction : public CastBuffSpellAction { - public: - CastDeathchillAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "deathchill") {} - virtual NextAction** getPrerequisites() { - return NextAction::merge(NextAction::array(0, new NextAction("frost presence"), NULL), CastSpellAction::getPrerequisites()); - } - }; - - class CastDarkCommandAction : public CastBuffSpellAction { - public: - CastDarkCommandAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "dark command") {} - virtual NextAction** getPrerequisites() { - return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), NULL), CastSpellAction::getPrerequisites()); - } - }; - - BEGIN_RANGED_SPELL_ACTION(CastDeathGripAction, "death grip") - END_SPELL_ACTION() - - // Unholy presence - class CastUnholyMeleeSpellAction : public CastMeleeSpellAction { - public: - CastUnholyMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} - virtual NextAction** getPrerequisites() { - return NextAction::merge(NextAction::array(0, new NextAction("unholy presence"), NULL), CastMeleeSpellAction::getPrerequisites()); - } - }; - - - // Frost presence - class CastFrostMeleeSpellAction : public CastMeleeSpellAction { - public: - CastFrostMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} - virtual NextAction** getPrerequisites() { - return NextAction::merge(NextAction::array(0, new NextAction("frost presence"), NULL), CastMeleeSpellAction::getPrerequisites()); - } - }; - - // Blood presence - class CastBloodMeleeSpellAction : public CastMeleeSpellAction { - public: - CastBloodMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} - virtual NextAction** getPrerequisites() { - return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), NULL), CastMeleeSpellAction::getPrerequisites()); - } - }; - // a - class CastRuneStrikeAction : public CastMeleeSpellAction { - public: - CastRuneStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rune strike") {} - }; - //debuff - BEGIN_DEBUFF_ACTION(CastPestilenceAction, "pestilence") - END_SPELL_ACTION() - - //debuff - BEGIN_DEBUFF_ACTION(CastHowlingBlastAction, "howling blast") - END_SPELL_ACTION() - - //debuff it - BEGIN_DEBUFF_ACTION(CastIcyTouchAction, "icy touch") - END_SPELL_ACTION() - - - class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnAttackerAction - { - public: - CastIcyTouchOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "icy touch") {} - }; - - //debuff ps - BEGIN_DEBUFF_ACTION(CastPlagueStrikeAction, "plague strike") - END_SPELL_ACTION() - - - class CastPlagueStrikeOnAttackerAction : public CastDebuffSpellOnAttackerAction - { - public: - CastPlagueStrikeOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "plague strike") {} - }; - - //debuff - BEGIN_DEBUFF_ACTION(CastMarkOfBloodAction, "mark of blood") - END_SPELL_ACTION() - - class CastMarkOfBloodOnAttackerAction : public CastDebuffSpellOnAttackerAction - { - public: - CastMarkOfBloodOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "mark of blood") {} - }; - - class CastUnholyBlightAction : public CastBuffSpellAction - { - public: - CastUnholyBlightAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unholy blight") {} - }; - - class CastSummonGargoyleAction : public CastBuffSpellAction - { - public: - CastSummonGargoyleAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "summon gargoyle") {} - }; - - class CastGhoulFrenzyAction : public CastBuffSpellAction - { - public: - CastGhoulFrenzyAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "ghoul frenzy") {} - }; - - BEGIN_MELEE_SPELL_ACTION(CastCorpseExplosionAction, "corpse explosion") - END_SPELL_ACTION() - - BEGIN_MELEE_SPELL_ACTION(CastAntiMagicShellAction, "anti magic shell") - END_SPELL_ACTION() - - - BEGIN_MELEE_SPELL_ACTION(CastAntiMagicZoneAction, "anti magic zone") - END_SPELL_ACTION() - - - class CastChainsOfIceAction : public CastSpellAction { - public: - CastChainsOfIceAction(PlayerbotAI* ai) : CastSpellAction(ai, "chains of ice") {} - }; - - class CastHungeringColdAction : public CastMeleeSpellAction { - public: - CastHungeringColdAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "hungering cold") {} - }; - - class CastHeartStrikeAction : public CastMeleeSpellAction { - public: - CastHeartStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "heart strike") {} - }; - - class CastBloodStrikeAction : public CastMeleeSpellAction { - public: - CastBloodStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "blood strike") {} - }; - - class CastFrostStrikeAction : public CastMeleeSpellAction { - public: - CastFrostStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "frost strike") {} - }; - - class CastObliterateAction : public CastMeleeSpellAction { - public: - CastObliterateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "obliterate") {} - }; - - class CastDeathStrikeAction : public CastMeleeSpellAction { - public: - CastDeathStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "death strike") {} - }; - - class CastScourgeStrikeAction : public CastMeleeSpellAction { - public: - CastScourgeStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "scorgue strike") {} - }; - - class CastDeathCoilAction : public CastSpellAction { - public: - CastDeathCoilAction(PlayerbotAI* ai) : CastSpellAction(ai, "death coill") {} - }; - - class CastBloodBoilAction : public CastBuffSpellAction { - public: - CastBloodBoilAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blood boil") {} - }; - - class CastDeathAndDecayAction : public CastSpellAction { - public: - CastDeathAndDecayAction(PlayerbotAI* ai) : CastSpellAction(ai, "death and decay") {} - }; - - class CastHornOfWinterAction : public CastBuffSpellAction - { - public: - CastHornOfWinterAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "horn of winter") {} - }; - - class CastImprovedIcyTalonsAction : public CastBuffSpellAction - { - public: - CastImprovedIcyTalonsAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "improved icy talons") {} - }; - - class CastBoneShieldAction : public CastBuffSpellAction - { - public: - CastBoneShieldAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "bone shield") {} - }; - - class CastDeathPactAction : public CastBuffSpellAction - { - public: - CastDeathPactAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "death pact") {} - }; - - class CastDeathRuneMasteryAction : public CastBuffSpellAction - { - public: - CastDeathRuneMasteryAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "death rune mastery") {} - }; - - class CastDancingWeaponAction : public CastBuffSpellAction - { - public: - CastDancingWeaponAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "dancing weapon") {} - }; - - class CastEmpowerRuneWeaponAction : public CastBuffSpellAction - { - public: - CastEmpowerRuneWeaponAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "empower rune weapon") {} - }; - - class CastArmyOfTheDeadAction : public CastBuffSpellAction - { - public: - CastArmyOfTheDeadAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "army of the dead") {} - }; - - - class CastRaiseDeadAction : public CastBuffSpellAction - { - public: - CastRaiseDeadAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "raise dead") {} - }; - - class CastKillingMachineAction : public CastBuffSpellAction - { - public: - CastKillingMachineAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "killing machine") {} - }; - - class CastIceboundFortitudeAction : public CastBuffSpellAction - { - public: - CastIceboundFortitudeAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "icebound fortitude") {} - }; - - class CastUnbreakableArmorAction : public CastBuffSpellAction - { - public: - CastUnbreakableArmorAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unbreakable armor") {} - }; - - class CastVampiricBloodAction : public CastBuffSpellAction - { - public: - CastVampiricBloodAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "vampiric blood") {} - }; - - class CastMindFreezeAction : public CastMeleeSpellAction { - public: - CastMindFreezeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "mind freeze") {} - }; - - class CastStrangulateAction : public CastMeleeSpellAction { - public: - CastStrangulateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "strangulate") {} - }; + class CastBloodPresenceAction : public CastBuffSpellAction + { + public: + CastBloodPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blood presence") {} + }; + + class CastFrostPresenceAction : public CastBuffSpellAction + { + public: + CastFrostPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "frost presence") {} + }; + + class CastUnholyPresenceAction : public CastBuffSpellAction + { + public: + CastUnholyPresenceAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unholy presence") {} + }; + + class CastDeathchillAction : public CastBuffSpellAction + { + public: + CastDeathchillAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "deathchill") {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("frost presence"), NULL), CastSpellAction::getPrerequisites()); + } + }; + + class CastDarkCommandAction : public CastBuffSpellAction + { + public: + CastDarkCommandAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "dark command") {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), NULL), CastSpellAction::getPrerequisites()); + } + }; + + BEGIN_RANGED_SPELL_ACTION(CastDeathGripAction, "death grip") + END_SPELL_ACTION() + + // Unholy presence + class CastUnholyMeleeSpellAction : public CastMeleeSpellAction { + public: + CastUnholyMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("unholy presence"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + + + // Frost presence + class CastFrostMeleeSpellAction : public CastMeleeSpellAction + { + public: + CastFrostMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("frost presence"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + + // Blood presence + class CastBloodMeleeSpellAction : public CastMeleeSpellAction + { + public: + CastBloodMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + virtual NextAction** getPrerequisites() { + return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), NULL), CastMeleeSpellAction::getPrerequisites()); + } + }; + // a + class CastRuneStrikeAction : public CastMeleeSpellAction + { + public: + CastRuneStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rune strike") {} + }; + //debuff + BEGIN_DEBUFF_ACTION(CastPestilenceAction, "pestilence") + END_SPELL_ACTION() + + //debuff + BEGIN_DEBUFF_ACTION(CastHowlingBlastAction, "howling blast") + END_SPELL_ACTION() + + //debuff it + BEGIN_DEBUFF_ACTION(CastIcyTouchAction, "icy touch") + END_SPELL_ACTION() + + + class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastIcyTouchOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "icy touch") {} + }; + + //debuff ps + BEGIN_DEBUFF_ACTION(CastPlagueStrikeAction, "plague strike") + END_SPELL_ACTION() + + + class CastPlagueStrikeOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastPlagueStrikeOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "plague strike") {} + }; + + //debuff + BEGIN_DEBUFF_ACTION(CastMarkOfBloodAction, "mark of blood") + END_SPELL_ACTION() + + class CastMarkOfBloodOnAttackerAction : public CastDebuffSpellOnAttackerAction + { + public: + CastMarkOfBloodOnAttackerAction(PlayerbotAI* ai) : CastDebuffSpellOnAttackerAction(ai, "mark of blood") {} + }; + + class CastUnholyBlightAction : public CastBuffSpellAction + { + public: + CastUnholyBlightAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unholy blight") {} + }; + + class CastSummonGargoyleAction : public CastBuffSpellAction + { + public: + CastSummonGargoyleAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "summon gargoyle") {} + }; + + class CastGhoulFrenzyAction : public CastBuffSpellAction + { + public: + CastGhoulFrenzyAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "ghoul frenzy") {} + }; + + BEGIN_MELEE_SPELL_ACTION(CastCorpseExplosionAction, "corpse explosion") + END_SPELL_ACTION() + + BEGIN_MELEE_SPELL_ACTION(CastAntiMagicShellAction, "anti magic shell") + END_SPELL_ACTION() + + + BEGIN_MELEE_SPELL_ACTION(CastAntiMagicZoneAction, "anti magic zone") + END_SPELL_ACTION() + + + class CastChainsOfIceAction : public CastSpellAction + { + public: + CastChainsOfIceAction(PlayerbotAI* ai) : CastSpellAction(ai, "chains of ice") {} + }; + + class CastHungeringColdAction : public CastMeleeSpellAction + { + public: + CastHungeringColdAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "hungering cold") {} + }; + + class CastHeartStrikeAction : public CastMeleeSpellAction + { + public: + CastHeartStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "heart strike") {} + }; + + class CastBloodStrikeAction : public CastMeleeSpellAction + { + public: + CastBloodStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "blood strike") {} + }; + + class CastFrostStrikeAction : public CastMeleeSpellAction + { + public: + CastFrostStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "frost strike") {} + }; + + class CastObliterateAction : public CastMeleeSpellAction + { + public: + CastObliterateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "obliterate") {} + }; + + class CastDeathStrikeAction : public CastMeleeSpellAction + { + public: + CastDeathStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "death strike") {} + }; + + class CastScourgeStrikeAction : public CastMeleeSpellAction + { + public: + CastScourgeStrikeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "scorgue strike") {} + }; + + class CastDeathCoilAction : public CastSpellAction + { + public: + CastDeathCoilAction(PlayerbotAI* ai) : CastSpellAction(ai, "death coill") {} + }; + + class CastBloodBoilAction : public CastBuffSpellAction + { + public: + CastBloodBoilAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "blood boil") {} + }; + + class CastDeathAndDecayAction : public CastSpellAction + { + public: + CastDeathAndDecayAction(PlayerbotAI* ai) : CastSpellAction(ai, "death and decay") {} + }; + + class CastHornOfWinterAction : public CastBuffSpellAction + { + public: + CastHornOfWinterAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "horn of winter") {} + }; + + class CastImprovedIcyTalonsAction : public CastBuffSpellAction + { + public: + CastImprovedIcyTalonsAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "improved icy talons") {} + }; + + class CastBoneShieldAction : public CastBuffSpellAction + { + public: + CastBoneShieldAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "bone shield") {} + }; + + class CastDeathPactAction : public CastBuffSpellAction + { + public: + CastDeathPactAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "death pact") {} + }; + + class CastDeathRuneMasteryAction : public CastBuffSpellAction + { + public: + CastDeathRuneMasteryAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "death rune mastery") {} + }; + + class CastDancingWeaponAction : public CastBuffSpellAction + { + public: + CastDancingWeaponAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "dancing weapon") {} + }; + + class CastEmpowerRuneWeaponAction : public CastBuffSpellAction + { + public: + CastEmpowerRuneWeaponAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "empower rune weapon") {} + }; + + class CastArmyOfTheDeadAction : public CastBuffSpellAction + { + public: + CastArmyOfTheDeadAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "army of the dead") {} + }; + + class CastRaiseDeadAction : public CastBuffSpellAction + { + public: + CastRaiseDeadAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "raise dead") {} + }; + + class CastKillingMachineAction : public CastBuffSpellAction + { + public: + CastKillingMachineAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "killing machine") {} + }; + + class CastIceboundFortitudeAction : public CastBuffSpellAction + { + public: + CastIceboundFortitudeAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "icebound fortitude") {} + }; + + class CastUnbreakableArmorAction : public CastBuffSpellAction + { + public: + CastUnbreakableArmorAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "unbreakable armor") {} + }; + + class CastVampiricBloodAction : public CastBuffSpellAction + { + public: + CastVampiricBloodAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "vampiric blood") {} + }; + + class CastMindFreezeAction : public CastMeleeSpellAction + { + public: + CastMindFreezeAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "mind freeze") {} + }; + + class CastStrangulateAction : public CastMeleeSpellAction + { + public: + CastStrangulateAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "strangulate") {} + }; class CastMindFreezeOnEnemyHealerAction : public CastSpellOnEnemyHealerAction { public: - CastMindFreezeOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "mind freeze") {} + CastMindFreezeOnEnemyHealerAction(PlayerbotAI* ai) : CastSpellOnEnemyHealerAction(ai, "mind freeze") {} }; - class CastRuneTapAction : public CastMeleeSpellAction { - public: - CastRuneTapAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rune tap") {} + class CastRuneTapAction : public CastMeleeSpellAction + { + public: + CastRuneTapAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "rune tap") {} + }; - }; - class CastBloodTapAction : public CastMeleeSpellAction { - public: - CastBloodTapAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "blood tap") {} - }; + class CastBloodTapAction : public CastMeleeSpellAction + { + public: + CastBloodTapAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "blood tap") {} + }; } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp index 9f7b837523..ead202a4bf 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.cpp @@ -13,7 +13,6 @@ using namespace ai; - namespace ai { namespace DK @@ -27,33 +26,33 @@ namespace ai { creators["nc"] = &DK::StrategyFactoryInternal::nc; creators["pull"] = &DK::StrategyFactoryInternal::pull; - creators["frost aoe"] = &DK::StrategyFactoryInternal::frost_aoe; - creators["unholy aoe"] = &DK::StrategyFactoryInternal::unholy_aoe; + creators["frost aoe"] = &DK::StrategyFactoryInternal::frost_aoe; + creators["unholy aoe"] = &DK::StrategyFactoryInternal::unholy_aoe; } private: static Strategy* nc(PlayerbotAI* ai) { return new GenericDKNonCombatStrategy(ai); } static Strategy* pull(PlayerbotAI* ai) { return new PullStrategy(ai, "icy touch"); } - static Strategy* frost_aoe(PlayerbotAI* ai) { return new FrostDKAoeStrategy(ai); } - static Strategy* unholy_aoe(PlayerbotAI* ai) { return new UnholyDKAoeStrategy(ai); } + static Strategy* frost_aoe(PlayerbotAI* ai) { return new FrostDKAoeStrategy(ai); } + static Strategy* unholy_aoe(PlayerbotAI* ai) { return new UnholyDKAoeStrategy(ai); } }; class CombatStrategyFactoryInternal : public NamedObjectContext { public: - CombatStrategyFactoryInternal() : NamedObjectContext(false, true) + CombatStrategyFactoryInternal() : NamedObjectContext(false, true) { creators["tank"] = &DK::CombatStrategyFactoryInternal::blood; - creators["blood"] = &DK::CombatStrategyFactoryInternal::blood; + creators["blood"] = &DK::CombatStrategyFactoryInternal::blood; creators["frost"] = &DK::CombatStrategyFactoryInternal::frost_dps; - creators["unholy"] = &DK::CombatStrategyFactoryInternal::unholy_dps; + creators["unholy"] = &DK::CombatStrategyFactoryInternal::unholy_dps; } private: static Strategy* frost_dps(PlayerbotAI* ai) { return new FrostDKStrategy(ai); } static Strategy* unholy_dps(PlayerbotAI* ai) { return new UnholyDKStrategy(ai); } static Strategy* tank(PlayerbotAI* ai) { return new BloodDKStrategy(ai); } - static Strategy* blood(PlayerbotAI* ai) { return new BloodDKStrategy(ai); } + static Strategy* blood(PlayerbotAI* ai) { return new BloodDKStrategy(ai); } }; class DKBuffStrategyFactoryInternal : public NamedObjectContext @@ -61,7 +60,6 @@ namespace ai public: DKBuffStrategyFactoryInternal() : NamedObjectContext(false, true) { - creators["bdps"] = &DK::DKBuffStrategyFactoryInternal::bdps; } @@ -81,49 +79,47 @@ namespace ai class TriggerFactoryInternal : public NamedObjectContext { public: - TriggerFactoryInternal() + TriggerFactoryInternal() { creators["bone shield"] = &TriggerFactoryInternal::bone_shield; creators["pestilence"] = &TriggerFactoryInternal::pestilence; creators["blood strike"] = &TriggerFactoryInternal::blood_strike; - creators["plague strike"] = &TriggerFactoryInternal::plague_strike; - creators["plague strike on attacker"] = &TriggerFactoryInternal::plague_strike_on_attacker; + creators["plague strike"] = &TriggerFactoryInternal::plague_strike; + creators["plague strike on attacker"] = &TriggerFactoryInternal::plague_strike_on_attacker; creators["icy touch"] = &TriggerFactoryInternal::icy_touch; - creators["death coil"] = &TriggerFactoryInternal::death_coil; - creators["icy touch on attacker"] = &TriggerFactoryInternal::icy_touch_on_attacker; + creators["death coil"] = &TriggerFactoryInternal::death_coil; + creators["icy touch on attacker"] = &TriggerFactoryInternal::icy_touch_on_attacker; creators["improved icy talons"] = &TriggerFactoryInternal::improved_icy_talons; creators["plague strike"] = &TriggerFactoryInternal::plague_strike; creators["horn of winter"] = &TriggerFactoryInternal::horn_of_winter; creators["mind freeze"] = &TriggerFactoryInternal::mind_freeze; creators["mind freeze on enemy healer"] = &TriggerFactoryInternal::mind_freeze_on_enemy_healer; - creators["strangulate"] = &TriggerFactoryInternal::strangulate; - creators["strangulate on enemy healer"] = &TriggerFactoryInternal::strangulate_on_enemy_healer; - creators["blood tap"] = &TriggerFactoryInternal::blood_tap; - creators["raise dead"] = &TriggerFactoryInternal::raise_dead; - creators["chains of ice"] = &TriggerFactoryInternal::chains_of_ice; + creators["strangulate"] = &TriggerFactoryInternal::strangulate; + creators["strangulate on enemy healer"] = &TriggerFactoryInternal::strangulate_on_enemy_healer; + creators["blood tap"] = &TriggerFactoryInternal::blood_tap; + creators["raise dead"] = &TriggerFactoryInternal::raise_dead; + creators["chains of ice"] = &TriggerFactoryInternal::chains_of_ice; } private: static Trigger* bone_shield(PlayerbotAI* ai) { return new BoneShieldTrigger(ai); } static Trigger* pestilence(PlayerbotAI* ai) { return new PestilenceTrigger(ai); } static Trigger* blood_strike(PlayerbotAI* ai) { return new BloodStrikeTrigger(ai); } - static Trigger* plague_strike(PlayerbotAI* ai) { return new PlagueStrikeDebuffTrigger(ai); } - static Trigger* plague_strike_on_attacker(PlayerbotAI* ai) { return new PlagueStrikeDebuffOnAttackerTrigger(ai); } + static Trigger* plague_strike(PlayerbotAI* ai) { return new PlagueStrikeDebuffTrigger(ai); } + static Trigger* plague_strike_on_attacker(PlayerbotAI* ai) { return new PlagueStrikeDebuffOnAttackerTrigger(ai); } static Trigger* icy_touch(PlayerbotAI* ai) { return new IcyTouchDebuffTrigger(ai); } - static Trigger* death_coil(PlayerbotAI* ai) { return new DeathCoilTrigger(ai); } - static Trigger* icy_touch_on_attacker(PlayerbotAI* ai) { return new IcyTouchDebuffOnAttackerTrigger(ai); } + static Trigger* death_coil(PlayerbotAI* ai) { return new DeathCoilTrigger(ai); } + static Trigger* icy_touch_on_attacker(PlayerbotAI* ai) { return new IcyTouchDebuffOnAttackerTrigger(ai); } static Trigger* improved_icy_talons(PlayerbotAI* ai) { return new ImprovedIcyTalonsTrigger(ai); } static Trigger* horn_of_winter(PlayerbotAI* ai) { return new HornOfWinterTrigger(ai); } static Trigger* mind_freeze(PlayerbotAI* ai) { return new MindFreezeInterruptSpellTrigger(ai); } static Trigger* mind_freeze_on_enemy_healer(PlayerbotAI* ai) { return new MindFreezeOnEnemyHealerTrigger(ai); } - static Trigger* strangulate(PlayerbotAI* ai) { return new StrangulateInterruptSpellTrigger(ai); } - static Trigger* strangulate_on_enemy_healer(PlayerbotAI* ai) { return new StrangulateOnEnemyHealerTrigger(ai); } - static Trigger* blood_tap(PlayerbotAI* ai) { return new BloodTapTrigger(ai); } - static Trigger* raise_dead(PlayerbotAI* ai) { return new RaiseDeadTrigger(ai); } - static Trigger* chains_of_ice(PlayerbotAI* ai) { return new ChainsOfIceSnareTrigger(ai); } - - - }; + static Trigger* strangulate(PlayerbotAI* ai) { return new StrangulateInterruptSpellTrigger(ai); } + static Trigger* strangulate_on_enemy_healer(PlayerbotAI* ai) { return new StrangulateOnEnemyHealerTrigger(ai); } + static Trigger* blood_tap(PlayerbotAI* ai) { return new BloodTapTrigger(ai); } + static Trigger* raise_dead(PlayerbotAI* ai) { return new RaiseDeadTrigger(ai); } + static Trigger* chains_of_ice(PlayerbotAI* ai) { return new ChainsOfIceSnareTrigger(ai); } + }; }; }; @@ -139,119 +135,116 @@ namespace ai public: AiObjectContextInternal() { - - // Unholy - creators["bone shield"] = &AiObjectContextInternal::bone_shield; - creators["plague strike"] = &AiObjectContextInternal::plague_strike; - creators["plague strike on attacker"] = &AiObjectContextInternal::plague_strike_on_attacker; - creators["death grip"] = &AiObjectContextInternal::death_grip; - creators["death coil"] = &AiObjectContextInternal::death_coil; - creators["death strike"] = &AiObjectContextInternal::death_strike; - creators["unholy blight"] = &AiObjectContextInternal::unholy_blight; - creators["scourge strike"] = &AiObjectContextInternal::scourge_strike; - creators["death and decay"] = &AiObjectContextInternal::death_and_decay; - creators["unholy pressence"] = &AiObjectContextInternal::unholy_pressence; - creators["raise dead"] = &AiObjectContextInternal::raise_dead; - creators["army of the dead"] = &AiObjectContextInternal::army_of_the_dead; - creators["summon gargoyle"] = &AiObjectContextInternal::summon_gargoyle; - creators["anti magic shell"] = &AiObjectContextInternal::anti_magic_shell; - creators["anti magic zone"] = &AiObjectContextInternal::anti_magic_zone; - creators["ghoul frenzy"] = &AiObjectContextInternal::ghoul_frenzy; - creators["corpse explosion"] = &AiObjectContextInternal::corpse_explosion; - // Frost - creators["icy touch"] = &AiObjectContextInternal::icy_touch; - creators["icy touch on attacker"] = &AiObjectContextInternal::icy_touch_on_attacker; - creators["obliterate"] = &AiObjectContextInternal::obliterate; - creators["howling blast"] = &AiObjectContextInternal::howling_blast; - creators["frost strike"] = &AiObjectContextInternal::frost_strike; - creators["chains of ice"] = &AiObjectContextInternal::chains_of_ice; - creators["rune strike"] = &AiObjectContextInternal::rune_strike; - //creators["icy clutch"] = &AiObjectContextInternal::icy_clutch; - creators["horn of winter"] = &AiObjectContextInternal::horn_of_winter; - creators["killing machine"] = &AiObjectContextInternal::killing_machine; - creators["frost presence"] = &AiObjectContextInternal::frost_presence; - creators["deathchill"] = &AiObjectContextInternal::deathchill; - creators["icebound fortitude"] = &AiObjectContextInternal::icebound_fortitude; - creators["mind freeze"] = &AiObjectContextInternal::mind_freeze; - creators["empower rune weapon"] = &AiObjectContextInternal::empower_rune_weapon; - creators["hungering cold"] = &AiObjectContextInternal::hungering_cold; - creators["unbreakable armor"] = &AiObjectContextInternal::unbreakable_armor; - creators["improved icy talons"] = &AiObjectContextInternal::improved_icy_talons; - // blood - creators["blood strike"] = &AiObjectContextInternal::blood_strike; - creators["blood tap"] = &AiObjectContextInternal::blood_tap; - creators["pestilence"] = &AiObjectContextInternal::pestilence; - creators["strangulate"] = &AiObjectContextInternal::strangulate; - creators["blood boil"] = &AiObjectContextInternal::blood_boil; - creators["heart strike"] = &AiObjectContextInternal::heart_strike; - creators["mark of_blood"] = &AiObjectContextInternal::mark_of_blood; - creators["blood presence"] = &AiObjectContextInternal::blood_presence; - creators["rune tap"] = &AiObjectContextInternal::rune_tap; - creators["vampiric blood"] = &AiObjectContextInternal::vampiric_blood; - creators["death pact"] = &AiObjectContextInternal::death_pact; - creators["death rune_mastery"] = &AiObjectContextInternal::death_rune_mastery; - //creators["hysteria"] = &AiObjectContextInternal::hysteria; - creators["dancing weapon"] = &AiObjectContextInternal::dancing_weapon; - creators["dark command"] = &AiObjectContextInternal::dark_command; + // Unholy + creators["bone shield"] = &AiObjectContextInternal::bone_shield; + creators["plague strike"] = &AiObjectContextInternal::plague_strike; + creators["plague strike on attacker"] = &AiObjectContextInternal::plague_strike_on_attacker; + creators["death grip"] = &AiObjectContextInternal::death_grip; + creators["death coil"] = &AiObjectContextInternal::death_coil; + creators["death strike"] = &AiObjectContextInternal::death_strike; + creators["unholy blight"] = &AiObjectContextInternal::unholy_blight; + creators["scourge strike"] = &AiObjectContextInternal::scourge_strike; + creators["death and decay"] = &AiObjectContextInternal::death_and_decay; + creators["unholy pressence"] = &AiObjectContextInternal::unholy_pressence; + creators["raise dead"] = &AiObjectContextInternal::raise_dead; + creators["army of the dead"] = &AiObjectContextInternal::army_of_the_dead; + creators["summon gargoyle"] = &AiObjectContextInternal::summon_gargoyle; + creators["anti magic shell"] = &AiObjectContextInternal::anti_magic_shell; + creators["anti magic zone"] = &AiObjectContextInternal::anti_magic_zone; + creators["ghoul frenzy"] = &AiObjectContextInternal::ghoul_frenzy; + creators["corpse explosion"] = &AiObjectContextInternal::corpse_explosion; + // Frost + creators["icy touch"] = &AiObjectContextInternal::icy_touch; + creators["icy touch on attacker"] = &AiObjectContextInternal::icy_touch_on_attacker; + creators["obliterate"] = &AiObjectContextInternal::obliterate; + creators["howling blast"] = &AiObjectContextInternal::howling_blast; + creators["frost strike"] = &AiObjectContextInternal::frost_strike; + creators["chains of ice"] = &AiObjectContextInternal::chains_of_ice; + creators["rune strike"] = &AiObjectContextInternal::rune_strike; + //creators["icy clutch"] = &AiObjectContextInternal::icy_clutch; + creators["horn of winter"] = &AiObjectContextInternal::horn_of_winter; + creators["killing machine"] = &AiObjectContextInternal::killing_machine; + creators["frost presence"] = &AiObjectContextInternal::frost_presence; + creators["deathchill"] = &AiObjectContextInternal::deathchill; + creators["icebound fortitude"] = &AiObjectContextInternal::icebound_fortitude; + creators["mind freeze"] = &AiObjectContextInternal::mind_freeze; + creators["empower rune weapon"] = &AiObjectContextInternal::empower_rune_weapon; + creators["hungering cold"] = &AiObjectContextInternal::hungering_cold; + creators["unbreakable armor"] = &AiObjectContextInternal::unbreakable_armor; + creators["improved icy talons"] = &AiObjectContextInternal::improved_icy_talons; + // blood + creators["blood strike"] = &AiObjectContextInternal::blood_strike; + creators["blood tap"] = &AiObjectContextInternal::blood_tap; + creators["pestilence"] = &AiObjectContextInternal::pestilence; + creators["strangulate"] = &AiObjectContextInternal::strangulate; + creators["blood boil"] = &AiObjectContextInternal::blood_boil; + creators["heart strike"] = &AiObjectContextInternal::heart_strike; + creators["mark of_blood"] = &AiObjectContextInternal::mark_of_blood; + creators["blood presence"] = &AiObjectContextInternal::blood_presence; + creators["rune tap"] = &AiObjectContextInternal::rune_tap; + creators["vampiric blood"] = &AiObjectContextInternal::vampiric_blood; + creators["death pact"] = &AiObjectContextInternal::death_pact; + creators["death rune_mastery"] = &AiObjectContextInternal::death_rune_mastery; + //creators["hysteria"] = &AiObjectContextInternal::hysteria; + creators["dancing weapon"] = &AiObjectContextInternal::dancing_weapon; + creators["dark command"] = &AiObjectContextInternal::dark_command; } private: - - // Unholy - static Action* bone_shield(PlayerbotAI* ai) { return new CastBoneShieldAction(ai); } - static Action* plague_strike(PlayerbotAI* ai) { return new CastPlagueStrikeAction(ai); } - static Action* plague_strike_on_attacker(PlayerbotAI* ai) { return new CastPlagueStrikeOnAttackerAction(ai); } - static Action* death_grip(PlayerbotAI* ai) { return new CastDeathGripAction(ai); } - static Action* death_coil(PlayerbotAI* ai) { return new CastDeathCoilAction(ai); } - static Action* death_strike(PlayerbotAI* ai) { return new CastDeathStrikeAction(ai); } - static Action* unholy_blight(PlayerbotAI* ai) { return new CastUnholyBlightAction(ai); } - static Action* scourge_strike(PlayerbotAI* ai) { return new CastScourgeStrikeAction(ai); } - static Action* death_and_decay(PlayerbotAI* ai) { return new CastDeathAndDecayAction(ai); } - static Action* unholy_pressence(PlayerbotAI* ai) { return new CastUnholyPresenceAction(ai); } - static Action* raise_dead(PlayerbotAI* ai) { return new CastRaiseDeadAction(ai); } - static Action* army_of_the_dead(PlayerbotAI* ai) { return new CastArmyOfTheDeadAction(ai); } - static Action* summon_gargoyle(PlayerbotAI* ai) { return new CastSummonGargoyleAction(ai); } - static Action* anti_magic_shell(PlayerbotAI* ai) { return new CastAntiMagicShellAction(ai); } - static Action* anti_magic_zone(PlayerbotAI* ai) { return new CastAntiMagicZoneAction(ai); } - static Action* ghoul_frenzy(PlayerbotAI* ai) { return new CastGhoulFrenzyAction(ai); } - static Action* corpse_explosion(PlayerbotAI* ai) { return new CastCorpseExplosionAction(ai); } - // Frost - static Action* icy_touch(PlayerbotAI* ai) { return new CastIcyTouchAction(ai); } - static Action* icy_touch_on_attacker(PlayerbotAI* ai) { return new CastIcyTouchOnAttackerAction(ai); } - static Action* obliterate(PlayerbotAI* ai) { return new CastObliterateAction(ai); } - static Action* howling_blast(PlayerbotAI* ai) { return new CastHowlingBlastAction(ai); } - static Action* frost_strike(PlayerbotAI* ai) { return new CastFrostStrikeAction(ai); } - static Action* chains_of_ice(PlayerbotAI* ai) { return new CastChainsOfIceAction(ai); } - static Action* rune_strike(PlayerbotAI* ai) { return new CastRuneStrikeAction(ai); } - //static Action* icy_clutch(PlayerbotAI* ai) { return new CastIcyClutchAction(ai); } - static Action* horn_of_winter(PlayerbotAI* ai) { return new CastHornOfWinterAction(ai); } - static Action* killing_machine(PlayerbotAI* ai) { return new CastKillingMachineAction(ai); } - static Action* frost_presence(PlayerbotAI* ai) { return new CastFrostPresenceAction(ai); } - static Action* deathchill(PlayerbotAI* ai) { return new CastDeathchillAction(ai); } - static Action* icebound_fortitude(PlayerbotAI* ai) { return new CastIceboundFortitudeAction(ai); } - static Action* mind_freeze(PlayerbotAI* ai) { return new CastMindFreezeAction(ai); } - static Action* empower_rune_weapon(PlayerbotAI* ai) { return new CastEmpowerRuneWeaponAction(ai); } - static Action* hungering_cold(PlayerbotAI* ai) { return new CastHungeringColdAction(ai); } - static Action* unbreakable_armor(PlayerbotAI* ai) { return new CastUnbreakableArmorAction(ai); } - static Action* improved_icy_talons(PlayerbotAI* ai) { return new CastImprovedIcyTalonsAction(ai); } - // blood - static Action* blood_strike(PlayerbotAI* ai) { return new CastBloodStrikeAction(ai); } - static Action* blood_tap(PlayerbotAI* ai) { return new CastBloodTapAction(ai); } - static Action* pestilence(PlayerbotAI* ai) { return new CastPestilenceAction(ai); } - static Action* strangulate(PlayerbotAI* ai) { return new CastStrangulateAction(ai); } - static Action* blood_boil(PlayerbotAI* ai) { return new CastBloodBoilAction(ai); } - static Action* heart_strike(PlayerbotAI* ai) { return new CastHeartStrikeAction(ai); } - static Action* mark_of_blood(PlayerbotAI* ai) { return new CastMarkOfBloodAction(ai); } - static Action* blood_presence(PlayerbotAI* ai) { return new CastBloodPresenceAction(ai); } - static Action* rune_tap(PlayerbotAI* ai) { return new CastRuneTapAction(ai); } - static Action* vampiric_blood(PlayerbotAI* ai) { return new CastVampiricBloodAction(ai); } - static Action* death_pact(PlayerbotAI* ai) { return new CastDeathPactAction(ai); } - static Action* death_rune_mastery(PlayerbotAI* ai) { return new CastDeathRuneMasteryAction(ai); } - //static Action* hysteria(PlayerbotAI* ai) { return new CastHysteriaAction(ai); } - static Action* dancing_weapon(PlayerbotAI* ai) { return new CastDancingWeaponAction(ai); } - static Action* dark_command(PlayerbotAI* ai) { return new CastDarkCommandAction(ai); } + // Unholy + static Action* bone_shield(PlayerbotAI* ai) { return new CastBoneShieldAction(ai); } + static Action* plague_strike(PlayerbotAI* ai) { return new CastPlagueStrikeAction(ai); } + static Action* plague_strike_on_attacker(PlayerbotAI* ai) { return new CastPlagueStrikeOnAttackerAction(ai); } + static Action* death_grip(PlayerbotAI* ai) { return new CastDeathGripAction(ai); } + static Action* death_coil(PlayerbotAI* ai) { return new CastDeathCoilAction(ai); } + static Action* death_strike(PlayerbotAI* ai) { return new CastDeathStrikeAction(ai); } + static Action* unholy_blight(PlayerbotAI* ai) { return new CastUnholyBlightAction(ai); } + static Action* scourge_strike(PlayerbotAI* ai) { return new CastScourgeStrikeAction(ai); } + static Action* death_and_decay(PlayerbotAI* ai) { return new CastDeathAndDecayAction(ai); } + static Action* unholy_pressence(PlayerbotAI* ai) { return new CastUnholyPresenceAction(ai); } + static Action* raise_dead(PlayerbotAI* ai) { return new CastRaiseDeadAction(ai); } + static Action* army_of_the_dead(PlayerbotAI* ai) { return new CastArmyOfTheDeadAction(ai); } + static Action* summon_gargoyle(PlayerbotAI* ai) { return new CastSummonGargoyleAction(ai); } + static Action* anti_magic_shell(PlayerbotAI* ai) { return new CastAntiMagicShellAction(ai); } + static Action* anti_magic_zone(PlayerbotAI* ai) { return new CastAntiMagicZoneAction(ai); } + static Action* ghoul_frenzy(PlayerbotAI* ai) { return new CastGhoulFrenzyAction(ai); } + static Action* corpse_explosion(PlayerbotAI* ai) { return new CastCorpseExplosionAction(ai); } + // Frost + static Action* icy_touch(PlayerbotAI* ai) { return new CastIcyTouchAction(ai); } + static Action* icy_touch_on_attacker(PlayerbotAI* ai) { return new CastIcyTouchOnAttackerAction(ai); } + static Action* obliterate(PlayerbotAI* ai) { return new CastObliterateAction(ai); } + static Action* howling_blast(PlayerbotAI* ai) { return new CastHowlingBlastAction(ai); } + static Action* frost_strike(PlayerbotAI* ai) { return new CastFrostStrikeAction(ai); } + static Action* chains_of_ice(PlayerbotAI* ai) { return new CastChainsOfIceAction(ai); } + static Action* rune_strike(PlayerbotAI* ai) { return new CastRuneStrikeAction(ai); } + //static Action* icy_clutch(PlayerbotAI* ai) { return new CastIcyClutchAction(ai); } + static Action* horn_of_winter(PlayerbotAI* ai) { return new CastHornOfWinterAction(ai); } + static Action* killing_machine(PlayerbotAI* ai) { return new CastKillingMachineAction(ai); } + static Action* frost_presence(PlayerbotAI* ai) { return new CastFrostPresenceAction(ai); } + static Action* deathchill(PlayerbotAI* ai) { return new CastDeathchillAction(ai); } + static Action* icebound_fortitude(PlayerbotAI* ai) { return new CastIceboundFortitudeAction(ai); } + static Action* mind_freeze(PlayerbotAI* ai) { return new CastMindFreezeAction(ai); } + static Action* empower_rune_weapon(PlayerbotAI* ai) { return new CastEmpowerRuneWeaponAction(ai); } + static Action* hungering_cold(PlayerbotAI* ai) { return new CastHungeringColdAction(ai); } + static Action* unbreakable_armor(PlayerbotAI* ai) { return new CastUnbreakableArmorAction(ai); } + static Action* improved_icy_talons(PlayerbotAI* ai) { return new CastImprovedIcyTalonsAction(ai); } + // blood + static Action* blood_strike(PlayerbotAI* ai) { return new CastBloodStrikeAction(ai); } + static Action* blood_tap(PlayerbotAI* ai) { return new CastBloodTapAction(ai); } + static Action* pestilence(PlayerbotAI* ai) { return new CastPestilenceAction(ai); } + static Action* strangulate(PlayerbotAI* ai) { return new CastStrangulateAction(ai); } + static Action* blood_boil(PlayerbotAI* ai) { return new CastBloodBoilAction(ai); } + static Action* heart_strike(PlayerbotAI* ai) { return new CastHeartStrikeAction(ai); } + static Action* mark_of_blood(PlayerbotAI* ai) { return new CastMarkOfBloodAction(ai); } + static Action* blood_presence(PlayerbotAI* ai) { return new CastBloodPresenceAction(ai); } + static Action* rune_tap(PlayerbotAI* ai) { return new CastRuneTapAction(ai); } + static Action* vampiric_blood(PlayerbotAI* ai) { return new CastVampiricBloodAction(ai); } + static Action* death_pact(PlayerbotAI* ai) { return new CastDeathPactAction(ai); } + static Action* death_rune_mastery(PlayerbotAI* ai) { return new CastDeathRuneMasteryAction(ai); } + //static Action* hysteria(PlayerbotAI* ai) { return new CastHysteriaAction(ai); } + static Action* dancing_weapon(PlayerbotAI* ai) { return new CastDancingWeaponAction(ai); } + static Action* dark_command(PlayerbotAI* ai) { return new CastDarkCommandAction(ai); } static Action* mind_freeze_on_enemy_healer(PlayerbotAI* ai) { return new CastMindFreezeOnEnemyHealerAction(ai); } - }; }; }; diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h index b5b86ca7c9..4a89b598a1 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKAiObjectContext.h @@ -9,4 +9,4 @@ namespace ai public: DKAiObjectContext(PlayerbotAI* ai); }; -} \ No newline at end of file +} diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h b/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h index 7cfbdd46e8..4294e4e899 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKMultipliers.h @@ -1,6 +1,4 @@ #pragma once namespace ai -{ - -} \ No newline at end of file +{ } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h index 816f0e3d8f..23d38fcab6 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h @@ -3,23 +3,22 @@ namespace ai { - BUFF_TRIGGER(HornOfWinterTrigger, "horn of winter"); BUFF_TRIGGER(BoneShieldTrigger, "bone shield"); BUFF_TRIGGER(ImprovedIcyTalonsTrigger, "improved icy talons"); DEBUFF_TRIGGER(PlagueStrikeDebuffTrigger, "plague strike"); DEBUFF_TRIGGER(IcyTouchDebuffTrigger, "icy touch"); - class PlagueStrikeDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger - { - public: - PlagueStrikeDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "plague strike") {} - }; - class IcyTouchDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger - { - public: - IcyTouchDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "icy touch") {} - }; + class PlagueStrikeDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + PlagueStrikeDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "plague strike") {} + }; + class IcyTouchDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger + { + public: + IcyTouchDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "icy touch") {} + }; class DKPresenceTrigger : public BuffTrigger { public: @@ -27,76 +26,76 @@ namespace ai virtual bool IsActive(); }; - class BloodTapTrigger : public BuffTrigger { - public: - BloodTapTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "blood tap") {} - }; + class BloodTapTrigger : public BuffTrigger { + public: + BloodTapTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "blood tap") {} + }; - class RaiseDeadTrigger : public BuffTrigger { - public: - RaiseDeadTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "raise dead") {} - }; + class RaiseDeadTrigger : public BuffTrigger { + public: + RaiseDeadTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "raise dead") {} + }; - class RuneStrikeTrigger : public SpellCanBeCastTrigger { - public: - RuneStrikeTrigger(PlayerbotAI* ai) : SpellCanBeCastTrigger(ai, "rune strike") {} - }; + class RuneStrikeTrigger : public SpellCanBeCastTrigger { + public: + RuneStrikeTrigger(PlayerbotAI* ai) : SpellCanBeCastTrigger(ai, "rune strike") {} + }; - class DeathCoilTrigger : public SpellCanBeCastTrigger { - public: - DeathCoilTrigger(PlayerbotAI* ai) : SpellCanBeCastTrigger(ai, "death coil") {} - }; + class DeathCoilTrigger : public SpellCanBeCastTrigger { + public: + DeathCoilTrigger(PlayerbotAI* ai) : SpellCanBeCastTrigger(ai, "death coil") {} + }; - class PestilenceTrigger : public DebuffTrigger { - public: - PestilenceTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "pestilence") {} - }; + class PestilenceTrigger : public DebuffTrigger { + public: + PestilenceTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "pestilence") {} + }; - class BloodStrikeTrigger : public DebuffTrigger { - public: - BloodStrikeTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "blood strike") {} - }; + class BloodStrikeTrigger : public DebuffTrigger { + public: + BloodStrikeTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "blood strike") {} + }; - class HowlingBlastTrigger : public DebuffTrigger { - public: - HowlingBlastTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "howling blast") {} - }; + class HowlingBlastTrigger : public DebuffTrigger { + public: + HowlingBlastTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "howling blast") {} + }; class MindFreezeInterruptSpellTrigger : public InterruptSpellTrigger { public: - MindFreezeInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "mind freeze") {} + MindFreezeInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "mind freeze") {} }; - class StrangulateInterruptSpellTrigger : public InterruptSpellTrigger - { - public: - StrangulateInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "strangulate") {} - }; + class StrangulateInterruptSpellTrigger : public InterruptSpellTrigger + { + public: + StrangulateInterruptSpellTrigger(PlayerbotAI* ai) : InterruptSpellTrigger(ai, "strangulate") {} + }; class KillingMachineTrigger : public BoostTrigger { public: - KillingMachineTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "killing machine") {} + KillingMachineTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "killing machine") {} }; class MindFreezeOnEnemyHealerTrigger : public InterruptEnemyHealerTrigger { public: - MindFreezeOnEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "mind freeze") {} + MindFreezeOnEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "mind freeze") {} }; - class ChainsOfIceSnareTrigger : public SnareTargetTrigger - { - public: - ChainsOfIceSnareTrigger(PlayerbotAI* ai) : SnareTargetTrigger(ai, "chains of ice") {} - }; + class ChainsOfIceSnareTrigger : public SnareTargetTrigger + { + public: + ChainsOfIceSnareTrigger(PlayerbotAI* ai) : SnareTargetTrigger(ai, "chains of ice") {} + }; - class StrangulateOnEnemyHealerTrigger : public InterruptEnemyHealerTrigger - { - public: - StrangulateOnEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "strangulate") {} - }; + class StrangulateOnEnemyHealerTrigger : public InterruptEnemyHealerTrigger + { + public: + StrangulateOnEnemyHealerTrigger(PlayerbotAI* ai) : InterruptEnemyHealerTrigger(ai, "strangulate") {} + }; } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp index b3736b5300..3ca8fd9e36 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.cpp @@ -8,71 +8,69 @@ using namespace ai; class FrostDKStrategyActionNodeFactory : public NamedObjectFactory { public: - FrostDKStrategyActionNodeFactory() - { - //creators["icy touch"] = &icy_touch; - creators["obliterate"] = &obliterate; - creators["howling blast"] = &howling_blast; - creators["frost strike"] = &frost_strike; - //creators["chains of ice"] = &chains_of_ice; - creators["rune strike"] = &rune_strike; - //creators["icy clutch"] = &icy_clutch; - //creators["horn of winter"] = &horn_of_winter; - //creators["killing machine"] = &killing_machine; - //creators["frost presence"] = &frost_presence; - //creators["deathchill"] = &deathchill; - //creators["icebound fortitude"] = &icebound_fortitude; - //creators["mind freeze"] = &mind_freeze; - //creators["empower weapon"] = &empower_weapon; - //creators["hungering cold"] = &hungering_cold; - //creators["unbreakable armor"] = &unbreakable_armor; - //creators["improved icy talons"] = &improved_icy_talons; - } + FrostDKStrategyActionNodeFactory() + { + //creators["icy touch"] = &icy_touch; + creators["obliterate"] = &obliterate; + creators["howling blast"] = &howling_blast; + creators["frost strike"] = &frost_strike; + //creators["chains of ice"] = &chains_of_ice; + creators["rune strike"] = &rune_strike; + //creators["icy clutch"] = &icy_clutch; + //creators["horn of winter"] = &horn_of_winter; + //creators["killing machine"] = &killing_machine; + //creators["frost presence"] = &frost_presence; + //creators["deathchill"] = &deathchill; + //creators["icebound fortitude"] = &icebound_fortitude; + //creators["mind freeze"] = &mind_freeze; + //creators["empower weapon"] = &empower_weapon; + //creators["hungering cold"] = &hungering_cold; + //creators["unbreakable armor"] = &unbreakable_armor; + //creators["improved icy talons"] = &improved_icy_talons; + } - private: - - - static ActionNode* obliterate(PlayerbotAI* ai) - { - return new ActionNode("obliterate", - /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), - /*A*/ NextAction::array(0, new NextAction("frost strike"), NULL), - /*C*/ NULL); - } - static ActionNode* rune_strike(PlayerbotAI* ai) - { - return new ActionNode("rune strike", - /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), - /*A*/ NextAction::array(0, new NextAction("melee"), NULL), - /*C*/ NULL); - } - static ActionNode* frost_strike(PlayerbotAI* ai) - { - return new ActionNode("frost strike", - /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), - /*A*/ NULL, - /*C*/ NULL); - } - static ActionNode* howling_blast(PlayerbotAI* ai) - { - return new ActionNode("howling blast", - /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), - /*A*/ NextAction::array(0, new NextAction("icy touch"), NULL), - /*C*/ NULL); - } + private: + static ActionNode* obliterate(PlayerbotAI* ai) + { + return new ActionNode("obliterate", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("frost strike"), NULL), + /*C*/ NULL); + } + static ActionNode* rune_strike(PlayerbotAI* ai) + { + return new ActionNode("rune strike", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("melee"), NULL), + /*C*/ NULL); + } + static ActionNode* frost_strike(PlayerbotAI* ai) + { + return new ActionNode("frost strike", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* howling_blast(PlayerbotAI* ai) + { + return new ActionNode("howling blast", + /*P*/ NextAction::array(0, new NextAction("blood presence"), NULL), + /*A*/ NextAction::array(0, new NextAction("icy touch"), NULL), + /*C*/ NULL); + } }; - FrostDKStrategy::FrostDKStrategy(PlayerbotAI* ai) : GenericDKStrategy(ai) - { - actionNodeFactories.Add(new FrostDKStrategyActionNodeFactory()); - } +FrostDKStrategy::FrostDKStrategy(PlayerbotAI* ai) : GenericDKStrategy(ai) +{ + actionNodeFactories.Add(new FrostDKStrategyActionNodeFactory()); +} - NextAction** FrostDKStrategy::getDefaultActions() - { +NextAction** FrostDKStrategy::getDefaultActions() +{ return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), new NextAction("frost strike", ACTION_NORMAL + 5), - new NextAction("obliterate", ACTION_NORMAL + 4), NULL); - } + new NextAction("obliterate", ACTION_NORMAL + 4), NULL); +} void FrostDKStrategy::InitTriggers(std::list &triggers) { @@ -85,7 +83,7 @@ void FrostDKStrategy::InitTriggers(std::list &triggers) void FrostDKAoeStrategy::InitTriggers(std::list &triggers) { - triggers.push_back(new TriggerNode( - "light aoe", - NextAction::array(0, new NextAction("howling blast", ACTION_NORMAL + 4), NULL))); + triggers.push_back(new TriggerNode( + "light aoe", + NextAction::array(0, new NextAction("howling blast", ACTION_NORMAL + 4), NULL))); } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h index 0f33cbe437..6a9136d141 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/FrostDKStrategy.h @@ -14,7 +14,7 @@ namespace ai virtual void InitTriggers(std::list &triggers); virtual string getName() { return "frost"; } virtual NextAction** getDefaultActions(); - virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } }; class FrostDKAoeStrategy : public CombatStrategy diff --git a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp index 414789a586..d121d1b432 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.cpp @@ -39,17 +39,17 @@ void GenericDKNonCombatStrategy::InitTriggers(std::list &triggers) { NonCombatStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode( - "raise dead", - NextAction::array(0, new NextAction("raise dead", ACTION_NORMAL + 1), NULL))); + triggers.push_back(new TriggerNode( + "raise dead", + NextAction::array(0, new NextAction("raise dead", ACTION_NORMAL + 1), NULL))); triggers.push_back(new TriggerNode( "horn of winter", NextAction::array(0, new NextAction("horn of winter", 21.0f), NULL))); - triggers.push_back(new TriggerNode( - "bone shield", - NextAction::array(0, new NextAction("bone shield", 21.0f), NULL))); + triggers.push_back(new TriggerNode( + "bone shield", + NextAction::array(0, new NextAction("bone shield", 21.0f), NULL))); } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h index 4ea0cd4ddb..8d6fc01973 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKNonCombatStrategy.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include "GenericDKStrategy.h" #include "../generic/NonCombatStrategy.h" diff --git a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp index 8ddd906f18..a0d91a9585 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/deathknight/GenericDKStrategy.cpp @@ -11,87 +11,86 @@ class GenericDKStrategyActionNodeFactory : public NamedObjectFactory public: GenericDKStrategyActionNodeFactory() { - //blood - //creators["rune tap"] = &rune_tap; cd - //creators["vampiric blood"] = &vampiric_blood; - //creators["death pact"] = &death_pact; - //creators["hysteria"] = &hysteria; boost party - //creators["dancing rune weapon"] = &dancing_rune_weapon; //cd - //creators["dark command"] = &dark_command; taunt - - //frost - //creators["chains of ice"] = &chains_of_ice; - //creators["icy clutch"] = &icy_clutch; - creators["horn of winter"] = &horn_of_winter; - creators["killing machine"] = &killing_machine; // buff - //creators["deathchill"] = &deathchill; //boost - creators["icebound fortitude"] = &icebound_fortitude; - //creators["mind freeze"] = &mind_freeze; interrupt - //creators["empower rune weapon"] = &empower_rune_weapon; boost - //creators["hungering cold"] = &hungering_cold; snare - //creators["unbreakable armor"] = &unbreakable_armor; boost +cd - //creators["improved icy talons"] = &improved_icy_talons; boost party - - //unholy - //creators["death and decay"] = &death_and_decay; - //creators["raise dead"] = &raise_dead; - //creators["army of the dead"] = &army of the dead; - //creators["summon gargoyle"] = &army of the dead; - //creators["anti magic shell"] = &anti_magic_shell; cd - creators["anti magic zone"] = &anti_magic_zone; - //creators["ghoul frenzy"] = &ghoul_frenzy; - creators["corpse explosion"] = &corpse_explosion; - creators["bone shield"] = &bone_shield; - creators["heart strike"] = &heart_strike; - creators["death grip"] = &death_grip; - creators["plague strike"] = &plague_strike; - creators["pestilence"] = &pestilence; - creators["icy touch"] = &icy_touch; - + //blood + //creators["rune tap"] = &rune_tap; cd + //creators["vampiric blood"] = &vampiric_blood; + //creators["death pact"] = &death_pact; + //creators["hysteria"] = &hysteria; boost party + //creators["dancing rune weapon"] = &dancing_rune_weapon; //cd + //creators["dark command"] = &dark_command; taunt + + //frost + //creators["chains of ice"] = &chains_of_ice; + //creators["icy clutch"] = &icy_clutch; + creators["horn of winter"] = &horn_of_winter; + creators["killing machine"] = &killing_machine; // buff + //creators["deathchill"] = &deathchill; //boost + creators["icebound fortitude"] = &icebound_fortitude; + //creators["mind freeze"] = &mind_freeze; interrupt + //creators["empower rune weapon"] = &empower_rune_weapon; boost + //creators["hungering cold"] = &hungering_cold; snare + //creators["unbreakable armor"] = &unbreakable_armor; boost +cd + //creators["improved icy talons"] = &improved_icy_talons; boost party + + //unholy + //creators["death and decay"] = &death_and_decay; + //creators["raise dead"] = &raise_dead; + //creators["army of the dead"] = &army of the dead; + //creators["summon gargoyle"] = &army of the dead; + //creators["anti magic shell"] = &anti_magic_shell; cd + creators["anti magic zone"] = &anti_magic_zone; + //creators["ghoul frenzy"] = &ghoul_frenzy; + creators["corpse explosion"] = &corpse_explosion; + creators["bone shield"] = &bone_shield; + creators["heart strike"] = &heart_strike; + creators["death grip"] = &death_grip; + creators["plague strike"] = &plague_strike; + creators["pestilence"] = &pestilence; + creators["icy touch"] = &icy_touch; } private: - static ActionNode* death_coil(PlayerbotAI* ai) - { - return new ActionNode("death coil", - /*P*/ NULL, - /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), - /*C*/ NULL); - } - static ActionNode* death_grip(PlayerbotAI* ai) - { - return new ActionNode("death grip", - /*P*/ NULL, - /*A*/ NextAction::array(0, new NextAction("icy touch"), NULL), - /*C*/ NULL); - } - static ActionNode* plague_strike(PlayerbotAI* ai) - { - return new ActionNode("plague strike", - /*P*/ NULL, - /*A*/ NULL, - /*C*/ NULL); - } - static ActionNode* icy_touch(PlayerbotAI* ai) - { - return new ActionNode("icy touch", - /*P*/ NULL, - /*A*/ NULL, - /*C*/ NULL); - } - static ActionNode* heart_strike(PlayerbotAI* ai) - { - return new ActionNode("heart strike", - /*P*/ NULL, - /*A*/ NextAction::array(0, new NextAction("blood strike"), NULL), - /*C*/ NULL); - } - static ActionNode* pestilence(PlayerbotAI* ai) - { - return new ActionNode("pestilence", - /*P*/ NULL, - /*A*/ NULL, - /*C*/ NULL); - } + static ActionNode* death_coil(PlayerbotAI* ai) + { + return new ActionNode("death coil", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), + /*C*/ NULL); + } + static ActionNode* death_grip(PlayerbotAI* ai) + { + return new ActionNode("death grip", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("icy touch"), NULL), + /*C*/ NULL); + } + static ActionNode* plague_strike(PlayerbotAI* ai) + { + return new ActionNode("plague strike", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* icy_touch(PlayerbotAI* ai) + { + return new ActionNode("icy touch", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* heart_strike(PlayerbotAI* ai) + { + return new ActionNode("heart strike", + /*P*/ NULL, + /*A*/ NextAction::array(0, new NextAction("blood strike"), NULL), + /*C*/ NULL); + } + static ActionNode* pestilence(PlayerbotAI* ai) + { + return new ActionNode("pestilence", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL); + } static ActionNode* horn_of_winter(PlayerbotAI* ai) { return new ActionNode ("horn of winter", @@ -133,7 +132,6 @@ class GenericDKStrategyActionNodeFactory : public NamedObjectFactory /*P*/ NULL, /*A*/ NULL, /*C*/ NULL); - } }; @@ -144,24 +142,24 @@ GenericDKStrategy::GenericDKStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai) void GenericDKStrategy::InitTriggers(std::list &triggers) { - MeleeCombatStrategy::InitTriggers(triggers); + MeleeCombatStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode( - "high aoe", - NextAction::array(0, - new NextAction("anti magic shell", ACTION_NORMAL + 3), NULL))); + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, + new NextAction("anti magic shell", ACTION_NORMAL + 3), NULL))); - triggers.push_back(new TriggerNode( - "death coil", - NextAction::array(0, new NextAction("death coil", ACTION_NORMAL + 3), NULL))); + triggers.push_back(new TriggerNode( + "death coil", + NextAction::array(0, new NextAction("death coil", ACTION_NORMAL + 3), NULL))); - triggers.push_back(new TriggerNode( - "critical aoe heal", - NextAction::array(0, new NextAction("anti magic zone", ACTION_EMERGENCY + 1), NULL))); + triggers.push_back(new TriggerNode( + "critical aoe heal", + NextAction::array(0, new NextAction("anti magic zone", ACTION_EMERGENCY + 1), NULL))); - triggers.push_back(new TriggerNode( - "no pet", - NextAction::array(0, new NextAction("raise dead", ACTION_NORMAL + 5), NULL))); + triggers.push_back(new TriggerNode( + "no pet", + NextAction::array(0, new NextAction("raise dead", ACTION_NORMAL + 5), NULL))); triggers.push_back(new TriggerNode( "mind freeze", @@ -171,69 +169,65 @@ void GenericDKStrategy::InitTriggers(std::list &triggers) "bone shield", NextAction::array(0, new NextAction("bone shield", ACTION_NORMAL + 1), NULL))); - triggers.push_back(new TriggerNode( - "horn of winter", - NextAction::array(0, new NextAction("horn of winter", ACTION_NORMAL + 1), NULL))); + triggers.push_back(new TriggerNode( + "horn of winter", + NextAction::array(0, new NextAction("horn of winter", ACTION_NORMAL + 1), NULL))); triggers.push_back(new TriggerNode( "mind freeze on enemy healer", NextAction::array(0, new NextAction("mind freeze on enemy healer", ACTION_HIGH + 1), NULL))); - - triggers.push_back(new TriggerNode( - "enemy out of melee", - NextAction::array(0, new NextAction("icy touch", ACTION_NORMAL + 9), - new NextAction("death grip", ACTION_NORMAL + 9), - new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); - - triggers.push_back(new TriggerNode( - "low health", - NextAction::array(0, new NextAction("icebound fortitude", ACTION_HIGH + 5), - new NextAction("rune tap", ACTION_HIGH + 4), NULL))); - - - triggers.push_back(new TriggerNode( - "medium health", - NextAction::array(0, new NextAction("rune tap", ACTION_NORMAL + 4), - new NextAction("death strike", ACTION_NORMAL + 3), NULL))); - - triggers.push_back(new TriggerNode( - "icy touch on attacker", - NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), NULL))); - - triggers.push_back(new TriggerNode( - "icy touch", - NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), NULL))); - - triggers.push_back(new TriggerNode( - "plague strike", - NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), NULL))); - - triggers.push_back(new TriggerNode( - "plague strike on attacker", - NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), NULL))); - - triggers.push_back(new TriggerNode( - "high aoe", - NextAction::array(0, - new NextAction("unholy blight", ACTION_NORMAL + 6), - new NextAction("death and decay", ACTION_NORMAL + 5), - new NextAction("pestilence", ACTION_NORMAL + 4), - new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); - - triggers.push_back(new TriggerNode( - "medium aoe", - NextAction::array(0, - new NextAction("death and decay", ACTION_NORMAL + 5), - new NextAction("pestilence", ACTION_NORMAL + 4), - new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); - - triggers.push_back(new TriggerNode("light aoe", - NextAction::array(0, - new NextAction("howling blast", ACTION_NORMAL + 5), - new NextAction("pestilence", ACTION_NORMAL + 4), - new NextAction("hearth strike", ACTION_NORMAL + 3), - new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("icy touch", ACTION_NORMAL + 9), + new NextAction("death grip", ACTION_NORMAL + 9), + new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); + + triggers.push_back(new TriggerNode( + "low health", + NextAction::array(0, new NextAction("icebound fortitude", ACTION_HIGH + 5), + new NextAction("rune tap", ACTION_HIGH + 4), NULL))); + triggers.push_back(new TriggerNode( + "medium health", + NextAction::array(0, new NextAction("rune tap", ACTION_NORMAL + 4), + new NextAction("death strike", ACTION_NORMAL + 3), NULL))); + triggers.push_back(new TriggerNode( + "icy touch on attacker", + NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "icy touch", + NextAction::array(0, new NextAction("icy touch", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "plague strike", + NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "plague strike on attacker", + NextAction::array(0, new NextAction("plague strike", ACTION_HIGH + 1), NULL))); + + triggers.push_back(new TriggerNode( + "high aoe", + NextAction::array(0, + new NextAction("unholy blight", ACTION_NORMAL + 6), + new NextAction("death and decay", ACTION_NORMAL + 5), + new NextAction("pestilence", ACTION_NORMAL + 4), + new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, + new NextAction("death and decay", ACTION_NORMAL + 5), + new NextAction("pestilence", ACTION_NORMAL + 4), + new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); + + triggers.push_back(new TriggerNode("light aoe", + NextAction::array(0, + new NextAction("howling blast", ACTION_NORMAL + 5), + new NextAction("pestilence", ACTION_NORMAL + 4), + new NextAction("hearth strike", ACTION_NORMAL + 3), + new NextAction("blood boil", ACTION_NORMAL + 3), NULL))); } diff --git a/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp index d69bfe7193..5be79a3c69 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.cpp @@ -8,81 +8,76 @@ using namespace ai; class UnholyDKStrategyActionNodeFactory : public NamedObjectFactory { public: - UnholyDKStrategyActionNodeFactory() - { - // Unholy - //creators["bone shield"] = &bone_shield; - //creators["plague strike"] = &plague_strike; - //creators["death grip"] = &death_grip; - //creators["death coil"] = &death_coil; - creators["death strike"] = &death_strike; - //creators["unholy blight"] = &unholy_blight; - creators["scourge strike"] = &scourge_strike; - //creators["death and decay"] = &death_and_decay; - //creators["unholy pressence"] = &unholy_pressence; - //creators["raise dead"] = &raise_dead; - //creators["army of the dead"] = &army of the dead; - //creators["summon gargoyle"] = &army of the dead; - //creators["anti magic shell"] = &anti_magic_shell; - //creators["anti magic zone"] = &anti_magic_zone; - //creators["ghoul frenzy"] = &ghoul_frenzy; - creators["corpse explosion"] = &corpse_explosion; - } + UnholyDKStrategyActionNodeFactory() + { + // Unholy + //creators["bone shield"] = &bone_shield; + //creators["plague strike"] = &plague_strike; + //creators["death grip"] = &death_grip; + //creators["death coil"] = &death_coil; + creators["death strike"] = &death_strike; + //creators["unholy blight"] = &unholy_blight; + creators["scourge strike"] = &scourge_strike; + //creators["death and decay"] = &death_and_decay; + //creators["unholy pressence"] = &unholy_pressence; + //creators["raise dead"] = &raise_dead; + //creators["army of the dead"] = &army of the dead; + //creators["summon gargoyle"] = &army of the dead; + //creators["anti magic shell"] = &anti_magic_shell; + //creators["anti magic zone"] = &anti_magic_zone; + //creators["ghoul frenzy"] = &ghoul_frenzy; + creators["corpse explosion"] = &corpse_explosion; + } private: - - - static ActionNode* death_strike(PlayerbotAI* ai) - { - return new ActionNode("death strike", - /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), - /*A*/ NULL, - /*C*/ NULL); - } - static ActionNode* corpse_explosion(PlayerbotAI* ai) - { - return new ActionNode("corpse explosion", - /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), - /*A*/ NULL, - /*C*/ NULL); - } - static ActionNode* scourge_strike(PlayerbotAI* ai) - { - return new ActionNode("scourge strike", - /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), - /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), - /*C*/ NULL); - } + static ActionNode* death_strike(PlayerbotAI* ai) + { + return new ActionNode("death strike", + /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* corpse_explosion(PlayerbotAI* ai) + { + return new ActionNode("corpse explosion", + /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), + /*A*/ NULL, + /*C*/ NULL); + } + static ActionNode* scourge_strike(PlayerbotAI* ai) + { + return new ActionNode("scourge strike", + /*P*/ NextAction::array(0, new NextAction("unholy pressence"), NULL), + /*A*/ NextAction::array(0, new NextAction("death strike"), NULL), + /*C*/ NULL); + } }; - - NextAction** UnholyDKStrategy::getDefaultActions() - { +NextAction** UnholyDKStrategy::getDefaultActions() +{ return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), new NextAction("scourge strike" , ACTION_NORMAL + 3), NULL); - } +} void UnholyDKStrategy::InitTriggers(std::list &triggers) { GenericDKStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode( - "often", - NextAction::array(0, new NextAction("ghoul frenzy", ACTION_NORMAL + 2), NULL))); + triggers.push_back(new TriggerNode( + "often", + NextAction::array(0, new NextAction("ghoul frenzy", ACTION_NORMAL + 2), NULL))); - triggers.push_back(new TriggerNode( - "critical health", - NextAction::array(0, new NextAction("death pact", ACTION_EMERGENCY + 1), NULL))); + triggers.push_back(new TriggerNode( + "critical health", + NextAction::array(0, new NextAction("death pact", ACTION_EMERGENCY + 1), NULL))); } - void UnholyDKAoeStrategy::InitTriggers(std::list &triggers) { - triggers.push_back(new TriggerNode( - "loot available", - NextAction::array(0, new NextAction("corpse explosion", ACTION_NORMAL + 1), NULL))); + triggers.push_back(new TriggerNode( + "loot available", + NextAction::array(0, new NextAction("corpse explosion", ACTION_NORMAL + 1), NULL))); triggers.push_back(new TriggerNode( "medium aoe", NextAction::array(0, new NextAction("death and decay", ACTION_NORMAL + 3), - new NextAction("corpse explosion", ACTION_NORMAL + 3), NULL))); + new NextAction("corpse explosion", ACTION_NORMAL + 3), NULL))); } - diff --git a/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h index c02075194e..71189c290a 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/UnholyDKStrategy.h @@ -13,8 +13,8 @@ namespace ai public: virtual void InitTriggers(std::list &triggers); virtual string getName() { return "unholy"; } - virtual NextAction** getDefaultActions(); - virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } + virtual NextAction** getDefaultActions(); + virtual int GetType() { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } }; class UnholyDKAoeStrategy : public CombatStrategy From ce98b1e551c715f5cc09884363450072d5bc53bb Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Thu, 31 Mar 2022 14:10:07 -0400 Subject: [PATCH 5/9] Skip mounting if bot controller is in taxi flight --- .gitignore | 3 +++ src/modules/Bots/ahbot/ahbot.conf.dist.in | 2 +- .../Bots/playerbot/strategy/actions/CheckMountStateAction.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 618749bd5f..71ab1f4fbc 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,9 @@ /*.sublime-project /*.sublime-workspace +# VSCode +/.vscode + # Numerous always-ignore extensions *.a *.bak diff --git a/src/modules/Bots/ahbot/ahbot.conf.dist.in b/src/modules/Bots/ahbot/ahbot.conf.dist.in index f50ffc269c..dd2819a326 100644 --- a/src/modules/Bots/ahbot/ahbot.conf.dist.in +++ b/src/modules/Bots/ahbot/ahbot.conf.dist.in @@ -3,7 +3,7 @@ ################################################ [AhbotConf] -ConfVersion=2010102201 +ConfVersion=2021010100 ################################################################################################################### # AUCTION HOUSE BOT SETTINGS diff --git a/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp b/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp index 3f3c39ac1b..fbced56929 100644 --- a/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/CheckMountStateAction.cpp @@ -14,7 +14,7 @@ bool CheckMountStateAction::Execute(Event event) return false; } - if (bot->IsTaxiFlying()) + if (bot->IsTaxiFlying() || master->IsTaxiFlying()) { return false; } From 2c99fcc7a44a67dcf3ea21b8d08bafa37ecde595 Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Fri, 1 Apr 2022 10:05:48 -0400 Subject: [PATCH 6/9] AHBot integration and death knight strategy files Post-increments converted to pre-increments for efficiency --- src/game/CMakeLists.txt | 8 +++++- src/game/WorldHandlers/World.cpp | 3 ++- src/modules/Bots/ahbot/AhBot.cpp | 34 +++++++++++++------------- src/modules/Bots/ahbot/AhBotConfig.cpp | 2 +- src/modules/Bots/ahbot/ItemBag.cpp | 8 +++--- src/modules/Bots/ahbot/ItemBag.h | 2 +- 6 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index e3c9a34144..76dd98f8e1 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -89,7 +89,7 @@ endif() if(PLAYERBOTS) -#Base files +#Playerbot Module group file(GLOB Playerbot_Source ${CMAKE_SOURCE_DIR}/src/modules/Bots/playerbot/*.cpp ${CMAKE_SOURCE_DIR}/src/modules/Bots/playerbot/*.h) source_group("Player Bot" FILES ${Playerbot_Source}) file(GLOB AHbot_Source ${CMAKE_SOURCE_DIR}/src/modules/Bots/ahbot/*.cpp ${CMAKE_SOURCE_DIR}/src/modules/Bots/ahbot/*.h) @@ -126,6 +126,11 @@ source_group("Player Bot\\Strategies\\Values" FILES ${Playerbot_Values}) LIST(APPEND SRC_GRP_BOTS ${Playerbot_Values}) ## Class files +#Deathknight AI +file(GLOB Playerbot_Druid ${CMAKE_SOURCE_DIR}/src/modules/Bots/playerbot/strategy/deathknight/*.cpp ${CMAKE_SOURCE_DIR}/src/modules/Bots/playerbot/strategy/deathknight/*.h) +source_group("Player Bot\\Strategies\\Druid" FILES ${Playerbot_Death_Knight}) +LIST(APPEND SRC_GRP_BOTS ${Playerbot_Death_Knight}) + #Druid AI file(GLOB Playerbot_Druid ${CMAKE_SOURCE_DIR}/src/modules/Bots/playerbot/strategy/druid/*.cpp ${CMAKE_SOURCE_DIR}/src/modules/Bots/playerbot/strategy/druid/*.h) source_group("Player Bot\\Strategies\\Druid" FILES ${Playerbot_Druid}) @@ -172,6 +177,7 @@ source_group("Player Bot\\Strategies\\Warrior" FILES ${Playerbot_Warrior}) LIST(APPEND SRC_GRP_BOTS ${Playerbot_Warrior}) configure_file(${CMAKE_SOURCE_DIR}/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in ${CMAKE_CURRENT_BINARY_DIR}/aiplayerbot.conf.dist) +configure_file(${CMAKE_SOURCE_DIR}/src/modules/Bots/ahbot/ahbot.conf.dist.in ${CMAKE_CURRENT_BINARY_DIR}/AuctionHouseBot/ahplayerbot.conf.dist) endif() diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 7a291cb5f5..5159f67987 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -87,7 +87,7 @@ #endif /* ENABLE_ELUNA */ #ifdef ENABLE_PLAYERBOTS - +#include "AhBotConfig.h" #include "PlayerbotAIConfig.h" #include "RandomPlayerbotMgr.h" #endif @@ -1602,6 +1602,7 @@ void World::SetInitialWorldSettings() #endif #ifdef ENABLE_PLAYERBOTS + auctionbot.Initialize(); sPlayerbotAIConfig.Initialize(); #endif diff --git a/src/modules/Bots/ahbot/AhBot.cpp b/src/modules/Bots/ahbot/AhBot.cpp index 593ed0451c..c33e6d7140 100644 --- a/src/modules/Bots/ahbot/AhBot.cpp +++ b/src/modules/Bots/ahbot/AhBot.cpp @@ -170,12 +170,12 @@ void AhBot::ForceUpdate() CheckCategoryMultipliers(); int answered = 0, added = 0; - for (int i = 0; i < MAX_AUCTIONS; i++) + for (int i = 0; i < MAX_AUCTIONS; ++i) { InAuctionItemsBag inAuctionItems(auctionIds[i]); inAuctionItems.Init(true); - for (int j = 0; j < CategoryList::instance.size(); j++) + for (int j = 0; j < CategoryList::instance.size(); ++j) { Category* category = CategoryList::instance[j]; answered += Answer(i, category, &inAuctionItems); @@ -421,7 +421,7 @@ int AhBot::Answer(int auction, Category* category, ItemBag* inAuctionItems) CharacterDatabase.PExecute("DELETE FROM `ahbot_history` WHERE `item` = '%u' AND `won` = 4 AND `auction_house` = '%u' ", proto->ItemId, factions[auctionIds[auction]]); - answered++; + ++answered; } return answered; @@ -655,7 +655,7 @@ void AhBot::HandleCommand(string command) if (command == "expire") { - for (int i = 0; i < MAX_AUCTIONS; i++) + for (int i = 0; i < MAX_AUCTIONS; ++i) { Expire(i); } @@ -665,7 +665,7 @@ void AhBot::HandleCommand(string command) if (command == "stats") { - for (int i = 0; i < MAX_AUCTIONS; i++) + for (int i = 0; i < MAX_AUCTIONS; ++i) { PrintStats(i); } @@ -696,7 +696,7 @@ void AhBot::HandleCommand(string command) return; } - for (int i=0; iContains(proto)) @@ -712,7 +712,7 @@ void AhBot::HandleCommand(string command) << category->GetMaxAllowedAuctionCount() << "x" << category->GetMaxAllowedItemAuctionCount(proto) << "x" << category->GetStackCount(proto) << " max" << "\n"; - for (int auction = 0; auction < MAX_AUCTIONS; auction++) + for (int auction = 0; auction < MAX_AUCTIONS; ++auction) { const AuctionHouseEntry* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); out << "--- auction house " << auctionIds[auction] << "(faction: " << factions[auctionIds[auction]] << ", money: " @@ -757,7 +757,7 @@ void AhBot::Expire(int auction) if (IsBotAuction(itr->second->owner)) { itr->second->expireTime = sWorld.GetGameTime(); - count++; + ++count; } ++itr; @@ -805,7 +805,7 @@ void AhBot::AddToHistory(AuctionEntry* entry, uint32 won) } string category = ""; - for (int i = 0; i < CategoryList::instance.size(); i++) + for (int i = 0; i < CategoryList::instance.size(); ++i) { if (CategoryList::instance[i]->Contains(proto)) { @@ -936,7 +936,7 @@ void AhBot::CheckCategoryMultipliers() CharacterDatabase.PExecute("DELETE FROM `ahbot_category`"); - for (int i = 0; i < CategoryList::instance.size(); i++) + for (int i = 0; i < CategoryList::instance.size(); ++i) { string name = CategoryList::instance[i]->GetName(); if (categoryMultiplierExpireTimes[name] <= time(0) || categoryMultipliers[name] <= 0) @@ -997,7 +997,7 @@ uint32 AhBot::GetRandomBidder(uint32 auctionHouse) void AhBot::LoadRandomBots() { - for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); i++) + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); ++i) { uint32 accountId = *i; if (!sAccountMgr.GetCharactersCount(accountId)) @@ -1028,7 +1028,7 @@ void AhBot::LoadRandomBots() { uint32 guid = sAhBotConfig.guid; allBidders.insert(guid); - for (int i = 1; i <= 3; i++) + for (int i = 1; i <= 3; ++i) { bidders[i].push_back(guid); } @@ -1045,7 +1045,7 @@ int32 AhBot::GetSellPrice(ItemPrototype const* proto) } int32 maxPrice = 0; - for (int i=0; iContains(proto)) @@ -1053,7 +1053,7 @@ int32 AhBot::GetSellPrice(ItemPrototype const* proto) continue; } - for (int auction = 0; auction < MAX_AUCTIONS; auction++) + for (int auction = 0; auction < MAX_AUCTIONS; ++auction) { int32 price = (int32)category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]); if (!price) @@ -1079,7 +1079,7 @@ int32 AhBot::GetBuyPrice(ItemPrototype const* proto) } int32 maxPrice = 0; - for (int i=0; iContains(proto)) @@ -1087,7 +1087,7 @@ int32 AhBot::GetBuyPrice(ItemPrototype const* proto) continue; } - for (int auction = 0; auction < MAX_AUCTIONS; auction++) + for (int auction = 0; auction < MAX_AUCTIONS; ++auction) { int32 price = (int32)category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); if (!price) @@ -1112,7 +1112,7 @@ double AhBot::GetRarityPriceMultiplier(const ItemPrototype* proto) return 1.0; } - for (int i=0; iContains(proto)) diff --git a/src/modules/Bots/ahbot/AhBotConfig.cpp b/src/modules/Bots/ahbot/AhBotConfig.cpp index 44046169d9..d03b409d2c 100644 --- a/src/modules/Bots/ahbot/AhBotConfig.cpp +++ b/src/modules/Bots/ahbot/AhBotConfig.cpp @@ -15,7 +15,7 @@ template void LoadSet(string value, T &res) { vector ids = split(value, ','); - for (vector::iterator i = ids.begin(); i != ids.end(); i++) + for (vector::iterator i = ids.begin(); i != ids.end(); ++i) { uint32 id = atoi((*i).c_str()); if (!id) diff --git a/src/modules/Bots/ahbot/ItemBag.cpp b/src/modules/Bots/ahbot/ItemBag.cpp index bb3bc20ac2..7c602969c4 100644 --- a/src/modules/Bots/ahbot/ItemBag.cpp +++ b/src/modules/Bots/ahbot/ItemBag.cpp @@ -59,7 +59,7 @@ CategoryList::~CategoryList() ItemBag::ItemBag() { - for (int i = 0; i < CategoryList::instance.size(); i++) + for (int i = 0; i < CategoryList::instance.size(); ++i) { content[CategoryList::instance[i]] = vector(); } @@ -77,7 +77,7 @@ void ItemBag::Init(bool silent) Load(); - for (int i = 0; i < CategoryList::instance.size(); i++) + for (int i = 0; i < CategoryList::instance.size(); ++i) { Category* category = CategoryList::instance[i]; Shuffle(content[category]); @@ -94,7 +94,7 @@ int32 ItemBag::GetCount(Category* category, uint32 item) { if (*i == item) { - count++; + ++count; } } @@ -128,7 +128,7 @@ bool ItemBag::Add(ItemPrototype const* proto) return false; } - for (int i = 0; i < CategoryList::instance.size(); i++) + for (int i = 0; i < CategoryList::instance.size(); ++i) { if (CategoryList::instance[i]->Contains(proto)) { diff --git a/src/modules/Bots/ahbot/ItemBag.h b/src/modules/Bots/ahbot/ItemBag.h index fd422c8102..8d1559d52c 100644 --- a/src/modules/Bots/ahbot/ItemBag.h +++ b/src/modules/Bots/ahbot/ItemBag.h @@ -26,7 +26,7 @@ namespace ahbot void Shuffle(vector& items) { uint32 count = items.size(); - for (uint32 i = 0; i < count * 5; i++) + for (uint32 i = 0; i < count * 5; ++i) { int i1 = urand(0, count - 1); int i2 = urand(0, count - 1); From 6ef5fa910628ed050d3b660eb46c7011bbcac085 Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Fri, 1 Apr 2022 11:12:53 -0400 Subject: [PATCH 7/9] Codacity fix - incorrect syntax in death knight strategy files --- .../Bots/playerbot/strategy/deathknight/DKTriggers.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h index 23d38fcab6..1b8d3dabdb 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKTriggers.h @@ -3,13 +3,13 @@ namespace ai { - BUFF_TRIGGER(HornOfWinterTrigger, "horn of winter"); - BUFF_TRIGGER(BoneShieldTrigger, "bone shield"); - BUFF_TRIGGER(ImprovedIcyTalonsTrigger, "improved icy talons"); - DEBUFF_TRIGGER(PlagueStrikeDebuffTrigger, "plague strike"); - DEBUFF_TRIGGER(IcyTouchDebuffTrigger, "icy touch"); + BUFF_TRIGGER(HornOfWinterTrigger, "horn of winter", "horn of winter"); + BUFF_TRIGGER(BoneShieldTrigger, "bone shield", "bone shield"); + BUFF_TRIGGER(ImprovedIcyTalonsTrigger, "improved icy talons", "improved icy talons"); + DEBUFF_TRIGGER(PlagueStrikeDebuffTrigger, "plague strike", "plague strike"); + DEBUFF_TRIGGER(IcyTouchDebuffTrigger, "icy touch", "icy touch"); - class PlagueStrikeDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger + class PlagueStrikeDebuffOnAttackerTrigger : public DebuffOnAttackerTrigger { public: PlagueStrikeDebuffOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "plague strike") {} From 469fb55bd9f22f888bdf2d044da05f69f919378f Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Sat, 9 Apr 2022 08:49:02 -0400 Subject: [PATCH 8/9] CPP Check fixes * Convert .find -> .starts_with * Pass string by constant reference instead of value * Pre-increment in the for loop post-action --- src/game/WorldHandlers/World.cpp | 2 +- src/modules/Bots/ahbot/AhBotConfig.cpp | 7 +++- src/modules/Bots/ahbot/AhBotConfig.h | 10 ++--- src/modules/Bots/ahbot/PricingStrategy.h | 2 +- src/modules/Bots/playerbot/ChatFilter.cpp | 8 ++-- src/modules/Bots/playerbot/ChatHelper.cpp | 2 +- src/modules/Bots/playerbot/ChatHelper.h | 2 +- src/modules/Bots/playerbot/FleeManager.cpp | 6 +-- .../Bots/playerbot/LootObjectStack.cpp | 18 ++------ src/modules/Bots/playerbot/PlayerbotAI.cpp | 14 +++---- src/modules/Bots/playerbot/PlayerbotAI.h | 2 +- .../Bots/playerbot/PlayerbotAIConfig.cpp | 8 ++-- .../Bots/playerbot/PlayerbotFactory.cpp | 2 +- src/modules/Bots/playerbot/PlayerbotMgr.cpp | 4 +- .../Bots/playerbot/RandomPlayerbotMgr.cpp | 2 +- src/modules/Bots/playerbot/strategy/Action.h | 8 ++-- .../Bots/playerbot/strategy/AiObject.h | 2 +- .../Bots/playerbot/strategy/AiObjectContext.h | 4 +- .../Bots/playerbot/strategy/Engine.cpp | 42 +++++++++---------- src/modules/Bots/playerbot/strategy/Event.h | 14 ++----- .../Bots/playerbot/strategy/ItemVisitors.h | 4 +- .../Bots/playerbot/strategy/Multiplier.h | 2 +- .../playerbot/strategy/NamedObjectContext.h | 12 +++--- .../playerbot/strategy/PassiveMultiplier.cpp | 4 +- src/modules/Bots/playerbot/strategy/Queue.cpp | 6 +-- src/modules/Bots/playerbot/strategy/Trigger.h | 4 +- src/modules/Bots/playerbot/strategy/Value.h | 20 ++++----- .../strategy/actions/AcceptQuestAction.h | 2 +- .../strategy/actions/AddLootAction.cpp | 4 +- .../strategy/actions/AddLootAction.h | 2 +- .../playerbot/strategy/actions/AttackAction.h | 6 +-- .../playerbot/strategy/actions/BankAction.cpp | 6 +-- .../playerbot/strategy/actions/BuffAction.cpp | 2 +- .../playerbot/strategy/actions/BuyAction.cpp | 2 +- .../strategy/actions/ChangeStrategyAction.h | 2 +- .../strategy/actions/DestroyItemAction.cpp | 2 +- .../strategy/actions/EquipAction.cpp | 2 +- .../strategy/actions/FollowActions.h | 2 +- .../strategy/actions/GenericSpellActions.h | 36 +++++++--------- .../strategy/actions/InventoryAction.cpp | 6 +-- .../strategy/actions/InventoryAction.h | 2 +- .../strategy/actions/LeaveGroupAction.h | 2 +- .../strategy/actions/LogLevelAction.cpp | 2 +- .../strategy/actions/LootStrategyAction.cpp | 6 +-- .../strategy/actions/MovementActions.cpp | 4 +- .../strategy/actions/MovementActions.h | 2 +- .../strategy/actions/PositionAction.h | 2 +- .../strategy/actions/QueryItemUsageAction.cpp | 4 +- .../strategy/actions/QueryItemUsageAction.h | 2 +- .../playerbot/strategy/actions/QuestAction.h | 2 +- .../strategy/actions/ReachTargetActions.h | 4 +- .../strategy/actions/ReadyCheckAction.h | 2 +- .../strategy/actions/RepairAllAction.cpp | 2 +- .../actions/ReviveFromCorpseAction.cpp | 2 +- .../strategy/actions/RewardAction.cpp | 4 +- .../playerbot/strategy/actions/SellAction.cpp | 2 +- .../strategy/actions/SetHomeAction.cpp | 2 +- .../strategy/actions/StayActions.cpp | 2 +- .../playerbot/strategy/actions/StayActions.h | 2 +- .../playerbot/strategy/actions/TaxiAction.cpp | 6 ++- .../strategy/actions/TeleportAction.cpp | 2 +- .../strategy/actions/TellItemCountAction.cpp | 2 +- .../strategy/actions/TellLosAction.cpp | 4 +- .../strategy/actions/TellMasterAction.h | 2 +- .../strategy/actions/TellTargetAction.cpp | 2 +- .../strategy/actions/TradeAction.cpp | 2 +- .../strategy/actions/UnequipAction.cpp | 2 +- .../strategy/actions/UseItemAction.h | 4 +- .../actions/UseMeetingStoneAction.cpp | 2 +- .../strategy/actions/UseMeetingStoneAction.h | 2 +- .../playerbot/strategy/actions/WhoAction.cpp | 2 +- .../strategy/deathknight/DKActions.h | 6 +-- .../strategy/generic/PassTroughStrategy.h | 2 +- .../strategy/generic/PullStrategy.cpp | 2 +- .../playerbot/strategy/generic/PullStrategy.h | 2 +- .../strategy/rogue/RogueComboActions.h | 2 +- .../playerbot/strategy/shaman/ShamanActions.h | 2 +- .../strategy/shaman/ShamanTriggers.h | 2 +- .../strategy/triggers/ChatCommandTrigger.h | 2 +- .../strategy/triggers/CureTriggers.h | 6 +-- .../strategy/triggers/GenericTriggers.h | 32 +++++++------- .../strategy/triggers/HealthTriggers.h | 10 ++--- .../strategy/triggers/RangeTriggers.h | 4 +- .../strategy/triggers/WorldPacketTrigger.h | 2 +- .../strategy/values/AttackerCountValues.cpp | 4 +- .../strategy/values/AttackersValue.cpp | 4 +- .../strategy/values/CcTargetValue.cpp | 2 +- .../strategy/values/CurrentCcTargetValue.cpp | 2 +- .../strategy/values/GrindTargetValue.cpp | 4 +- .../playerbot/strategy/values/HasTotemValue.h | 2 +- .../strategy/values/ItemCountValue.cpp | 2 +- .../strategy/values/LastMovementValue.h | 20 ++++----- .../values/PartyMemberWithoutAuraValue.cpp | 2 +- .../strategy/values/RtiTargetValue.h | 2 +- .../playerbot/strategy/values/TargetValue.cpp | 2 +- .../strategy/values/ThreatValues.cpp | 2 +- .../strategy/warlock/WarlockTriggers.h | 2 +- .../strategy/warrior/WarriorActions.h | 4 +- 98 files changed, 241 insertions(+), 254 deletions(-) diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index 5159f67987..cbf58b944a 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -1602,7 +1602,7 @@ void World::SetInitialWorldSettings() #endif #ifdef ENABLE_PLAYERBOTS - auctionbot.Initialize(); + sAhBotConfig.Initialize(); sPlayerbotAIConfig.Initialize(); #endif diff --git a/src/modules/Bots/ahbot/AhBotConfig.cpp b/src/modules/Bots/ahbot/AhBotConfig.cpp index d03b409d2c..9de895e8f9 100644 --- a/src/modules/Bots/ahbot/AhBotConfig.cpp +++ b/src/modules/Bots/ahbot/AhBotConfig.cpp @@ -9,10 +9,14 @@ INSTANTIATE_SINGLETON_1(AhBotConfig); AhBotConfig::AhBotConfig() { + enabled = false; + priceMultiplier = 1.0f; + priceQualityMultiplier = 1.0f; + underPriceProbability = 0.05f; } template -void LoadSet(string value, T &res) +void LoadSet(const string& value, T &res) { vector ids = split(value, ','); for (vector::iterator i = ids.begin(); i != ids.end(); ++i) @@ -59,6 +63,7 @@ bool AhBotConfig::Initialize() priceQualityMultiplier = config.GetFloatDefault("AhBot.PriceQualityMultiplier", 1.0f); underPriceProbability = config.GetFloatDefault("AhBot.UnderPriceProbability", 0.05f); LoadSet >(config.GetStringDefault("AhBot.IgnoreItemIds", "49283,52200,8494,6345,6891,2460,37164,34835"), ignoreItemIds); + sLog.outString("AhBot loaded"); } else { diff --git a/src/modules/Bots/ahbot/AhBotConfig.h b/src/modules/Bots/ahbot/AhBotConfig.h index f81a2bbd2b..b9f182e6cc 100644 --- a/src/modules/Bots/ahbot/AhBotConfig.h +++ b/src/modules/Bots/ahbot/AhBotConfig.h @@ -25,22 +25,22 @@ class AhBotConfig float underPriceProbability; std::set ignoreItemIds; - float GetSellPriceMultiplier(string category) + float GetSellPriceMultiplier(const string& category) { return GetCategoryParameter(sellPriceMultipliers, "PriceMultiplier.Sell", category, 1.0f); } - float GetBuyPriceMultiplier(string category) + float GetBuyPriceMultiplier(const string& category) { return GetCategoryParameter(buyPriceMultipliers, "PriceMultiplier.Buy", category, 1.0f); } - float GetItemPriceMultiplier(string name) + float GetItemPriceMultiplier(const string& name) { return GetCategoryParameter(itemPriceMultipliers, "PriceMultiplier.Item", name, 1.0f); } - int32 GetMaxAllowedAuctionCount(string category) + int32 GetMaxAllowedAuctionCount(const string& category) { return (int32)GetCategoryParameter(maxAuctionCount, "MaxAuctionCount", category, 5); } @@ -66,7 +66,7 @@ class AhBotConfig } private: - float GetCategoryParameter(map& cache, string type, string category, float defaultValue) + float GetCategoryParameter(map& cache, const string& type, const string& category, float defaultValue) { if (cache.find(category) == cache.end()) { diff --git a/src/modules/Bots/ahbot/PricingStrategy.h b/src/modules/Bots/ahbot/PricingStrategy.h index 80f9530fd4..de50f484e5 100644 --- a/src/modules/Bots/ahbot/PricingStrategy.h +++ b/src/modules/Bots/ahbot/PricingStrategy.h @@ -45,7 +45,7 @@ namespace ahbot class PricingStrategyFactory { public: - static PricingStrategy* Create(string name, Category* category) + static PricingStrategy* Create(const string& name, Category* category) { if (name == "buyOnlyRare") { diff --git a/src/modules/Bots/playerbot/ChatFilter.cpp b/src/modules/Bots/playerbot/ChatFilter.cpp index 0a2d7cb6b6..29c6b59ad8 100644 --- a/src/modules/Bots/playerbot/ChatFilter.cpp +++ b/src/modules/Bots/playerbot/ChatFilter.cpp @@ -180,7 +180,7 @@ class RtiChatFilter : public ChatFilter } bool found = false; - for (list::iterator i = rtis.begin(); i != rtis.end(); i++) + for (list::iterator i = rtis.begin(); i != rtis.end(); ++i) { string rti = *i; @@ -247,7 +247,7 @@ class ClassChatFilter : public ChatFilter Player* bot = ai->GetBot(); bool found = false; - for (map::iterator i = classNames.begin(); i != classNames.end(); i++) + for (map::iterator i = classNames.begin(); i != classNames.end(); ++i) { bool isClass = message.find(i->first) == 0; if (isClass && bot->getClass() != i->second) @@ -286,7 +286,7 @@ CompositeChatFilter::CompositeChatFilter(PlayerbotAI* ai) : ChatFilter(ai) CompositeChatFilter::~CompositeChatFilter() { - for (list::iterator i = filters.begin(); i != filters.end(); i++) + for (list::iterator i = filters.begin(); i != filters.end(); ++i) { delete (*i); } @@ -296,7 +296,7 @@ string CompositeChatFilter::Filter(string message) { for (int j = 0; j < filters.size(); ++j) { - for (list::iterator i = filters.begin(); i != filters.end(); i++) + for (list::iterator i = filters.begin(); i != filters.end(); ++i) { message = (*i)->Filter(message); if (message.empty()) diff --git a/src/modules/Bots/playerbot/ChatHelper.cpp b/src/modules/Bots/playerbot/ChatHelper.cpp index f724155abf..6cdf2e7d82 100644 --- a/src/modules/Bots/playerbot/ChatHelper.cpp +++ b/src/modules/Bots/playerbot/ChatHelper.cpp @@ -376,7 +376,7 @@ list ChatHelper::parseGameobjects(string& text) return gos; } -string ChatHelper::formatQuestObjective(string name, int available, int required) +string ChatHelper::formatQuestObjective(const string &name, int available, int required) { ostringstream out; out << "|cFFFFFFFF" << name << (available >= required ? "|c0000FF00: " : "|c00FF0000: ") diff --git a/src/modules/Bots/playerbot/ChatHelper.h b/src/modules/Bots/playerbot/ChatHelper.h index d1a4d5d020..aa0bcf9027 100644 --- a/src/modules/Bots/playerbot/ChatHelper.h +++ b/src/modules/Bots/playerbot/ChatHelper.h @@ -21,7 +21,7 @@ namespace ai static string formatItem(ItemPrototype const * proto, int count = 0); static string formatSpell(SpellEntry const *sInfo); static string formatGameobject(GameObject* go); - static string formatQuestObjective(string name, int available, int required); + static string formatQuestObjective(const string &name, int available, int required); static list parseGameobjects(string& text); static ChatMsg parseChat(string& text); diff --git a/src/modules/Bots/playerbot/FleeManager.cpp b/src/modules/Bots/playerbot/FleeManager.cpp index 85d0c71e31..2592cab7e8 100644 --- a/src/modules/Bots/playerbot/FleeManager.cpp +++ b/src/modules/Bots/playerbot/FleeManager.cpp @@ -91,7 +91,7 @@ void FleeManager::calculatePossibleDestinations(list &points) void FleeManager::cleanup(list &points) { - for (list::iterator i = points.begin(); i != points.end(); i++) + for (list::iterator i = points.begin(); i != points.end(); ++i) { FleePoint* point = *i; delete point; @@ -124,7 +124,7 @@ bool FleePoint::isBetterByAll(FleePoint* other) FleePoint* FleeManager::selectOptimalDestination(list &points) { FleePoint* byCreatures = NULL; - for (list::iterator i = points.begin(); i != points.end(); i++) + for (list::iterator i = points.begin(); i != points.end(); ++i) { FleePoint* point = *i; if (point->isReasonable() && (!byCreatures || point->isBetterByCreatures(byCreatures))) @@ -134,7 +134,7 @@ FleePoint* FleeManager::selectOptimalDestination(list &points) } FleePoint* byAll = NULL; - for (list::iterator i = points.begin(); i != points.end(); i++) + for (list::iterator i = points.begin(); i != points.end(); ++i) { FleePoint* point = *i; if (point->isReasonable() && (!byAll || point->isBetterByAll(byAll))) diff --git a/src/modules/Bots/playerbot/LootObjectStack.cpp b/src/modules/Bots/playerbot/LootObjectStack.cpp index a684b0628a..982f45910e 100644 --- a/src/modules/Bots/playerbot/LootObjectStack.cpp +++ b/src/modules/Bots/playerbot/LootObjectStack.cpp @@ -11,11 +11,7 @@ LootTarget::LootTarget(ObjectGuid guid) : guid(guid), asOfTime(time(0)) { } -LootTarget::LootTarget(LootTarget const& other) -{ - guid = other.guid; - asOfTime = other.asOfTime; -} +LootTarget::LootTarget(LootTarget const& other): guid(other.guid), asOfTime(other.asOfTime) {}; LootTarget& LootTarget::operator=(LootTarget const& other) { @@ -143,13 +139,7 @@ WorldObject* LootObject::GetWorldObject(Player* bot) return NULL; } -LootObject::LootObject(const LootObject& other) -{ - guid = other.guid; - skillId = other.skillId; - reqSkillValue = other.reqSkillValue; - reqItem = other.reqItem; -} +LootObject::LootObject(const LootObject& other): guid(other.guid), skillId(other.skillId), reqSkillValue(other.reqSkillValue), reqItem(other.reqItem) {}; bool LootObject::IsLootPossible(Player* bot) { @@ -247,7 +237,7 @@ vector LootObjectStack::OrderByDistance(float maxDistance) map sortedMap; LootTargetList safeCopy(availableLoot); - for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); i++) + for (LootTargetList::iterator i = safeCopy.begin(); i != safeCopy.end(); ++i) { ObjectGuid guid = i->guid; LootObject lootObject(bot, guid); @@ -264,7 +254,7 @@ vector LootObjectStack::OrderByDistance(float maxDistance) } vector result; - for (map::iterator i = sortedMap.begin(); i != sortedMap.end(); i++) + for (map::iterator i = sortedMap.begin(); i != sortedMap.end(); ++i) { result.push_back(i->second); } diff --git a/src/modules/Bots/playerbot/PlayerbotAI.cpp b/src/modules/Bots/playerbot/PlayerbotAI.cpp index 5a705f4b91..c6ba4cdc38 100644 --- a/src/modules/Bots/playerbot/PlayerbotAI.cpp +++ b/src/modules/Bots/playerbot/PlayerbotAI.cpp @@ -32,7 +32,7 @@ uint32 PlayerbotChatHandler::extractQuestId(string str) return cId ? atol(cId) : 0; } -void PacketHandlingHelper::AddHandler(uint16 opcode, string handler) +void PacketHandlingHelper::AddHandler(uint16 opcode, const string &handler) { handlers[opcode] = handler; } @@ -246,7 +246,7 @@ void PlayerbotAI::HandleCommand(uint32 type, const string& text, Player& fromPla string filtered = text; if (!sPlayerbotAIConfig.commandPrefix.empty()) { - if (filtered.find(sPlayerbotAIConfig.commandPrefix) != 0) + if (filtered.starts_with(sPlayerbotAIConfig.commandPrefix)) { return; } @@ -260,7 +260,7 @@ void PlayerbotAI::HandleCommand(uint32 type, const string& text, Player& fromPla return; } - if (filtered.find("who") != 0 && !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, &fromPlayer)) + if (filtered.starts_with("who") && !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, &fromPlayer)) { return; } @@ -710,7 +710,7 @@ Creature* PlayerbotAI::GetCreature(ObjectGuid guid) MaNGOS::UnitListSearcher searcher(targets, u_check); Cell::VisitAllObjects(bot, searcher, sPlayerbotAIConfig.sightDistance); - for(list::iterator i = targets.begin(); i != targets.end(); i++) + for(list::iterator i = targets.begin(); i != targets.end(); ++i) { Creature* creature = dynamic_cast(*i); if (creature) @@ -735,7 +735,7 @@ GameObject* PlayerbotAI::GetGameObject(ObjectGuid guid) MaNGOS::GameObjectListSearcher searcher(targets, u_check); Cell::VisitAllObjects(bot, searcher, sPlayerbotAIConfig.sightDistance); - for(list::iterator i = targets.begin(); i != targets.end(); i++) + for(list::iterator i = targets.begin(); i != targets.end(); ++i) { GameObject* go = *i; if (go && go->isSpawned()) @@ -769,7 +769,7 @@ bool PlayerbotAI::TellMasterNoFacing(string text, PlayerbotSecurityLevel securit return true; } -bool PlayerbotAI::TellMaster(string text, PlayerbotSecurityLevel securityLevel) +bool PlayerbotAI::TellMaster(const string &text, PlayerbotSecurityLevel securityLevel) { if (!TellMasterNoFacing(text, securityLevel)) { @@ -839,7 +839,7 @@ bool PlayerbotAI::HasAura(string name, Unit* unit) for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++) { Unit::AuraList const& auras = unit->GetAurasByType((AuraType)auraType); - for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); i++) + for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i) { Aura* aura = *i; if (!aura) diff --git a/src/modules/Bots/playerbot/PlayerbotAI.h b/src/modules/Bots/playerbot/PlayerbotAI.h index b36d188dca..87eb372cc3 100644 --- a/src/modules/Bots/playerbot/PlayerbotAI.h +++ b/src/modules/Bots/playerbot/PlayerbotAI.h @@ -82,7 +82,7 @@ class PacketHandlingHelper class ChatCommandHolder { public: - ChatCommandHolder(string command, Player* owner = NULL, uint32 type = CHAT_MSG_WHISPER) : command(command), owner(owner), type(type) {} + ChatCommandHolder(const string &command, Player* owner = NULL, uint32 type = CHAT_MSG_WHISPER) : command(command), owner(owner), type(type) {} ChatCommandHolder(ChatCommandHolder const& other) { this->command = other.command; diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp index 7a44be874e..9549011773 100644 --- a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp @@ -14,10 +14,10 @@ PlayerbotAIConfig::PlayerbotAIConfig() } template -void LoadList(string value, T &list) +void LoadList(const string &value, T &list) { vector ids = split(value, ','); - for (vector::iterator i = ids.begin(); i != ids.end(); i++) + for (vector::iterator i = ids.begin(); i != ids.end(); ++i) { uint32 id = atoi((*i).c_str()); if (!id) @@ -144,7 +144,7 @@ bool PlayerbotAIConfig::IsInRandomQuestItemList(uint32 id) return find(randomBotQuestItems.begin(), randomBotQuestItems.end(), id) != randomBotQuestItems.end(); } -string PlayerbotAIConfig::GetValue(string name) +string PlayerbotAIConfig::GetValue(const string &name) { ostringstream out; @@ -211,7 +211,7 @@ string PlayerbotAIConfig::GetValue(string name) return out.str(); } -void PlayerbotAIConfig::SetValue(string name, string value) +void PlayerbotAIConfig::SetValue(const string &name, string value) { istringstream out(value, istringstream::in); diff --git a/src/modules/Bots/playerbot/PlayerbotFactory.cpp b/src/modules/Bots/playerbot/PlayerbotFactory.cpp index a8d4811bd0..9d77e64c4f 100644 --- a/src/modules/Bots/playerbot/PlayerbotFactory.cpp +++ b/src/modules/Bots/playerbot/PlayerbotFactory.cpp @@ -1316,7 +1316,7 @@ void PlayerbotFactory::InitTalents(uint32 specNo) ObjectGuid PlayerbotFactory::GetRandomBot() { vector guids; - for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); i++) + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); ++i) { uint32 accountId = *i; if (!sAccountMgr.GetCharactersCount(accountId)) diff --git a/src/modules/Bots/playerbot/PlayerbotMgr.cpp b/src/modules/Bots/playerbot/PlayerbotMgr.cpp index bbf94c61c0..b03205b4b4 100644 --- a/src/modules/Bots/playerbot/PlayerbotMgr.cpp +++ b/src/modules/Bots/playerbot/PlayerbotMgr.cpp @@ -125,7 +125,7 @@ void PlayerbotHolder::OnBotLogin(Player * const bot) ai->TellMaster("Hello!"); } -bool PlayerbotHolder::ProcessBotCommand(string cmd, ObjectGuid guid, bool admin, uint32 masterAccountId) +bool PlayerbotHolder::ProcessBotCommand(const string &cmd, ObjectGuid guid, bool admin, uint32 masterAccountId) { // if (!sPlayerbotAIConfig.enabled || guid.IsEmpty()) // { @@ -325,7 +325,7 @@ list PlayerbotHolder::HandlePlayerbotCommand(char* args, Player* master) } vector chars = split(charnameStr, ','); - for (vector::iterator i = chars.begin(); i != chars.end(); i++) + for (vector::iterator i = chars.begin(); i != chars.end(); ++i) { string s = *i; diff --git a/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp index 071bb925dc..52d8710c8d 100644 --- a/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp +++ b/src/modules/Bots/playerbot/RandomPlayerbotMgr.cpp @@ -544,7 +544,7 @@ vector RandomPlayerbotMgr::GetFreeBots(bool alliance) } vector guids; - for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); i++) + for (list::iterator i = sPlayerbotAIConfig.randomBotAccounts.begin(); i != sPlayerbotAIConfig.randomBotAccounts.end(); ++i) { uint32 accountId = *i; if (!sAccountMgr.GetCharactersCount(accountId)) diff --git a/src/modules/Bots/playerbot/strategy/Action.h b/src/modules/Bots/playerbot/strategy/Action.h index 84213a9784..f5ecba626e 100644 --- a/src/modules/Bots/playerbot/strategy/Action.h +++ b/src/modules/Bots/playerbot/strategy/Action.h @@ -8,7 +8,7 @@ namespace ai class NextAction { public: - NextAction(string name, float relevance = 0.0f) + NextAction(const string &name, float relevance = 0.0f) { this->name = name; this->relevance = relevance; @@ -49,7 +49,7 @@ namespace ai class Action : public AiNamedObject { public: - Action(PlayerbotAI* ai, string name = "action") : verbose(false), AiNamedObject(ai, name) { } + Action(PlayerbotAI* ai, const string &name = "action") : verbose(false), AiNamedObject(ai, name) { } virtual ~Action(void) {} public: @@ -74,7 +74,7 @@ namespace ai class ActionNode { public: - ActionNode(string name, NextAction** prerequisites = NULL, NextAction** alternatives = NULL, NextAction** continuers = NULL) + ActionNode(const string &name, NextAction** prerequisites = NULL, NextAction** alternatives = NULL, NextAction** continuers = NULL) { this->action = NULL; this->name = name; @@ -112,7 +112,7 @@ namespace ai class ActionBasket { public: - ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, Event event) : + ActionBasket(ActionNode* action, float relevance, bool skipPrerequisites, const Event &event) : action(action), relevance(relevance), skipPrerequisites(skipPrerequisites), event(event) {} virtual ~ActionBasket(void) {} public: diff --git a/src/modules/Bots/playerbot/strategy/AiObject.h b/src/modules/Bots/playerbot/strategy/AiObject.h index b16756c607..5b7624ce5b 100644 --- a/src/modules/Bots/playerbot/strategy/AiObject.h +++ b/src/modules/Bots/playerbot/strategy/AiObject.h @@ -22,7 +22,7 @@ namespace ai class AiNamedObject : public AiObject { public: - AiNamedObject(PlayerbotAI* ai, string name) : AiObject(ai), name(name) {} + AiNamedObject(PlayerbotAI* ai, const string &name) : AiObject(ai), name(name) {} public: virtual string getName() { return name; } diff --git a/src/modules/Bots/playerbot/strategy/AiObjectContext.h b/src/modules/Bots/playerbot/strategy/AiObjectContext.h index 7a3d24e198..104bd5910e 100644 --- a/src/modules/Bots/playerbot/strategy/AiObjectContext.h +++ b/src/modules/Bots/playerbot/strategy/AiObjectContext.h @@ -22,13 +22,13 @@ namespace ai virtual UntypedValue* GetUntypedValue(string name) { return valueContexts.GetObject(name, ai); } template - Value* GetValue(string name) + Value* GetValue(const string &name) { return dynamic_cast*>(GetUntypedValue(name)); } template - Value* GetValue(string name, string param) + Value* GetValue(const string &name, const string ¶m) { return GetValue((string(name) + "::" + param)); } diff --git a/src/modules/Bots/playerbot/strategy/Engine.cpp b/src/modules/Bots/playerbot/strategy/Engine.cpp index cd68defe43..9a5f60d109 100644 --- a/src/modules/Bots/playerbot/strategy/Engine.cpp +++ b/src/modules/Bots/playerbot/strategy/Engine.cpp @@ -16,7 +16,7 @@ Engine::Engine(PlayerbotAI* ai, AiObjectContext *factory) : PlayerbotAIAware(ai) bool ActionExecutionListeners::Before(Action* action, Event event) { bool result = true; - for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + for (list::iterator i = listeners.begin(); i!=listeners.end(); ++i) { result &= (*i)->Before(action, event); } @@ -25,7 +25,7 @@ bool ActionExecutionListeners::Before(Action* action, Event event) void ActionExecutionListeners::After(Action* action, bool executed, Event event) { - for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + for (list::iterator i = listeners.begin(); i!=listeners.end(); ++i) { (*i)->After(action, executed, event); } @@ -34,7 +34,7 @@ void ActionExecutionListeners::After(Action* action, bool executed, Event event) bool ActionExecutionListeners::OverrideResult(Action* action, bool executed, Event event) { bool result = executed; - for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + for (list::iterator i = listeners.begin(); i!=listeners.end(); ++i) { result = (*i)->OverrideResult(action, result, event); } @@ -44,7 +44,7 @@ bool ActionExecutionListeners::OverrideResult(Action* action, bool executed, Eve bool ActionExecutionListeners::AllowExecution(Action* action, Event event) { bool result = true; - for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + for (list::iterator i = listeners.begin(); i!=listeners.end(); ++i) { result &= (*i)->AllowExecution(action, event); } @@ -53,7 +53,7 @@ bool ActionExecutionListeners::AllowExecution(Action* action, Event event) ActionExecutionListeners::~ActionExecutionListeners() { - for (list::iterator i = listeners.begin(); i!=listeners.end(); i++) + for (list::iterator i = listeners.begin(); i!=listeners.end(); ++i) { delete *i; } @@ -77,14 +77,14 @@ void Engine::Reset() delete action; } while (action); - for (list::iterator i = triggers.begin(); i != triggers.end(); i++) + for (list::iterator i = triggers.begin(); i != triggers.end(); ++i) { TriggerNode* trigger = *i; delete trigger; } triggers.clear(); - for (list::iterator i = multipliers.begin(); i != multipliers.end(); i++) + for (list::iterator i = multipliers.begin(); i != multipliers.end(); ++i) { Multiplier* multiplier = *i; delete multiplier; @@ -96,7 +96,7 @@ void Engine::Init() { Reset(); - for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + for (map::iterator i = strategies.begin(); i != strategies.end(); ++i) { Strategy* strategy = i->second; strategy->InitMultipliers(multipliers); @@ -152,7 +152,7 @@ bool Engine::DoNextAction(Unit* unit, int depth) } else if (action->isUseful()) { - for (list::iterator i = multipliers.begin(); i!= multipliers.end(); i++) + for (list::iterator i = multipliers.begin(); i!= multipliers.end(); ++i) { Multiplier* multiplier = *i; relevance *= multiplier->GetValue(action); @@ -230,7 +230,7 @@ bool Engine::DoNextAction(Unit* unit, int depth) ActionNode* Engine::CreateActionNode(string name) { - for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + for (map::iterator i = strategies.begin(); i != strategies.end(); ++i) { Strategy* strategy = i->second; ActionNode* node = strategy->GetAction(name); @@ -283,7 +283,7 @@ bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool sk return pushed; } -ActionResult Engine::ExecuteAction(string name) +ActionResult Engine::ExecuteAction(const string& name) { bool result = false; @@ -327,7 +327,7 @@ void Engine::addStrategy(string name) if (strategy) { set siblings = aiObjectContext->GetSiblingStrategy(name); - for (set::iterator i = siblings.begin(); i != siblings.end(); i++) + for (set::iterator i = siblings.begin(); i != siblings.end(); ++i) { removeStrategy(*i); } @@ -379,7 +379,7 @@ void Engine::removeAllStrategies() Init(); } -void Engine::toggleStrategy(string name) +void Engine::toggleStrategy(const string& name) { if (!removeStrategy(name)) { @@ -394,7 +394,7 @@ bool Engine::HasStrategy(string name) void Engine::ProcessTriggers() { - for (list::iterator i = triggers.begin(); i != triggers.end(); i++) + for (list::iterator i = triggers.begin(); i != triggers.end(); ++i) { TriggerNode* node = *i; if (!node) @@ -426,7 +426,7 @@ void Engine::ProcessTriggers() MultiplyAndPush(node->getHandlers(), 0.0f, false, event); } } - for (list::iterator i = triggers.begin(); i != triggers.end(); i++) + for (list::iterator i = triggers.begin(); i != triggers.end(); ++i) { Trigger* trigger = (*i)->getTrigger(); if (trigger) trigger->Reset(); @@ -435,7 +435,7 @@ void Engine::ProcessTriggers() void Engine::PushDefaultActions() { - for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + for (map::iterator i = strategies.begin(); i != strategies.end(); ++i) { Strategy* strategy = i->second; Event emptyEvent; @@ -452,7 +452,7 @@ string Engine::ListStrategies() return s; } - for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + for (map::iterator i = strategies.begin(); i != strategies.end(); ++i) { s.append(i->first); s.append(", "); @@ -460,7 +460,7 @@ string Engine::ListStrategies() return s.substr(0, s.length() - 2); } -void Engine::PushAgain(ActionNode* actionNode, float relevance, Event event) +void Engine::PushAgain(ActionNode* actionNode, float relevance, const Event& event) { NextAction** nextAction = new NextAction*[2]; nextAction[0] = new NextAction(actionNode->getName(), relevance); @@ -471,7 +471,7 @@ void Engine::PushAgain(ActionNode* actionNode, float relevance, Event event) bool Engine::ContainsStrategy(StrategyType type) { - for (map::iterator i = strategies.begin(); i != strategies.end(); i++) + for (map::iterator i = strategies.begin(); i != strategies.end(); ++i) { Strategy* strategy = i->second; if (strategy->GetType() & type) @@ -539,10 +539,10 @@ void Engine::LogAction(const char* format, ...) } } -void Engine::ChangeStrategy(string names) +void Engine::ChangeStrategy(const string& names) { vector splitted = split(names, ','); - for (vector::iterator i = splitted.begin(); i != splitted.end(); i++) + for (vector::iterator i = splitted.begin(); i != splitted.end(); ++i) { const char* name = i->c_str(); switch (name[0]) diff --git a/src/modules/Bots/playerbot/strategy/Event.h b/src/modules/Bots/playerbot/strategy/Event.h index 68d8b5186e..a92c321407 100644 --- a/src/modules/Bots/playerbot/strategy/Event.h +++ b/src/modules/Bots/playerbot/strategy/Event.h @@ -5,17 +5,11 @@ namespace ai class Event { public: - Event(Event const& other) - { - source = other.source; - param = other.param; - packet = other.packet; - owner = other.owner; - } + Event(Event const& other): source(other.source), param(other.param), packet(other.packet), owner(other.owner) {} Event() {} - Event(string source) : source(source) {} - Event(string source, string param, Player* owner = NULL) : source(source), param(param), owner(owner) {} - Event(string source, WorldPacket &packet, Player* owner = NULL) : source(source), packet(packet), owner(owner) {} + Event(const string &source) : source(source) {} + Event(const string &source, const string ¶m, Player* owner = NULL) : source(source), param(param), owner(owner) {} + Event(const string &source, WorldPacket &packet, Player* owner = NULL) : source(source), packet(packet), owner(owner) {} virtual ~Event() {} public: diff --git a/src/modules/Bots/playerbot/strategy/ItemVisitors.h b/src/modules/Bots/playerbot/strategy/ItemVisitors.h index 8fe03d8cab..8ecee5b564 100644 --- a/src/modules/Bots/playerbot/strategy/ItemVisitors.h +++ b/src/modules/Bots/playerbot/strategy/ItemVisitors.h @@ -186,7 +186,7 @@ namespace ai class QueryNamedItemCountVisitor : public QueryItemCountVisitor { public: - QueryNamedItemCountVisitor(string name) : QueryItemCountVisitor(0) + QueryNamedItemCountVisitor(const string &name) : QueryItemCountVisitor(0) { this->name = name; } @@ -208,7 +208,7 @@ namespace ai class FindUsableNamedItemVisitor : public FindUsableItemVisitor { public: - FindUsableNamedItemVisitor(Player* bot, string name) : FindUsableItemVisitor(bot) + FindUsableNamedItemVisitor(Player* bot, const string &name) : FindUsableItemVisitor(bot) { this->name = name; } diff --git a/src/modules/Bots/playerbot/strategy/Multiplier.h b/src/modules/Bots/playerbot/strategy/Multiplier.h index e86fa05c28..a4780e0ead 100644 --- a/src/modules/Bots/playerbot/strategy/Multiplier.h +++ b/src/modules/Bots/playerbot/strategy/Multiplier.h @@ -6,7 +6,7 @@ namespace ai class Multiplier : public AiNamedObject { public: - Multiplier(PlayerbotAI* ai, string name) : AiNamedObject(ai, name) {} + Multiplier(PlayerbotAI* ai, const string &name) : AiNamedObject(ai, name) {} virtual ~Multiplier() {} public: diff --git a/src/modules/Bots/playerbot/strategy/NamedObjectContext.h b/src/modules/Bots/playerbot/strategy/NamedObjectContext.h index 77bf1beb8f..e7de43248f 100644 --- a/src/modules/Bots/playerbot/strategy/NamedObjectContext.h +++ b/src/modules/Bots/playerbot/strategy/NamedObjectContext.h @@ -10,7 +10,7 @@ namespace ai Qualified() {}; public: - void Qualify(string qualifier) { this->qualifier = qualifier; } + void Qualify(const string &qualifier) { this->qualifier = qualifier; } protected: string qualifier; @@ -57,7 +57,7 @@ namespace ai set supports() { set keys; - for (typename map::iterator it = creators.begin(); it != creators.end(); it++) + for (typename map::iterator it = creators.begin(); it != creators.end(); ++it) { keys.insert(it->first); } @@ -89,7 +89,7 @@ namespace ai void Clear() { - for (typename map::iterator i = created.begin(); i != created.end(); i++) + for (typename map::iterator i = created.begin(); i != created.end(); ++i) { if (i->second) { @@ -102,7 +102,7 @@ namespace ai void Update() { - for (typename map::iterator i = created.begin(); i != created.end(); i++) + for (typename map::iterator i = created.begin(); i != created.end(); ++i) { if (i->second) { @@ -113,7 +113,7 @@ namespace ai void Reset() { - for (typename map::iterator i = created.begin(); i != created.end(); i++) + for (typename map::iterator i = created.begin(); i != created.end(); ++i) { if (i->second) { @@ -128,7 +128,7 @@ namespace ai set GetCreated() { set keys; - for (typename map::iterator it = created.begin(); it != created.end(); it++) + for (typename map::iterator it = created.begin(); it != created.end(); ++it) { keys.insert(it->first); } diff --git a/src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp b/src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp index 060805a9be..91902123c7 100644 --- a/src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp +++ b/src/modules/Bots/playerbot/strategy/PassiveMultiplier.cpp @@ -33,7 +33,7 @@ float PassiveMultiplier::GetValue(Action* action) { string name = action->getName(); - for (list::iterator i = allowedActions.begin(); i != allowedActions.end(); i++) + for (list::iterator i = allowedActions.begin(); i != allowedActions.end(); ++i) { if (name == *i) { @@ -41,7 +41,7 @@ float PassiveMultiplier::GetValue(Action* action) { } } - for (list::iterator i = allowedParts.begin(); i != allowedParts.end(); i++) + for (list::iterator i = allowedParts.begin(); i != allowedParts.end(); ++i) { if (name.find(*i) != string::npos) { diff --git a/src/modules/Bots/playerbot/strategy/Queue.cpp b/src/modules/Bots/playerbot/strategy/Queue.cpp index b65f9c663d..fa000c9afb 100644 --- a/src/modules/Bots/playerbot/strategy/Queue.cpp +++ b/src/modules/Bots/playerbot/strategy/Queue.cpp @@ -10,7 +10,7 @@ void Queue::Push(ActionBasket *action) { if (action) { - for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) + for (std::list::iterator iter = actions.begin(); iter != actions.end(); ++iter) { ActionBasket* basket = *iter; if (action->getAction()->getName() == basket->getAction()->getName()) @@ -42,7 +42,7 @@ ActionNode* Queue::Pop() { float max = -1; ActionBasket* selection = NULL; - for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) + for (std::list::iterator iter = actions.begin(); iter != actions.end(); ++iter) { ActionBasket* basket = *iter; if (basket->getRelevance() > max) @@ -65,7 +65,7 @@ ActionBasket* Queue::Peek() { float max = -1; ActionBasket* selection = NULL; - for (std::list::iterator iter = actions.begin(); iter != actions.end(); iter++) + for (std::list::iterator iter = actions.begin(); iter != actions.end(); ++iter) { ActionBasket* basket = *iter; if (basket->getRelevance() > max) diff --git a/src/modules/Bots/playerbot/strategy/Trigger.h b/src/modules/Bots/playerbot/strategy/Trigger.h index d36c767821..1c92cc5f7f 100644 --- a/src/modules/Bots/playerbot/strategy/Trigger.h +++ b/src/modules/Bots/playerbot/strategy/Trigger.h @@ -22,7 +22,7 @@ namespace ai class Trigger : public AiNamedObject { public: - Trigger(PlayerbotAI* ai, string name = "trigger", int checkInterval = 1) : AiNamedObject(ai, name) { + Trigger(PlayerbotAI* ai, const string &name = "trigger", int checkInterval = 1) : AiNamedObject(ai, name) { this->checkInterval = checkInterval; ticksElapsed = 0; } @@ -59,7 +59,7 @@ namespace ai class TriggerNode { public: - TriggerNode(string name, NextAction** handlers = NULL) + TriggerNode(const string &name, NextAction** handlers = NULL) { this->name = name; this->handlers = handlers; diff --git a/src/modules/Bots/playerbot/strategy/Value.h b/src/modules/Bots/playerbot/strategy/Value.h index e0ba55f7f4..8daf059e12 100644 --- a/src/modules/Bots/playerbot/strategy/Value.h +++ b/src/modules/Bots/playerbot/strategy/Value.h @@ -9,7 +9,7 @@ namespace ai class UntypedValue : public AiNamedObject { public: - UntypedValue(PlayerbotAI* ai, string name) : AiNamedObject(ai, name) {} + UntypedValue(PlayerbotAI* ai, const string &name) : AiNamedObject(ai, name) {} virtual void Update() {} virtual void Reset() {} virtual string Format() { return "?"; } @@ -28,7 +28,7 @@ namespace ai class CalculatedValue : public UntypedValue, public Value { public: - CalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : UntypedValue(ai, name), + CalculatedValue(PlayerbotAI* ai, const string &name = "value", int checkInterval = 1) : UntypedValue(ai, name), checkInterval(checkInterval), ticksElapsed(checkInterval) { } virtual ~CalculatedValue() {} @@ -66,7 +66,7 @@ namespace ai class Uint8CalculatedValue : public CalculatedValue { public: - Uint8CalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + Uint8CalculatedValue(PlayerbotAI* ai, const string &name = "value", int checkInterval = 1) : CalculatedValue(ai, name, checkInterval) {} virtual string Format() @@ -79,7 +79,7 @@ namespace ai class Uint32CalculatedValue : public CalculatedValue { public: - Uint32CalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + Uint32CalculatedValue(PlayerbotAI* ai, const string &name = "value", int checkInterval = 1) : CalculatedValue(ai, name, checkInterval) {} virtual string Format() @@ -92,7 +92,7 @@ namespace ai class FloatCalculatedValue : public CalculatedValue { public: - FloatCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + FloatCalculatedValue(PlayerbotAI* ai, const string &name = "value", int checkInterval = 1) : CalculatedValue(ai, name, checkInterval) {} virtual string Format() @@ -105,7 +105,7 @@ namespace ai class BoolCalculatedValue : public CalculatedValue { public: - BoolCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + BoolCalculatedValue(PlayerbotAI* ai, const string &name = "value", int checkInterval = 1) : CalculatedValue(ai, name, checkInterval) {} virtual string Format() @@ -117,7 +117,7 @@ namespace ai class UnitCalculatedValue : public CalculatedValue { public: - UnitCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + UnitCalculatedValue(PlayerbotAI* ai, const string &name = "value", int checkInterval = 1) : CalculatedValue(ai, name, checkInterval) {} virtual string Format() @@ -130,7 +130,7 @@ namespace ai class ObjectGuidListCalculatedValue : public CalculatedValue > { public: - ObjectGuidListCalculatedValue(PlayerbotAI* ai, string name = "value", int checkInterval = 1) : + ObjectGuidListCalculatedValue(PlayerbotAI* ai, const string &name = "value", int checkInterval = 1) : CalculatedValue >(ai, name, checkInterval) {} virtual string Format() @@ -151,7 +151,7 @@ namespace ai class ManualSetValue : public UntypedValue, public Value { public: - ManualSetValue(PlayerbotAI* ai, T defaultValue, string name = "value") : + ManualSetValue(PlayerbotAI* ai, const T& defaultValue, const string &name = "value") : UntypedValue(ai, name), value(defaultValue), defaultValue(defaultValue) {} virtual ~ManualSetValue() {} @@ -169,7 +169,7 @@ namespace ai class UnitManualSetValue : public ManualSetValue { public: - UnitManualSetValue(PlayerbotAI* ai, Unit* defaultValue, string name = "value") : + UnitManualSetValue(PlayerbotAI* ai, Unit* defaultValue, const string &name = "value") : ManualSetValue(ai, defaultValue, name) {} virtual string Format() diff --git a/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h b/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h index 856c697180..d844d32e1d 100644 --- a/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/AcceptQuestAction.h @@ -7,7 +7,7 @@ namespace ai { class AcceptAllQuestsAction : public QuestAction { public: - AcceptAllQuestsAction(PlayerbotAI* ai, string name = "accept all quests") : QuestAction(ai, name) {} + AcceptAllQuestsAction(PlayerbotAI* ai, const string& name = "accept all quests") : QuestAction(ai, name) {} protected: virtual void ProcessQuest(Quest const* quest, WorldObject* questGiver); diff --git a/src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp index 704ff2e278..f08aab59fe 100644 --- a/src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.cpp @@ -22,13 +22,13 @@ bool AddAllLootAction::Execute(Event event) bool added = false; list gos = context->GetValue >("nearest game objects")->Get(); - for (list::iterator i = gos.begin(); i != gos.end(); i++) + for (list::iterator i = gos.begin(); i != gos.end(); ++i) { added |= AddLoot(*i); } list corpses = context->GetValue >("nearest corpses")->Get(); - for (list::iterator i = corpses.begin(); i != corpses.end(); i++) + for (list::iterator i = corpses.begin(); i != corpses.end(); ++i) { added |= AddLoot(*i); } diff --git a/src/modules/Bots/playerbot/strategy/actions/AddLootAction.h b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.h index 402c50ad4d..809111c17f 100644 --- a/src/modules/Bots/playerbot/strategy/actions/AddLootAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/AddLootAction.h @@ -13,7 +13,7 @@ namespace ai class AddAllLootAction : public Action { public: - AddAllLootAction(PlayerbotAI* ai, string name = "add all loot") : Action(ai, name) {} + AddAllLootAction(PlayerbotAI* ai, const string &name = "add all loot") : Action(ai, name) {} virtual bool Execute(Event event); virtual bool isUseful(); diff --git a/src/modules/Bots/playerbot/strategy/actions/AttackAction.h b/src/modules/Bots/playerbot/strategy/actions/AttackAction.h index e13eb40943..2b43031eef 100644 --- a/src/modules/Bots/playerbot/strategy/actions/AttackAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/AttackAction.h @@ -8,7 +8,7 @@ namespace ai class AttackAction : public MovementAction { public: - AttackAction(PlayerbotAI* ai, string name) : MovementAction(ai, name) {} + AttackAction(PlayerbotAI* ai, const string &name) : MovementAction(ai, name) {} public: virtual bool Execute(Event event); @@ -20,7 +20,7 @@ namespace ai class AttackMyTargetAction : public AttackAction { public: - AttackMyTargetAction(PlayerbotAI* ai, string name = "attack my target") : AttackAction(ai, name) {} + AttackMyTargetAction(PlayerbotAI* ai, const string &name = "attack my target") : AttackAction(ai, name) {} public: virtual bool Execute(Event event); @@ -29,7 +29,7 @@ namespace ai class AttackDuelOpponentAction : public AttackAction { public: - AttackDuelOpponentAction(PlayerbotAI* ai, string name = "attack duel opponent") : AttackAction(ai, name) {} + AttackDuelOpponentAction(PlayerbotAI* ai, const string &name = "attack duel opponent") : AttackAction(ai, name) {} public: virtual bool Execute(Event event); diff --git a/src/modules/Bots/playerbot/strategy/actions/BankAction.cpp b/src/modules/Bots/playerbot/strategy/actions/BankAction.cpp index 294f27f375..360499fa26 100644 --- a/src/modules/Bots/playerbot/strategy/actions/BankAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/BankAction.cpp @@ -12,7 +12,7 @@ bool BankAction::Execute(Event event) string text = event.getParam(); list npcs = AI_VALUE(list, "nearest npcs"); - for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + for (list::iterator i = npcs.begin(); i != npcs.end(); ++i) { Unit* npc = ai->GetUnit(*i); if (!npc || !bot->GetNPCIfCanInteractWith(npc->GetObjectGuid(), UNIT_NPC_FLAG_BANKER)) @@ -39,7 +39,7 @@ bool BankAction::Execute(string text, Unit* bank) if (text[0] == '-') { ItemIds found = chat->parseItems(text); - for (ItemIds::iterator i = found.begin(); i != found.end(); i++) + for (ItemIds::iterator i = found.begin(); i != found.end(); ++i) { uint32 itemId = *i; result &= Withdraw(itemId); @@ -53,7 +53,7 @@ bool BankAction::Execute(string text, Unit* bank) return false; } - for (list::iterator i = found.begin(); i != found.end(); i++) + for (list::iterator i = found.begin(); i != found.end(); ++i) { Item* item = *i; if (!item) diff --git a/src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp b/src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp index 333e98e2dd..0b117c4aab 100644 --- a/src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/BuffAction.cpp @@ -34,7 +34,7 @@ class FindBuffVisitor : public IterateItemsVisitor { proto->SubClass != ITEM_SUBCLASS_ITEM_ENHANCEMENT) return true; - for (int i=0; iSpells[i].SpellId; if (!spellId) diff --git a/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp b/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp index 214dcddb74..91424ab16d 100644 --- a/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/BuyAction.cpp @@ -43,7 +43,7 @@ bool BuyAction::Execute(Event event) return false; } - for (ItemIds::iterator i = itemIds.begin(); i != itemIds.end(); i++) + for (ItemIds::iterator i = itemIds.begin(); i != itemIds.end(); ++i) { for (uint32 slot = 0; slot < tItems->GetItemCount(); slot++) { diff --git a/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h b/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h index c1e53109c0..208e5877d5 100644 --- a/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/ChangeStrategyAction.h @@ -6,7 +6,7 @@ namespace ai { class ChangeCombatStrategyAction : public Action { public: - ChangeCombatStrategyAction(PlayerbotAI* ai, string name = "co") : Action(ai, name) {} + ChangeCombatStrategyAction(PlayerbotAI* ai, const string& name = "co") : Action(ai, name) {} public: virtual bool Execute(Event event); diff --git a/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp b/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp index 83f81696fc..fb1f04efea 100644 --- a/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/DestroyItemAction.cpp @@ -11,7 +11,7 @@ bool DestroyItemAction::Execute(Event event) string text = event.getParam(); ItemIds ids = chat->parseItems(text); - for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + for (ItemIds::iterator i =ids.begin(); i != ids.end(); ++i) { FindItemByIdVisitor visitor(*i); DestroyItem(&visitor); diff --git a/src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp b/src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp index 14a7bd4fad..2a10a9a832 100644 --- a/src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/EquipAction.cpp @@ -12,7 +12,7 @@ bool EquipAction::Execute(Event event) ItemIds ids = chat->parseItems(text); - for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + for (ItemIds::iterator i =ids.begin(); i != ids.end(); ++i) { FindItemByIdVisitor visitor(*i); EquipItem(&visitor); diff --git a/src/modules/Bots/playerbot/strategy/actions/FollowActions.h b/src/modules/Bots/playerbot/strategy/actions/FollowActions.h index 408ecb82af..6fe197770f 100644 --- a/src/modules/Bots/playerbot/strategy/actions/FollowActions.h +++ b/src/modules/Bots/playerbot/strategy/actions/FollowActions.h @@ -7,7 +7,7 @@ namespace ai { class FollowAction : public MovementAction { public: - FollowAction(PlayerbotAI* ai, string name) : MovementAction(ai, name) {} + FollowAction(PlayerbotAI* ai, const string& name) : MovementAction(ai, name) {} }; class FollowLineAction : public FollowAction { diff --git a/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h b/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h index 71824f49c3..76568f2e08 100644 --- a/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h +++ b/src/modules/Bots/playerbot/strategy/actions/GenericSpellActions.h @@ -47,7 +47,7 @@ namespace ai class CastSpellAction : public Action { public: - CastSpellAction(PlayerbotAI* ai, string spell) : Action(ai, spell), + CastSpellAction(PlayerbotAI* ai, const string &spell) : Action(ai, spell), range(sPlayerbotAIConfig.spellDistance) { this->spell = spell; @@ -84,7 +84,7 @@ namespace ai class CastAuraSpellAction : public CastSpellAction { public: - CastAuraSpellAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) {} + CastAuraSpellAction(PlayerbotAI* ai, const string &spell) : CastSpellAction(ai, spell) {} virtual bool isUseful(); }; @@ -93,7 +93,7 @@ namespace ai class CastMeleeSpellAction : public CastSpellAction { public: - CastMeleeSpellAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) { + CastMeleeSpellAction(PlayerbotAI* ai, const string &spell) : CastSpellAction(ai, spell) { range = ATTACK_DISTANCE; } }; @@ -102,13 +102,13 @@ namespace ai class CastDebuffSpellAction : public CastAuraSpellAction { public: - CastDebuffSpellAction(PlayerbotAI* ai, string spell) : CastAuraSpellAction(ai, spell) {} + CastDebuffSpellAction(PlayerbotAI* ai, const string &spell) : CastAuraSpellAction(ai, spell) {} }; class CastDebuffSpellOnAttackerAction : public CastAuraSpellAction { public: - CastDebuffSpellOnAttackerAction(PlayerbotAI* ai, string spell) : CastAuraSpellAction(ai, spell) {} + CastDebuffSpellOnAttackerAction(PlayerbotAI* ai, const string &spell) : CastAuraSpellAction(ai, spell) {} Value* GetTargetValue() { return context->GetValue("attacker without aura", spell); @@ -120,7 +120,7 @@ namespace ai class CastBuffSpellAction : public CastAuraSpellAction { public: - CastBuffSpellAction(PlayerbotAI* ai, string spell) : CastAuraSpellAction(ai, spell) + CastBuffSpellAction(PlayerbotAI* ai, const string &spell) : CastAuraSpellAction(ai, spell) { range = sPlayerbotAIConfig.spellDistance; } @@ -131,7 +131,7 @@ namespace ai class CastEnchantItemAction : public CastSpellAction { public: - CastEnchantItemAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) + CastEnchantItemAction(PlayerbotAI* ai, const string &spell) : CastSpellAction(ai, spell) { range = sPlayerbotAIConfig.spellDistance; } @@ -145,7 +145,7 @@ namespace ai class CastHealingSpellAction : public CastAuraSpellAction { public: - CastHealingSpellAction(PlayerbotAI* ai, string spell, uint8 estAmount = 15.0f) : CastAuraSpellAction(ai, spell) + CastHealingSpellAction(PlayerbotAI* ai, const string &spell, uint8 estAmount = 15.0f) : CastAuraSpellAction(ai, spell) { this->estAmount = estAmount; range = sPlayerbotAIConfig.spellDistance; @@ -161,7 +161,7 @@ namespace ai class CastAoeHealSpellAction : public CastHealingSpellAction { public: - CastAoeHealSpellAction(PlayerbotAI* ai, string spell, uint8 estAmount = 15.0f) : CastHealingSpellAction(ai, spell, estAmount) {} + CastAoeHealSpellAction(PlayerbotAI* ai, const string &spell, uint8 estAmount = 15.0f) : CastHealingSpellAction(ai, spell, estAmount) {} virtual string GetTargetName() { return "party member to heal"; } virtual bool isUseful(); }; @@ -169,7 +169,7 @@ namespace ai class CastCureSpellAction : public CastSpellAction { public: - CastCureSpellAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) + CastCureSpellAction(PlayerbotAI* ai, const string &spell) : CastSpellAction(ai, spell) { range = sPlayerbotAIConfig.spellDistance; } @@ -179,11 +179,7 @@ namespace ai class PartyMemberActionNameSupport { public: - PartyMemberActionNameSupport(string spell) - { - name = string(spell) + " on party"; - } - + PartyMemberActionNameSupport(const string &spell): name(string(spell) + " on party") {} virtual string getName() { return name; } private: @@ -193,7 +189,7 @@ namespace ai class HealPartyMemberAction : public CastHealingSpellAction, public PartyMemberActionNameSupport { public: - HealPartyMemberAction(PlayerbotAI* ai, string spell, uint8 estAmount = 15.0f) : + HealPartyMemberAction(PlayerbotAI* ai, const string &spell, uint8 estAmount = 15.0f) : CastHealingSpellAction(ai, spell, estAmount), PartyMemberActionNameSupport(spell) {} virtual string GetTargetName() { return "party member to heal"; } @@ -203,7 +199,7 @@ namespace ai class ResurrectPartyMemberAction : public CastSpellAction { public: - ResurrectPartyMemberAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) {} + ResurrectPartyMemberAction(PlayerbotAI* ai, const string &spell) : CastSpellAction(ai, spell) {} virtual string GetTargetName() { return "party member to resurrect"; } }; @@ -212,7 +208,7 @@ namespace ai class CurePartyMemberAction : public CastSpellAction, public PartyMemberActionNameSupport { public: - CurePartyMemberAction(PlayerbotAI* ai, string spell, uint32 dispelType) : + CurePartyMemberAction(PlayerbotAI* ai, const string &spell, uint32 dispelType) : CastSpellAction(ai, spell), PartyMemberActionNameSupport(spell) { this->dispelType = dispelType; @@ -230,7 +226,7 @@ namespace ai class BuffOnPartyAction : public CastBuffSpellAction, public PartyMemberActionNameSupport { public: - BuffOnPartyAction(PlayerbotAI* ai, string spell) : + BuffOnPartyAction(PlayerbotAI* ai, const string &spell) : CastBuffSpellAction(ai, spell), PartyMemberActionNameSupport(spell) {} public: virtual Value* GetTargetValue(); @@ -267,7 +263,7 @@ namespace ai class CastSpellOnEnemyHealerAction : public CastSpellAction { public: - CastSpellOnEnemyHealerAction(PlayerbotAI* ai, string spell) : CastSpellAction(ai, spell) {} + CastSpellOnEnemyHealerAction(PlayerbotAI* ai, const string &spell) : CastSpellAction(ai, spell) {} Value* GetTargetValue() { return context->GetValue("enemy healer target", spell); diff --git a/src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp index 48a5222e73..ad3ba8f7bf 100644 --- a/src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.cpp @@ -151,7 +151,7 @@ bool compare_items_by_level(const Item* item1, const Item* item2) void InventoryAction::TellItems(map itemMap) { list items; - for (map::iterator i = itemMap.begin(); i != itemMap.end(); i++) + for (map::iterator i = itemMap.begin(); i != itemMap.end(); ++i) { items.push_back(sItemStorage.LookupEntry(i->first)); } @@ -159,7 +159,7 @@ void InventoryAction::TellItems(map itemMap) items.sort(compare_items); uint32 oldClass = -1; - for (list::iterator i = items.begin(); i != items.end(); i++) + for (list::iterator i = items.begin(); i != items.end(); ++i) { ItemPrototype const *proto = *i; @@ -289,7 +289,7 @@ list InventoryAction::parseItems(string text) } ItemIds ids = chat->parseItems(text); - for (ItemIds::iterator i = ids.begin(); i != ids.end(); i++) + for (ItemIds::iterator i = ids.begin(); i != ids.end(); ++i) { FindItemByIdVisitor visitor(*i); IterateItems(&visitor, ITERATE_ALL_ITEMS); diff --git a/src/modules/Bots/playerbot/strategy/actions/InventoryAction.h b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.h index ab90bf6f9d..38a43385e3 100644 --- a/src/modules/Bots/playerbot/strategy/actions/InventoryAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/InventoryAction.h @@ -9,7 +9,7 @@ namespace ai class InventoryAction : public Action { public: - InventoryAction(PlayerbotAI* ai, string name) : Action(ai, name) {} + InventoryAction(PlayerbotAI* ai, const string &name) : Action(ai, name) {} protected: void IterateItems(IterateItemsVisitor* visitor, IterateItemsMask mask = ITERATE_ITEMS_IN_BAGS); diff --git a/src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h b/src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h index 4541270903..e00247d21f 100644 --- a/src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/LeaveGroupAction.h @@ -7,7 +7,7 @@ namespace ai { class LeaveGroupAction : public Action { public: - LeaveGroupAction(PlayerbotAI* ai, string name = "leave") : Action(ai, name) {} + LeaveGroupAction(PlayerbotAI* ai, const string& name = "leave") : Action(ai, name) {} virtual bool Execute(Event event) { diff --git a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp index f4869cfd27..b8791158c0 100644 --- a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp @@ -38,7 +38,7 @@ string LogLevelAction::logLevel2string(LogLevel level) return "debug"; } } -LogLevel LogLevelAction::string2logLevel(string level) +LogLevel LogLevelAction::string2logLevel(const string& level) { if (level == "debug") { diff --git a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp index 24f4cd2448..e5e37940e5 100644 --- a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp @@ -21,7 +21,7 @@ bool LootStrategyAction::Execute(Event event) out << LootStrategy2string(lootStrategy->Get()); out << ", always loot items: "; - for (set::iterator i = alwaysLootItems.begin(); i != alwaysLootItems.end(); i++) + for (set::iterator i = alwaysLootItems.begin(); i != alwaysLootItems.end(); ++i) { ItemPrototype const *proto = sItemStorage.LookupEntry(*i); if (!proto) @@ -47,7 +47,7 @@ bool LootStrategyAction::Execute(Event event) } bool remove = strategy.size() > 1 && strategy.substr(0, 1) == "-"; - for (ItemIds::iterator i = items.begin(); i != items.end(); i++) + for (ItemIds::iterator i = items.begin(); i != items.end(); ++i) { uint32 itemid = *i; if (remove) @@ -72,7 +72,7 @@ bool LootStrategyAction::Execute(Event event) } -LootStrategy LootStrategyAction::String2LootStrategy(string strategy) +LootStrategy LootStrategyAction::String2LootStrategy(const string& strategy) { if (strategy == "*" || strategy == "all") { diff --git a/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp b/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp index a04926d51e..d33bd2a45d 100644 --- a/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp @@ -322,7 +322,7 @@ bool MoveRandomAction::Execute(Event event) if (!(rand() % 3)) { list npcs = AI_VALUE(list, "nearest npcs"); - for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + for (list::iterator i = npcs.begin(); i != npcs.end(); ++i) { target = ai->GetUnit(*i); @@ -336,7 +336,7 @@ bool MoveRandomAction::Execute(Event event) if (!target || !(rand() % 3)) { list gos = AI_VALUE(list, "nearest game objects"); - for (list::iterator i = gos.begin(); i != gos.end(); i++) + for (list::iterator i = gos.begin(); i != gos.end(); ++i) { target = ai->GetGameObject(*i); diff --git a/src/modules/Bots/playerbot/strategy/actions/MovementActions.h b/src/modules/Bots/playerbot/strategy/actions/MovementActions.h index 96d8d51820..36c18b28a4 100644 --- a/src/modules/Bots/playerbot/strategy/actions/MovementActions.h +++ b/src/modules/Bots/playerbot/strategy/actions/MovementActions.h @@ -7,7 +7,7 @@ namespace ai { class MovementAction : public Action { public: - MovementAction(PlayerbotAI* ai, string name) : Action(ai, name) + MovementAction(PlayerbotAI* ai, const string &name) : Action(ai, name) { bot = ai->GetBot(); } diff --git a/src/modules/Bots/playerbot/strategy/actions/PositionAction.h b/src/modules/Bots/playerbot/strategy/actions/PositionAction.h index f96553b6ca..c5b96e5374 100644 --- a/src/modules/Bots/playerbot/strategy/actions/PositionAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/PositionAction.h @@ -18,7 +18,7 @@ namespace ai class MoveToPositionAction : public MovementAction { public: - MoveToPositionAction(PlayerbotAI* ai, string qualifier) : MovementAction(ai, "move to position"), qualifier(qualifier) + MoveToPositionAction(PlayerbotAI* ai, const string& qualifier) : MovementAction(ai, "move to position"), qualifier(qualifier) {} virtual bool Execute(Event event); diff --git a/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp index c5db73730f..3a51a97937 100644 --- a/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.cpp @@ -134,7 +134,7 @@ void QueryItemUsageAction::QueryItemPrice(ItemPrototype const *item) void QueryItemUsageAction::QueryItemsUsage(ItemIds items) { - for (ItemIds::iterator i = items.begin(); i != items.end(); i++) + for (ItemIds::iterator i = items.begin(); i != items.end(); ++i) { ItemPrototype const *item = sItemStorage.LookupEntry(*i); QueryItemUsage(item); @@ -147,7 +147,7 @@ void QueryItemUsageAction::QueryQuestItem(uint32 itemId) { Player *bot = ai->GetBot(); QuestStatusMap& questMap = bot->getQuestStatusMap(); - for (QuestStatusMap::const_iterator i = questMap.begin(); i != questMap.end(); i++) + for (QuestStatusMap::const_iterator i = questMap.begin(); i != questMap.end(); ++i) { const Quest *questTemplate = sObjectMgr.GetQuestTemplate( i->first ); if( !questTemplate ) diff --git a/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h index 11899cb96e..f9273921bd 100644 --- a/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/QueryItemUsageAction.h @@ -7,7 +7,7 @@ namespace ai { class QueryItemUsageAction : public InventoryAction { public: - QueryItemUsageAction(PlayerbotAI* ai, string name = "query item usage") : InventoryAction(ai, name) {} + QueryItemUsageAction(PlayerbotAI* ai, const string& name = "query item usage") : InventoryAction(ai, name) {} virtual bool Execute(Event event); protected: diff --git a/src/modules/Bots/playerbot/strategy/actions/QuestAction.h b/src/modules/Bots/playerbot/strategy/actions/QuestAction.h index 7708fc6d68..cbc30490c2 100644 --- a/src/modules/Bots/playerbot/strategy/actions/QuestAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/QuestAction.h @@ -8,7 +8,7 @@ namespace ai class QuestAction : public Action { public: - QuestAction(PlayerbotAI* ai, string name) : Action(ai, name) {} + QuestAction(PlayerbotAI* ai, const string& name) : Action(ai, name) {} public: virtual bool Execute(Event event); diff --git a/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h b/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h index 426e72ec9e..5d04e822de 100644 --- a/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h +++ b/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h @@ -9,7 +9,7 @@ namespace ai class ReachTargetAction : public MovementAction { public: - ReachTargetAction(PlayerbotAI* ai, string name, float distance) : MovementAction(ai, name) + ReachTargetAction(PlayerbotAI* ai, const string &name, float distance) : MovementAction(ai, name) { this->distance = distance; } @@ -30,7 +30,7 @@ namespace ai class CastReachTargetSpellAction : public CastSpellAction { public: - CastReachTargetSpellAction(PlayerbotAI* ai, string spell, float distance) : CastSpellAction(ai, spell) + CastReachTargetSpellAction(PlayerbotAI* ai, const string &spell, float distance) : CastSpellAction(ai, spell) { this->distance = distance; } diff --git a/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h b/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h index 0e26b616ad..4b2cbedd85 100644 --- a/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/ReadyCheckAction.h @@ -7,7 +7,7 @@ namespace ai class ReadyCheckAction : public Action { public: - ReadyCheckAction(PlayerbotAI* ai, string name = "ready check") : Action(ai, name) {} + ReadyCheckAction(PlayerbotAI* ai, const string& name = "ready check") : Action(ai, name) {} virtual bool Execute(Event event); diff --git a/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp b/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp index 62301877f8..89eee5bef9 100644 --- a/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/RepairAllAction.cpp @@ -8,7 +8,7 @@ using namespace ai; bool RepairAllAction::Execute(Event event) { list npcs = AI_VALUE(list, "nearest npcs"); - for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + for (list::iterator i = npcs.begin(); i != npcs.end(); ++i) { Creature *unit = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_REPAIR); if (!unit) diff --git a/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp b/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp index 5c6addc185..9248878f03 100644 --- a/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/ReviveFromCorpseAction.cpp @@ -40,7 +40,7 @@ bool SpiritHealerAction::Execute(Event event) } list npcs = AI_VALUE(list, "nearest npcs"); - for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + for (list::iterator i = npcs.begin(); i != npcs.end(); ++i) { Unit* unit = ai->GetUnit(*i); if (unit && unit->IsSpiritHealer()) diff --git a/src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp b/src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp index ed312e155f..a6dae0297c 100644 --- a/src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/RewardAction.cpp @@ -19,7 +19,7 @@ bool RewardAction::Execute(Event event) uint32 itemId = *itemIds.begin(); list npcs = AI_VALUE(list, "nearest npcs"); - for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + for (list::iterator i = npcs.begin(); i != npcs.end(); ++i) { Unit* npc = ai->GetUnit(*i); if (npc && Reward(itemId, npc)) @@ -29,7 +29,7 @@ bool RewardAction::Execute(Event event) } list gos = AI_VALUE(list, "nearest game objects"); - for (list::iterator i = gos.begin(); i != gos.end(); i++) + for (list::iterator i = gos.begin(); i != gos.end(); ++i) { GameObject* go = ai->GetGameObject(*i); if (go && Reward(itemId, go)) diff --git a/src/modules/Bots/playerbot/strategy/actions/SellAction.cpp b/src/modules/Bots/playerbot/strategy/actions/SellAction.cpp index e4cec28c6a..bb75d6be35 100644 --- a/src/modules/Bots/playerbot/strategy/actions/SellAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/SellAction.cpp @@ -59,7 +59,7 @@ bool SellAction::Execute(Event event) ItemIds ids = chat->parseItems(text); - for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + for (ItemIds::iterator i =ids.begin(); i != ids.end(); ++i) { FindItemByIdVisitor visitor(*i); Sell(&visitor); diff --git a/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp b/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp index f1f4863247..324cf33379 100644 --- a/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/SetHomeAction.cpp @@ -32,7 +32,7 @@ bool SetHomeAction::Execute(Event event) } list npcs = AI_VALUE(list, "nearest npcs"); - for (list::iterator i = npcs.begin(); i != npcs.end(); i++) + for (list::iterator i = npcs.begin(); i != npcs.end(); ++i) { Creature *unit = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_INNKEEPER); if (!unit) diff --git a/src/modules/Bots/playerbot/strategy/actions/StayActions.cpp b/src/modules/Bots/playerbot/strategy/actions/StayActions.cpp index 9bc41a27e8..5e196032b8 100644 --- a/src/modules/Bots/playerbot/strategy/actions/StayActions.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/StayActions.cpp @@ -67,7 +67,7 @@ bool StayActionBase::StaySingleLine(vector line, float diff, float cx, float y = cy + sin(angle) * (range * floor(count / 2.0f) + diff); int index = 0; - for (vector::iterator i = line.begin(); i != line.end(); i++) + for (vector::iterator i = line.begin(); i != line.end(); ++i) { Player* member = *i; diff --git a/src/modules/Bots/playerbot/strategy/actions/StayActions.h b/src/modules/Bots/playerbot/strategy/actions/StayActions.h index 809f32a8b2..a5ea962df2 100644 --- a/src/modules/Bots/playerbot/strategy/actions/StayActions.h +++ b/src/modules/Bots/playerbot/strategy/actions/StayActions.h @@ -7,7 +7,7 @@ namespace ai { class StayActionBase : public MovementAction { public: - StayActionBase(PlayerbotAI* ai, string name) : MovementAction(ai, name) {} + StayActionBase(PlayerbotAI* ai, const string &name) : MovementAction(ai, name) {} protected: void Stay(); diff --git a/src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp index 69af4f9260..bd336d9c81 100644 --- a/src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/TaxiAction.cpp @@ -23,7 +23,7 @@ bool TaxiAction::Execute(Event event) } list units = *context->GetValue >("nearest npcs"); - for (list::iterator i = units.begin(); i != units.end(); i++) + for (list::iterator i = units.begin(); i != units.end(); ++i) { Creature *npc = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_FLIGHTMASTER); if (!npc) @@ -31,6 +31,10 @@ bool TaxiAction::Execute(Event event) continue; } + // If master in flight -> copy movement nodes + // If master not in flight -> Get taxi nodes from: + // player->m_taxi? + // `bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, Team team)` if (movement.taxiNodes.empty()) { ostringstream out; diff --git a/src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp index b9bceb1388..8f69b8c8db 100644 --- a/src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/TeleportAction.cpp @@ -8,7 +8,7 @@ using namespace ai; bool TeleportAction::Execute(Event event) { list gos = *context->GetValue >("nearest game objects"); - for (list::iterator i = gos.begin(); i != gos.end(); i++) + for (list::iterator i = gos.begin(); i != gos.end(); ++i) { GameObject* go = ai->GetGameObject(*i); if (!go) diff --git a/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp index fe67ff4f0f..1895f6299a 100644 --- a/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/TellItemCountAction.cpp @@ -9,7 +9,7 @@ bool TellItemCountAction::Execute(Event event) { string text = event.getParam(); list found = parseItems(text); - for (list::iterator i = found.begin(); i != found.end(); i++) + for (list::iterator i = found.begin(); i != found.end(); ++i) { TellItem((*i)->GetProto(), (*i)->GetCount()); } diff --git a/src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp index da5c325606..dfa59faa95 100644 --- a/src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/TellLosAction.cpp @@ -40,7 +40,7 @@ void TellLosAction::ListUnits(string title, list units) { ai->TellMaster(title); - for (list::iterator i = units.begin(); i != units.end(); i++) + for (list::iterator i = units.begin(); i != units.end(); ++i) { Unit* unit = ai->GetUnit(*i); if (unit) @@ -54,7 +54,7 @@ void TellLosAction::ListGameObjects(string title, list gos) { ai->TellMaster(title); - for (list::iterator i = gos.begin(); i != gos.end(); i++) + for (list::iterator i = gos.begin(); i != gos.end(); ++i) { GameObject* go = ai->GetGameObject(*i); if (go) diff --git a/src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h b/src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h index 4174708d57..c3eb2cda87 100644 --- a/src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/TellMasterAction.h @@ -6,7 +6,7 @@ namespace ai { class TellMasterAction : public Action { public: - TellMasterAction(PlayerbotAI* ai, string text) : Action(ai, "tell master"), text(text) {} + TellMasterAction(PlayerbotAI* ai, const string& text) : Action(ai, "tell master"), text(text) {} virtual bool Execute(Event event) { diff --git a/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp index 33daaf3dad..165657e4ad 100644 --- a/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/TellTargetAction.cpp @@ -25,7 +25,7 @@ bool TellAttackersAction::Execute(Event event) ai->TellMaster("--- Attackers ---"); list attackers = context->GetValue >("attackers")->Get(); - for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) { Unit* unit = ai->GetUnit(*i); if (!unit || !unit->IsAlive()) diff --git a/src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp b/src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp index 17f3ca9045..cc18f15933 100644 --- a/src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/TradeAction.cpp @@ -25,7 +25,7 @@ bool TradeAction::Execute(Event event) return false; } - for (list::iterator i = found.begin(); i != found.end(); i++) + for (list::iterator i = found.begin(); i != found.end(); ++i) { TradeItem(**i, slot); } diff --git a/src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp b/src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp index 826caef67e..17b51ec322 100644 --- a/src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/UnequipAction.cpp @@ -11,7 +11,7 @@ bool UnequipAction::Execute(Event event) string text = event.getParam(); ItemIds ids = chat->parseItems(text); - for (ItemIds::iterator i =ids.begin(); i != ids.end(); i++) + for (ItemIds::iterator i =ids.begin(); i != ids.end(); ++i) { FindItemByIdVisitor visitor(*i); UnequipItem(&visitor); diff --git a/src/modules/Bots/playerbot/strategy/actions/UseItemAction.h b/src/modules/Bots/playerbot/strategy/actions/UseItemAction.h index 5afb80b316..b0a431c159 100644 --- a/src/modules/Bots/playerbot/strategy/actions/UseItemAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/UseItemAction.h @@ -6,7 +6,7 @@ namespace ai { class UseItemAction : public Action { public: - UseItemAction(PlayerbotAI* ai, string name = "use", bool selfOnly = false) : Action(ai, name), selfOnly(selfOnly) {} + UseItemAction(PlayerbotAI* ai, const string &name = "use", bool selfOnly = false) : Action(ai, name), selfOnly(selfOnly) {} public: virtual bool Execute(Event event); @@ -26,7 +26,7 @@ namespace ai class UseSpellItemAction : public UseItemAction { public: - UseSpellItemAction(PlayerbotAI* ai, string name, bool selfOnly = false) : UseItemAction(ai, name, selfOnly) {} + UseSpellItemAction(PlayerbotAI* ai, const string &name, bool selfOnly = false) : UseItemAction(ai, name, selfOnly) {} public: virtual bool isUseful(); diff --git a/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp index 84f2bd756c..578af41c11 100644 --- a/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.cpp @@ -71,7 +71,7 @@ bool UseMeetingStoneAction::Execute(Event event) Cell::VisitAllObjects(master, searcher, sPlayerbotAIConfig.sightDistance); GameObject* gameObject = NULL; - for(list::iterator i = targets.begin(); i != targets.end(); i++) + for(list::iterator i = targets.begin(); i != targets.end(); ++i) { GameObject* go = *i; if (go && go->isSpawned()) diff --git a/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h index e787d24d4d..559a0af876 100644 --- a/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/UseMeetingStoneAction.h @@ -8,7 +8,7 @@ namespace ai class SummonAction : public MovementAction { public: - SummonAction(PlayerbotAI* ai, string name = "summon") : MovementAction(ai, name) {} + SummonAction(PlayerbotAI* ai, const string& name = "summon") : MovementAction(ai, name) {} virtual bool Execute(Event event); diff --git a/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp b/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp index 25b476218d..9957deae5b 100644 --- a/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp @@ -109,7 +109,7 @@ string WhoAction::QuerySkill(string text) return out.str(); } -string WhoAction::QuerySpec(string text) +string WhoAction::QuerySpec(const string& text) { ostringstream out; diff --git a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h index 6a0378d05d..0d18d30e31 100644 --- a/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h +++ b/src/modules/Bots/playerbot/strategy/deathknight/DKActions.h @@ -46,7 +46,7 @@ namespace ai // Unholy presence class CastUnholyMeleeSpellAction : public CastMeleeSpellAction { public: - CastUnholyMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + CastUnholyMeleeSpellAction(PlayerbotAI* ai, const string& spell) : CastMeleeSpellAction(ai, spell) {} virtual NextAction** getPrerequisites() { return NextAction::merge(NextAction::array(0, new NextAction("unholy presence"), NULL), CastMeleeSpellAction::getPrerequisites()); } @@ -57,7 +57,7 @@ namespace ai class CastFrostMeleeSpellAction : public CastMeleeSpellAction { public: - CastFrostMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + CastFrostMeleeSpellAction(PlayerbotAI* ai, const string& spell) : CastMeleeSpellAction(ai, spell) {} virtual NextAction** getPrerequisites() { return NextAction::merge(NextAction::array(0, new NextAction("frost presence"), NULL), CastMeleeSpellAction::getPrerequisites()); } @@ -67,7 +67,7 @@ namespace ai class CastBloodMeleeSpellAction : public CastMeleeSpellAction { public: - CastBloodMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + CastBloodMeleeSpellAction(PlayerbotAI* ai, const string& spell) : CastMeleeSpellAction(ai, spell) {} virtual NextAction** getPrerequisites() { return NextAction::merge(NextAction::array(0, new NextAction("blood presence"), NULL), CastMeleeSpellAction::getPrerequisites()); } diff --git a/src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h b/src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h index 14083d48bd..d75ac05ba2 100644 --- a/src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h +++ b/src/modules/Bots/playerbot/strategy/generic/PassTroughStrategy.h @@ -9,7 +9,7 @@ namespace ai virtual void InitTriggers(std::list &triggers) { - for (list::iterator i = supported.begin(); i != supported.end(); i++) + for (list::iterator i = supported.begin(); i != supported.end(); ++i) { string s = i->c_str(); diff --git a/src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp index 6e9a6d1b92..845acb1e4d 100644 --- a/src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.cpp @@ -8,7 +8,7 @@ using namespace ai; class MagePullMultiplier : public PassiveMultiplier { public: - MagePullMultiplier(PlayerbotAI* ai, string action) : PassiveMultiplier(ai) + MagePullMultiplier(PlayerbotAI* ai, const string& action) : PassiveMultiplier(ai) { this->action = action; } diff --git a/src/modules/Bots/playerbot/strategy/generic/PullStrategy.h b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.h index 946d47c9f2..126d70d6e3 100644 --- a/src/modules/Bots/playerbot/strategy/generic/PullStrategy.h +++ b/src/modules/Bots/playerbot/strategy/generic/PullStrategy.h @@ -7,7 +7,7 @@ namespace ai class PullStrategy : public RangedCombatStrategy { public: - PullStrategy(PlayerbotAI* ai, string action) : RangedCombatStrategy(ai) + PullStrategy(PlayerbotAI* ai, const string& action) : RangedCombatStrategy(ai) { this->action = action; } diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h b/src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h index 0568847e39..96830cb850 100644 --- a/src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueComboActions.h @@ -5,7 +5,7 @@ namespace ai class CastComboAction : public CastMeleeSpellAction { public: - CastComboAction(PlayerbotAI* ai, string name) : CastMeleeSpellAction(ai, name) {} + CastComboAction(PlayerbotAI* ai, const string& name) : CastMeleeSpellAction(ai, name) {} virtual bool isUseful() { diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h b/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h index 58ac0bcacd..2710741f8d 100644 --- a/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanActions.h @@ -60,7 +60,7 @@ namespace ai class CastTotemAction : public CastBuffSpellAction { public: - CastTotemAction(PlayerbotAI* ai, string spell) : CastBuffSpellAction(ai, spell) {} + CastTotemAction(PlayerbotAI* ai, const string& spell) : CastBuffSpellAction(ai, spell) {} virtual bool isUseful() { return CastBuffSpellAction::isUseful() && !AI_VALUE2(bool, "has totem", name); } }; diff --git a/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h b/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h index 96003249d8..9a10c311e4 100644 --- a/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h +++ b/src/modules/Bots/playerbot/strategy/shaman/ShamanTriggers.h @@ -13,7 +13,7 @@ namespace ai class TotemTrigger : public Trigger { public: - TotemTrigger(PlayerbotAI* ai, string spell, int attackerCount = 0) : Trigger(ai, spell), attackerCount(attackerCount) {} + TotemTrigger(PlayerbotAI* ai, const string& spell, int attackerCount = 0) : Trigger(ai, spell), attackerCount(attackerCount) {} virtual bool IsActive() { diff --git a/src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h b/src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h index 019a2f57d8..d7b935a87a 100644 --- a/src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h +++ b/src/modules/Bots/playerbot/strategy/triggers/ChatCommandTrigger.h @@ -6,7 +6,7 @@ namespace ai { class ChatCommandTrigger : public Trigger { public: - ChatCommandTrigger(PlayerbotAI* ai, string command) : Trigger(ai, command), triggered(false) {} + ChatCommandTrigger(PlayerbotAI* ai, const string& command) : Trigger(ai, command), triggered(false) {} virtual void ExternalEvent(string param, Player* owner = NULL) { diff --git a/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h index 4cdb151c32..71b43a282e 100644 --- a/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h +++ b/src/modules/Bots/playerbot/strategy/triggers/CureTriggers.h @@ -7,7 +7,7 @@ namespace ai class NeedCureTrigger : public SpellTrigger { public: - NeedCureTrigger(PlayerbotAI* ai, string spell, uint32 dispelType) : SpellTrigger(ai, spell) + NeedCureTrigger(PlayerbotAI* ai, const string &spell, uint32 dispelType) : SpellTrigger(ai, spell) { this->dispelType = dispelType; } @@ -20,14 +20,14 @@ namespace ai class TargetAuraDispelTrigger : public NeedCureTrigger { public: - TargetAuraDispelTrigger(PlayerbotAI* ai, string spell, uint32 dispelType) : + TargetAuraDispelTrigger(PlayerbotAI* ai, const string &spell, uint32 dispelType) : NeedCureTrigger(ai, spell, dispelType) {} virtual string GetTargetName() { return "current target"; } }; class PartyMemberNeedCureTrigger : public NeedCureTrigger { public: - PartyMemberNeedCureTrigger(PlayerbotAI* ai, string spell, uint32 dispelType) : + PartyMemberNeedCureTrigger(PlayerbotAI* ai, const string &spell, uint32 dispelType) : NeedCureTrigger(ai, spell, dispelType) {} virtual Value* GetTargetValue(); diff --git a/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h index d7a8cc58e4..2c1f850c38 100644 --- a/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h +++ b/src/modules/Bots/playerbot/strategy/triggers/GenericTriggers.h @@ -28,7 +28,7 @@ namespace ai class StatAvailable : public Trigger { public: - StatAvailable(PlayerbotAI* ai, int amount, string name = "stat available") : Trigger(ai, name) + StatAvailable(PlayerbotAI* ai, int amount, const string &name = "stat available") : Trigger(ai, name) { this->amount = amount; } @@ -109,7 +109,7 @@ namespace ai class SpellTrigger : public Trigger { public: - SpellTrigger(PlayerbotAI* ai, string spell, int checkInterval = 1) : Trigger(ai, spell, checkInterval) + SpellTrigger(PlayerbotAI* ai, const string &spell, int checkInterval = 1) : Trigger(ai, spell, checkInterval) { this->spell = spell; } @@ -125,7 +125,7 @@ namespace ai class SpellCanBeCastTrigger : public SpellTrigger { public: - SpellCanBeCastTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell) {} + SpellCanBeCastTrigger(PlayerbotAI* ai, const string &spell) : SpellTrigger(ai, spell) {} virtual bool IsActive(); }; @@ -133,7 +133,7 @@ namespace ai class InterruptSpellTrigger : public SpellTrigger { public: - InterruptSpellTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell) {} + InterruptSpellTrigger(PlayerbotAI* ai, const string &spell) : SpellTrigger(ai, spell) {} virtual bool IsActive(); }; @@ -227,7 +227,7 @@ namespace ai class BuffTrigger : public SpellTrigger { public: - BuffTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell, 5) {} + BuffTrigger(PlayerbotAI* ai, const string &spell) : SpellTrigger(ai, spell, 5) {} public: virtual string GetTargetName() { return "self target"; } virtual bool IsActive(); @@ -236,7 +236,7 @@ namespace ai class BuffOnPartyTrigger : public BuffTrigger { public: - BuffOnPartyTrigger(PlayerbotAI* ai, string spell) : BuffTrigger(ai, spell) {} + BuffOnPartyTrigger(PlayerbotAI* ai, const string &spell) : BuffTrigger(ai, spell) {} public: virtual Value* GetTargetValue(); }; @@ -259,7 +259,7 @@ namespace ai class DebuffTrigger : public BuffTrigger { public: - DebuffTrigger(PlayerbotAI* ai, string spell) : BuffTrigger(ai, spell) { + DebuffTrigger(PlayerbotAI* ai, const string &spell) : BuffTrigger(ai, spell) { checkInterval = 1; } public: @@ -270,7 +270,7 @@ namespace ai class DebuffOnAttackerTrigger : public DebuffTrigger { public: - DebuffOnAttackerTrigger(PlayerbotAI* ai, string spell) : DebuffTrigger(ai, spell) {} + DebuffOnAttackerTrigger(PlayerbotAI* ai, const string &spell) : DebuffTrigger(ai, spell) {} public: virtual Value* GetTargetValue(); virtual string getName() { return spell + " on attacker"; } @@ -279,7 +279,7 @@ namespace ai class BoostTrigger : public BuffTrigger { public: - BoostTrigger(PlayerbotAI* ai, string spell, float balance = 50) : BuffTrigger(ai, spell) + BoostTrigger(PlayerbotAI* ai, const string &spell, float balance = 50) : BuffTrigger(ai, spell) { this->balance = balance; } @@ -344,7 +344,7 @@ namespace ai class SnareTargetTrigger : public DebuffTrigger { public: - SnareTargetTrigger(PlayerbotAI* ai, string aura) : DebuffTrigger(ai, aura) {} + SnareTargetTrigger(PlayerbotAI* ai, const string &aura) : DebuffTrigger(ai, aura) {} public: virtual bool IsActive(); virtual string getName() { return "target is moving"; } @@ -383,7 +383,7 @@ namespace ai class ItemCountTrigger : public Trigger { public: - ItemCountTrigger(PlayerbotAI* ai, string item, int count) : Trigger(ai, item, 5) { + ItemCountTrigger(PlayerbotAI* ai, const string &item, int count) : Trigger(ai, item, 5) { this->item = item; this->count = count; } @@ -398,7 +398,7 @@ namespace ai class HasAuraTrigger : public Trigger { public: - HasAuraTrigger(PlayerbotAI* ai, string spell) : Trigger(ai, spell, 5) {} + HasAuraTrigger(PlayerbotAI* ai, const string &spell) : Trigger(ai, spell, 5) {} virtual string GetTargetName() { return "self target"; } virtual bool IsActive(); @@ -445,7 +445,7 @@ namespace ai class HasCcTargetTrigger : public Trigger { public: - HasCcTargetTrigger(PlayerbotAI* ai, string name) : Trigger(ai, name) {} + HasCcTargetTrigger(PlayerbotAI* ai, const string &name) : Trigger(ai, name) {} public: virtual bool IsActive(); @@ -454,7 +454,7 @@ namespace ai class NoMovementTrigger : public Trigger { public: - NoMovementTrigger(PlayerbotAI* ai, string name) : Trigger(ai, name) {} + NoMovementTrigger(PlayerbotAI* ai, const string &name) : Trigger(ai, name) {} public: virtual bool IsActive(); @@ -509,7 +509,7 @@ namespace ai class HasItemForSpellTrigger : public Trigger { public: - HasItemForSpellTrigger(PlayerbotAI* ai, string spell) : Trigger(ai, spell) {} + HasItemForSpellTrigger(PlayerbotAI* ai, const string &spell) : Trigger(ai, spell) {} public: virtual bool IsActive(); @@ -527,7 +527,7 @@ namespace ai class InterruptEnemyHealerTrigger : public SpellTrigger { public: - InterruptEnemyHealerTrigger(PlayerbotAI* ai, string spell) : SpellTrigger(ai, spell) {} + InterruptEnemyHealerTrigger(PlayerbotAI* ai, const string &spell) : SpellTrigger(ai, spell) {} public: virtual Value* GetTargetValue(); virtual string getName() { return spell + " on enemy healer"; } diff --git a/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h index 1e72eba313..024859b050 100644 --- a/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h +++ b/src/modules/Bots/playerbot/strategy/triggers/HealthTriggers.h @@ -7,7 +7,7 @@ namespace ai class ValueInRangeTrigger : public Trigger { public: - ValueInRangeTrigger(PlayerbotAI* ai, string name, float maxValue, float minValue) : Trigger(ai, name) { + ValueInRangeTrigger(PlayerbotAI* ai, const string &name, float maxValue, float minValue) : Trigger(ai, name) { this->maxValue = maxValue; this->minValue = minValue; } @@ -25,7 +25,7 @@ namespace ai class HealthInRangeTrigger : public ValueInRangeTrigger { public: - HealthInRangeTrigger(PlayerbotAI* ai, string name, float maxValue, float minValue = 0) : + HealthInRangeTrigger(PlayerbotAI* ai, const string &name, float maxValue, float minValue = 0) : ValueInRangeTrigger(ai, name, maxValue, minValue) {} virtual bool IsActive() @@ -39,7 +39,7 @@ namespace ai class LowHealthTrigger : public HealthInRangeTrigger { public: - LowHealthTrigger(PlayerbotAI* ai, string name = "low health", + LowHealthTrigger(PlayerbotAI* ai, const string &name = "low health", float value = sPlayerbotAIConfig.lowHealth, float minValue = sPlayerbotAIConfig.criticalHealth) : HealthInRangeTrigger(ai, name, value, minValue) {} @@ -70,7 +70,7 @@ namespace ai class PartyMemberLowHealthTrigger : public HealthInRangeTrigger { public: - PartyMemberLowHealthTrigger(PlayerbotAI* ai, string name = "party member low health", float value = sPlayerbotAIConfig.lowHealth, float minValue = sPlayerbotAIConfig.criticalHealth) : + PartyMemberLowHealthTrigger(PlayerbotAI* ai, const string &name = "party member low health", float value = sPlayerbotAIConfig.lowHealth, float minValue = sPlayerbotAIConfig.criticalHealth) : HealthInRangeTrigger(ai, name, value, minValue) {} virtual string GetTargetName() { return "party member to heal"; } @@ -126,7 +126,7 @@ namespace ai class AoeHealTrigger : public Trigger { public: - AoeHealTrigger(PlayerbotAI* ai, string name, string type, int count) : + AoeHealTrigger(PlayerbotAI* ai, const string &name, const string &type, int count) : Trigger(ai, name), type(type), count(count) {} public: virtual bool IsActive(); diff --git a/src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h b/src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h index 9729877e5b..381d0e22e1 100644 --- a/src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h +++ b/src/modules/Bots/playerbot/strategy/triggers/RangeTriggers.h @@ -26,7 +26,7 @@ namespace ai class OutOfRangeTrigger : public Trigger { public: - OutOfRangeTrigger(PlayerbotAI* ai, string name, float distance) : Trigger(ai, name) + OutOfRangeTrigger(PlayerbotAI* ai, const string &name, float distance) : Trigger(ai, name) { this->distance = distance; } @@ -62,7 +62,7 @@ namespace ai class FarFromMasterTrigger : public Trigger { public: - FarFromMasterTrigger(PlayerbotAI* ai, string name = "far from master", float distance = 12.0f, int checkInterval = 1) : Trigger(ai, name, checkInterval), distance(distance) {} + FarFromMasterTrigger(PlayerbotAI* ai, const string &name = "far from master", float distance = 12.0f, int checkInterval = 1) : Trigger(ai, name, checkInterval), distance(distance) {} virtual bool IsActive() { diff --git a/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h b/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h index 69a9104482..fe9f1c8d80 100644 --- a/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h +++ b/src/modules/Bots/playerbot/strategy/triggers/WorldPacketTrigger.h @@ -6,7 +6,7 @@ namespace ai { class WorldPacketTrigger : public Trigger { public: - WorldPacketTrigger(PlayerbotAI* ai, string command) : Trigger(ai, command), triggered(false) {} + WorldPacketTrigger(PlayerbotAI* ai, const string& command) : Trigger(ai, command), triggered(false) {} virtual void ExternalEvent(WorldPacket &packet, Player* owner = NULL) { diff --git a/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp b/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp index 4f4d96b41e..2b19ae6a86 100644 --- a/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp +++ b/src/modules/Bots/playerbot/strategy/values/AttackerCountValues.cpp @@ -44,7 +44,7 @@ uint8 AttackerCountValue::Calculate() float range = sPlayerbotAIConfig.sightDistance; list attackers = context->GetValue >("attackers")->Get(); - for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) { Unit* unit = ai->GetUnit(*i); if (!unit || !unit->IsAlive()) @@ -85,7 +85,7 @@ uint8 BalancePercentValue::Calculate() list v = context->GetValue >("attackers")->Get(); - for (list::iterator i = v.begin(); i!=v.end(); i++) + for (list::iterator i = v.begin(); i!=v.end(); ++i) { Creature* creature = ai->GetCreature((*i)); if (!creature || !creature->IsAlive()) diff --git a/src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp b/src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp index 4b7d12c6db..f66d583281 100644 --- a/src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp +++ b/src/modules/Bots/playerbot/strategy/values/AttackersValue.cpp @@ -24,7 +24,7 @@ list AttackersValue::Calculate() RemoveNonThreating(targets); list result; - for (set::iterator i = targets.begin(); i != targets.end(); i++) + for (set::iterator i = targets.begin(); i != targets.end(); ++i) { result.push_back((*i)->GetObjectGuid()); } @@ -63,7 +63,7 @@ void AttackersValue::AddAttackersOf(Player* player, set& targets) MaNGOS::AnyUnfriendlyUnitInObjectRangeCheck u_check(player, sPlayerbotAIConfig.sightDistance); MaNGOS::UnitListSearcher searcher(units, u_check); Cell::VisitAllObjects(player, searcher, sPlayerbotAIConfig.sightDistance); - for (list::iterator i = units.begin(); i != units.end(); i++) + for (list::iterator i = units.begin(); i != units.end(); ++i) { targets.insert(*i); } diff --git a/src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp index 88506cb5ad..18e83557b8 100644 --- a/src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp +++ b/src/modules/Bots/playerbot/strategy/values/CcTargetValue.cpp @@ -9,7 +9,7 @@ using namespace ai; class FindTargetForCcStrategy : public FindTargetStrategy { public: - FindTargetForCcStrategy(PlayerbotAI* ai, string spell) : FindTargetStrategy(ai) + FindTargetForCcStrategy(PlayerbotAI* ai, const string& spell) : FindTargetStrategy(ai) { this->spell = spell; maxDistance = 0; diff --git a/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp index 5ab1b7bdc7..e90fd74e99 100644 --- a/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp +++ b/src/modules/Bots/playerbot/strategy/values/CurrentCcTargetValue.cpp @@ -7,7 +7,7 @@ using namespace ai; class FindCurrentCcTargetStrategy : public FindTargetStrategy { public: - FindCurrentCcTargetStrategy(PlayerbotAI* ai, string spell) : FindTargetStrategy(ai) + FindCurrentCcTargetStrategy(PlayerbotAI* ai, const string& spell) : FindTargetStrategy(ai) { this->spell = spell; } diff --git a/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp index c41bffa2c8..c8120b2b04 100644 --- a/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp +++ b/src/modules/Bots/playerbot/strategy/values/GrindTargetValue.cpp @@ -33,7 +33,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(int assistCount) Player* master = GetMaster(); list attackers = context->GetValue >("attackers")->Get(); - for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) { Unit* unit = ai->GetUnit(*i); if (!unit || !unit->IsAlive()) @@ -53,7 +53,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(int assistCount) float distance = 0; Unit* result = NULL; - for(list::iterator tIter = targets.begin(); tIter != targets.end(); tIter++) + for(list::iterator tIter = targets.begin(); tIter != targets.end(); ++tIter) { Unit* unit = ai->GetUnit(*tIter); if (!unit) diff --git a/src/modules/Bots/playerbot/strategy/values/HasTotemValue.h b/src/modules/Bots/playerbot/strategy/values/HasTotemValue.h index e9f3f0c179..feb58f10de 100644 --- a/src/modules/Bots/playerbot/strategy/values/HasTotemValue.h +++ b/src/modules/Bots/playerbot/strategy/values/HasTotemValue.h @@ -14,7 +14,7 @@ namespace ai bool Calculate() { list units = *context->GetValue >("nearest npcs"); - for (list::iterator i = units.begin(); i != units.end(); i++) + for (list::iterator i = units.begin(); i != units.end(); ++i) { Unit* unit = ai->GetUnit(*i); if (!unit) diff --git a/src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp b/src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp index dec931f994..34ee25393a 100644 --- a/src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp +++ b/src/modules/Bots/playerbot/strategy/values/ItemCountValue.cpp @@ -11,7 +11,7 @@ list InventoryItemValueBase::Find(string qualifier) Player* bot = InventoryAction::ai->GetBot(); list items = InventoryAction::parseItems(qualifier); - for (list::iterator i = items.begin(); i != items.end(); i++) + for (list::iterator i = items.begin(); i != items.end(); ++i) { result.push_back(*i); } diff --git a/src/modules/Bots/playerbot/strategy/values/LastMovementValue.h b/src/modules/Bots/playerbot/strategy/values/LastMovementValue.h index 8adcb09f01..10c6792b17 100644 --- a/src/modules/Bots/playerbot/strategy/values/LastMovementValue.h +++ b/src/modules/Bots/playerbot/strategy/values/LastMovementValue.h @@ -15,17 +15,15 @@ namespace ai lastFollow = NULL; } - LastMovement(LastMovement& other) - { - taxiNodes = other.taxiNodes; - taxiMaster = other.taxiMaster; - lastFollow = other.lastFollow; - lastAreaTrigger = other.lastAreaTrigger; - lastMoveToX = other.lastMoveToX; - lastMoveToY = other.lastMoveToY; - lastMoveToZ = other.lastMoveToZ; - lastMoveToOri = other.lastMoveToOri; - } + LastMovement(LastMovement& other): + taxiNodes(other.taxiNodes), + taxiMaster(other.taxiMaster), + lastFollow(other.lastFollow), + lastAreaTrigger(other.lastAreaTrigger), + lastMoveToX(other.lastMoveToX), + lastMoveToY(other.lastMoveToY), + lastMoveToZ(other.lastMoveToZ), + lastMoveToOri(other.lastMoveToOri) {}; void Set(Unit* lastFollow) { diff --git a/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp b/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp index f2ab8aa1c4..b55df84e9f 100644 --- a/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp +++ b/src/modules/Bots/playerbot/strategy/values/PartyMemberWithoutAuraValue.cpp @@ -7,7 +7,7 @@ using namespace ai; class PlayerWithoutAuraPredicate : public FindPlayerPredicate, public PlayerbotAIAware { public: - PlayerWithoutAuraPredicate(PlayerbotAI* ai, string aura) : + PlayerWithoutAuraPredicate(PlayerbotAI* ai, const string& aura) : PlayerbotAIAware(ai), FindPlayerPredicate(), aura(aura) {} public: diff --git a/src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h b/src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h index 855717f5c2..eecdea62ae 100644 --- a/src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h +++ b/src/modules/Bots/playerbot/strategy/values/RtiTargetValue.h @@ -10,7 +10,7 @@ namespace ai {} public: - static int GetRtiIndex(string rti) + static int GetRtiIndex(const string &rti) { int index = -1; if(rti == "star") diff --git a/src/modules/Bots/playerbot/strategy/values/TargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/TargetValue.cpp index 0fdc4a3c2c..c89b6fe25a 100644 --- a/src/modules/Bots/playerbot/strategy/values/TargetValue.cpp +++ b/src/modules/Bots/playerbot/strategy/values/TargetValue.cpp @@ -37,7 +37,7 @@ void FindTargetStrategy::GetPlayerCount(Unit* creature, int* tankCount, int* dps *dpsCount = 0; Unit::AttackerSet attackers(creature->getAttackers()); - for (set::const_iterator i = attackers.begin(); i != attackers.end(); i++) + for (set::const_iterator i = attackers.begin(); i != attackers.end(); ++i) { Unit* attacker = *i; if (!attacker || !attacker->IsAlive() || attacker == bot) diff --git a/src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp b/src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp index 09ff3820ef..607ecc949c 100644 --- a/src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp +++ b/src/modules/Bots/playerbot/strategy/values/ThreatValues.cpp @@ -11,7 +11,7 @@ uint8 ThreatValue::Calculate() { uint8 maxThreat = 0; list attackers = context->GetValue >("attackers")->Get(); - for (list::iterator i = attackers.begin(); i != attackers.end(); i++) + for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) { Unit* unit = ai->GetUnit(*i); if (!unit || !unit->IsAlive()) diff --git a/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h b/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h index 227c39889c..3a4fa91913 100644 --- a/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h +++ b/src/modules/Bots/playerbot/strategy/warlock/WarlockTriggers.h @@ -49,7 +49,7 @@ namespace ai class WarlockConjuredItemTrigger : public ItemCountTrigger { public: - WarlockConjuredItemTrigger(PlayerbotAI* ai, string item) : ItemCountTrigger(ai, item, 1) {} + WarlockConjuredItemTrigger(PlayerbotAI* ai, const string& item) : ItemCountTrigger(ai, item, 1) {} virtual bool IsActive() { return ItemCountTrigger::IsActive() && AI_VALUE2(uint8, "item count", "soul shard") > 0; } }; diff --git a/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h b/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h index 9cc7d342a3..c0f166de5a 100644 --- a/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h +++ b/src/modules/Bots/playerbot/strategy/warrior/WarriorActions.h @@ -6,7 +6,7 @@ namespace ai // battle class CastBattleMeleeSpellAction : public CastMeleeSpellAction { public: - CastBattleMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + CastBattleMeleeSpellAction(PlayerbotAI* ai, const string& spell) : CastMeleeSpellAction(ai, spell) {} virtual NextAction** getPrerequisites() { return NextAction::merge( NextAction::array(0, new NextAction("battle stance"), NULL), CastMeleeSpellAction::getPrerequisites()); } @@ -15,7 +15,7 @@ namespace ai // defensive class CastDefensiveMeleeSpellAction : public CastMeleeSpellAction { public: - CastDefensiveMeleeSpellAction(PlayerbotAI* ai, string spell) : CastMeleeSpellAction(ai, spell) {} + CastDefensiveMeleeSpellAction(PlayerbotAI* ai, const string& spell) : CastMeleeSpellAction(ai, spell) {} virtual NextAction** getPrerequisites() { return NextAction::merge( NextAction::array(0, new NextAction("defensive stance"), NULL), CastMeleeSpellAction::getPrerequisites()); } From b5717b996bb7689e3f42072dff7ffea3359142f3 Mon Sep 17 00:00:00 2001 From: Tim Forbes Date: Mon, 11 Apr 2022 10:55:01 -0400 Subject: [PATCH 9/9] Fix ahbot module integration * Built-in and module auctionhouse bots conflict on the .ahbot command. Reconfigure module integration for .auctionbot command and finish integrating. * cppcheck fixes * Bot module documentation --- src/game/AuctionHouseBot/AuctionHouseBot.cpp | 7 +- src/game/AuctionHouseBot/AuctionHouseBot.h | 7 + src/game/ChatCommands/AHBotCommands.cpp | 9 +- src/game/WorldHandlers/Chat.cpp | 2 +- src/game/WorldHandlers/World.cpp | 35 +- src/game/WorldHandlers/World.h | 11 +- src/modules/Bots/ahbot/AhBot.cpp | 948 +++++++++--------- src/modules/Bots/ahbot/AhBot.h | 38 +- src/modules/Bots/ahbot/AhBotConfig.cpp | 16 +- src/modules/Bots/ahbot/PricingStrategy.cpp | 2 +- src/modules/Bots/ahbot/README.md | 26 + src/modules/Bots/ahbot/ahbot.conf.dist.in | 9 +- src/modules/Bots/playerbot/AiFactory.cpp | 2 +- src/modules/Bots/playerbot/PlayerbotAI.cpp | 4 +- src/modules/Bots/playerbot/PlayerbotAI.h | 4 +- .../Bots/playerbot/PlayerbotAIConfig.cpp | 9 +- .../Bots/playerbot/PlayerbotAIConfig.h | 5 +- src/modules/Bots/playerbot/PlayerbotMgr.h | 2 +- src/modules/Bots/playerbot/README.md | 101 ++ .../Bots/playerbot/aiplayerbot.conf.dist.in | 9 +- .../Bots/playerbot/strategy/Engine.cpp | 4 +- src/modules/Bots/playerbot/strategy/Engine.h | 8 +- .../strategy/actions/LogLevelAction.cpp | 2 +- .../strategy/actions/LogLevelAction.h | 2 +- .../strategy/actions/LootStrategyAction.cpp | 2 +- .../strategy/actions/LootStrategyAction.h | 2 +- .../playerbot/strategy/actions/WhoAction.cpp | 2 +- .../playerbot/strategy/actions/WhoAction.h | 2 +- 28 files changed, 726 insertions(+), 544 deletions(-) create mode 100644 src/modules/Bots/ahbot/README.md create mode 100644 src/modules/Bots/playerbot/README.md diff --git a/src/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/game/AuctionHouseBot/AuctionHouseBot.cpp index 0d0c12ca28..eb7461eb63 100644 --- a/src/game/AuctionHouseBot/AuctionHouseBot.cpp +++ b/src/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -2212,7 +2212,7 @@ void AuctionHouseBot::Rebuild(bool all) void AuctionHouseBot::Update() { // nothing do... - if (!m_Buyer && !m_Seller) + if (!Enabled()) { return; } @@ -2250,4 +2250,9 @@ void AuctionHouseBot::Update() } } } + +bool AuctionHouseBot::Enabled() +{ + return (m_Buyer != NULL || m_Seller != NULL); +} /** @} */ diff --git a/src/game/AuctionHouseBot/AuctionHouseBot.h b/src/game/AuctionHouseBot/AuctionHouseBot.h index 764b3b21dc..922322ae33 100644 --- a/src/game/AuctionHouseBot/AuctionHouseBot.h +++ b/src/game/AuctionHouseBot/AuctionHouseBot.h @@ -456,6 +456,13 @@ class AuctionHouseBot * */ void Initialize(); + /** + * @brief Whether the AuctionHouseBot is enabled + * + * @return true if buyer or seller agent exists + * @return false if neither buyer nor seller agents exist + */ + bool Enabled(); // Followed method is mainly used by level3.cpp for ingame/console command /** diff --git a/src/game/ChatCommands/AHBotCommands.cpp b/src/game/ChatCommands/AHBotCommands.cpp index 133f39ace8..e0a40ebb1a 100644 --- a/src/game/ChatCommands/AHBotCommands.cpp +++ b/src/game/ChatCommands/AHBotCommands.cpp @@ -29,7 +29,9 @@ #include "Chat.h" #include "Language.h" #include "AuctionHouseBot/AuctionHouseBot.h" - +#ifdef ENABLE_PLAYERBOTS +#include "AhBot.h" +#endif /********************************************************************** Useful constants definition @@ -49,6 +51,11 @@ static uint32 ahbotQualityIds[MAX_AUCTION_QUALITY] = bool ChatHandler::HandleAHBotRebuildCommand(char* args) { + if (!sAuctionBot.Enabled()) + { + return false; + } + bool all = false; if (*args) { diff --git a/src/game/WorldHandlers/Chat.cpp b/src/game/WorldHandlers/Chat.cpp index cc1a8ad018..9dfab9dbef 100644 --- a/src/game/WorldHandlers/Chat.cpp +++ b/src/game/WorldHandlers/Chat.cpp @@ -845,7 +845,7 @@ ChatCommand* ChatHandler::getCommandTable() #ifdef ENABLE_PLAYERBOTS { "bot", SEC_PLAYER, false, &ChatHandler::HandlePlayerbotCommand, "", NULL }, { "rndbot", SEC_CONSOLE, true, &ChatHandler::HandlePlayerbotConsoleCommand, "", NULL }, - { "ahbot", SEC_GAMEMASTER, true, &ChatHandler::HandleAhBotCommand, "", NULL }, + { "auctionbot", SEC_GAMEMASTER, true, &ChatHandler::HandleAhBotCommand, "", NULL }, #endif { NULL, 0, false, NULL, "", NULL } diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index cbf58b944a..41907117b8 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -88,6 +88,7 @@ #ifdef ENABLE_PLAYERBOTS #include "AhBotConfig.h" +#include "AhBot.h" #include "PlayerbotAIConfig.h" #include "RandomPlayerbotMgr.h" #endif @@ -850,24 +851,13 @@ void World::LoadConfigSettings(bool reload) setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT, "PetUnsummonAtMount", true); #ifdef ENABLE_PLAYERBOTS - setConfig(CONFIG_BOOL_PLAYERBOT_DISABLE, "PlayerbotAI.DisableBots", true); - setConfig(CONFIG_BOOL_PLAYERBOT_DEBUGWHISPER, "PlayerbotAI.DebugWhisper", false); + setConfig(CONFIG_BOOL_PLAYERBOT_ENABLE, "AiPlayerbot.Enabled", true); + setConfig(CONFIG_BOOL_PLAYERBOT_DEBUGWHISPER, "AiPlayerbot.DebugWhisper", false); setConfigMinMax(CONFIG_UINT32_PLAYERBOT_MAXBOTS, "PlayerbotAI.MaxNumBots", 3, 1, 9); setConfigMinMax(CONFIG_UINT32_PLAYERBOT_RESTRICTLEVEL, "PlayerbotAI.RestrictBotLevel", getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL), 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)); setConfigMinMax(CONFIG_UINT32_PLAYERBOT_MINBOTLEVEL, "PlayerbotAI.MinBotLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)); setConfig(CONFIG_FLOAT_PLAYERBOT_MINDISTANCE, "PlayerbotAI.FollowDistanceMin", 0.5f); setConfig(CONFIG_FLOAT_PLAYERBOT_MAXDISTANCE, "PlayerbotAI.FollowDistanceMax", 1.0f); - - setConfig(CONFIG_BOOL_PLAYERBOT_ALLOW_SUMMON_OPPOSITE_FACTION, "PlayerbotAI.AllowSummonOppositeFaction", false); - setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_COMBAT, "PlayerbotAI.Collect.Combat", true); - setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_QUESTS, "PlayerbotAI.Collect.Quest", true); - setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_PROFESSION, "PlayerbotAI.Collect.Profession", true); - setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_LOOT, "PlayerbotAI.Collect.Loot", true); - setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_SKIN, "PlayerbotAI.Collect.Skin", true); - setConfig(CONFIG_BOOL_PLAYERBOT_COLLECT_OBJECTS, "PlayerbotAI.Collect.Objects", true); - setConfig(CONFIG_BOOL_PLAYERBOT_SELL_TRASH, "PlayerbotAI.SellGarbage", true); - - setConfig(CONFIG_BOOL_PLAYERBOT_SHAREDBOTS, "PlayerbotAI.SharedBots", true); #endif // WARDEN @@ -1602,7 +1592,7 @@ void World::SetInitialWorldSettings() #endif #ifdef ENABLE_PLAYERBOTS - sAhBotConfig.Initialize(); + auctionbot.Init(); sPlayerbotAIConfig.Initialize(); #endif @@ -1628,15 +1618,22 @@ void World::showFooter() #endif // PLAYERBOTS can be included or excluded but also disabled via mangos.conf -#ifdef ENABLE_PLAYERBOTS - bool playerBotActive = sConfig.GetBoolDefault("PlayerbotAI.DisableBots", true); - if (playerBotActive) +#ifdef ENABLE_PLAYERBOTS] + if (sPlayerbotAIConfig.enabled) + { + modules_.insert(" PlayerBots : Enabled"); + } + else { modules_.insert(" PlayerBots : Disabled"); } + if (sAhBotConfig.enabled) + { + modules_.insert(" AuctionBot : Enabled"); + } else { - modules_.insert(" PlayerBots : Enabled"); + modules_.insert(" AuctionBot : Disabled"); } #endif @@ -1848,6 +1845,7 @@ void World::Update(uint32 diff) #ifdef ENABLE_PLAYERBOTS sRandomPlayerbotMgr.UpdateAI(diff); sRandomPlayerbotMgr.UpdateSessions(diff); + auctionbot.Update(); #endif ///
  • Handle session updates @@ -2256,6 +2254,7 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode) #ifdef ENABLE_PLAYERBOTS sRandomPlayerbotMgr.LogoutAllBots(); + auctionbot.Update(); #endif ///- Used by Eluna diff --git a/src/game/WorldHandlers/World.h b/src/game/WorldHandlers/World.h index 14539521bc..cb9429d46b 100644 --- a/src/game/WorldHandlers/World.h +++ b/src/game/WorldHandlers/World.h @@ -379,17 +379,8 @@ enum eConfigBoolValues CONFIG_BOOL_ELUNA_ENABLED, CONFIG_BOOL_PLAYER_COMMANDS, #ifdef ENABLE_PLAYERBOTS - CONFIG_BOOL_PLAYERBOT_DISABLE, + CONFIG_BOOL_PLAYERBOT_ENABLE, CONFIG_BOOL_PLAYERBOT_DEBUGWHISPER, - CONFIG_BOOL_PLAYERBOT_SHAREDBOTS, - CONFIG_BOOL_PLAYERBOT_ALLOW_SUMMON_OPPOSITE_FACTION, - CONFIG_BOOL_PLAYERBOT_COLLECT_COMBAT, - CONFIG_BOOL_PLAYERBOT_COLLECT_QUESTS, - CONFIG_BOOL_PLAYERBOT_COLLECT_PROFESSION, - CONFIG_BOOL_PLAYERBOT_COLLECT_LOOT, - CONFIG_BOOL_PLAYERBOT_COLLECT_SKIN, - CONFIG_BOOL_PLAYERBOT_COLLECT_OBJECTS, - CONFIG_BOOL_PLAYERBOT_SELL_TRASH, #endif // Warden CONFIG_BOOL_WARDEN_WIN_ENABLED, diff --git a/src/modules/Bots/ahbot/AhBot.cpp b/src/modules/Bots/ahbot/AhBot.cpp index c33e6d7140..c40c65cd97 100644 --- a/src/modules/Bots/ahbot/AhBot.cpp +++ b/src/modules/Bots/ahbot/AhBot.cpp @@ -71,7 +71,49 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid ) bool ChatHandler::HandleAhBotCommand(char* args) { - auctionbot.HandleCommand(args); + ostringstream out; + if (!sAhBotConfig.enabled) + { + out << "Module AHBot is disabled"; + } + else if (strcmp(args, "expire") == 0) + { + auctionbot.ExpireAll(); + out << "Auctions expired"; + } + else if (strcmp(args, "stats") == 0) + { + out << auctionbot.PrintAllStats(); + } + else if (strcmp(args, "update") == 0) + { + auctionbot.ActivateNewThread(); + out << "Update started"; + } + else + { + uint32 itemId = atoi(args); + if(itemId) + { + out << auctionbot.LookupItem(itemId); + } + else + { + out << "auctionbot stats - show short summary\n"; + out << "auctionbot expire - expire all auctions\n"; + out << "auctionbot update - update all auctions\n"; + out << "auctionbot - show item price\n"; + } + } + + if (m_session) + { + PSendSysMessage(out.str().c_str()); + } + else + { + sLog.outString(out.str().c_str()); + } return true; } @@ -81,9 +123,11 @@ uint32 AhBot::auctionIds[MAX_AUCTIONS] = {1,6,7}; uint32 AhBot::auctioneers[MAX_AUCTIONS] = {79707,4656,23442}; map AhBot::factions; +// Public + void AhBot::Init() { - sLog.outString("Initializing AhBot by ike3"); + sLog.outString("Initializing module Ahbot by ike3, based on the original Playerbot by blueboy"); if (!sAhBotConfig.Initialize()) { @@ -100,7 +144,7 @@ void AhBot::Init() availableItems.Init(); - sLog.outString("AhBot configuration loaded"); + sLog.outString("AhBot module loaded"); } AhBot::~AhBot() @@ -141,6 +185,20 @@ void AhBot::Update() thread->activate(); } +void AhBot::ActivateNewThread() +{ + AhbotThread *thread = new AhbotThread(this); + thread->activate(); +} + +void AhBot::ExpireAll() +{ + for (int i = 0; i < MAX_AUCTIONS; ++i) + { + Expire(i); + } +} + void AhBot::ForceUpdate() { if (!sAhBotConfig.enabled) @@ -153,7 +211,7 @@ void AhBot::ForceUpdate() return; } - sLog.outString("AhBot is now checking auctions"); + sLog.outString("Ahbot module is now checking auctions"); updating = true; if (!allBidders.size()) @@ -163,7 +221,7 @@ void AhBot::ForceUpdate() if (!allBidders.size()) { - sLog.outError("Ahbot is disabled but there is no bidders available"); + sLog.outError("Ahbot module is disabled but there are no bidders available"); return; } @@ -185,101 +243,159 @@ void AhBot::ForceUpdate() CleanupHistory(); - sLog.outString("AhBot auction check finished. %d auctions answered, %d new auctions added. Next check in %d seconds", + sLog.outString("Ahbot module auction check finished. %d auctions answered, %d new auctions added. Next check in %d seconds", answered, added, sAhBotConfig.updateInterval); updating = false; } -struct SortByPricePredicate +int32 AhBot::GetBuyPrice(ItemPrototype const* proto) { - bool operator()(AuctionEntry* const & a, AuctionEntry* const & b) const + if (!sAhBotConfig.enabled) { - if (a->startbid == b->startbid) - { - return a->buyout < b->buyout; - } - - return a->startbid < b->startbid; + return 0; } -}; -vector AhBot::LoadAuctions(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, - Category*& category, int& auction) -{ - vector entries; - for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + int32 maxPrice = 0; + for (int i=0; isecond; - if (IsBotAuction(entry->owner) || IsBotAuction(entry->bidder)) + Category* category = CategoryList::instance[i]; + if (!category->Contains(proto)) { continue; } - Item *item = sAuctionMgr.GetAItem(entry->itemGuidLow); - if (!item) + for (int auction = 0; auction < MAX_AUCTIONS; ++auction) { - continue; - } + int32 price = (int32)category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); + if (!price) + { + continue; + } - if (!category->Contains(item->GetProto())) - { - continue; + if (price > maxPrice) + { + maxPrice = price; + } } + } - uint32 price = category->GetPricingStrategy()->GetBuyPrice(item->GetProto(), auctionIds[auction]); - if (!price || !item->GetCount()) + return maxPrice; +} + +double AhBot::GetRarityPriceMultiplier(const ItemPrototype* proto) +{ + if (!sAhBotConfig.enabled) + { + return 1.0; + } + + for (int i=0; iContains(proto)) { - sLog.outDetail("%s (x%d) in auction %d: price cannot be determined", - item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); continue; } - entries.push_back(entry); + return category->GetPricingStrategy()->GetRarityPriceMultiplier(proto->ItemId); } - sort(entries.begin(), entries.end(), SortByPricePredicate()); - return entries; + + return 1.0; + } -void AhBot::FindMinPrice(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, AuctionEntry*& entry, Item*& item, uint32* minBid, - uint32* minBuyout) +int32 AhBot::GetSellPrice(ItemPrototype const* proto) { - *minBid = 0; - *minBuyout = 0; - for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + if (!sAhBotConfig.enabled) { - AuctionEntry *other = itr->second; - if (other->owner == entry->owner) + return 0; + } + + int32 maxPrice = 0; + for (int i=0; iContains(proto)) { continue; } - Item *otherItem = sAuctionMgr.GetAItem(other->itemGuidLow); - if (!otherItem || !otherItem->GetCount() || otherItem->GetProto()->ItemId != item->GetProto()->ItemId) + for (int auction = 0; auction < MAX_AUCTIONS; ++auction) { - continue; + int32 price = (int32)category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]); + if (!price) + { + price = (int32)category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); + } + + if (price > maxPrice) + { + maxPrice = price; + } } + } - uint32 startbid = other->startbid / otherItem->GetCount() * item->GetCount(); - uint32 bid = other->bid / otherItem->GetCount() * item->GetCount(); - uint32 buyout = other->buyout / otherItem->GetCount() * item->GetCount(); + return maxPrice; +} - if (!bid && startbid && (!*minBid || *minBid > startbid)) - { - *minBid = startbid; - } +string AhBot::LookupItem(uint32 itemId) +{ + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + return "Unknown item"; + } - if (bid && (*minBid || *minBid > bid)) + for (int i=0; iContains(proto)) { - *minBid = bid; - } + vector items = availableItems.Get(category); + if (find(items.begin(), items.end(), proto->ItemId) == items.end()) + { + continue; + } - if (buyout && (!*minBuyout || *minBuyout > buyout)) - { - *minBuyout = buyout; + ostringstream out; + out << proto->Name1 << " (" << category->GetDisplayName() << "), " + << category->GetMaxAllowedAuctionCount() << "x" << category->GetMaxAllowedItemAuctionCount(proto) + << "x" << category->GetStackCount(proto) << " max" + << "\n"; + for (int auction = 0; auction < MAX_AUCTIONS; ++auction) + { + const AuctionHouseEntry* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + out << "--- auction house " << auctionIds[auction] << "(faction: " << factions[auctionIds[auction]] << ", money: " + << GetAvailableMoney(auctionIds[auction]) + << ") ---\n"; + + out << "sell: " << category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]) + << " (" << category->GetPricingStrategy()->ExplainSellPrice(proto, auctionIds[auction]) << ")" + << "\n"; + + out << "buy: " << category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]) + << " (" << category->GetPricingStrategy()->ExplainBuyPrice(proto, auctionIds[auction]) << ")" + << "\n"; + } + return out.str(); } } + + return "Unable to find requested item."; +} + +string AhBot::PrintAllStats() +{ + ostringstream out; + for (int i = 0; i < MAX_AUCTIONS; ++i) + { + out << PrintStats(i); + } + return out.str(); } +// Private + int AhBot::Answer(int auction, Category* category, ItemBag* inAuctionItems) { const AuctionHouseEntry* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); @@ -402,7 +518,7 @@ int AhBot::Answer(int auction, Category* category, ItemBag* inAuctionItems) if ((entry->buyout && (entry->bid >= entry->buyout || 100 * (entry->buyout - entry->bid) / price < 25)) && !(minBuyout && entry->buyout && minBuyout < entry->buyout)) { - sLog.outDetail("AhBot %d won %s (x%d) in auction %d for %d", + sLog.outDetail("Ahbot module %d won %s (x%d) in auction %d for %d", bidder, item->GetProto()->Name1, item->GetCount(), auctionIds[auction], entry->buyout); entry->bid = entry->buyout; @@ -410,7 +526,7 @@ int AhBot::Answer(int auction, Category* category, ItemBag* inAuctionItems) } else { - sLog.outDetail("AhBot %d placed bid %d for %s (x%d) in auction %d", + sLog.outDetail("Ahbot module %d placed bid %d for %s (x%d) in auction %d", bidder, entry->bid, item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); CharacterDatabase.PExecute("UPDATE `auction` SET `buyguid` = '%u',`lastbid` = '%u' WHERE `id` = '%u'", @@ -427,148 +543,55 @@ int AhBot::Answer(int auction, Category* category, ItemBag* inAuctionItems) return answered; } -uint32 AhBot::GetTime(string category, uint32 id, uint32 auctionHouse, uint32 type) +int AhBot::AddAuctions(int auction, Category* category, ItemBag* inAuctionItems) { - QueryResult* results = CharacterDatabase.PQuery("SELECT MAX(`buytime`) FROM `ahbot_history` WHERE `item` = '%u' AND `won` = '%u' AND `auction_house` = '%u' AND `category` = '%s'", - id, type, factions[auctionHouse], category.c_str()); + vector& inAuction = inAuctionItems->Get(category); - if (!results) + int32 maxAllowedAuctionCount = categoryMaxAuctionCount[category->GetName()]; + if (inAuctionItems->GetCount(category) >= maxAllowedAuctionCount) { return 0; } - Field* fields = results->Fetch(); - uint32 result = fields[0].GetUInt32(); - delete results; + int added = 0; + vector available = availableItems.Get(category); + for (int32 i = 0; i <= maxAllowedAuctionCount && available.size() > 0 && inAuctionItems->GetCount(category) < maxAllowedAuctionCount; ++i) + { + uint32 index = urand(0, available.size() - 1); + uint32 itemId = available[index]; - return result; -} + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); + if (!proto) + { + continue; + } -void AhBot::SetTime(string category, uint32 id, uint32 auctionHouse, uint32 type, uint32 value) -{ - CharacterDatabase.PExecute("DELETE FROM `ahbot_history` WHERE `item` = '%u' AND `won` = '%u' AND `auction_house` = '%u' AND `category` = '%s'", - id, type, factions[auctionHouse], category.c_str()); + int32 maxAllowedItems = category->GetMaxAllowedItemAuctionCount(proto); + if (maxAllowedItems && inAuctionItems->GetCount(category, proto->ItemId) >= maxAllowedItems) + { + continue; + } - CharacterDatabase.PExecute("INSERT INTO `ahbot_history` (`buytime`, `item`, `bid`, `buyout`, `category`, `won`, `auction_house`) " - "VALUES ('%u', '%u', '%u', '%u', '%s', '%u', '%u')", - value, id, 0, 0, - category.c_str(), type, factions[auctionHouse]); -} + uint32 sellTime = GetSellTime(proto->ItemId, auctionIds[auction], category); + if (time(0) < sellTime) + { + sLog.outDetail("%s in auction %d: will add in %d seconds", + proto->Name1, auctionIds[auction], sellTime - time(0)); + continue; + } + else if (time(0) - sellTime > sAhBotConfig.maxSellInterval) + { + sLog.outDetail("%s in auction %d: too old (%d secs)", + proto->Name1, auctionIds[auction], time(0) - sellTime); + continue; + } -uint32 AhBot::GetBuyTime(uint32 entry, uint32 itemId, uint32 auctionHouse, Category*& category, double priceLevel) -{ - uint32 entryTime = GetTime("entry", entry, auctionHouse, AHBOT_WON_DELAY); - if (entryTime > time(0)) - { - return entryTime; + inAuctionItems->Add(proto); + added += AddAuction(auction, category, proto); } - uint32 result = entryTime; - - string categoryName = category->GetName(); - uint32 categoryTime = GetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY); - uint32 itemTime = GetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY); - - if (categoryTime < time(0)) categoryTime = time(0); - { - if (itemTime < time(0)) itemTime = time(0); - } - - double rarity = category->GetPricingStrategy()->GetRarityPriceMultiplier(itemId); - categoryTime += urand(sAhBotConfig.itemBuyMinInterval, sAhBotConfig.itemBuyMaxInterval) * priceLevel; - itemTime += urand(sAhBotConfig.itemBuyMinInterval, sAhBotConfig.itemBuyMaxInterval) * priceLevel / rarity; - entryTime = max(categoryTime, itemTime); - - SetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY, categoryTime); - SetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY, itemTime); - SetTime("entry", entry, auctionHouse, AHBOT_WON_DELAY, entryTime); - - return result ? result : entryTime; -} - -uint32 AhBot::GetSellTime(uint32 itemId, uint32 auctionHouse, Category*& category) -{ - uint32 itemSellTime = GetTime("item", itemId, auctionHouse, AHBOT_SELL_DELAY); - uint32 itemBuyTime = GetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY); - uint32 itemTime = max(itemSellTime, itemBuyTime); - - if (itemTime > time(0)) - { - return itemTime; - } - - uint32 result = itemTime; - - string categoryName = category->GetName(); - uint32 categorySellTime = GetTime(categoryName, 0, auctionHouse, AHBOT_SELL_DELAY); - uint32 categoryBuyTime = GetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY); - uint32 categoryTime = max(categorySellTime, categoryBuyTime); - - if (categoryTime < time(0)) categoryTime = time(0); - { - if (itemTime < time(0)) itemTime = time(0); - } - - double rarity = category->GetPricingStrategy()->GetRarityPriceMultiplier(itemId); - categoryTime += urand(sAhBotConfig.itemSellMinInterval, sAhBotConfig.itemSellMaxInterval); - itemTime += urand(sAhBotConfig.itemSellMinInterval, sAhBotConfig.itemSellMaxInterval) * rarity; - itemTime = max(itemTime, categoryTime); - - SetTime(categoryName, 0, auctionHouse, AHBOT_SELL_DELAY, categoryTime); - SetTime("item", itemId, auctionHouse, AHBOT_SELL_DELAY, itemTime); - - return result ? result : itemTime; -} - -int AhBot::AddAuctions(int auction, Category* category, ItemBag* inAuctionItems) -{ - vector& inAuction = inAuctionItems->Get(category); - - int32 maxAllowedAuctionCount = categoryMaxAuctionCount[category->GetName()]; - if (inAuctionItems->GetCount(category) >= maxAllowedAuctionCount) - { - return 0; - } - - int added = 0; - vector available = availableItems.Get(category); - for (int32 i = 0; i <= maxAllowedAuctionCount && available.size() > 0 && inAuctionItems->GetCount(category) < maxAllowedAuctionCount; ++i) - { - uint32 index = urand(0, available.size() - 1); - uint32 itemId = available[index]; - - ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); - if (!proto) - { - continue; - } - - int32 maxAllowedItems = category->GetMaxAllowedItemAuctionCount(proto); - if (maxAllowedItems && inAuctionItems->GetCount(category, proto->ItemId) >= maxAllowedItems) - { - continue; - } - - uint32 sellTime = GetSellTime(proto->ItemId, auctionIds[auction], category); - if (time(0) < sellTime) - { - sLog.outDetail("%s in auction %d: will add in %d seconds", - proto->Name1, auctionIds[auction], sellTime - time(0)); - continue; - } - else if (time(0) - sellTime > sAhBotConfig.maxSellInterval) - { - sLog.outDetail("%s in auction %d: too old (%d secs)", - proto->Name1, auctionIds[auction], time(0) - sellTime); - continue; - } - - inAuctionItems->Add(proto); - added += AddAuction(auction, category, proto); - } - - return added; -} + return added; +} int AhBot::AddAuction(int auction, Category* category, ItemPrototype const* proto) { @@ -642,150 +665,10 @@ int AhBot::AddAuction(int auction, Category* category, ItemPrototype const* prot auctionHouse->AddAuction(auctionEntry); auctionEntry->SaveToDB(); - sLog.outDetail("AhBot %d added %d of %s to auction %d for %d..%d", owner, stackCount, proto->Name1, auctionIds[auction], bidPrice, buyoutPrice); + sLog.outDetail("Ahbot module %d added %d of %s to auction %d for %d..%d", owner, stackCount, proto->Name1, auctionIds[auction], bidPrice, buyoutPrice); return 1; } -void AhBot::HandleCommand(string command) -{ - if (!sAhBotConfig.enabled) - { - return; - } - - if (command == "expire") - { - for (int i = 0; i < MAX_AUCTIONS; ++i) - { - Expire(i); - } - - return; - } - - if (command == "stats") - { - for (int i = 0; i < MAX_AUCTIONS; ++i) - { - PrintStats(i); - } - - return; - } - - if (command == "update") - { - AhbotThread *thread = new AhbotThread(this); - thread->activate(); - return; - } - - uint32 itemId = atoi(command.c_str()); - if (!itemId) - { - sLog.outString("ahbot stats - show short summary"); - sLog.outString("ahbot expire - expire all auctions"); - sLog.outString("ahbot update - update all auctions"); - sLog.outString("ahbot - show item price"); - return; - } - - ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemId); - if (!proto) - { - return; - } - - for (int i=0; iContains(proto)) - { - vector items = availableItems.Get(category); - if (find(items.begin(), items.end(), proto->ItemId) == items.end()) - { - continue; - } - - ostringstream out; - out << proto->Name1 << " (" << category->GetDisplayName() << "), " - << category->GetMaxAllowedAuctionCount() << "x" << category->GetMaxAllowedItemAuctionCount(proto) - << "x" << category->GetStackCount(proto) << " max" - << "\n"; - for (int auction = 0; auction < MAX_AUCTIONS; ++auction) - { - const AuctionHouseEntry* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); - out << "--- auction house " << auctionIds[auction] << "(faction: " << factions[auctionIds[auction]] << ", money: " - << GetAvailableMoney(auctionIds[auction]) - << ") ---\n"; - - out << "sell: " << category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]) - << " (" << category->GetPricingStrategy()->ExplainSellPrice(proto, auctionIds[auction]) << ")" - << "\n"; - - out << "buy: " << category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]) - << " (" << category->GetPricingStrategy()->ExplainBuyPrice(proto, auctionIds[auction]) << ")" - << "\n"; - } - sLog.outString(out.str().c_str()); - break; - } - } -} - -void AhBot::Expire(int auction) -{ - if (!sAhBotConfig.enabled) - { - return; - } - - AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); - if(!ahEntry) - { - return; - } - - AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); - - AuctionHouseObject::AuctionEntryMap const& auctions = auctionHouse->GetAuctions(); - AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctions.begin(); - - int count = 0; - while (itr != auctions.end()) - { - if (IsBotAuction(itr->second->owner)) - { - itr->second->expireTime = sWorld.GetGameTime(); - ++count; - } - - ++itr; - } - - CharacterDatabase.PExecute("DELETE FROM `ahbot_category`"); - sLog.outString("%d auctions marked as expired in auction %d", count, auctionIds[auction]); -} - -void AhBot::PrintStats(int auction) -{ - if (!sAhBotConfig.enabled) - { - return; - } - - AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); - if(!ahEntry) - { - return; - } - - AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); - AuctionHouseObject::AuctionEntryMap const& auctions = auctionHouse->GetAuctions(); - - sLog.outString("%d auctions available on auction house %d", auctions.size(), auctionIds[auction]); -} - void AhBot::AddToHistory(AuctionEntry* entry, uint32 won) { if (!sAhBotConfig.enabled || !entry) @@ -834,25 +717,40 @@ void AhBot::AddToHistory(AuctionEntry* entry, uint32 won) category.c_str(), won, factions[entry->auctionHouseEntry->houseId]); } -uint32 AhBot::GetAnswerCount(uint32 itemId, uint32 auctionHouse, uint32 withinTime) +void AhBot::CheckCategoryMultipliers() { - uint32 count = 0; - - QueryResult* results = CharacterDatabase.PQuery("SELECT COUNT(*) FROM `ahbot_history` WHERE " - "`item` = '%u' AND `won` in (2, 3) AND `auction_house` = '%u' AND `buytime` > '%u'", - itemId, factions[auctionHouse], time(0) - withinTime); + QueryResult* results = CharacterDatabase.PQuery("SELECT `category`, `multiplier`, `max_auction_count`, `expire_time` FROM `ahbot_category`"); if (results) { do { Field* fields = results->Fetch(); - count = fields[0].GetUInt32(); + categoryMultipliers[fields[0].GetCppString()] = fields[1].GetFloat(); + categoryMaxAuctionCount[fields[0].GetCppString()] = fields[2].GetInt32(); + categoryMultiplierExpireTimes[fields[0].GetCppString()] = fields[3].GetUInt64(); + } while (results->NextRow()); delete results; } - return count; + CharacterDatabase.PExecute("DELETE FROM `ahbot_category`"); + + for (int i = 0; i < CategoryList::instance.size(); ++i) + { + string name = CategoryList::instance[i]->GetName(); + if (categoryMultiplierExpireTimes[name] <= time(0) || categoryMultipliers[name] <= 0) + { + categoryMultipliers[name] = (double)urand(20, 100) / 20.0; + uint32 maxAllowedAuctionCount = CategoryList::instance[i]->GetMaxAllowedAuctionCount(); + categoryMaxAuctionCount[name] = urand(maxAllowedAuctionCount / 2, maxAllowedAuctionCount); + categoryMultiplierExpireTimes[name] = time(0) + urand(4, 7) * 3600 * 24; + } + + CharacterDatabase.PExecute("INSERT INTO `ahbot_category` (`category`, `multiplier`, `max_auction_count`, `expire_time`) " + "VALUES ('%s', '%f', '%u', '%u')", + name.c_str(), categoryMultipliers[name], categoryMaxAuctionCount[name], categoryMultiplierExpireTimes[name]); + } } void AhBot::CleanupHistory() @@ -861,9 +759,99 @@ void AhBot::CleanupHistory() CharacterDatabase.PExecute("DELETE FROM `ahbot_history` WHERE `buytime` < '%u'", when); } -uint32 AhBot::GetAvailableMoney(uint32 auctionHouse) +void AhBot::Expire(int auction) { - int64 result = sAhBotConfig.alwaysAvailableMoney; + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + if(!ahEntry) + { + return; + } + + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); + + AuctionHouseObject::AuctionEntryMap const& auctions = auctionHouse->GetAuctions(); + AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctions.begin(); + + int count = 0; + while (itr != auctions.end()) + { + if (IsBotAuction(itr->second->owner)) + { + itr->second->expireTime = sWorld.GetGameTime(); + ++count; + } + + ++itr; + } + + CharacterDatabase.PExecute("DELETE FROM `ahbot_category`"); + sLog.outString("%d auctions marked as expired in auction %d", count, auctionIds[auction]); +} + +void AhBot::FindMinPrice(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, AuctionEntry*& entry, Item*& item, uint32* minBid, + uint32* minBuyout) +{ + *minBid = 0; + *minBuyout = 0; + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + { + AuctionEntry *other = itr->second; + if (other->owner == entry->owner) + { + continue; + } + + Item *otherItem = sAuctionMgr.GetAItem(other->itemGuidLow); + if (!otherItem || !otherItem->GetCount() || otherItem->GetProto()->ItemId != item->GetProto()->ItemId) + { + continue; + } + + uint32 startbid = other->startbid / otherItem->GetCount() * item->GetCount(); + uint32 bid = other->bid / otherItem->GetCount() * item->GetCount(); + uint32 buyout = other->buyout / otherItem->GetCount() * item->GetCount(); + + if (!bid && startbid && (!*minBid || *minBid > startbid)) + { + *minBid = startbid; + } + + if (bid && (*minBid || *minBid > bid)) + { + *minBid = bid; + } + + if (buyout && (!*minBuyout || *minBuyout > buyout)) + { + *minBuyout = buyout; + } + } +} + +uint32 AhBot::GetAnswerCount(uint32 itemId, uint32 auctionHouse, uint32 withinTime) +{ + uint32 count = 0; + + QueryResult* results = CharacterDatabase.PQuery("SELECT COUNT(*) FROM `ahbot_history` WHERE " + "`item` = '%u' AND `won` in (2, 3) AND `auction_house` = '%u' AND `buytime` > '%u'", + itemId, factions[auctionHouse], time(0) - withinTime); + if (results) + { + do + { + Field* fields = results->Fetch(); + count = fields[0].GetUInt32(); + } while (results->NextRow()); + + delete results; + } + + return count; +} + +uint32 AhBot::GetAvailableMoney(uint32 auctionHouse) +{ + int64 result = sAhBotConfig.alwaysAvailableMoney; map data; data[AHBOT_WON_PLAYER] = 0; @@ -917,65 +905,98 @@ uint32 AhBot::GetAvailableMoney(uint32 auctionHouse) return result < 0 ? 0 : (uint32)result; } -void AhBot::CheckCategoryMultipliers() +uint32 AhBot::GetBuyTime(uint32 entry, uint32 itemId, uint32 auctionHouse, Category*& category, double priceLevel) { - QueryResult* results = CharacterDatabase.PQuery("SELECT `category`, `multiplier`, `max_auction_count`, `expire_time` FROM `ahbot_category`"); - if (results) + uint32 entryTime = GetTime("entry", entry, auctionHouse, AHBOT_WON_DELAY); + if (entryTime > time(0)) { - do - { - Field* fields = results->Fetch(); - categoryMultipliers[fields[0].GetCppString()] = fields[1].GetFloat(); - categoryMaxAuctionCount[fields[0].GetCppString()] = fields[2].GetInt32(); - categoryMultiplierExpireTimes[fields[0].GetCppString()] = fields[3].GetUInt64(); + return entryTime; + } - } while (results->NextRow()); + uint32 result = entryTime; - delete results; + string categoryName = category->GetName(); + uint32 categoryTime = GetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY); + uint32 itemTime = GetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY); + + if (categoryTime < time(0)) categoryTime = time(0); + { + if (itemTime < time(0)) itemTime = time(0); } - CharacterDatabase.PExecute("DELETE FROM `ahbot_category`"); + double rarity = category->GetPricingStrategy()->GetRarityPriceMultiplier(itemId); + categoryTime += urand(sAhBotConfig.itemBuyMinInterval, sAhBotConfig.itemBuyMaxInterval) * priceLevel; + itemTime += urand(sAhBotConfig.itemBuyMinInterval, sAhBotConfig.itemBuyMaxInterval) * priceLevel / rarity; + entryTime = max(categoryTime, itemTime); - for (int i = 0; i < CategoryList::instance.size(); ++i) - { - string name = CategoryList::instance[i]->GetName(); - if (categoryMultiplierExpireTimes[name] <= time(0) || categoryMultipliers[name] <= 0) - { - categoryMultipliers[name] = (double)urand(20, 100) / 20.0; - uint32 maxAllowedAuctionCount = CategoryList::instance[i]->GetMaxAllowedAuctionCount(); - categoryMaxAuctionCount[name] = urand(maxAllowedAuctionCount / 2, maxAllowedAuctionCount); - categoryMultiplierExpireTimes[name] = time(0) + urand(4, 7) * 3600 * 24; - } + SetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY, categoryTime); + SetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY, itemTime); + SetTime("entry", entry, auctionHouse, AHBOT_WON_DELAY, entryTime); - CharacterDatabase.PExecute("INSERT INTO `ahbot_category` (`category`, `multiplier`, `max_auction_count`, `expire_time`) " - "VALUES ('%s', '%f', '%u', '%u')", - name.c_str(), categoryMultipliers[name], categoryMaxAuctionCount[name], categoryMultiplierExpireTimes[name]); - } + return result ? result : entryTime; } +uint32 AhBot::GetRandomBidder(uint32 auctionHouse) +{ + vector guids = bidders[factions[auctionHouse]]; + if (guids.empty()) + { + return 0; + } + + int index = urand(0, guids.size() - 1); + return guids[index]; +} -void AhBot::updateMarketPrice(uint32 itemId, double price, uint32 auctionHouse) +uint32 AhBot::GetSellTime(uint32 itemId, uint32 auctionHouse, Category*& category) { - double marketPrice = 0; + uint32 itemSellTime = GetTime("item", itemId, auctionHouse, AHBOT_SELL_DELAY); + uint32 itemBuyTime = GetTime("item", itemId, auctionHouse, AHBOT_WON_DELAY); + uint32 itemTime = max(itemSellTime, itemBuyTime); - QueryResult* results = CharacterDatabase.PQuery("SELECT `price` FROM `ahbot_price` WHERE `item` = '%u' AND `auction_house` = '%u'", itemId, auctionHouse); - if (results) + if (itemTime > time(0)) { - marketPrice = results->Fetch()[0].GetFloat(); - delete results; + return itemTime; } - if (marketPrice > 0) + uint32 result = itemTime; + + string categoryName = category->GetName(); + uint32 categorySellTime = GetTime(categoryName, 0, auctionHouse, AHBOT_SELL_DELAY); + uint32 categoryBuyTime = GetTime(categoryName, 0, auctionHouse, AHBOT_WON_DELAY); + uint32 categoryTime = max(categorySellTime, categoryBuyTime); + + if (categoryTime < time(0)) categoryTime = time(0); { - marketPrice = (marketPrice + price) / 2; + if (itemTime < time(0)) itemTime = time(0); } - else + + double rarity = category->GetPricingStrategy()->GetRarityPriceMultiplier(itemId); + categoryTime += urand(sAhBotConfig.itemSellMinInterval, sAhBotConfig.itemSellMaxInterval); + itemTime += urand(sAhBotConfig.itemSellMinInterval, sAhBotConfig.itemSellMaxInterval) * rarity; + itemTime = max(itemTime, categoryTime); + + SetTime(categoryName, 0, auctionHouse, AHBOT_SELL_DELAY, categoryTime); + SetTime("item", itemId, auctionHouse, AHBOT_SELL_DELAY, itemTime); + + return result ? result : itemTime; +} + +uint32 AhBot::GetTime(string category, uint32 id, uint32 auctionHouse, uint32 type) +{ + QueryResult* results = CharacterDatabase.PQuery("SELECT MAX(`buytime`) FROM `ahbot_history` WHERE `item` = '%u' AND `won` = '%u' AND `auction_house` = '%u' AND `category` = '%s'", + id, type, factions[auctionHouse], category.c_str()); + + if (!results) { - marketPrice = price; + return 0; } - CharacterDatabase.PExecute("DELETE FROM `ahbot_price` WHERE `item` = '%u' AND `auction_house` = '%u'", itemId, auctionHouse); - CharacterDatabase.PExecute("INSERT INTO `ahbot_price` (`item`, `price`, `auction_house`) VALUES ('%u', '%lf', '%u')", itemId, marketPrice, auctionHouse); + Field* fields = results->Fetch(); + uint32 result = fields[0].GetUInt32(); + delete results; + + return result; } bool AhBot::IsBotAuction(uint32 bidder) @@ -983,16 +1004,54 @@ bool AhBot::IsBotAuction(uint32 bidder) return allBidders.find(bidder) != allBidders.end(); } -uint32 AhBot::GetRandomBidder(uint32 auctionHouse) +struct SortByPricePredicate { - vector guids = bidders[factions[auctionHouse]]; - if (guids.empty()) + bool operator()(AuctionEntry* const & a, AuctionEntry* const & b) const { - return 0; + if (a->startbid == b->startbid) + { + return a->buyout < b->buyout; + } + + return a->startbid < b->startbid; } +}; - int index = urand(0, guids.size() - 1); - return guids[index]; +vector AhBot::LoadAuctions(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, + Category*& category, int& auction) +{ + vector entries; + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionEntryMap.begin(); itr != auctionEntryMap.end(); ++itr) + { + AuctionEntry *entry = itr->second; + if (IsBotAuction(entry->owner) || IsBotAuction(entry->bidder)) + { + continue; + } + + Item *item = sAuctionMgr.GetAItem(entry->itemGuidLow); + if (!item) + { + continue; + } + + if (!category->Contains(item->GetProto())) + { + continue; + } + + uint32 price = category->GetPricingStrategy()->GetBuyPrice(item->GetProto(), auctionIds[auction]); + if (!price || !item->GetCount()) + { + sLog.outDetail("%s (x%d) in auction %d: price cannot be determined", + item->GetProto()->Name1, item->GetCount(), auctionIds[auction]); + continue; + } + + entries.push_back(entry); + } + sort(entries.begin(), entries.end(), SortByPricePredicate()); + return entries; } void AhBot::LoadRandomBots() @@ -1037,92 +1096,71 @@ void AhBot::LoadRandomBots() sLog.outDetail("{A=%d,H=%d,N=%d} bidders loaded", bidders[1].size(), bidders[2].size(), bidders[3].size()); } -int32 AhBot::GetSellPrice(ItemPrototype const* proto) +string AhBot::PrintStats(int auction) { - if (!sAhBotConfig.enabled) - { - return 0; - } + string ahouse = ""; - int32 maxPrice = 0; - for (int i=0; iContains(proto)) - { - continue; - } - - for (int auction = 0; auction < MAX_AUCTIONS; ++auction) - { - int32 price = (int32)category->GetPricingStrategy()->GetSellPrice(proto, auctionIds[auction]); - if (!price) - { - price = (int32)category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); - } - - if (price > maxPrice) - { - maxPrice = price; - } - } - } - - return maxPrice; -} + case 0: + ahouse = "Alliance"; + break; + case 1: + ahouse = "Horde"; + break; + case 2: + ahouse = "Goblin"; + break; + }; -int32 AhBot::GetBuyPrice(ItemPrototype const* proto) -{ - if (!sAhBotConfig.enabled) + ostringstream out; + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auctionIds[auction]); + if(!ahEntry) { - return 0; + out << "Unknown entry: " << auction; } - - int32 maxPrice = 0; - for (int i=0; iContains(proto)) - { - continue; - } + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(ahEntry); + AuctionHouseObject::AuctionEntryMap const& auctions = auctionHouse->GetAuctions(); - for (int auction = 0; auction < MAX_AUCTIONS; ++auction) - { - int32 price = (int32)category->GetPricingStrategy()->GetBuyPrice(proto, auctionIds[auction]); - if (!price) - { - continue; - } - - if (price > maxPrice) - { - maxPrice = price; - } - } + out << auctions.size() << " auctions available in the " << ahouse << " auction house\n"; + // out << auctions.size() << " auctions available on auction house " << auctionIds[auction] << "\n"; } + return out.str(); +} - return maxPrice; +void AhBot::SetTime(string category, uint32 id, uint32 auctionHouse, uint32 type, uint32 value) +{ + CharacterDatabase.PExecute("DELETE FROM `ahbot_history` WHERE `item` = '%u' AND `won` = '%u' AND `auction_house` = '%u' AND `category` = '%s'", + id, type, factions[auctionHouse], category.c_str()); + + CharacterDatabase.PExecute("INSERT INTO `ahbot_history` (`buytime`, `item`, `bid`, `buyout`, `category`, `won`, `auction_house`) " + "VALUES ('%u', '%u', '%u', '%u', '%s', '%u', '%u')", + value, id, 0, 0, + category.c_str(), type, factions[auctionHouse]); } -double AhBot::GetRarityPriceMultiplier(const ItemPrototype* proto) +void AhBot::updateMarketPrice(uint32 itemId, double price, uint32 auctionHouse) { - if (!sAhBotConfig.enabled) + double marketPrice = 0; + + QueryResult* results = CharacterDatabase.PQuery("SELECT `price` FROM `ahbot_price` WHERE `item` = '%u' AND `auction_house` = '%u'", itemId, auctionHouse); + if (results) { - return 1.0; + marketPrice = results->Fetch()[0].GetFloat(); + delete results; } - for (int i=0; i 0) { - Category* category = CategoryList::instance[i]; - if (!category->Contains(proto)) - { - continue; - } - - return category->GetPricingStrategy()->GetRarityPriceMultiplier(proto->ItemId); + marketPrice = (marketPrice + price) / 2; + } + else + { + marketPrice = price; } - return 1.0; - + CharacterDatabase.PExecute("DELETE FROM `ahbot_price` WHERE `item` = '%u' AND `auction_house` = '%u'", itemId, auctionHouse); + CharacterDatabase.PExecute("INSERT INTO `ahbot_price` (`item`, `price`, `auction_house`) VALUES ('%u', '%lf', '%u')", itemId, marketPrice, auctionHouse); } diff --git a/src/modules/Bots/ahbot/AhBot.h b/src/modules/Bots/ahbot/AhBot.h index ac063b3d0c..43ca87de5c 100644 --- a/src/modules/Bots/ahbot/AhBot.h +++ b/src/modules/Bots/ahbot/AhBot.h @@ -26,46 +26,46 @@ namespace ahbot virtual ~AhBot(); public: - ObjectGuid GetAHBplayerGUID(); void Init(); + ObjectGuid GetAHBplayerGUID(); void Update(); + void ActivateNewThread(); + void ExpireAll(); void ForceUpdate(); - void HandleCommand(string command); - void Won(AuctionEntry* entry) { AddToHistory(entry); } - void Expired(AuctionEntry* entry) {} - double GetCategoryMultiplier(string category) { return categoryMultipliers[category]; } - - int32 GetSellPrice(const ItemPrototype* proto); int32 GetBuyPrice(const ItemPrototype* proto); double GetRarityPriceMultiplier(const ItemPrototype* proto); + int32 GetSellPrice(const ItemPrototype* proto); + string LookupItem(uint32 itemId); + string PrintAllStats(); + void Won(AuctionEntry* entry) { AddToHistory(entry); } private: int Answer(int auction, Category* category, ItemBag* inAuctionItems); int AddAuctions(int auction, Category* category, ItemBag* inAuctionItems); int AddAuction(int auction, Category* category, const ItemPrototype* proto); - void Expire(int auction); - void PrintStats(int auction); void AddToHistory(AuctionEntry* entry, uint32 won = 0); - void CleanupHistory(); - uint32 GetAvailableMoney(uint32 auctionHouse); void CheckCategoryMultipliers(); - void updateMarketPrice(uint32 itemId, double price, uint32 auctionHouse); - bool IsBotAuction(uint32 bidder); - uint32 GetRandomBidder(uint32 auctionHouse); - void LoadRandomBots(); - uint32 GetAnswerCount(uint32 itemId, uint32 auctionHouse, uint32 withinTime); - vector LoadAuctions(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, Category*& category, - int& auction); + void CleanupHistory(); + void Expire(int auction); void FindMinPrice(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, AuctionEntry*& entry, Item*& item, uint32* minBid, uint32* minBuyout); + uint32 GetAnswerCount(uint32 itemId, uint32 auctionHouse, uint32 withinTime); + uint32 GetAvailableMoney(uint32 auctionHouse); uint32 GetBuyTime(uint32 entry, uint32 itemId, uint32 auctionHouse, Category*& category, double priceLevel); + uint32 GetRandomBidder(uint32 auctionHouse); + uint32 GetSellTime(uint32 itemId, uint32 auctionHouse, Category*& category); uint32 GetTime(string category, uint32 id, uint32 auctionHouse, uint32 type); + bool IsBotAuction(uint32 bidder); + vector LoadAuctions(const AuctionHouseObject::AuctionEntryMap& auctionEntryMap, Category*& category, + int& auction); + void LoadRandomBots(); + string PrintStats(int auction); void SetTime(string category, uint32 id, uint32 auctionHouse, uint32 type, uint32 value); - uint32 GetSellTime(uint32 itemId, uint32 auctionHouse, Category*& category); + void updateMarketPrice(uint32 itemId, double price, uint32 auctionHouse); public: static uint32 auctionIds[MAX_AUCTIONS]; diff --git a/src/modules/Bots/ahbot/AhBotConfig.cpp b/src/modules/Bots/ahbot/AhBotConfig.cpp index 9de895e8f9..d286733d9d 100644 --- a/src/modules/Bots/ahbot/AhBotConfig.cpp +++ b/src/modules/Bots/ahbot/AhBotConfig.cpp @@ -7,13 +7,7 @@ using namespace std; INSTANTIATE_SINGLETON_1(AhBotConfig); -AhBotConfig::AhBotConfig() -{ - enabled = false; - priceMultiplier = 1.0f; - priceQualityMultiplier = 1.0f; - underPriceProbability = 0.05f; -} +AhBotConfig::AhBotConfig(): enabled(false) {}; template void LoadSet(const string& value, T &res) @@ -33,13 +27,11 @@ void LoadSet(const string& value, T &res) bool AhBotConfig::Initialize() { - sLog.outString("Initializing AhBot by ike3, based on the original Playerbot by blueboy"); - const char* cfg_file = SYSCONFDIR"ahbot.conf"; if (!config.SetSource(cfg_file)) { - sLog.outString("AhBot is Disabled in %s", cfg_file); + sLog.outString("Failed to load config file %s", cfg_file); return false; } @@ -63,11 +55,11 @@ bool AhBotConfig::Initialize() priceQualityMultiplier = config.GetFloatDefault("AhBot.PriceQualityMultiplier", 1.0f); underPriceProbability = config.GetFloatDefault("AhBot.UnderPriceProbability", 0.05f); LoadSet >(config.GetStringDefault("AhBot.IgnoreItemIds", "49283,52200,8494,6345,6891,2460,37164,34835"), ignoreItemIds); - sLog.outString("AhBot loaded"); + sLog.outString("AhBot module config loaded"); } else { - sLog.outString("AhBot is Disabled in ahbot.conf"); + sLog.outString("AhBot module is disabled in ahbot.conf"); } return enabled; } diff --git a/src/modules/Bots/ahbot/PricingStrategy.cpp b/src/modules/Bots/ahbot/PricingStrategy.cpp index 765a609a58..64cf58c6ce 100644 --- a/src/modules/Bots/ahbot/PricingStrategy.cpp +++ b/src/modules/Bots/ahbot/PricingStrategy.cpp @@ -61,7 +61,7 @@ string PricingStrategy::ExplainSellPrice(ItemPrototype const* proto, uint32 auct uint32 untilTime = time(0); out << sAhBotConfig.GetItemPriceMultiplier(proto->Name1) << " (item const) * " << auctionbot.GetCategoryMultiplier(category->GetName()) << " (random) * " << - GetRarityPriceMultiplier(proto->ItemId) << " (rariry) * " << + GetRarityPriceMultiplier(proto->ItemId) << " (rarity) * " << GetCategoryPriceMultiplier(untilTime, auctionHouse) << " (category) * " << GetItemPriceMultiplier(proto, untilTime, auctionHouse) << " (item) * " << sAhBotConfig.GetSellPriceMultiplier(category->GetName()) << " (sell) * " << diff --git a/src/modules/Bots/ahbot/README.md b/src/modules/Bots/ahbot/README.md new file mode 100644 index 0000000000..d992ca4819 --- /dev/null +++ b/src/modules/Bots/ahbot/README.md @@ -0,0 +1,26 @@ +# Auction House bot + +This Auction House bot module was rebuilt from the blueboy Playerbot by ike3 and further adapted into Mangos by several contributors. It provides an alternative for the built-in AuctionHouseBot (which should be disabled by ahbot.conf). + +## Commands + +So-as not to conflict with the built-in auction house bot this module uses the keyword `auctionbot`. + +* auctionbot stats +* auctionbot expire +* auctionbot update +* auctionbot + +## Config +### Enabling the bot + +At the top of the ahbot.conf should be the two entries that disable the built-in auction house bot's agents: +``` +AuctionHouseBot.Seller.Enabled = 0 +AuctionHouseBot.Buyer.Enabled = 0 +``` + +Add the ahbot module's enable flag +``` +AhBot.Enabled = 1 +``` diff --git a/src/modules/Bots/ahbot/ahbot.conf.dist.in b/src/modules/Bots/ahbot/ahbot.conf.dist.in index dd2819a326..3c17028a6f 100644 --- a/src/modules/Bots/ahbot/ahbot.conf.dist.in +++ b/src/modules/Bots/ahbot/ahbot.conf.dist.in @@ -20,6 +20,9 @@ AhBot.Enabled = 1 # Should be used only if random bots are disabled # AhBot.GUID = 0 +AhBot.UpdateIntervalInSeconds = 300 +AhBot.History.Days = 30 + # 199 for 80, 80 for 70, 70 for 60, ..., 25 for 20 AhBot.MaxItemLevel = 199 # Same as level cap @@ -28,10 +31,12 @@ AhBot.MaxRequiredLevel = 80 # Ignore items by ID AhBot.IgnoreItemIds = 49283,52200,8494,6345,6891,2460 -AhBot.PriceMultiplier = 1.0 +AhBot.AlwaysAvailableMoney = 2000000 AhBot.DefaultMinPrice = 20 +AhBot.MaxSellInterval = 28800 # 8 hours +AhBot.PriceMultiplier = 1.0 AhBot.PriceQualityMultiplier = 1.0 -AhBot.AlwaysAvailableMoney = 2000000 +AhBot.UnderPriceProbability = 0.05 # Buy/sell delays AhBot.ItemBuyMinInterval = 7200 diff --git a/src/modules/Bots/playerbot/AiFactory.cpp b/src/modules/Bots/playerbot/AiFactory.cpp index bebe984eab..6b7c64e40b 100644 --- a/src/modules/Bots/playerbot/AiFactory.cpp +++ b/src/modules/Bots/playerbot/AiFactory.cpp @@ -49,7 +49,7 @@ AiObjectContext* AiFactory::createAiObjectContext(Player* player, PlayerbotAI* a case CLASS_ROGUE: return new RogueAiObjectContext(ai); break; - /* TODO: Implement DK AI */ + /* TODO: Implement Death Knights */ // case CLASS_DEATH_KNIGHT: // return new DKAiObjectContext(ai); // break; diff --git a/src/modules/Bots/playerbot/PlayerbotAI.cpp b/src/modules/Bots/playerbot/PlayerbotAI.cpp index c6ba4cdc38..376a5305e1 100644 --- a/src/modules/Bots/playerbot/PlayerbotAI.cpp +++ b/src/modules/Bots/playerbot/PlayerbotAI.cpp @@ -246,7 +246,7 @@ void PlayerbotAI::HandleCommand(uint32 type, const string& text, Player& fromPla string filtered = text; if (!sPlayerbotAIConfig.commandPrefix.empty()) { - if (filtered.starts_with(sPlayerbotAIConfig.commandPrefix)) + if (filtered.find(sPlayerbotAIConfig.commandPrefix) != 0) { return; } @@ -260,7 +260,7 @@ void PlayerbotAI::HandleCommand(uint32 type, const string& text, Player& fromPla return; } - if (filtered.starts_with("who") && !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, &fromPlayer)) + if (filtered.find("who") != 0 && !GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_ALLOW_ALL, type != CHAT_MSG_WHISPER, &fromPlayer)) { return; } diff --git a/src/modules/Bots/playerbot/PlayerbotAI.h b/src/modules/Bots/playerbot/PlayerbotAI.h index 87eb372cc3..d5335377e1 100644 --- a/src/modules/Bots/playerbot/PlayerbotAI.h +++ b/src/modules/Bots/playerbot/PlayerbotAI.h @@ -70,7 +70,7 @@ enum BotState class PacketHandlingHelper { public: - void AddHandler(uint16 opcode, string handler); + void AddHandler(uint16 opcode, const string &handler); void Handle(ExternalEventHelper &helper); void AddPacket(const WorldPacket& packet); @@ -132,7 +132,7 @@ class PlayerbotAI : public PlayerbotAIBase Unit* GetUnit(ObjectGuid guid); GameObject* GetGameObject(ObjectGuid guid); bool TellMaster(ostringstream &stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL) { return TellMaster(stream.str(), securityLevel); } - bool TellMaster(string text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); + bool TellMaster(const string &text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); bool TellMasterNoFacing(string text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); void SpellInterrupted(uint32 spellid); uint32 CalculateGlobalCooldown(uint32 spellid); diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp index 9549011773..8347a0bd8b 100644 --- a/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.cpp @@ -114,6 +114,8 @@ bool PlayerbotAIConfig::Initialize() randomBotCombatStrategies = sConfig.GetStringDefault("AiPlayerbot.RandomBotCombatStrategies", "+dps,+attack weak"); randomBotNonCombatStrategies = sConfig.GetStringDefault("AiPlayerbot.RandomBotNonCombatStrategies", "+grind,+move random,+loot"); + spellDump = sConfig.GetBoolDefault("AiPlayerbot.SpellDump", false); + commandPrefix = sConfig.GetStringDefault("AiPlayerbot.CommandPrefix", ""); commandServerPort = sConfig.GetIntDefault("AiPlayerbot.CommandServerPort", 0); @@ -127,13 +129,15 @@ bool PlayerbotAIConfig::Initialize() } } - CreateRandomBots(); + if (sConfig.GetBoolDefault("AiPlayerbot.RandomBotAutoCreate", false)) + { + CreateRandomBots(); + } sLog.outString("AI Playerbot configuration loaded"); return true; } - bool PlayerbotAIConfig::IsInRandomAccountList(uint32 id) { return find(randomBotAccounts.begin(), randomBotAccounts.end(), id) != randomBotAccounts.end(); @@ -276,7 +280,6 @@ void PlayerbotAIConfig::SetValue(const string &name, string value) } } - void PlayerbotAIConfig::CreateRandomBots() { string randomBotAccountPrefix = sConfig.GetStringDefault("AiPlayerbot.RandomBotAccountPrefix", "rndbot"); diff --git a/src/modules/Bots/playerbot/PlayerbotAIConfig.h b/src/modules/Bots/playerbot/PlayerbotAIConfig.h index 2c2aa9a4ee..850d3bab95 100644 --- a/src/modules/Bots/playerbot/PlayerbotAIConfig.h +++ b/src/modules/Bots/playerbot/PlayerbotAIConfig.h @@ -49,6 +49,7 @@ class PlayerbotAIConfig std::string randomBotCombatStrategies, randomBotNonCombatStrategies; uint32 randomBotMinLevel, randomBotMaxLevel; float randomChangeMultiplier; + bool spellDump; uint32 specProbability[MAX_CLASSES][3]; std::string commandPrefix; @@ -56,8 +57,8 @@ class PlayerbotAIConfig int commandServerPort; - std::string GetValue(std::string name); - void SetValue(std::string name, std::string value); + std::string GetValue(const std::string &name); + void SetValue(const std::string &name, std::string value); private: void CreateRandomBots(); diff --git a/src/modules/Bots/playerbot/PlayerbotMgr.h b/src/modules/Bots/playerbot/PlayerbotMgr.h index b6169c0956..9950613924 100644 --- a/src/modules/Bots/playerbot/PlayerbotMgr.h +++ b/src/modules/Bots/playerbot/PlayerbotMgr.h @@ -31,7 +31,7 @@ class MANGOS_DLL_SPEC PlayerbotHolder : public PlayerbotAIBase void OnBotLogin(Player * const bot); list HandlePlayerbotCommand(char* args, Player* master = NULL); - bool ProcessBotCommand(string cmd, ObjectGuid guid, bool admin, uint32 masterAccountId); + bool ProcessBotCommand(const string &cmd, ObjectGuid guid, bool admin, uint32 masterAccountId); uint32 GetAccountId(string name); protected: diff --git a/src/modules/Bots/playerbot/README.md b/src/modules/Bots/playerbot/README.md new file mode 100644 index 0000000000..e76a76e1b5 --- /dev/null +++ b/src/modules/Bots/playerbot/README.md @@ -0,0 +1,101 @@ +# Player Bot Module + +The Playerbot module integrates with Mangos to provide user-controll AI characters for groups and raids. This is especially helpful on low-activity servers. + +## Player Bots + +Alternative characters can join the game as a playerbot, controlled by the human player. + +## Random Bots + +Based on the configuration found in aiplayerbot.conf a number of bots will be randomly generated and added to the server. These bots will perform random grinding actions until invited to a group by a human player. + +## Commands + +### Chat + +To add, remove, or initialize a playerbot a player can use the `.bot` command. Players can further interact with Playerbots or Randombots by whispering or chatting in group, guild, or raid chats. + +See the reference below for bot commands. + +### Console + +A console user can interact with the Random Bots module using the `rndbot` command + +## Reference + +* http://ike3.github.io/mangosbot-docs/ + +### Command Reference from IKE3 documentation + +| Command | Description | +| --- | --- | +| Movement | | +| follow | Follow master | +| stay | Stay in place | +| flee | Flee with master (ignore everything else) | +| d attack my target | Attack my target | +| d add all loot | Check every corpse and game object for loot | +| grind | Attack anything | +| Strategies | | +| co +s1,-s2,~s3,? | Add, remove, toggle and show combat strategies | +| nc +s1,-s2,~s3,? | Add, remove, toggle and show non-combat strategies | +| ds +s1,-s2,~s3,? | Add, remove, toggle and show dead strategies | +| Items | | +| e \[item\] | Equip item | +| ue \[item\] | Unequip item | +| u \[item\] | Use item | +| u \[item\] \[target\] | Use item on target (e.g. use gem on item) | +| destroy \[item\] | Destroy item | +| \[item\] | Add to trade window if trading, show if it is useful | +| Quests | | +| accept \[quest\] | Accept quest at the selected quest giver | +| accept * | Accept all quests at the selected quest giver | +| drop \[quest\] | Abandon quest | +| r \[item\] | Choose quest reward | +| quests | Show quest summary | +| \[quest\] | Show quest and objectives status | +| talk | Talk to the selected NPC (to complete a quest) | +| u \[game object\] | Use game object (use los command to obtain the game object link) | +| Misc | | +| los | Enlist game objects, items, creatures and NPCs bot can see | +| stats | Show stat summary (inventory, gold, xp, etc.) | +| leave | Leave party | +| trainer | Show what bot can learn from the selected trainer | +| trainer learn | Learn from the selected trainer | +| spells | Show bot's spells | +| cast \[spell\] | Cast the spell | +| home | Set home at the selected innkeeper | +| summon | Summon bot at the inn | +| release | Release spirit when dead | +| revive | Revive when near a spirit healer | + +There are some of master's actions bot can react. For example: + +| Action | Bot reaction | +| --- | --- | +| accept a quest | Bot will accept it as well | +| talk to a quest giver | Bot will turn in his completed quests | +| use meeting stone | Teleport using the stone | +| start using game object and interrupt | Use the game object | +| open trade window | Show inventory and start trading | +| invite to a party/raid | Accept the invitation | +| start raid ready check | Tell his ready status | +| mount/unmount | Mount/unmount as well | +| go through a dungeon portal | Follow into the dungeon | + +**HINT**: you can create key-binded macros for any of this command for quick usage, e.g. + +| Key | Macro | Decription | +| --- | --- | --- | +| F | /p follow | Follow me | +| G | /p stay | Stay | +| H | /p flee | Pull back | +| Shift+T | /p d attack my target | Attack my target | +| T | /p @tank d attack my target | Attack my target (for tanks only) | +| P | /p co ~passive,? | Toggle active/passive mode (assist or ignore) | +| J | /p d add all loot | Loot everything | + +*/p* can be replaced with */r* if you are in raid group. + +To learn about other commands tell bot someting invalid and it will enlist all the commands and stategies available. \ No newline at end of file diff --git a/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in b/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in index a4191acfe4..b5fd19c439 100644 --- a/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in +++ b/src/modules/Bots/playerbot/aiplayerbot.conf.dist.in @@ -28,6 +28,10 @@ AiPlayerbot.RandomClassSpecProbability.4.2 = 10 AiPlayerbot.RandomClassSpecProbability.5.0 = 40 AiPlayerbot.RandomClassSpecProbability.5.1 = 40 AiPlayerbot.RandomClassSpecProbability.5.2 = 20 +# Death Knight +AiPlayerbot.RandomClassSpecProbability.6.0 = 10 +AiPlayerbot.RandomClassSpecProbability.6.1 = 5 +AiPlayerbot.RandomClassSpecProbability.6.2 = 5 # Shaman AiPlayerbot.RandomClassSpecProbability.7.0 = 10 AiPlayerbot.RandomClassSpecProbability.7.1 = 45 @@ -143,6 +147,8 @@ AiPlayerbot.RandomBotTeleLevel = 3 #AiPlayerbot.MaxRandomBotInWorldTime = 1209600 #AiPlayerbot.MinRandomBotRandomizeTime = 7200 #AiPlayerbot.MaxRandomRandomizeTime = 1209600 +#AiPlayerbot.MinRandomBotReviveTime = 60 +#AiPlayerbot.MaxRandomReviveTime = 300 #AiPlayerbot.MinRandomBotsPerInterval = 50 #AiPlayerbot.MaxRandomBotsPerInterval = 100 #AiPlayerbot.MinRandomBotsPriceChangeInterval = 7200 @@ -155,10 +161,11 @@ AiPlayerbot.RandomBotTeleLevel = 3 #AiPlayerbot.RandomBotTeleportDistance = 1000 # Debug switches -#AiPlayerbot.SpellDump = 0 +#AiPlayerbot.DebugWhisper = 0 #AiPlayerbot.LogInGroupOnly = 1 #AiPlayerbot.LogValuesPerTick = 0 #AiPlayerbot.RandomChangeMultiplier = 1 +#AiPlayerbot.SpellDump = 0 # Command server port, 0 - disabled #AiPlayerbot.CommandServerPort = 8888 diff --git a/src/modules/Bots/playerbot/strategy/Engine.cpp b/src/modules/Bots/playerbot/strategy/Engine.cpp index 9a5f60d109..4c7e5eb9d3 100644 --- a/src/modules/Bots/playerbot/strategy/Engine.cpp +++ b/src/modules/Bots/playerbot/strategy/Engine.cpp @@ -283,7 +283,7 @@ bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool sk return pushed; } -ActionResult Engine::ExecuteAction(const string& name) +ActionResult Engine::ExecuteAction(const string &name) { bool result = false; @@ -539,7 +539,7 @@ void Engine::LogAction(const char* format, ...) } } -void Engine::ChangeStrategy(const string& names) +void Engine::ChangeStrategy(const string &names) { vector splitted = split(names, ','); for (vector::iterator i = splitted.begin(); i != splitted.end(); ++i) diff --git a/src/modules/Bots/playerbot/strategy/Engine.h b/src/modules/Bots/playerbot/strategy/Engine.h index 5e658eb928..a3f46e6306 100644 --- a/src/modules/Bots/playerbot/strategy/Engine.h +++ b/src/modules/Bots/playerbot/strategy/Engine.h @@ -68,15 +68,15 @@ namespace ai bool removeStrategy(string name); bool HasStrategy(string name); void removeAllStrategies(); - void toggleStrategy(string name); + void toggleStrategy(const string &name); std::string ListStrategies(); bool ContainsStrategy(StrategyType type); - void ChangeStrategy(string names); + void ChangeStrategy(const string &names); string GetLastAction() { return lastAction; } public: virtual bool DoNextAction(Unit*, int depth = 0); - ActionResult ExecuteAction(string name); + ActionResult ExecuteAction(const string &name); public: void AddActionExecutionListener(ActionExecutionListener* listener) @@ -96,7 +96,7 @@ namespace ai void Reset(); void ProcessTriggers(); void PushDefaultActions(); - void PushAgain(ActionNode* actionNode, float relevance, Event event); + void PushAgain(ActionNode* actionNode, float relevance, const Event &event); ActionNode* CreateActionNode(string name); Action* InitializeAction(ActionNode* actionNode); bool ListenAndExecute(Action* action, Event event); diff --git a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp index b8791158c0..faa8c428cb 100644 --- a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.cpp @@ -38,7 +38,7 @@ string LogLevelAction::logLevel2string(LogLevel level) return "debug"; } } -LogLevel LogLevelAction::string2logLevel(const string& level) +LogLevel LogLevelAction::string2logLevel(const string &level) { if (level == "debug") { diff --git a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h index 4ad2a33f11..7de5328ab1 100644 --- a/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/LogLevelAction.h @@ -11,7 +11,7 @@ namespace ai public: static string logLevel2string(LogLevel level); - static LogLevel string2logLevel(string level); + static LogLevel string2logLevel(const string &level); }; } \ No newline at end of file diff --git a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp index e5e37940e5..746571f559 100644 --- a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.cpp @@ -72,7 +72,7 @@ bool LootStrategyAction::Execute(Event event) } -LootStrategy LootStrategyAction::String2LootStrategy(const string& strategy) +LootStrategy LootStrategyAction::String2LootStrategy(const string &strategy) { if (strategy == "*" || strategy == "all") { diff --git a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h index 935c442071..5ab7d839da 100644 --- a/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/LootStrategyAction.h @@ -11,7 +11,7 @@ namespace ai virtual bool Execute(Event event); private: - static LootStrategy String2LootStrategy(string strategy); + static LootStrategy String2LootStrategy(const string &strategy); static string LootStrategy2string(LootStrategy lootStrategy); }; diff --git a/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp b/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp index 9957deae5b..bd0ad41175 100644 --- a/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/WhoAction.cpp @@ -109,7 +109,7 @@ string WhoAction::QuerySkill(string text) return out.str(); } -string WhoAction::QuerySpec(const string& text) +string WhoAction::QuerySpec(const string &text) { ostringstream out; diff --git a/src/modules/Bots/playerbot/strategy/actions/WhoAction.h b/src/modules/Bots/playerbot/strategy/actions/WhoAction.h index 92ed834ace..6519f84e6a 100644 --- a/src/modules/Bots/playerbot/strategy/actions/WhoAction.h +++ b/src/modules/Bots/playerbot/strategy/actions/WhoAction.h @@ -17,7 +17,7 @@ namespace ai void InitSkills(); string QueryTrade(string text); string QuerySkill(string text); - string QuerySpec(string text); + string QuerySpec(const string &text); }; }