Compare commits

..

14 Commits

Author SHA1 Message Date
bash
284e8c17b5 Update PlayerbotMgr.cpp 2025-07-02 21:54:42 +02:00
Alex Dcnh
57a2c9a742 Update PlayerbotMgr.cpp (#1412)
Remove double #include "ChannelMngr.h"
2025-07-02 20:27:04 +02:00
brighton-chi
3dd0f11453 Corrections to Vanilla max iLevels (#1409)
* Corrections to Vanilla max iLevels

This reverts commit 681ec5c5b583dc935d60172f1790c6635eaef9ab, reversing
changes made to f4e6b1644ff2c3fa4b5f97a5b4d7cea14e352263.

* Corrections to Vanilla max iLevels
2025-07-01 18:39:12 +02:00
ThePenguinMan96
00cc2468f1 Warlock overhaul (#1397)
This is a complete overhaul of the warlock class, making 3 new strategies (affliction, demonology, and destruction), as well as finishing the warlock tank strategy (shadow ward and searing pain). It also includes a soulstone fix, where the bots can change who they soulstone based on the non-combat strategies you set for them. It also includes a self-resurrect action and trigger that allows the bots to resurrect using a soulstone or reincarnation. Many other skills were added to finish out the warlock skillset.
2025-06-27 20:00:38 +02:00
Jelly
cf8253579e Update Pvp Prohibited Zone Id's (#1390) 2025-06-24 20:00:34 +02:00
Jelly
2000c06167 Fix various hunter bugs (Amended w/ Nullptr check) (#1389)
* Fixes #1093 (Hunter's stuck in Autoshoot and Can't equip gear)

* Fixes #1093 (Hunter's stuck in Autoshoot and Can't equip gear)
2025-06-22 12:55:35 +08:00
Veit F.
453925153f [URGENT Fix] Trinket proc effects are getting cast even if they are not onUse - Leads to big server lags (#1385)
* fix: 🚑 Add spellProcFlag check for flag 2 at UseTrinket Context-Action

Bots will "learn" the trinket proc, so CanCastSpell() will be true e.g. on Item https://www.wowhead.com/wotlk/item=44074/oracle-talisman-of-ablution leading to constant casting of the proc spell onto themselfes https://www.wowhead.com/wotlk/spell=59787/oracle-ablutions. This will lead to multiple hundreds of entries in m_appliedAuras -> Once killing an enemy -> Big diff time spikes. See diagnosis

* perf:  Should futher reduce the problems, hindering trinkets with other proc flags of being used, see https://www.azerothcore.org/wiki/spell_proc_event

I have tested bots with active trinkets and they are still using them, as well as onhit trinkets are still being triggered like they should. Could also fix some other weird behavior.
2025-06-22 00:08:47 +02:00
Jelly
9a10f07c74 Fixes #1093 (Hunter's stuck in Auto shot pose and Can't equip gear) (#1377)
* Fixes #1093 (Hunter's stuck in Autoshoot and Can't equip gear)

* Fixes #1093 (Hunter's stuck in Autoshoot and Can't equip gear)
2025-06-21 16:09:19 +08:00
Noscopezz
7d6f44ab09 ICC Fix/Improve (#1380)
* ICC PP WIP

WIP

* added mutated plague for PP

* BPC added (kinetic and boss targeting need to be done by player)

OT collects dark nucles, bots spread on vortex and other stuff they do ok on their own.
Tested only on 10NM, should work on 25NM

* Tank pos. correction

* BQL, ranged spread, link, flame, bite, tanking tested 10NM

to do (better fire spread, hc tacti, melee spread when in air)

* LDW improved

improved shadow logic, ranged spread for easier shadow handling

* dbs update, fixed teleporting

Bots should only go and teleport to the mage that is actually below zero now

* DBS ranged fix

Ranged should spread more quickly and freak out less

* Festergut && DBS

fixed ranged spread (both)
fixed spore logic (fester)

* Rotface fix

Improved big ooze tanking (static pos, todo kiting)
ooze explosion spread mechanic fix
ooze pool fix
Player needs to mark rotface with skull icon, oterwise bots try to attack oozes

* BQL fixed for 25nm

todo: better melee logic in air phase, better melee flame spread

* VDW, Sister Svalna, Sindy update

Sister Svalna, bots can pickup spears and throw at svalna when she has shield up

VDW added healer strats to use portal and heal boss (atm druids are for raid healing only, so use druide + any other healer, ideally player should be healer)
todo (focus on supressers, add healer rotations, atm they use quickest spell they can)

Sindragosa
Added tank boss manipulation (boss orientation and position)
bots detect (buffet, unchained magic and chilled to the bone and act accordingly)
bots detect frost beacon move to safe spot and los frost bombs around them, while dpsing tombs (todo stop dps if only one tomb is left, if we have frost bombs around, not a big deal atm since in nm they dont one shot)
Last phase bots los behind tomb to loose buffet, tanks swap when they have hi buffet count.
Player should tell bots with skull rti if they should kill tomb or focus boss.
todo (dynamic tomb los in last phase so that healers can see tank but also hide behind tomb to break los from boss)

Removed some debug messages, improved LM spike action (nearest bots also try to help kill it)

Improved Lady Deathwshiper shade action (only targeted bots will run away instead of every bot that is near it)

dbs improved tank switch

I recommend to use 3 healers (just to be safe) and 2 paladin tanks (warr seems to struggle with agro) in 10 man
25 man 6-7 healers (just to be safe) Since most of the bosses are about survival and not dps

* LK Update (doable)

LK added

Improved tank switching for all bosses

Fixed PP gas cloud kiting
Malleable goo todo (dont know how to detect it since its not object or npc) just summon ranged bots to safe position to bypass

BPC  fixed OT sometimes not tanking kele
kinectic bombs todo (for now player should take care of them)

Sindragosa fixed rare case when she is in air phase but tombs went to last phase position

LK
Bots can handle necrotic
Bots can handle adds
Bots should focus valkyre that actually grabbed someone (if unlucky and player just use attack command and summon bots to you if they are far away from you) if they grab bots you can either summon to make them useless or let bots cc them and do it legit way.

Defile should be watched by player and once it was cast just summon bots to you
Vile spirits for some reason go to the ground and get nuked by bots aoe spells so there is not much to be done

**Player needs to be alive the whole LK fight since you will have to watch out for frost spehers (sometimes bots ignore them), summon bots when defile is up and summon ranged bots if they get stuck near shambling or raging spirits since their aoe will wipe you)

all in all LK  is doable both 10 and 25nm, player needs to have knowledge of lk fight and needs to know how to use multibot addon and make macros for eg summoning or commanding groups of bots or individual bots)

Dont forget frost/shadow/nature resist auras in whole ICC since it will help alot

I have done whole icc 10 and 25 with 2 pala tanks, 2/5 heals and rest dps,  if you use +1 or +2 heals it should be easier (since I was testing I did close to 0 dmg in fights same with heals)

* fixed changes made by mistake

fix

* Malleable fix (simple spread mechanic)

Malleable mechanic added (simple spread for now)
Gas cloud fixed (Bots sometimes got stuck between puddle and kite location)

* Defile Update

Bots detect and avoid defile (they struggle to find a way back to the boss around it tho, use summon to help them)

Melee bots should be able to stand behind/to the flank of shambling/spirits

* GS fixed bots not returning to their ship for A and H

Bots will return back to ship after killing mage

* PP gas cloud kiting improved

PP gas cloud kiting improved

* BPC targeting fixed

Bots will mark valid prince with skull RTI now

* BQL added melee spread in air pahse

BQL added melee spread

* VDW healing rotation improved

Healers will now use strong heals and hots

* Fixed Necrotic Plague

Fixed issue with Necrotic where it would get dispelled too soon, or would not get dispelled at all

* LK Update

Refined defile logic
Added 3 points for ranged and melee in winter phase (east, west, south when facing throne)
fixed frost spheres targeting (hunter will focus them)
Atm bots will reset z axis if they fall underground or if they get teleported by lk
Better positioning in 1st phase

* 10HC update until PP

LK defile improved for 10nm (bots sometimes stood 2 close to defile until it grew few times)

Improved rotface for HC

PP remade for 10HC.
Gas cloud is now properly kited
Fixed a rare case of server crash when there were ooze and gas cloud alive at same time.
Bots will move around puddles according to its size now.
Bots that get unboud plague will simply move away from raid and die thus loosing it from raid.
Volatile ooze improved stacking.
Fixed ranged sometimes glitching thru walls when spreading out from other members.

10HC PP is now doable but its hard without summoning (summoning break gascloud and ooze targets so its easier to do). You need to watch boss so you dont phase 2 soon otherwise you will get 2x ooze and cloud which is almoust always a wipe. If abo is not played near perfection bots will struggle with oozes and gas clouds if they are not slowed on time. Always save energy to slow gas cloud since it will wipe the group if it reach its target.
Bots will sometimes stand in puddle, just command them to move and they will figure out what to do.

todo (proper malleable handling)

* Up until Sindy 10HC

BPC added shadow prison handling, bots stop moving if more than 12 stack, tanks more than 18
Improved spreading logic

VDW
fixed issue where bots in portal wold move at half speed compared to real player

* fixed accidental change

* LK 10HC update

Added Shadow trap logic
(if they stand in it, not a big deal since bots wont get yeeted only players will)
When harvest soul, only player will be in another dimension (you must survive)

**Sindy and LK can be done, but I must dissapoint purist, at my skill level I could not achieve to do HC without using summon or other "cheat" bot functions.

Other bosses are all doable now in 10hc

* ICC fixes GS, PP; BQL, SINDY

Minor fixes, bite action improved

* ICC improve Sindy

Bots will now choose non beacon position based on difficulty, 10/25

* ICC fixed missing A/H buff

Fixed missing ICC buff for A and H

Buff will only be present when logged on and in ICC, once any bot or player leave ICC the buff is gone to prevent abuse.

This will make ICC easier now and with recent DPS update and movement improvement bots will now actully do decent dps and even greater healing.

Ally buff
https://www.wowhead.com/wotlk/spell=73828/strength-of-wrynn

Horde buff
https://www.wowhead.com/wotlk/spell=73822/hellscreams-warsong

* revert last change

revert buff

* ICC improve Rotface

Bots will now mark Rotface with skull icon, which will make them focus boss instead of oozes automatically

* ICC Festergut 10 Man fix

There was a rare case in 10 Man when 2 tanks would get spores which made them both stack at melee spot. Now the code will check if any of the spored player is main tank, if it is, it will stay at melee and other spores will go at ranged spot since off tank doesn't really need to stand near main tank all the time.

* ICC BPC major update, fix and improve

Fixed main tank sometimes not tanking both bosses (vala and talda)

Improved marking of current prince

Empowered vortex: bots will now spread out when it is being cast, instead of always spreading(ranged). This will make melee also spread better now since bots will calculate and move to optimal positions.

Added Kinetic bomb handling.
Hunters will take care of bombs, if no hunter is present then any ranged dps will take care of kinetic bombs.

* ICC BQL/VDW major update + minor fixes/improvements

LDW improved spreading for ranged, tanks will move boss in the middle of the room now when shield is depleted which will make bots bug less around pillars

GS Assist tank will not teleport to enemy ship and will keep tanking adds on our ship now

DBS ranged spread improved (they will calcualte spot for each bot and stick with it reducing movment to minimum), fixed bug where in 25 man ranged bots would go behind walls, making them unable to dps boss, improved rune of blood tanking

Festergut ranged spread improved (they will calcualte spot for each bot and stick with it reducing movment to minimum)

BQL Melee spread improved, bite logic improved, added swarming shadows logic (not perfect but at least it wont be all over the room anymore), Tanks will properly handle blood mirror now

VDW boss and raid healers will be automatically assinged depening by number of healers(if more than 3 healers in group, 2 will focus on raid and others will heal boss, otherwise one healer will heal raid). Druid will be assigned to raid healing if no druid present then some other random heal class. Added rotations for druid healers if they end up healing the boss. Raid healers will not use portals anymore. Healers will come to the ground now after using portals (they were stuck in air)

* ICC LK minor update

PP

Removed pre stacking for ranged when volatile ooze spawn (they will kill it much faster now and only stack if someone actually gets targeted by ooze)

LK

Hunters will use trnaq shot to remove enrage from shamblings

Improved valkyr cc

Minimized ping-ponging during winter phase

* ICC minor Sindy improve

Reduced position tolerances and forced movement for beacon and non beacon positions which will make bots move to spot that they actually need to be at instead of randomly running to sindragosa or beaconed players.

* ICC minor update

GS

Bots will mark mage with skull rti

Rotface

Fixed bots glitching thru walls and floors (added check if position is valid before moving)

PP

Bots will mark volatile ooze with skull rti now which will help them focus it and kill asap (usefull for heroic when both volatile ooze and gas cloud are present at the same time)

VDW

Added default group position in the middle if the room so that bots don't spread out too much which will force them to focus supressers more

Fixed Boss healers not keeping themself alive when low on HP

* ICC LK minor update

Commented out z axis bypass since it was fixed with recent core updates.

Bots no longer fall thru buggy platforms so its no longer needed which in return makes valkyrs works as they should.

* ICC LM & LDW Improved

LM

Removed Attack Action since it was buggy and replaced it with RTI. (Improved DPS)

Simplified trigger for spike action, since attack logic is handled by skull RTI now.

Bots (tanks) will mark spikes with skull RTI, which will make bots instantly switch to Spike targets. If no spike is present, the boss will be marked.

Added logic that will make non-tank bots move away from LM to a fixed position behind LM if they happened to be in front of LM (No more insta kills with cleave).
If LM is casting Bone Storm, bots will ignore the above logic and do max dps.

LDW

Removed Attack Action since it was buggy and replaced it with RTI. (Improved DPS)

Bots (tanks) will mark adds with skull RTI, which will make bots instantly switch to adds targets. If no spike is present, the boss will be marked, which will help with keeping allies alive when they get mind controlled by LDW.

Moved 2nd phase position deeper into the room and reduced boss hp trigger to 95%, which will keep tanks where they should be during 1st phase (sometimes the boss dropped below 98% and tanks would ping pong around the room).

Ranged bots will now spread closer to each other now and will ignore spreading if they are 2 far or 2 close to the boss so they can properly reposition.

These changes should also fix recent bugs with bots not casting/standing still on LM and LDW.

* ICC DBS Improve

Replaced attack action with RTI. (Improved DPS)

Ranged bots will move away from blood beast if targeted by it now.

* ICC Sindragosa and LK Improve

Sindragosa

Improved tomb los for frost bombs. Bots will now mark tomb with moon rti to avoid killing it too soon. (If they still attack the tomb, simply reset and after bombs are over, simply attack the tomb to kill or mark with a skull.)
Main Tank will reset mystic buffet stacks now to avoid tank swapping since it's really unreliable which will make sindy less frustrating to kill (other bots will need to do mechanics properly by hiding behind ice tombs).

LK

Necrotic plague action

Bots will now check before moving to the Shambling if they are in front of the Shambling to avoid getting one shoted by shockwave.
Improved multiplier, which will now properly handle dispelling of necrotic plague.

Winter phase action

Bots will properly move behind adds to avoid getting one shoted by shamblings or raging spirits.
If there is a hunter in the grouphunter will focus on spheres; if not, any ranged DPS will focus spheres.

Adds action

Bots will now be in proper positions during the 1st phase, and when the off tank is done collecting shamblings, it will move away from the group.
Bots (non-tanks) will move behind the shambling if they are in front of it to avoid getting one shoted in the 1st phase.
Restored action for checking if bots are at ground level, since they were still sometimes glitching through the floor (valkrys will be able to carry bots and drop them off the edge if not killed in time).
Improved defile calculations for 10 man and 25 man raids since defile was growing differently for 10 and 25, which would make bots in 25 man move very far away from somewhat small defile puddle.
Bots will now properly CC any valkyr that wasn't CC'd, and they won't freak out anymore if multiple valkyrs are present. (They can't tell which valkyr is holding bots/ players, so we should command an attack on valkyrs that are holding someone.)
Bots will now run away from Vile Spirits if they are targeted by them during the last phase.

* ICC 25HC ldw shades fix

Fixed bots could not detect shade if there were multiple present

* ICC trigger optimization

Optimized trigger and action for:

KineticBomb
OozePuddle

* ICC LK Improve

Improved Shadow Trap, Winter phase and 1st phase.

Bots will now have fixed positions for 1st phase if no shadow trap is present.

Tanks will now take care of taunting adds during winter phase. (Assist tank will collect adds and bring them to main tank, main tank will take over the adds so we have minimal chance of adds rotating towards the raid)

Fixed shadow trap detection.

* ToC dungeon update

Added TOC dungeon strategies for 1st encounter.

Other encounters are pretty easy and straightforward so they do not require strategies. They can be all done with follow, reset, summon, attack, skull icon etc...

Bots (A/H) will automatically check if they have lance equiped or in inventory. If they don't have lance they will pick it up from nearest lance stand and equip it.

Bots will mount nearest mount if they have lance equipped.

Once mounted they will keep Defend aura at 3 stacks (top priority).
In fight they will cast charge if more than 5f away, they will cast shield break if target has Defended aura active and they will use Thrust if they cant use anything else.
In short they will melt any target and enemies wont stand a chance keeping their defend aura up.

Once champions are defeated bot will automatically equip best weapon they have in inventory (weapon that was swapped with lance)

* ICC minor update

LM

Bots will now move in smaller increments to get behind boss
They will still move towards fixed position, but as soon they are not in front of boss, they will stop moving and do other actions.

GS

Fixed cannon trigger, now will return true if cannon is 100f from bots.
It used to return true all the time.

* ToC added Eadric strat

bots will look away during radiance cast

* ICC LK minor fix

fixed crash in icclichkingsaddsaction

* ICC GS fix

While encountering edge case when playing horde, the logic was to detect mages, there are usually 2 around, but the longer the fight last the bigger the chance that cannons would kill all the mages thus once we kill the mage that was casting deep freeze bots could not execute action that would return them back to the ship, so the boss had the time to nuke them one by one.
Even tanks have hard time surviving the boss.
I have changed it now (both A/H) so that we keep track of the enemy boss (which is hard if not impossible to kill as main trigger) and we are keeping track of the  mage that is actually casting deep freeze, we mark it with skull, and now as soon the mage is dead, bots will remove the mark so there is 0 confusion about what to do next on their side, and they will come back asap.

* FoS Improved and fixed, ICC LM, LDW and PP updates

FoS

Improved/fixed triggers, Improved/fixed actions.

Bronjahm

Tank will properly kite soul fragment around the room
Replaced attack action with skull rti to focus soul fragments
Non-tank bots will only try to stay within 10f of boss only once we enter last phase, tank will be in the middle of the room if it is not kiting soul fragment

Devourer of Souls

DPS bots will stop dps if boss is casting mirrored soul
Laser can be easily avoided with follow/summon

ICC

LM

Tank will only move to tank position if it actually have the agro, it used to move there without agro and few of the bots would get killed since tank was unable to reach bot

LDW

Fixed edge case where tank would be target of shade and it would be unable to move away it from it due to tank position restrictions, now if Tank is targeted by shade it will be able to move and run away from it (in hc this could cause wipes since explosion is aoe + tons of dmg)

PP

When oozes spawn, tank will move towards green ooze spawn to keep raid near green ooze (faster kill) and far away from gas cloud (better chance to kill if abo didn't manage to slow it)

* PoS Strategies

Ick and Krick

All boss mechanics implemented

Forgemaster Garfrost

Easily doable with follow/stay/summon

Scourgelord Tyrannus

Ranged bots will spread so that they all don't get frozen by dragon

They avoid everything else on their own

* ICC Refactor, All bosses improved NM and HC

Major Update

* Update playerbots.conf.dist

* ICC Fixes/Improvements

LM
Assist tank moving to kill spikes (it should always stack with main tank to soak dmg)

LDW
Improved shade evasion (added los checks before moving to avoid clipping thru walls and floor)
Fixed tanks moving to tank position befor having aggro

Festergut
Fixed ranged position overlaping with each other
Fixed sometimes hunters were placed to close to the boss

PP
Improved gas cloud kiting, bots should not get stuck in corners anymore while moving away
Gas cloud target will use nitro boosts now, so that players dont wipe if abo fails to slow gas cloud
Due to possible oozes duplications in hc caused by bad phasing, bots will kill duplicates to make encounter a bit easier

BQL
Fixed bots failing to link up in 25man

VDW
Group 1 and Group 2 can move freely now around the room, but once group set their marker they will focus left or right side depending on their assigned position
(Positions were to limiting in 25 man and they could not kill adds fast enough)
Fixed marker overlaping
Optimized cloud collecting for portal bots

LK
Fixed in winter phase tank not collecting adds if more than one add is present

* Hotfix

Possible crash fix prevention
Increased kiting radius for assist tank on Rotface

* minor improve

Added nitro boosts on sindy for beaconed player in last phase (they could be all over the place and wipe raid since they could not reach position in time)
2025-06-17 01:18:59 +02:00
NoxMax
bb004825aa AutoScaleActivity refactoring (#1375)
* AutoScaleActivity refactoring

* Abandon AutoScaleActivity 5% stepping
2025-06-12 23:21:35 +02:00
Veit F.
097bd00f38 fix: added missing guildTaskEnabled checks for GuildTaskMgr (#1374)
Even if guildTaskEnabled was set to 0 in the configuration file, a few queries like PLAYERBOTS_SEL_GUILD_TASKS_BY_VALUE, PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER were executed, which lead to a massive amount of unnecessary database load
2025-06-12 23:18:13 +02:00
Veit F.
290bf50faf fix: added missing checks for PetIsDeadValue (#1376)
* fix:  added missing guildTaskEnabled checks for GuildTaskMgr

Even if guildTaskEnabled was set to 0 in the configuration file, a few queries like PLAYERBOTS_SEL_GUILD_TASKS_BY_VALUE, PLAYERBOTS_SEL_GUILD_TASKS_BY_OWNER were executed, which lead to a massive amount of unnecessary database load

* fix:  added missing checks for PetIsDeadValue

Hunter under level 10, which are not able to summon their pets defined in the database spammed SELECT id FROM character_pet WHERE owner = {}, since the result of the query was true. Bots under level 10 already have pets in their stables. Also the same thing applied to Bots on mounts, because, while mounted, pets get despawned. This should drastically improve server performance.

* fix:  refactored query, pet should only check death state of his current pet

The old query also fetched all pets out of his stable, which is not needed, since we are looking for slot 0 (active pet)

* style: 🎨 and to AND typo

* fix: 🐛 Reverted 5a6182f977

A few hunters with pets in stable, where slot = 100 would not summon their pets
2025-06-12 23:17:43 +02:00
Noscopezz
e739f7820b ICC Refactor, All bosses improved NM/HC (#1370)
* ICC PP WIP

WIP

* added mutated plague for PP

* BPC added (kinetic and boss targeting need to be done by player)

OT collects dark nucles, bots spread on vortex and other stuff they do ok on their own.
Tested only on 10NM, should work on 25NM

* Tank pos. correction

* BQL, ranged spread, link, flame, bite, tanking tested 10NM

to do (better fire spread, hc tacti, melee spread when in air)

* LDW improved

improved shadow logic, ranged spread for easier shadow handling

* dbs update, fixed teleporting

Bots should only go and teleport to the mage that is actually below zero now

* DBS ranged fix

Ranged should spread more quickly and freak out less

* Festergut && DBS

fixed ranged spread (both)
fixed spore logic (fester)

* Rotface fix

Improved big ooze tanking (static pos, todo kiting)
ooze explosion spread mechanic fix
ooze pool fix
Player needs to mark rotface with skull icon, oterwise bots try to attack oozes

* BQL fixed for 25nm

todo: better melee logic in air phase, better melee flame spread

* VDW, Sister Svalna, Sindy update

Sister Svalna, bots can pickup spears and throw at svalna when she has shield up

VDW added healer strats to use portal and heal boss (atm druids are for raid healing only, so use druide + any other healer, ideally player should be healer)
todo (focus on supressers, add healer rotations, atm they use quickest spell they can)

Sindragosa
Added tank boss manipulation (boss orientation and position)
bots detect (buffet, unchained magic and chilled to the bone and act accordingly)
bots detect frost beacon move to safe spot and los frost bombs around them, while dpsing tombs (todo stop dps if only one tomb is left, if we have frost bombs around, not a big deal atm since in nm they dont one shot)
Last phase bots los behind tomb to loose buffet, tanks swap when they have hi buffet count.
Player should tell bots with skull rti if they should kill tomb or focus boss.
todo (dynamic tomb los in last phase so that healers can see tank but also hide behind tomb to break los from boss)

Removed some debug messages, improved LM spike action (nearest bots also try to help kill it)

Improved Lady Deathwshiper shade action (only targeted bots will run away instead of every bot that is near it)

dbs improved tank switch

I recommend to use 3 healers (just to be safe) and 2 paladin tanks (warr seems to struggle with agro) in 10 man
25 man 6-7 healers (just to be safe) Since most of the bosses are about survival and not dps

* LK Update (doable)

LK added

Improved tank switching for all bosses

Fixed PP gas cloud kiting
Malleable goo todo (dont know how to detect it since its not object or npc) just summon ranged bots to safe position to bypass

BPC  fixed OT sometimes not tanking kele
kinectic bombs todo (for now player should take care of them)

Sindragosa fixed rare case when she is in air phase but tombs went to last phase position

LK
Bots can handle necrotic
Bots can handle adds
Bots should focus valkyre that actually grabbed someone (if unlucky and player just use attack command and summon bots to you if they are far away from you) if they grab bots you can either summon to make them useless or let bots cc them and do it legit way.

Defile should be watched by player and once it was cast just summon bots to you
Vile spirits for some reason go to the ground and get nuked by bots aoe spells so there is not much to be done

**Player needs to be alive the whole LK fight since you will have to watch out for frost spehers (sometimes bots ignore them), summon bots when defile is up and summon ranged bots if they get stuck near shambling or raging spirits since their aoe will wipe you)

all in all LK  is doable both 10 and 25nm, player needs to have knowledge of lk fight and needs to know how to use multibot addon and make macros for eg summoning or commanding groups of bots or individual bots)

Dont forget frost/shadow/nature resist auras in whole ICC since it will help alot

I have done whole icc 10 and 25 with 2 pala tanks, 2/5 heals and rest dps,  if you use +1 or +2 heals it should be easier (since I was testing I did close to 0 dmg in fights same with heals)

* fixed changes made by mistake

fix

* Malleable fix (simple spread mechanic)

Malleable mechanic added (simple spread for now)
Gas cloud fixed (Bots sometimes got stuck between puddle and kite location)

* Defile Update

Bots detect and avoid defile (they struggle to find a way back to the boss around it tho, use summon to help them)

Melee bots should be able to stand behind/to the flank of shambling/spirits

* GS fixed bots not returning to their ship for A and H

Bots will return back to ship after killing mage

* PP gas cloud kiting improved

PP gas cloud kiting improved

* BPC targeting fixed

Bots will mark valid prince with skull RTI now

* BQL added melee spread in air pahse

BQL added melee spread

* VDW healing rotation improved

Healers will now use strong heals and hots

* Fixed Necrotic Plague

Fixed issue with Necrotic where it would get dispelled too soon, or would not get dispelled at all

* LK Update

Refined defile logic
Added 3 points for ranged and melee in winter phase (east, west, south when facing throne)
fixed frost spheres targeting (hunter will focus them)
Atm bots will reset z axis if they fall underground or if they get teleported by lk
Better positioning in 1st phase

* 10HC update until PP

LK defile improved for 10nm (bots sometimes stood 2 close to defile until it grew few times)

Improved rotface for HC

PP remade for 10HC.
Gas cloud is now properly kited
Fixed a rare case of server crash when there were ooze and gas cloud alive at same time.
Bots will move around puddles according to its size now.
Bots that get unboud plague will simply move away from raid and die thus loosing it from raid.
Volatile ooze improved stacking.
Fixed ranged sometimes glitching thru walls when spreading out from other members.

10HC PP is now doable but its hard without summoning (summoning break gascloud and ooze targets so its easier to do). You need to watch boss so you dont phase 2 soon otherwise you will get 2x ooze and cloud which is almoust always a wipe. If abo is not played near perfection bots will struggle with oozes and gas clouds if they are not slowed on time. Always save energy to slow gas cloud since it will wipe the group if it reach its target.
Bots will sometimes stand in puddle, just command them to move and they will figure out what to do.

todo (proper malleable handling)

* Up until Sindy 10HC

BPC added shadow prison handling, bots stop moving if more than 12 stack, tanks more than 18
Improved spreading logic

VDW
fixed issue where bots in portal wold move at half speed compared to real player

* fixed accidental change

* LK 10HC update

Added Shadow trap logic
(if they stand in it, not a big deal since bots wont get yeeted only players will)
When harvest soul, only player will be in another dimension (you must survive)

**Sindy and LK can be done, but I must dissapoint purist, at my skill level I could not achieve to do HC without using summon or other "cheat" bot functions.

Other bosses are all doable now in 10hc

* ICC fixes GS, PP; BQL, SINDY

Minor fixes, bite action improved

* ICC improve Sindy

Bots will now choose non beacon position based on difficulty, 10/25

* ICC fixed missing A/H buff

Fixed missing ICC buff for A and H

Buff will only be present when logged on and in ICC, once any bot or player leave ICC the buff is gone to prevent abuse.

This will make ICC easier now and with recent DPS update and movement improvement bots will now actully do decent dps and even greater healing.

Ally buff
https://www.wowhead.com/wotlk/spell=73828/strength-of-wrynn

Horde buff
https://www.wowhead.com/wotlk/spell=73822/hellscreams-warsong

* revert last change

revert buff

* ICC improve Rotface

Bots will now mark Rotface with skull icon, which will make them focus boss instead of oozes automatically

* ICC Festergut 10 Man fix

There was a rare case in 10 Man when 2 tanks would get spores which made them both stack at melee spot. Now the code will check if any of the spored player is main tank, if it is, it will stay at melee and other spores will go at ranged spot since off tank doesn't really need to stand near main tank all the time.

* ICC BPC major update, fix and improve

Fixed main tank sometimes not tanking both bosses (vala and talda)

Improved marking of current prince

Empowered vortex: bots will now spread out when it is being cast, instead of always spreading(ranged). This will make melee also spread better now since bots will calculate and move to optimal positions.

Added Kinetic bomb handling.
Hunters will take care of bombs, if no hunter is present then any ranged dps will take care of kinetic bombs.

* ICC BQL/VDW major update + minor fixes/improvements

LDW improved spreading for ranged, tanks will move boss in the middle of the room now when shield is depleted which will make bots bug less around pillars

GS Assist tank will not teleport to enemy ship and will keep tanking adds on our ship now

DBS ranged spread improved (they will calcualte spot for each bot and stick with it reducing movment to minimum), fixed bug where in 25 man ranged bots would go behind walls, making them unable to dps boss, improved rune of blood tanking

Festergut ranged spread improved (they will calcualte spot for each bot and stick with it reducing movment to minimum)

BQL Melee spread improved, bite logic improved, added swarming shadows logic (not perfect but at least it wont be all over the room anymore), Tanks will properly handle blood mirror now

VDW boss and raid healers will be automatically assinged depening by number of healers(if more than 3 healers in group, 2 will focus on raid and others will heal boss, otherwise one healer will heal raid). Druid will be assigned to raid healing if no druid present then some other random heal class. Added rotations for druid healers if they end up healing the boss. Raid healers will not use portals anymore. Healers will come to the ground now after using portals (they were stuck in air)

* ICC LK minor update

PP

Removed pre stacking for ranged when volatile ooze spawn (they will kill it much faster now and only stack if someone actually gets targeted by ooze)

LK

Hunters will use trnaq shot to remove enrage from shamblings

Improved valkyr cc

Minimized ping-ponging during winter phase

* ICC minor Sindy improve

Reduced position tolerances and forced movement for beacon and non beacon positions which will make bots move to spot that they actually need to be at instead of randomly running to sindragosa or beaconed players.

* ICC minor update

GS

Bots will mark mage with skull rti

Rotface

Fixed bots glitching thru walls and floors (added check if position is valid before moving)

PP

Bots will mark volatile ooze with skull rti now which will help them focus it and kill asap (usefull for heroic when both volatile ooze and gas cloud are present at the same time)

VDW

Added default group position in the middle if the room so that bots don't spread out too much which will force them to focus supressers more

Fixed Boss healers not keeping themself alive when low on HP

* ICC LK minor update

Commented out z axis bypass since it was fixed with recent core updates.

Bots no longer fall thru buggy platforms so its no longer needed which in return makes valkyrs works as they should.

* ICC LM & LDW Improved

LM

Removed Attack Action since it was buggy and replaced it with RTI. (Improved DPS)

Simplified trigger for spike action, since attack logic is handled by skull RTI now.

Bots (tanks) will mark spikes with skull RTI, which will make bots instantly switch to Spike targets. If no spike is present, the boss will be marked.

Added logic that will make non-tank bots move away from LM to a fixed position behind LM if they happened to be in front of LM (No more insta kills with cleave).
If LM is casting Bone Storm, bots will ignore the above logic and do max dps.

LDW

Removed Attack Action since it was buggy and replaced it with RTI. (Improved DPS)

Bots (tanks) will mark adds with skull RTI, which will make bots instantly switch to adds targets. If no spike is present, the boss will be marked, which will help with keeping allies alive when they get mind controlled by LDW.

Moved 2nd phase position deeper into the room and reduced boss hp trigger to 95%, which will keep tanks where they should be during 1st phase (sometimes the boss dropped below 98% and tanks would ping pong around the room).

Ranged bots will now spread closer to each other now and will ignore spreading if they are 2 far or 2 close to the boss so they can properly reposition.

These changes should also fix recent bugs with bots not casting/standing still on LM and LDW.

* ICC DBS Improve

Replaced attack action with RTI. (Improved DPS)

Ranged bots will move away from blood beast if targeted by it now.

* ICC Sindragosa and LK Improve

Sindragosa

Improved tomb los for frost bombs. Bots will now mark tomb with moon rti to avoid killing it too soon. (If they still attack the tomb, simply reset and after bombs are over, simply attack the tomb to kill or mark with a skull.)
Main Tank will reset mystic buffet stacks now to avoid tank swapping since it's really unreliable which will make sindy less frustrating to kill (other bots will need to do mechanics properly by hiding behind ice tombs).

LK

Necrotic plague action

Bots will now check before moving to the Shambling if they are in front of the Shambling to avoid getting one shoted by shockwave.
Improved multiplier, which will now properly handle dispelling of necrotic plague.

Winter phase action

Bots will properly move behind adds to avoid getting one shoted by shamblings or raging spirits.
If there is a hunter in the grouphunter will focus on spheres; if not, any ranged DPS will focus spheres.

Adds action

Bots will now be in proper positions during the 1st phase, and when the off tank is done collecting shamblings, it will move away from the group.
Bots (non-tanks) will move behind the shambling if they are in front of it to avoid getting one shoted in the 1st phase.
Restored action for checking if bots are at ground level, since they were still sometimes glitching through the floor (valkrys will be able to carry bots and drop them off the edge if not killed in time).
Improved defile calculations for 10 man and 25 man raids since defile was growing differently for 10 and 25, which would make bots in 25 man move very far away from somewhat small defile puddle.
Bots will now properly CC any valkyr that wasn't CC'd, and they won't freak out anymore if multiple valkyrs are present. (They can't tell which valkyr is holding bots/ players, so we should command an attack on valkyrs that are holding someone.)
Bots will now run away from Vile Spirits if they are targeted by them during the last phase.

* ICC 25HC ldw shades fix

Fixed bots could not detect shade if there were multiple present

* ICC trigger optimization

Optimized trigger and action for:

KineticBomb
OozePuddle

* ICC LK Improve

Improved Shadow Trap, Winter phase and 1st phase.

Bots will now have fixed positions for 1st phase if no shadow trap is present.

Tanks will now take care of taunting adds during winter phase. (Assist tank will collect adds and bring them to main tank, main tank will take over the adds so we have minimal chance of adds rotating towards the raid)

Fixed shadow trap detection.

* ToC dungeon update

Added TOC dungeon strategies for 1st encounter.

Other encounters are pretty easy and straightforward so they do not require strategies. They can be all done with follow, reset, summon, attack, skull icon etc...

Bots (A/H) will automatically check if they have lance equiped or in inventory. If they don't have lance they will pick it up from nearest lance stand and equip it.

Bots will mount nearest mount if they have lance equipped.

Once mounted they will keep Defend aura at 3 stacks (top priority).
In fight they will cast charge if more than 5f away, they will cast shield break if target has Defended aura active and they will use Thrust if they cant use anything else.
In short they will melt any target and enemies wont stand a chance keeping their defend aura up.

Once champions are defeated bot will automatically equip best weapon they have in inventory (weapon that was swapped with lance)

* ICC minor update

LM

Bots will now move in smaller increments to get behind boss
They will still move towards fixed position, but as soon they are not in front of boss, they will stop moving and do other actions.

GS

Fixed cannon trigger, now will return true if cannon is 100f from bots.
It used to return true all the time.

* ToC added Eadric strat

bots will look away during radiance cast

* ICC LK minor fix

fixed crash in icclichkingsaddsaction

* ICC GS fix

While encountering edge case when playing horde, the logic was to detect mages, there are usually 2 around, but the longer the fight last the bigger the chance that cannons would kill all the mages thus once we kill the mage that was casting deep freeze bots could not execute action that would return them back to the ship, so the boss had the time to nuke them one by one.
Even tanks have hard time surviving the boss.
I have changed it now (both A/H) so that we keep track of the enemy boss (which is hard if not impossible to kill as main trigger) and we are keeping track of the  mage that is actually casting deep freeze, we mark it with skull, and now as soon the mage is dead, bots will remove the mark so there is 0 confusion about what to do next on their side, and they will come back asap.

* FoS Improved and fixed, ICC LM, LDW and PP updates

FoS

Improved/fixed triggers, Improved/fixed actions.

Bronjahm

Tank will properly kite soul fragment around the room
Replaced attack action with skull rti to focus soul fragments
Non-tank bots will only try to stay within 10f of boss only once we enter last phase, tank will be in the middle of the room if it is not kiting soul fragment

Devourer of Souls

DPS bots will stop dps if boss is casting mirrored soul
Laser can be easily avoided with follow/summon

ICC

LM

Tank will only move to tank position if it actually have the agro, it used to move there without agro and few of the bots would get killed since tank was unable to reach bot

LDW

Fixed edge case where tank would be target of shade and it would be unable to move away it from it due to tank position restrictions, now if Tank is targeted by shade it will be able to move and run away from it (in hc this could cause wipes since explosion is aoe + tons of dmg)

PP

When oozes spawn, tank will move towards green ooze spawn to keep raid near green ooze (faster kill) and far away from gas cloud (better chance to kill if abo didn't manage to slow it)

* PoS Strategies

Ick and Krick

All boss mechanics implemented

Forgemaster Garfrost

Easily doable with follow/stay/summon

Scourgelord Tyrannus

Ranged bots will spread so that they all don't get frozen by dragon

They avoid everything else on their own

* ICC Refactor, All bosses improved NM and HC

Major Update

* Update playerbots.conf.dist
2025-06-11 23:27:44 +02:00
bash
6fbaf6510b Revert "Fixed opening trade window while using DBM or Questie addon (#1363)" (#1367)
This reverts commit dfa87faf5e.
2025-06-09 01:53:17 +02:00
44 changed files with 11223 additions and 4142 deletions

View File

@@ -483,8 +483,8 @@ AiPlayerbot.AutoGearQualityLimit = 3
# Equipment item level (not gearscore) limitation for autogear command (0 = no limit)
# Classic
# Max iLVL Tier 1 = 66 | Tier 2 = 76 | Tier 2.5 = 81 | Tier 3 = 99
# Max iLVL Phase 1 = 71(MC, ONY, ZG) | Phase 2(BWL) = 77 | Phase 2.5(AQ) = 88 | Phase 3(NAXX) = 100 (NOT RECOMMENDED SINCE ILVL OVERLAPS BETWEEN TIERS)
# Max iLVL Tier 1 = 66 | Tier 2 = 76 | Tier 2.5 = 88 | Tier 3 = 92
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
# TBC
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
@@ -642,8 +642,8 @@ AiPlayerbot.RandomGearQualityLimit = 3
# Equipment item level (not gearscore) limitation for randombots (0 = no limit)
# Classic
# Max iLVL Tier 1 = 66 | Tier 2 = 76 | Tier 2.5 = 81 | Tier 3 = 99
# Max iLVL Phase 1 = 71(MC, ONY, ZG) | Phase 2(BWL) = 77 | Phase 2.5(AQ) = 88 | Phase 3(NAXX) = 100 (NOT RECOMMENDED SINCE ILVL OVERLAPS BETWEEN TIERS)
# Max iLVL Tier 1 = 66 | Tier 2 = 76 | Tier 2.5 = 88 | Tier 3 = 92
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
# TBC
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
@@ -717,8 +717,8 @@ AiPlayerbot.BotActiveAloneForceWhenInGuild = 1
# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value.
# (The scaling will be overruled by the BotActiveAloneForceWhen...rules)
#
# Limitfloor - when DIFF (latency) above floor, activity scaling is applied starting with 90%
# LimitCeiling - when DIFF (latency) above ceiling, activity is 0%;
# Limitfloor - when DIFF (latency) is above floor, activity scaling begins
# LimitCeiling - when DIFF (latency) is above ceiling, activity is 0%
#
# MinLevel - only apply scaling when level is above or equal to min(bot)Level
# MaxLevel - only apply scaling when level is lower or equal of max(bot)Level
@@ -1062,7 +1062,7 @@ AiPlayerbot.DeleteRandomBotArenaTeams = 0
AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,139"
# PvP Restricted Areas (bots don't pvp)
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312"
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080"
# Improve reaction speeds in battlegrounds and arenas (may cause lag)
AiPlayerbot.FastReactInBG = 1
@@ -1341,8 +1341,8 @@ AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55
AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005
AiPlayerbot.PremadeSpecName.9.2 = destro pve
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,50077,43394,43393,42454
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203205210131051313230341
AiPlayerbot.PremadeSpecLink.9.2.80 = -03310030003-05203205210331051335230351
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151
AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351
#
#
@@ -1590,11 +1590,11 @@ AiPlayerbot.RandomClassSpecIndex.8.2 = 2
#
#
AiPlayerbot.RandomClassSpecProb.9.0 = 45
AiPlayerbot.RandomClassSpecProb.9.0 = 33
AiPlayerbot.RandomClassSpecIndex.9.0 = 0
AiPlayerbot.RandomClassSpecProb.9.1 = 45
AiPlayerbot.RandomClassSpecProb.9.1 = 34
AiPlayerbot.RandomClassSpecIndex.9.1 = 1
AiPlayerbot.RandomClassSpecProb.9.2 = 10
AiPlayerbot.RandomClassSpecProb.9.2 = 33
AiPlayerbot.RandomClassSpecIndex.9.2 = 2
#
@@ -1888,3 +1888,9 @@ AiPlayerbot.TargetPosRecalcDistance = 0.1
# Allow bots to be summoned near innkeepers
AiPlayerbot.SummonAtInnkeepersEnabled = 1
# Enable buffs in ICC to make Heroic easier and more casual.
# 30% more damage, 40% damage reduction (tank bots), increased all resistances, reduced threat for non tank bots, increased threat for tank bots.
# Buffs will be applied on PP, Sindragosa and Lich King
AiPlayerbot.EnableICCBuffs = 1

View File

@@ -385,8 +385,16 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
}
break;
case CLASS_WARLOCK:
engine->addStrategiesNoInit("dps assist", "dps", "dps debuff", "aoe", nullptr);
if (tab == 0) // Affliction
engine->addStrategiesNoInit("affli", "affli aoe", nullptr);
else if (tab == 1) // Demonology
engine->addStrategiesNoInit("demo", "demo aoe", "meta melee", nullptr);
else if (tab == 2) // Destruction
engine->addStrategiesNoInit("destro", "destro aoe", "curse of elements", nullptr);
engine->addStrategiesNoInit("cc", "dps assist", nullptr);
break;
case CLASS_DEATH_KNIGHT:
if (tab == 0)
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
@@ -588,15 +596,15 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
case CLASS_WARLOCK:
if (tab == WARLOCK_TAB_AFFLICATION)
{
nonCombatEngine->addStrategiesNoInit("bmana", nullptr);
nonCombatEngine->addStrategiesNoInit("felhunter", nullptr);
}
else if (tab == WARLOCK_TAB_DEMONOLOGY)
{
nonCombatEngine->addStrategiesNoInit("bdps", nullptr);
nonCombatEngine->addStrategiesNoInit("felguard", nullptr);
}
else if (tab == WARLOCK_TAB_DESTRUCTION)
{
nonCombatEngine->addStrategiesNoInit("bhealth", nullptr);
nonCombatEngine->addStrategiesNoInit("imp", nullptr);
}
nonCombatEngine->addStrategiesNoInit("dps assist", nullptr);
break;

View File

@@ -525,6 +525,11 @@ uint32 GuildTaskMgr::GetMaxItemTaskCount(uint32 itemId)
bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId)
{
if (!sPlayerbotAIConfig->guildTaskEnabled)
{
return 0;
}
uint32 value = 0;
PlayerbotsDatabasePreparedStatement* stmt =
@@ -548,6 +553,11 @@ bool GuildTaskMgr::IsGuildTaskItem(uint32 itemId, uint32 guildId)
std::map<uint32, uint32> GuildTaskMgr::GetTaskValues(uint32 owner, std::string const type,
[[maybe_unused]] uint32* validIn /* = nullptr */)
{
if (!sPlayerbotAIConfig->guildTaskEnabled)
{
return std::map<uint32, uint32>();
}
std::map<uint32, uint32> results;
PlayerbotsDatabasePreparedStatement* stmt =
@@ -576,6 +586,11 @@ std::map<uint32, uint32> GuildTaskMgr::GetTaskValues(uint32 owner, std::string c
uint32 GuildTaskMgr::GetTaskValue(uint32 owner, uint32 guildId, std::string const type, [[maybe_unused]] uint32* validIn /* = nullptr */)
{
if (!sPlayerbotAIConfig->guildTaskEnabled)
{
return 0;
}
uint32 value = 0;
PlayerbotsDatabasePreparedStatement* stmt =

View File

@@ -3154,22 +3154,41 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (pet && pet->HasSpell(spellId))
{
bool autocast = false;
for (unsigned int& m_autospell : pet->m_autospells)
// List of spell IDs for which we do NOT want to toggle auto-cast or send message
// We are excluding Spell Lock and Devour Magic because they are casted in the GenericWarlockStrategy
// Without this exclusion, the skill would be togged for auto-cast and the player would
// be spammed with messages about enabling/disabling auto-cast
switch (spellId)
{
if (m_autospell == spellId)
{
autocast = true;
case 19244: // Spell Lock rank 1
case 19647: // Spell Lock rank 2
case 19505: // Devour Magic rank 1
case 19731: // Devour Magic rank 2
case 19734: // Devour Magic rank 3
case 19736: // Devour Magic rank 4
case 27276: // Devour Magic rank 5
case 27277: // Devour Magic rank 6
case 48011: // Devour Magic rank 7
// No message - just break out of the switch and let normal cast logic continue
break;
}
}
default:
bool autocast = false;
for (unsigned int& m_autospell : pet->m_autospells)
{
if (m_autospell == spellId)
{
autocast = true;
break;
}
}
pet->ToggleAutocast(spellInfo, !autocast);
std::ostringstream out;
out << (autocast ? "|cffff0000|Disabling" : "|cFF00ff00|Enabling") << " pet auto-cast for ";
out << chatHelper.FormatSpell(spellInfo);
TellMaster(out);
return true;
pet->ToggleAutocast(spellInfo, !autocast);
std::ostringstream out;
out << (autocast ? "|cffff0000|Disabling" : "|cFF00ff00|Enabling") << " pet auto-cast for ";
out << chatHelper.FormatSpell(spellInfo);
TellMaster(out);
return true;
}
}
// aiObjectContext->GetValue<LastMovement&>("last movement")->Get().Set(nullptr);
@@ -4365,26 +4384,28 @@ bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow)
uint32 PlayerbotAI::AutoScaleActivity(uint32 mod)
{
// Current max server update time (ms), and the configured floor/ceiling values for bot scaling
uint32 maxDiff = sWorldUpdateTime.GetMaxUpdateTimeOfCurrentTable();
uint32 diffLimitFloor = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitfloor;
uint32 diffLimitCeiling = sPlayerbotAIConfig->botActiveAloneSmartScaleDiffLimitCeiling;
double spreadSize = (double)(diffLimitCeiling - diffLimitFloor) / 6;
// apply scaling
if (diffLimitCeiling <= diffLimitFloor)
{
// Perfrom binary decision if ceiling <= floor: Either all bots are active or none are
return (maxDiff > diffLimitCeiling) ? 0 : mod;
}
if (maxDiff > diffLimitCeiling)
return 0;
if (maxDiff > diffLimitFloor + (4 * spreadSize))
return (mod * 1) / 10;
if (maxDiff > diffLimitFloor + (3 * spreadSize))
return (mod * 3) / 10;
if (maxDiff > diffLimitFloor + (2 * spreadSize))
return (mod * 5) / 10;
if (maxDiff > diffLimitFloor + (1 * spreadSize))
return (mod * 7) / 10;
if (maxDiff > diffLimitFloor)
return (mod * 9) / 10;
return mod;
if (maxDiff <= diffLimitFloor)
return mod;
// Calculate lag progress from floor to ceiling (0 to 1)
double lagProgress = (maxDiff - diffLimitFloor) / (double)(diffLimitCeiling - diffLimitFloor);
// Apply the percentage of active bots (the complement of lag progress) to the mod value
return static_cast<uint32>(mod * (1 - lagProgress));
}
bool PlayerbotAI::IsOpposing(Player* player) { return IsOpposing(player->getRace(), bot->getRace()); }
@@ -6300,4 +6321,4 @@ void PlayerbotAI::AddTimedEvent(std::function<void()> callback, uint32 delayMs)
bot->m_Events.AddEvent(
new LambdaEvent(std::move(callback)),
bot->m_Events.CalculateTime(delayMs));
}
}

View File

@@ -189,6 +189,10 @@ bool PlayerbotAIConfig::Initialize()
maxRandomBotsPriceChangeInterval =
sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
//////////////////////////// ICC
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
//////////////////////////// CHAT
enableBroadcasts = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableBroadcasts", true);

View File

@@ -56,6 +56,7 @@ public:
bool enabled;
bool disabledWithoutRealPlayer;
bool EnableICCBuffs;
bool allowAccountBots, allowGuildBots, allowTrustedAccountBots;
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,

View File

@@ -83,7 +83,14 @@ bool DropTargetAction::Execute(Event event)
bot->SetTarget(ObjectGuid::Empty);
bot->SetSelection(ObjectGuid());
botAI->ChangeEngine(BOT_STATE_NON_COMBAT);
// botAI->InterruptSpell();
if (bot->getClass() == CLASS_HUNTER) // Check for Hunter Class
{
Spell const* spell = bot->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL); // Get the current spell being cast by the bot
if (spell && spell->m_spellInfo->Id == 75) //Check spell is not nullptr before accessing m_spellInfo
{
bot->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); // Interrupt Auto Shot
}
}
bot->AttackStop();
// if (Pet* pet = bot->GetPet())

View File

@@ -14,10 +14,25 @@ enum PetSpells
PET_PROWL_2 = 24452,
PET_PROWL_3 = 24453,
PET_COWER = 1742,
PET_LEAP = 47482
PET_LEAP = 47482,
PET_SPELL_LOCK_1 = 19244,
PET_SPELL_LOCK_2 = 19647,
PET_DEVOUR_MAGIC_1 = 19505,
PET_DEVOUR_MAGIC_2 = 19731,
PET_DEVOUR_MAGIC_3 = 19734,
PET_DEVOUR_MAGIC_4 = 19736,
PET_DEVOUR_MAGIC_5 = 27276,
PET_DEVOUR_MAGIC_6 = 27277,
PET_DEVOUR_MAGIC_7 = 48011
};
static std::vector<uint32> disabledPetSpells = {PET_PROWL_1, PET_PROWL_2, PET_PROWL_3, PET_COWER, PET_LEAP};
static std::vector<uint32> disabledPetSpells = {
PET_PROWL_1, PET_PROWL_2, PET_PROWL_3,
PET_COWER, PET_LEAP,
PET_SPELL_LOCK_1, PET_SPELL_LOCK_2,
PET_DEVOUR_MAGIC_1, PET_DEVOUR_MAGIC_2, PET_DEVOUR_MAGIC_3,
PET_DEVOUR_MAGIC_4, PET_DEVOUR_MAGIC_5, PET_DEVOUR_MAGIC_6, PET_DEVOUR_MAGIC_7
};
bool MeleeAction::isUseful()
{

View File

@@ -304,7 +304,6 @@ bool UseTrinketAction::Execute(Event event)
return true;
Item* trinket2 = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_TRINKET2);
if (trinket2 && UseTrinket(trinket2))
return true;
@@ -333,6 +332,15 @@ bool UseTrinketAction::UseTrinket(Item* item)
if (item->GetTemplate()->Spells[i].SpellId > 0 && item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
{
spellId = item->GetTemplate()->Spells[i].SpellId;
uint32 spellProcFlag = sSpellMgr->GetSpellInfo(spellId)->ProcFlags;
// Handle items with procflag "if you kill a target that grants honor or experience"
// Bots will "learn" the trinket proc, so CanCastSpell() will be true
// e.g. on Item https://www.wowhead.com/wotlk/item=44074/oracle-talisman-of-ablution leading to
// constant casting of the proc spell onto themselfes https://www.wowhead.com/wotlk/spell=59787/oracle-ablutions
// This will lead to multiple hundreds of entries in m_appliedAuras -> Once killing an enemy -> Big diff time spikes
if (spellProcFlag != 0) return false;
if (!botAI->CanCastSpell(spellId, bot, false))
{
return false;

View File

@@ -4,7 +4,7 @@
*/
#include "ReleaseSpiritAction.h"
#include "ServerFacade.h"
#include "Event.h"
#include "GameGraveyard.h"
#include "NearestNpcsValue.h"
@@ -13,6 +13,7 @@
#include "Playerbots.h"
#include "ServerFacade.h"
#include "Corpse.h"
#include "Log.h"
// ReleaseSpiritAction implementation
bool ReleaseSpiritAction::Execute(Event event)
@@ -247,3 +248,19 @@ void RepopAction::PerformGraveyardTeleport(const GraveyardStruct* graveyard) con
RESET_AI_VALUE(bool, "combat::self target");
RESET_AI_VALUE(WorldPosition, "current position");
}
// SelfResurrectAction implementation for Warlock's Soulstone Resurrection/Shaman's Reincarnation
bool SelfResurrectAction::Execute(Event event)
{
if (!bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL))
{
WorldPacket packet(CMSG_SELF_RES);
bot->GetSession()->HandleSelfResOpcode(packet);
return true;
}
return false;
}
bool SelfResurrectAction::isUseful()
{
return !bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL);
}

View File

@@ -56,4 +56,13 @@ private:
void PerformGraveyardTeleport(const GraveyardStruct* graveyard) const;
};
// SelfResurrectAction action registration
class SelfResurrectAction : public Action
{
public:
SelfResurrectAction(PlayerbotAI* ai) : Action(ai, "self resurrect") {}
virtual bool Execute(Event event) override;
bool isUseful() override;
};
#endif

View File

@@ -238,9 +238,24 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni
{
targetFlag = TARGET_FLAG_NONE;
packet << targetFlag;
packet << bot->GetPackGUID();
targetSelected = true;
out << " on self";
// Use the actual target if provided
if (unitTarget)
{
packet << unitTarget->GetGUID();
targetSelected = true;
// If the target is bot or is an enemy, say "on self"
if (unitTarget == bot || (unitTarget->IsHostileTo(bot)))
out << " on self";
else
out << " on " << unitTarget->GetName();
}
else
{
packet << bot->GetPackGUID();
targetSelected = true;
out << " on self";
}
}
ItemTemplate const* proto = item->GetTemplate();

View File

@@ -40,6 +40,7 @@
#include "TradeStatusExtendedAction.h"
#include "UseMeetingStoneAction.h"
#include "NamedObjectContext.h"
#include "ReleaseSpiritAction.h"
class PlayerbotAI;
@@ -68,6 +69,7 @@ public:
creators["accept trade"] = &WorldPacketActionContext::accept_trade;
creators["trade status extended"] = &WorldPacketActionContext::trade_status_extended;
creators["store loot"] = &WorldPacketActionContext::store_loot;
creators["self resurrect"] = &WorldPacketActionContext::self_resurrect;
// quest
creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest;
@@ -136,6 +138,7 @@ private:
static Action* tell_not_enough_money(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough money"); }
static Action* tell_not_enough_reputation(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough reputation"); }
static Action* tell_cannot_equip(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); }
static Action* self_resurrect(PlayerbotAI* botAI) { return new SelfResurrectAction(botAI); }
// quest
static Action* quest_update_add_kill(PlayerbotAI* ai) { return new QuestUpdateAddKillAction(ai); }

View File

@@ -25,6 +25,8 @@ void DeadStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new TriggerNode("falling far", NextAction::array(0, new NextAction("repop", relevance + 1.f), nullptr)));
triggers.push_back(
new TriggerNode("location stuck", NextAction::array(0, new NextAction("repop", relevance + 1), nullptr)));
triggers.push_back(new TriggerNode(
"can self resurrect", NextAction::array(0, new NextAction("self resurrect", relevance + 2.0f), nullptr)));
}
DeadStrategy::DeadStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) {}

View File

@@ -12,40 +12,52 @@ public:
{
creators["icc lm tank position"] = &RaidIccActionContext::icc_lm_tank_position;
creators["icc spike"] = &RaidIccActionContext::icc_spike;
creators["icc dark reckoning"] = &RaidIccActionContext::icc_dark_reckoning;
creators["icc ranged position lady deathwhisper"] = &RaidIccActionContext::icc_ranged_position_lady_deathwhisper;
creators["icc adds lady deathwhisper"] = &RaidIccActionContext::icc_adds_lady_deathwhisper;
creators["icc shade lady deathwhisper"] = &RaidIccActionContext::icc_shade_lady_deathwhisper;
creators["icc rotting frost giant tank position"] = &RaidIccActionContext::icc_rotting_frost_giant_tank_position;
creators["icc cannon fire"] = &RaidIccActionContext::icc_cannon_fire;
creators["icc gunship enter cannon"] = &RaidIccActionContext::icc_gunship_enter_cannon;
creators["icc gunship teleport ally"] = &RaidIccActionContext::icc_gunship_teleport_ally;
creators["icc gunship teleport horde"] = &RaidIccActionContext::icc_gunship_teleport_horde;
creators["icc dbs tank position"] = &RaidIccActionContext::icc_dbs_tank_position;
creators["icc adds dbs"] = &RaidIccActionContext::icc_adds_dbs;
creators["icc festergut tank position"] = &RaidIccActionContext::icc_festergut_tank_position;
creators["icc festergut group position"] = &RaidIccActionContext::icc_festergut_group_position;
creators["icc festergut spore"] = &RaidIccActionContext::icc_festergut_spore;
creators["icc rotface tank position"] = &RaidIccActionContext::icc_rotface_tank_position;
creators["icc rotface group position"] = &RaidIccActionContext::icc_rotface_group_position;
creators["icc rotface move away from explosion"] = &RaidIccActionContext::icc_rotface_move_away_from_explosion;
creators["icc putricide volatile ooze"] = &RaidIccActionContext::icc_putricide_volatile_ooze;
creators["icc putricide gas cloud"] = &RaidIccActionContext::icc_putricide_gas_cloud;
creators["icc putricide growing ooze puddle"] = &RaidIccActionContext::icc_putricide_growing_ooze_puddle;
creators["avoid malleable goo"] = &RaidIccActionContext::avoid_malleable_goo;
creators["icc putricide avoid malleable goo"] = &RaidIccActionContext::icc_putricide_avoid_malleable_goo;
creators["icc bpc keleseth tank"] = &RaidIccActionContext::icc_bpc_keleseth_tank;
creators["icc bpc nucleus"] = &RaidIccActionContext::icc_bpc_nucleus;
creators["icc bpc main tank"] = &RaidIccActionContext::icc_bpc_main_tank;
creators["icc bpc empowered vortex"] = &RaidIccActionContext::icc_bpc_empowered_vortex;
creators["icc bpc kinetic bomb"] = &RaidIccActionContext::icc_bpc_kinetic_bomb;
creators["icc bql tank position"] = &RaidIccActionContext::icc_bql_tank_position;
creators["icc bpc ball of flame"] = &RaidIccActionContext::icc_bpc_ball_of_flame;
creators["icc bql group position"] = &RaidIccActionContext::icc_bql_group_position;
creators["icc bql pact of darkfallen"] = &RaidIccActionContext::icc_bql_pact_of_darkfallen;
creators["icc bql vampiric bite"] = &RaidIccActionContext::icc_bql_vampiric_bite;
creators["icc valkyre spear"] = &RaidIccActionContext::icc_valkyre_spear;
creators["icc sister svalna"] = &RaidIccActionContext::icc_sister_svalna;
creators["icc valithria group"] = &RaidIccActionContext::icc_valithria_group;
creators["icc valithria portal"] = &RaidIccActionContext::icc_valithria_portal;
creators["icc valithria heal"] = &RaidIccActionContext::icc_valithria_heal;
creators["icc valithria dream cloud"] = &RaidIccActionContext::icc_valithria_dream_cloud;
creators["icc sindragosa tank position"] = &RaidIccActionContext::icc_sindragosa_tank_position;
creators["icc sindragosa group position"] = &RaidIccActionContext::icc_sindragosa_group_position;
creators["icc sindragosa frost beacon"] = &RaidIccActionContext::icc_sindragosa_frost_beacon;
creators["icc sindragosa blistering cold"] = &RaidIccActionContext::icc_sindragosa_blistering_cold;
creators["icc sindragosa unchained magic"] = &RaidIccActionContext::icc_sindragosa_unchained_magic;
@@ -53,6 +65,7 @@ public:
creators["icc sindragosa mystic buffet"] = &RaidIccActionContext::icc_sindragosa_mystic_buffet;
creators["icc sindragosa frost bomb"] = &RaidIccActionContext::icc_sindragosa_frost_bomb;
creators["icc sindragosa tank swap position"] = &RaidIccActionContext::icc_sindragosa_tank_swap_position;
creators["icc lich king shadow trap"] = &RaidIccActionContext::icc_lich_king_shadow_trap;
creators["icc lich king necrotic plague"] = &RaidIccActionContext::icc_lich_king_necrotic_plague;
creators["icc lich king winter"] = &RaidIccActionContext::icc_lich_king_winter;
@@ -62,40 +75,52 @@ public:
private:
static Action* icc_lm_tank_position(PlayerbotAI* ai) { return new IccLmTankPositionAction(ai); }
static Action* icc_spike(PlayerbotAI* ai) { return new IccSpikeAction(ai); }
static Action* icc_dark_reckoning(PlayerbotAI* ai) { return new IccDarkReckoningAction(ai); }
static Action* icc_ranged_position_lady_deathwhisper(PlayerbotAI* ai) { return new IccRangedPositionLadyDeathwhisperAction(ai); }
static Action* icc_adds_lady_deathwhisper(PlayerbotAI* ai) { return new IccAddsLadyDeathwhisperAction(ai); }
static Action* icc_shade_lady_deathwhisper(PlayerbotAI* ai) { return new IccShadeLadyDeathwhisperAction(ai); }
static Action* icc_rotting_frost_giant_tank_position(PlayerbotAI* ai) { return new IccRottingFrostGiantTankPositionAction(ai); }
static Action* icc_cannon_fire(PlayerbotAI* ai) { return new IccCannonFireAction(ai); }
static Action* icc_gunship_enter_cannon(PlayerbotAI* ai) { return new IccGunshipEnterCannonAction(ai); }
static Action* icc_gunship_teleport_ally(PlayerbotAI* ai) { return new IccGunshipTeleportAllyAction(ai); }
static Action* icc_gunship_teleport_horde(PlayerbotAI* ai) { return new IccGunshipTeleportHordeAction(ai); }
static Action* icc_gunship_teleport_horde(PlayerbotAI* ai) { return new IccGunshipTeleportHordeAction(ai); }
static Action* icc_dbs_tank_position(PlayerbotAI* ai) { return new IccDbsTankPositionAction(ai); }
static Action* icc_adds_dbs(PlayerbotAI* ai) { return new IccAddsDbsAction(ai); }
static Action* icc_festergut_tank_position(PlayerbotAI* ai) { return new IccFestergutTankPositionAction(ai); }
static Action* icc_festergut_group_position(PlayerbotAI* ai) { return new IccFestergutGroupPositionAction(ai); }
static Action* icc_festergut_spore(PlayerbotAI* ai) { return new IccFestergutSporeAction(ai); }
static Action* icc_rotface_tank_position(PlayerbotAI* ai) { return new IccRotfaceTankPositionAction(ai); }
static Action* icc_rotface_group_position(PlayerbotAI* ai) { return new IccRotfaceGroupPositionAction(ai); }
static Action* icc_rotface_move_away_from_explosion(PlayerbotAI* ai) { return new IccRotfaceMoveAwayFromExplosionAction(ai); }
static Action* icc_rotface_move_away_from_explosion(PlayerbotAI* ai) { return new IccRotfaceMoveAwayFromExplosionAction(ai); }
static Action* icc_putricide_volatile_ooze(PlayerbotAI* ai) { return new IccPutricideVolatileOozeAction(ai); }
static Action* icc_putricide_gas_cloud(PlayerbotAI* ai) { return new IccPutricideGasCloudAction(ai); }
static Action* icc_putricide_growing_ooze_puddle(PlayerbotAI* ai) { return new IccPutricideGrowingOozePuddleAction(ai); }
static Action* avoid_malleable_goo(PlayerbotAI* ai) { return new AvoidMalleableGooAction(ai); }
static Action* icc_putricide_avoid_malleable_goo(PlayerbotAI* ai) { return new IccPutricideAvoidMalleableGooAction(ai); }
static Action* icc_bpc_keleseth_tank(PlayerbotAI* ai) { return new IccBpcKelesethTankAction(ai); }
static Action* icc_bpc_nucleus(PlayerbotAI* ai) { return new IccBpcNucleusAction(ai); }
static Action* icc_bpc_main_tank(PlayerbotAI* ai) { return new IccBpcMainTankAction(ai); }
static Action* icc_bpc_empowered_vortex(PlayerbotAI* ai) { return new IccBpcEmpoweredVortexAction(ai); }
static Action* icc_bpc_kinetic_bomb(PlayerbotAI* ai) { return new IccBpcKineticBombAction(ai); }
static Action* icc_bql_tank_position(PlayerbotAI* ai) { return new IccBqlTankPositionAction(ai); }
static Action* icc_bpc_ball_of_flame(PlayerbotAI* ai) { return new IccBpcBallOfFlameAction(ai); }
static Action* icc_bql_group_position(PlayerbotAI* ai) { return new IccBqlGroupPositionAction(ai); }
static Action* icc_bql_pact_of_darkfallen(PlayerbotAI* ai) { return new IccBqlPactOfDarkfallenAction(ai); }
static Action* icc_bql_vampiric_bite(PlayerbotAI* ai) { return new IccBqlVampiricBiteAction(ai); }
static Action* icc_valkyre_spear(PlayerbotAI* ai) { return new IccValkyreSpearAction(ai); }
static Action* icc_sister_svalna(PlayerbotAI* ai) { return new IccSisterSvalnaAction(ai); }
static Action* icc_valithria_group(PlayerbotAI* ai) { return new IccValithriaGroupAction(ai); }
static Action* icc_valithria_portal(PlayerbotAI* ai) { return new IccValithriaPortalAction(ai); }
static Action* icc_valithria_heal(PlayerbotAI* ai) { return new IccValithriaHealAction(ai); }
static Action* icc_valithria_dream_cloud(PlayerbotAI* ai) { return new IccValithriaDreamCloudAction(ai); }
static Action* icc_sindragosa_tank_position(PlayerbotAI* ai) { return new IccSindragosaTankPositionAction(ai); }
static Action* icc_sindragosa_group_position(PlayerbotAI* ai) { return new IccSindragosaGroupPositionAction(ai); }
static Action* icc_sindragosa_frost_beacon(PlayerbotAI* ai) { return new IccSindragosaFrostBeaconAction(ai); }
static Action* icc_sindragosa_blistering_cold(PlayerbotAI* ai) { return new IccSindragosaBlisteringColdAction(ai); }
static Action* icc_sindragosa_unchained_magic(PlayerbotAI* ai) { return new IccSindragosaUnchainedMagicAction(ai); }
@@ -103,6 +128,7 @@ private:
static Action* icc_sindragosa_mystic_buffet(PlayerbotAI* ai) { return new IccSindragosaMysticBuffetAction(ai); }
static Action* icc_sindragosa_frost_bomb(PlayerbotAI* ai) { return new IccSindragosaFrostBombAction(ai); }
static Action* icc_sindragosa_tank_swap_position(PlayerbotAI* ai) { return new IccSindragosaTankSwapPositionAction(ai); }
static Action* icc_lich_king_shadow_trap(PlayerbotAI* ai) { return new IccLichKingShadowTrapAction(ai); }
static Action* icc_lich_king_necrotic_plague(PlayerbotAI* ai) { return new IccLichKingNecroticPlagueAction(ai); }
static Action* icc_lich_king_winter(PlayerbotAI* ai) { return new IccLichKingWinterAction(ai); }

File diff suppressed because it is too large Load Diff

View File

@@ -12,12 +12,17 @@
#include "RaidIccStrategy.h"
#include "ScriptedCreature.h"
#include "SharedDefines.h"
#include "Trigger.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Vehicle.h"
#include "RaidIccTriggers.h"
const Position ICC_LM_TANK_POSITION = Position(-391.0f, 2259.0f, 42.0f);
const Position ICC_DARK_RECKONING_SAFE_POSITION = Position(-523.33386f, 2211.2031f, 62.823116f);
const Position ICC_LDW_TANK_POSTION = Position(-570.1f, 2211.2456f, 49.476616f); //-590.0f
const Position ICC_ROTTING_FROST_GIANT_TANK_POSITION = Position(-265.90125f, 2209.0605f, 199.97006f);
const Position ICC_ROTTING_FROST_GIANT_TANK_POSITION = Position(-328.5085f, 2225.5142f, 199.97298f);
const Position ICC_GUNSHIP_TELEPORT_ALLY = Position (-370.04645f, 1993.3536f, 466.65656f);
const Position ICC_GUNSHIP_TELEPORT_ALLY2 = Position (-392.66208f, 2064.893f, 466.5672f, 5.058196f);
const Position ICC_GUNSHIP_TELEPORT_HORDE = Position (-449.5343f, 2477.2024f, 470.17648f);
@@ -29,33 +34,49 @@ const Position ICC_FESTERGUT_MELEE_SPORE = Position(4269.1772f, 3144.7673f, 360.
const Position ICC_ROTFACE_TANK_POSITION = Position(4447.061f, 3150.9758f, 360.38568f);
const Position ICC_ROTFACE_BIG_OOZE_POSITION = Position(4432.687f, 3142.3035f, 360.38623f);
const Position ICC_ROTFACE_SAFE_POSITION = Position(4446.557f, 3065.6594f, 360.51843f);
const Position ICC_PUTRICIDE_TANK_POSITION = Position(4393.7676f, 3214.9375f, 389.3997f);
//const Position ICC_PUTRICIDE_GAS1_POSITION = Position(4350.772f, 3249.9773f, 389.39508f);
//const Position ICC_PUTRICIDE_GAS2_POSITION = Position(4390.002f, 3204.8855f, 389.39938f);
const Position ICC_ROTFACE_CENTER_POSITION = Position(4446.0547f, 3144.8677f, 360.38593f); //actual center 4.74089 4445.6616f, 3137.1526f, 360.38608
const Position ICC_PUTRICIDE_TANK_POSITION = Position(4373.227f, 3222.058f, 389.4029f);
const Position ICC_PUTRICIDE_GREEN_POSITION = Position(4423.4126f, 3194.2715f, 389.37683f);
const Position ICC_PUTRICIDE_BAD_POSITION = Position(4356.1724f, 3261.5232f, 389.3985f);
//const Position ICC_PUTRICIDE_GAS3_POSITION = Position(4367.753f, 3177.5894f, 389.39575f);
//const Position ICC_PUTRICIDE_GAS4_POSITION = Position(4321.8486f, 3206.464f, 389.3982f);
const Position ICC_BPC_OT_POSITION = Position(4649.2236f, 2796.0972f, 361.1815f);
const Position ICC_BPC_MT_POSITION = Position(4648.5674f, 2744.847f, 361.18222f);
const Position ICC_BQL_CENTER_POSITION = Position(4595.0f, 2769.0f, 400.0f);
const Position ICC_BQL_TANK_POSITION = Position(4616.102f, 2768.9167f, 400.13797f);
const Position ICC_VDW_GROUP_POSITION = Position(4204.839f, 2484.9338f, 364.87f);
const Position ICC_BQL_LWALL1_POSITION = Position(4624.685f, 2789.4895f, 400.13834f);
const Position ICC_BQL_LWALL2_POSITION = Position(4600.749f, 2805.7568f, 400.1374f);
const Position ICC_BQL_LWALL3_POSITION = Position(4572.857f, 2797.3872f, 400.1374f);
const Position ICC_BQL_RWALL1_POSITION = Position(4625.724f, 2748.9917f, 400.13693f);
const Position ICC_BQL_RWALL2_POSITION = Position(4608.3774f, 2735.7466f, 400.13693f);
const Position ICC_BQL_RWALL3_POSITION = Position(4576.813f, 2739.6067f, 400.13693f);
const Position ICC_BQL_LRWALL4_POSITION = Position(4539.345f, 2769.3853f, 403.7267f);
const Position ICC_BQL_TANK_POSITION = Position(4629.746f, 2769.6396f, 401.7479f); //old just in front of stairs 4616.102f, 2768.9167f, 400.13797f
const Position ICC_VDW_HEAL_POSITION = Position(4203.752f, 2483.4343f, 364.87274f);
const Position ICC_VDW_GROUP1_POSITION = Position(4203.585f, 2464.422f, 364.86887f);
const Position ICC_VDW_GROUP2_POSITION = Position(4203.5806f, 2505.2383f, 364.87677f);
const Position ICC_VDW_PORTALSTART_POSITION = Position(4202.637f, 2488.171f, 375.00256f);
const Position ICC_SINDRAGOSA_TANK_POSITION = Position(4408.016f, 2508.0647f, 203.37955f);
const Position ICC_SINDRAGOSA_RANGED_POSITION = Position(4373.7686f, 2498.0042f, 203.38176f);
const Position ICC_SINDRAGOSA_MELEE_POSITION = Position(4389.22f, 2499.5237f, 203.38033f);
const Position ICC_SINDRAGOSA_BLISTERING_COLD_POSITION = Position(4345.922f, 2484.708f, 206.22516f);
const Position ICC_SINDRAGOSA_THOMB1_POSITION = Position(4381.819f, 2471.1448f, 203.37704f); // Westmost position
const Position ICC_SINDRAGOSA_THOMB2_POSITION = Position(4381.819f, 2483.1448f, 203.37704f); // 12y east from pos1
const Position ICC_SINDRAGOSA_THOMB3_POSITION = Position(4381.819f, 2471.1448f, 203.37704f); // Same as pos1
const Position ICC_SINDRAGOSA_THOMB4_POSITION = Position(4381.819f, 2483.1448f, 203.37704f); // Same as pos2
const Position ICC_SINDRAGOSA_THOMB5_POSITION = Position(4381.819f, 2495.1448f, 203.37704f); // 12y east from pos2/4
const Position ICC_SINDRAGOSA_FLYING_POSITION = Position(4525.6f, 2485.15f, 245.082f);
const Position ICC_SINDRAGOSA_RANGED_POSITION = Position(4441.572f, 2484.482f, 203.37836f);
const Position ICC_SINDRAGOSA_MELEE_POSITION = Position(4423.4546f, 2491.7175f, 203.37686f);
const Position ICC_SINDRAGOSA_BLISTERING_COLD_POSITION = Position(4473.6616f, 2484.8489f, 203.38258f);
const Position ICC_SINDRAGOSA_THOMB1_POSITION = Position(4433.6484f, 2469.4133f, 203.3806f);
const Position ICC_SINDRAGOSA_THOMB2_POSITION = Position(4434.143f, 2486.201f, 203.37473f);
const Position ICC_SINDRAGOSA_THOMB3_POSITION = Position(4436.1147f, 2501.464f, 203.38266f);
const Position ICC_SINDRAGOSA_UNCHAINEDMAGIC1_POSITION = Position(4444.9707f, 2455.7322f, 203.38701f);
const Position ICC_SINDRAGOSA_UNCHAINEDMAGIC2_POSITION = Position(4461.3945f, 2463.5513f, 203.38727f);
const Position ICC_SINDRAGOSA_UNCHAINEDMAGIC3_POSITION = Position(4473.6616f, 2484.8489f, 203.38258f);
const Position ICC_SINDRAGOSA_UNCHAINEDMAGIC4_POSITION = Position(4459.9336f, 2507.409f, 203.38606f);
const Position ICC_SINDRAGOSA_UNCHAINEDMAGIC5_POSITION = Position(4442.3096f, 2512.4688f, 203.38647f);
const Position ICC_SINDRAGOSA_CENTER_POSITION = Position(4408.0464f, 2484.478f, 203.37529f);
const Position ICC_SINDRAGOSA_THOMBMB2_POSITION = Position(4382.6113f, 2505.4922f, 203.38197f);
const Position ICC_SINDRAGOSA_FBOMB_POSITION = Position(4400.031f, 2507.0295f, 203.37929f); //old 4400.031f, 2507.0295f, 203.37929f //alternate for 10 man 4366.0225f, 2501.569f, 203.38226f
const Position ICC_SINDRAGOSA_FBOMB10_POSITION = Position(4366.0225f, 2501.569f, 203.38226f);
const Position ICC_SINDRAGOSA_LOS2_POSITION = Position(4376.0938f, 2511.103f, 203.38303f);
const Position ICC_SINDRAGOSA_THOMBMB2_POSITION = Position(4436.895f, 2498.1401f, 203.38133f);
const Position ICC_SINDRAGOSA_FBOMB_POSITION = Position(4449.3647f, 2486.4524f, 203.379f);
const Position ICC_SINDRAGOSA_FBOMB10_POSITION = Position(4449.3647f, 2486.4524f, 203.379f);
const Position ICC_SINDRAGOSA_LOS2_POSITION = Position(4441.8286f, 2501.946f, 203.38435f);
const Position ICC_LICH_KING_ADDS_POSITION = Position(476.7332f, -2095.3894f, 840.857f); // old 486.63647f, -2095.7915f, 840.857f
const Position ICC_LICH_KING_MELEE_POSITION = Position(503.5546f, -2106.8213f, 840.857f);
const Position ICC_LICH_KING_RANGED_POSITION = Position(501.3563f, -2085.1816f, 840.857f);
const Position ICC_LICH_KING_ASSISTHC_POSITION = Position(517.2145f, -2125.0674f, 840.857f);
const Position ICC_LK_FROST1_POSITION = Position(503.96548f, -2183.216f, 840.857f);
const Position ICC_LK_FROST2_POSITION = Position(563.07166f, -2125.7578f, 840.857f);
const Position ICC_LK_FROST3_POSITION = Position(503.40182f, -2067.3435f, 840.857f);
@@ -70,6 +91,8 @@ public:
IccLmTankPositionAction(PlayerbotAI* botAI, std::string const name = "icc lm tank position")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool MoveTowardPosition(const Position& position, float incrementSize);
};
class IccSpikeAction : public AttackAction
@@ -77,6 +100,10 @@ class IccSpikeAction : public AttackAction
public:
IccSpikeAction(PlayerbotAI* botAI) : AttackAction(botAI, "icc spike") {}
bool Execute(Event event) override;
bool HandleSpikeTargeting(Unit* boss);
bool MoveTowardPosition(const Position& position, float incrementSize);
void UpdateRaidTargetIcon(Unit* target);
};
//Lady Deathwhisper
@@ -94,6 +121,8 @@ public:
IccRangedPositionLadyDeathwhisperAction(PlayerbotAI* botAI, std::string const name = "icc ranged position lady deathwhisper")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool MaintainRangedSpacing();
};
class IccAddsLadyDeathwhisperAction : public AttackAction
@@ -102,6 +131,12 @@ public:
IccAddsLadyDeathwhisperAction(PlayerbotAI* botAI, std::string const name = "icc adds lady deathwhisper")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool IsTargetedByShade(uint32 shadeEntry);
bool MoveTowardPosition(const Position& position, float incrementSize);
bool HandleAddTargeting(Unit* boss);
void UpdateRaidTargetIcon(Unit* target);
};
class IccShadeLadyDeathwhisperAction : public MovementAction
@@ -127,6 +162,9 @@ public:
IccCannonFireAction(PlayerbotAI* botAI, std::string const name = "icc cannon fire")
: Action(botAI, name) {}
bool Execute(Event event) override;
Unit* FindValidCannonTarget();
bool TryCastCannonSpell(uint32 spellId, Unit* target, Unit* vehicleBase);
};
class IccGunshipEnterCannonAction : public MovementAction
@@ -135,7 +173,10 @@ public:
IccGunshipEnterCannonAction(PlayerbotAI* botAI, std::string const name = "icc gunship enter cannon")
: MovementAction(botAI, name) {}
bool Execute(Event event) override;
bool EnterVehicle(Unit* vehicleBase, bool moveIfFar);
Unit* FindBestAvailableCannon();
bool IsValidCannon(Unit* vehicle, const uint32 validEntries[]);
};
class IccGunshipTeleportAllyAction : public AttackAction
@@ -144,6 +185,10 @@ public:
IccGunshipTeleportAllyAction(PlayerbotAI* botAI, std::string const name = "icc gunship teleport ally")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool TeleportTo(const Position& position);
void CleanupSkullIcon(uint8_t SKULL_ICON_INDEX);
void UpdateBossSkullIcon(Unit* boss, uint8_t SKULL_ICON_INDEX);
};
class IccGunshipTeleportHordeAction : public AttackAction
@@ -152,6 +197,10 @@ public:
IccGunshipTeleportHordeAction(PlayerbotAI* botAI, std::string const name = "icc gunship teleport horde")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool TeleportTo(const Position& position);
void CleanupSkullIcon(uint8_t SKULL_ICON_INDEX);
void UpdateBossSkullIcon(Unit* boss, uint8_t SKULL_ICON_INDEX);
};
//DBS
@@ -161,6 +210,10 @@ public:
IccDbsTankPositionAction(PlayerbotAI* botAI, std::string const name = "icc dbs tank position")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool CrowdControlBloodBeasts();
bool EvadeBloodBeasts();
bool PositionInRangedFormation();
};
class IccAddsDbsAction : public AttackAction
@@ -169,15 +222,22 @@ public:
IccAddsDbsAction(PlayerbotAI* botAI, std::string const name = "icc adds dbs")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
Unit* FindPriorityTarget(Unit* boss);
void UpdateSkullMarker(Unit* priorityTarget);
};
//FESTERGUT
class IccFestergutTankPositionAction : public AttackAction
class IccFestergutGroupPositionAction : public AttackAction
{
public:
IccFestergutTankPositionAction(PlayerbotAI* botAI, std::string const name = "icc festergut tank position")
IccFestergutGroupPositionAction(PlayerbotAI* botAI, std::string const name = "icc festergut group position")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool HasSporesInGroup();
bool PositionNonTankMembers();
int CalculatePositionIndex(Group* group);
};
class IccFestergutSporeAction : public AttackAction
@@ -186,6 +246,17 @@ public:
IccFestergutSporeAction(PlayerbotAI* botAI, std::string const name = "icc festergut spore")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
Position CalculateSpreadPosition();
struct SporeInfo
{
std::vector<Unit*> sporedPlayers;
ObjectGuid lowestGuid;
bool hasLowestGuid = false;
};
SporeInfo FindSporedPlayers();
Position DetermineTargetPosition(bool hasSpore, const SporeInfo& sporeInfo, const Position& spreadRangedPos);
bool CheckMainTankSpore();
};
//Rotface
@@ -195,6 +266,11 @@ public:
IccRotfaceTankPositionAction(PlayerbotAI* botAI, std::string const name = "icc rotface tank position")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
void MarkBossWithSkull(Unit* boss);
bool PositionMainTankAndMelee(Unit *boss);
bool HandleAssistTankPositioning(Unit* boss);
bool HandleBigOozePositioning(Unit* boss);
};
class IccRotfaceGroupPositionAction : public AttackAction
@@ -203,25 +279,40 @@ public:
IccRotfaceGroupPositionAction(PlayerbotAI* botAI, std::string const name = "icc rotface group position")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
//bool MoveAwayFromBigOoze(Unit* bigOoze);
bool HandlePuddleAvoidance(Unit* boss);
bool MoveAwayFromPuddle(Unit* boss, Unit* puddle, float puddleDistance);
bool HandleOozeTargeting();
bool HandleOozeMemberPositioning();
bool PositionRangedAndHealers(Unit* boss,Unit* smallOoze);
bool FindAndMoveFromClosestMember(Unit* boss, Unit* smallOoze);
};
class IccRotfaceMoveAwayFromExplosionAction : public MovementAction
{
public:
IccRotfaceMoveAwayFromExplosionAction(PlayerbotAI* botAI, std::string const name = "icc rotface move away from explosion")
: MovementAction(botAI, name) {}
bool Execute(Event event) override;
public:
IccRotfaceMoveAwayFromExplosionAction(PlayerbotAI* botAI, std::string const name = "icc rotface move away from explosion")
: MovementAction(botAI, name) {}
bool Execute(Event event) override;
bool MoveToRandomSafeLocation();
};
//PP
class IccPutricideGrowingOozePuddleAction : public AttackAction
{
public:
IccPutricideGrowingOozePuddleAction(PlayerbotAI* botAI, std::string const name = "icc putricide growing ooze puddle")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
Unit* FindClosestThreateningPuddle();
Position CalculateSafeMovePosition(Unit* closestPuddle);
bool IsPositionTooCloseToOtherPuddles(float x, float y, Unit* ignorePuddle);
};
class IccPutricideVolatileOozeAction : public AttackAction
@@ -230,22 +321,41 @@ public:
IccPutricideVolatileOozeAction(PlayerbotAI* botAI, std::string const name = "icc putricide volatile ooze")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
void MarkOozeWithSkull(Unit* ooze);
Unit* FindAuraTarget();
};
class IccPutricideGasCloudAction : public AttackAction
{
public:
public:
IccPutricideGasCloudAction(PlayerbotAI* botAI, std::string const name = "icc putricide gas cloud")
: AttackAction(botAI, name) {}
bool Execute(Event event) override;
bool Execute(Event event) override;
bool HandleGaseousBloatMovement(Unit* gasCloud);
Position CalculateEmergencyPosition(const Position& botPos, float dx, float dy);
bool FindSafeMovementPosition(const Position& botPos, const Position& cloudPos, float dx, float dy, int numAngles,
Position& resultPos);
bool HandleGroupAuraSituation(Unit* gasCloud);
bool GroupHasGaseousBloat(Group* group);
};
class AvoidMalleableGooAction : public MovementAction
class IccPutricideAvoidMalleableGooAction : public MovementAction
{
public:
AvoidMalleableGooAction(PlayerbotAI* botAI, std::string const name = "avoid malleable goo" )
public:
IccPutricideAvoidMalleableGooAction(PlayerbotAI* botAI, std::string const name = "icc putricide avoid malleable goo")
: MovementAction(botAI, name) {}
bool Execute(Event event) override;
bool Execute(Event event) override;
bool HandleTankPositioning(Unit* boss);
bool HandleUnboundPlague(Unit* boss);
bool HandleBossPositioning(Unit* boss);
Position CalculateBossPosition(Unit* boss, float distance);
bool HasObstacleBetween(const Position& from, const Position& to);
bool IsOnPath(const Position& from, const Position& to, const Position& point, float threshold);
Position CalculateArcPoint(const Position& current, const Position& target, const Position& center);
Position CalculateIncrementalMove(const Position& current, const Position& target, float maxDistance);
};
//BPC
@@ -257,20 +367,14 @@ public:
bool Execute(Event event) override;
};
class IccBpcNucleusAction : public AttackAction
{
public:
IccBpcNucleusAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc bpc nucleus") {}
bool Execute(Event event) override;
};
class IccBpcMainTankAction : public AttackAction
{
public:
IccBpcMainTankAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc bpc main tank") {}
bool Execute(Event event) override;
void MarkEmpoweredPrince();
};
class IccBpcEmpoweredVortexAction : public MovementAction
@@ -279,6 +383,9 @@ public:
IccBpcEmpoweredVortexAction(PlayerbotAI* botAI)
: MovementAction(botAI, "icc bpc empowered vortex") {}
bool Execute(Event event) override;
bool MaintainRangedSpacing();
bool HandleEmpoweredVortexSpread();
};
class IccBpcKineticBombAction : public AttackAction
@@ -287,15 +394,45 @@ public:
IccBpcKineticBombAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc bpc kinetic bomb") {}
bool Execute(Event event) override;
Unit* FindOptimalKineticBomb();
bool IsBombAlreadyHandled(Unit* bomb, Group* group);
};
class IccBpcBallOfFlameAction : public MovementAction
{
public:
IccBpcBallOfFlameAction(PlayerbotAI* botAI)
: MovementAction(botAI, "icc bpc ball of flame") {}
bool Execute(Event event) override;
};
//Blood Queen Lana'thel
class IccBqlTankPositionAction : public AttackAction
class IccBqlGroupPositionAction : public AttackAction
{
public:
IccBqlTankPositionAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc bql tank position") {}
IccBqlGroupPositionAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc group tank position") {}
bool Execute(Event event) override;
bool HandleTankPosition(Unit* boss, Aura* frenzyAura, Aura* shadowAura);
bool HandleShadowsMovement();
Position AdjustControlPoint(const Position& wall, const Position& center, float factor);
Position CalculateBezierPoint(float t, const Position path[4]);
bool HandleGroupPosition(Unit* boss, Aura* frenzyAura, Aura* shadowAura);
private:
// Evaluate curves
struct CurveInfo
{
Position moveTarget;
int curveIdx = 0;
bool foundSafe = false;
float minDist = 0.0f;
float score = 0.0f;
Position closestPoint;
float t_closest = 0.0f;
};
};
class IccBqlPactOfDarkfallenAction : public MovementAction
@@ -304,6 +441,9 @@ public:
IccBqlPactOfDarkfallenAction(PlayerbotAI* botAI)
: MovementAction(botAI, "icc bql pact of darkfallen") {}
bool Execute(Event event) override;
void CalculateCenterPosition(Position& targetPos, const std::vector<Player*>& playersWithAura);
bool MoveToTargetPosition(const Position& targetPos, int auraCount);
};
class IccBqlVampiricBiteAction : public AttackAction
@@ -312,9 +452,14 @@ public:
IccBqlVampiricBiteAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc bql vampiric bite") {}
bool Execute(Event event) override;
Player* FindBestBiteTarget(Group* group);
bool IsInvalidTarget(Player* player);
bool MoveTowardsTarget(Player* target);
bool CastVampiricBite(Player* target);
};
//VDW
// Sister Svalna
class IccValkyreSpearAction : public AttackAction
{
public:
@@ -331,6 +476,21 @@ public:
bool Execute(Event event) override;
};
// Valithria Dreamwalker
class IccValithriaGroupAction : public AttackAction
{
public:
IccValithriaGroupAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc valithria group") {}
bool Execute(Event event) override;
bool MoveTowardsPosition(const Position& pos, float increment);
bool Handle25ManGroupLogic();
bool HandleMarkingLogic(bool inGroup1, bool inGroup2, const Position& group1Pos, const Position& group2Pos);
bool Handle10ManGroupLogic();
};
class IccValithriaPortalAction : public MovementAction
{
public:
@@ -356,12 +516,16 @@ public:
};
//Sindragosa
class IccSindragosaTankPositionAction : public AttackAction
class IccSindragosaGroupPositionAction : public AttackAction
{
public:
IccSindragosaTankPositionAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc sindragosa tank position") {}
IccSindragosaGroupPositionAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc sindragosa group position") {}
bool Execute(Event event) override;
bool HandleTankPositioning(Unit* boss);
bool HandleNonTankPositioning();
bool MoveIncrementallyToPosition(const Position& targetPos, float maxStep);
};
class IccSindragosaFrostBeaconAction : public MovementAction
@@ -370,6 +534,21 @@ public:
IccSindragosaFrostBeaconAction(PlayerbotAI* botAI)
: MovementAction(botAI, "icc sindragosa frost beacon") {}
bool Execute(Event event) override;
void HandleSupportActions();
bool HandleBeaconedPlayer(const Unit* boss);
bool HandleNonBeaconedPlayer(const Unit* boss);
bool MoveToPositionIfNeeded(const Position& position, float tolerance);
bool MoveToPosition(const Position& position);
bool IsBossFlying(const Unit* boss);
private:
static constexpr uint32 FROST_BEACON_AURA_ID = SPELL_FROST_BEACON;
static constexpr uint32 HAND_OF_FREEDOM_SPELL_ID = 1044;
static constexpr float POSITION_TOLERANCE = 1.0f;
static constexpr float TOMB_POSITION_TOLERANCE = 0.5f;
static constexpr float MIN_SAFE_DISTANCE = 13.0f;
static constexpr float MOVE_TOLERANCE = 2.0f;
};
class IccSindragosaBlisteringColdAction : public MovementAction
@@ -396,11 +575,11 @@ public:
bool Execute(Event event) override;
};
class IccSindragosaMysticBuffetAction : public AttackAction
class IccSindragosaMysticBuffetAction : public MovementAction
{
public:
IccSindragosaMysticBuffetAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc sindragosa mystic buffet") {}
: MovementAction(botAI, "icc sindragosa mystic buffet") {}
bool Execute(Event event) override;
};
@@ -444,6 +623,21 @@ class IccLichKingWinterAction : public AttackAction
IccLichKingWinterAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc lich king winter") {}
bool Execute(Event event) override;
void HandlePositionCorrection();
bool IsValidCollectibleAdd(Unit* unit);
bool IsPositionSafeFromDefile(float x, float y, float z, float minSafeDistance);
void HandleTankPositioning();
void HandleMeleePositioning();
void HandleRangedPositioning();
void HandleMainTankAddManagement(Unit* boss, const Position* tankPos);
void HandleAssistTankAddManagement(Unit* boss, const Position* tankPos);
private:
const Position* GetMainTankPosition();
const Position* GetMainTankRangedPosition();
bool TryMoveToPosition(float targetX, float targetY, float targetZ, bool isForced = true);
};
class IccLichKingAddsAction : public AttackAction
@@ -452,6 +646,28 @@ class IccLichKingAddsAction : public AttackAction
IccLichKingAddsAction(PlayerbotAI* botAI)
: AttackAction(botAI, "icc lich king adds") {}
bool Execute(Event event) override;
void HandleTeleportationFixes(Difficulty diff, Unit* terenasMenethilHC);
bool HandleSpiritBombAvoidance(Difficulty diff, Unit* terenasMenethilHC);
void HandleHeroicNonTankPositioning(Difficulty diff, Unit* terenasMenethilHC);
void HandleSpiritMarkingAndTargeting(Difficulty diff, Unit* terenasMenethilHC);
bool HandleQuakeMechanics(Unit* boss);
void HandleShamblingHorrors(Unit* boss, bool hasPlague);
bool HandleAssistTankAddManagement(Unit* boss, Difficulty diff);
void HandleMeleePositioning(Unit* boss, bool hasPlague, Difficulty diff);
void HandleMainTankTargeting(Unit* boss, Difficulty diff);
void HandleNonTankHeroicPositioning(Unit* boss, Difficulty diff, bool hasPlague);
void HandleRangedPositioning(Unit* boss, bool hasPlague, Difficulty diff);
void HandleDefileMechanics(Unit* boss, Difficulty diff);
void HandleValkyrMechanics(Difficulty diff);
std::vector<size_t> CalculateBalancedGroupSizes(size_t totalAssist, size_t numValkyrs);
size_t GetAssignedValkyrIndex(size_t assistIndex, const std::vector<size_t>& groupSizes);
std::string GetRTIValueForValkyr(size_t valkyrIndex);
void HandleValkyrMarking(const std::vector<Unit*>& grabbingValkyrs, Difficulty diff);
void HandleValkyrAssignment(const std::vector<Unit*>& grabbingValkyrs);
void ApplyCCToValkyr(Unit* valkyr);
bool IsValkyr(Unit* unit);
void HandleVileSpiritMechanics();
};

File diff suppressed because it is too large Load Diff

View File

@@ -68,20 +68,13 @@ public:
};
//BQL
class IccBqlPactOfDarkfallenMultiplier : public Multiplier
class IccBqlMultiplier : public Multiplier
{
public:
IccBqlPactOfDarkfallenMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "icc bql pact of darkfallen multiplier") {}
IccBqlMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "icc bql multiplier") {}
virtual float GetValue(Action* action) override;
};
class IccBqlVampiricBiteMultiplier : public Multiplier
{
public:
IccBqlVampiricBiteMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc bql vampiric bite") {}
virtual float GetValue(Action* action);
};
//VDW
class IccValithriaDreamCloudMultiplier : public Multiplier
{
@@ -91,56 +84,14 @@ public:
};
//SINDRAGOSA
class IccSindragosaTankPositionMultiplier : public Multiplier
class IccSindragosaMultiplier : public Multiplier
{
public:
IccSindragosaTankPositionMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc sindragosa tank position") {}
virtual float GetValue(Action* action);
};
class IccSindragosaFrostBeaconMultiplier : public Multiplier
{
public:
IccSindragosaFrostBeaconMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc sindragosa frost beacon") {}
virtual float GetValue(Action* action);
};
/*class IccSindragosaFlyingMultiplier : public Multiplier
{
public:
IccSindragosaFlyingMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc sindragosa flying") {}
virtual float GetValue(Action* action);
};*/
class IccSindragosaMysticBuffetMultiplier : public Multiplier
{
public:
IccSindragosaMysticBuffetMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc sindragosa mystic buffet") {}
virtual float GetValue(Action* action);
};
class IccSindragosaBlisteringColdPriorityMultiplier : public Multiplier
{
public:
IccSindragosaBlisteringColdPriorityMultiplier(PlayerbotAI* ai) : Multiplier(ai, "sindragosa blistering cold priority") {}
virtual float GetValue(Action* action) override;
};
class IccSindragosaFrostBombMultiplier : public Multiplier
{
public:
IccSindragosaFrostBombMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc sindragosa frost bomb") {}
virtual float GetValue(Action* action);
};
class IccLichKingNecroticPlagueMultiplier : public Multiplier
{
public:
IccLichKingNecroticPlagueMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc lich king necrotic plague") {}
IccSindragosaMultiplier(PlayerbotAI* ai) : Multiplier(ai, "icc sindragosa") {}
virtual float GetValue(Action* action);
};
//LK
class IccLichKingAddsMultiplier : public Multiplier
{
public:
@@ -149,4 +100,4 @@ public:
};
#endif
#endif

View File

@@ -5,25 +5,19 @@
void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
//Lord Marrogwar
triggers.push_back(new TriggerNode("icc lm tank position",
NextAction::array(0, new NextAction("icc lm tank position", ACTION_RAID + 5), nullptr)));
triggers.push_back(new TriggerNode("icc spike near",
NextAction::array(0, new NextAction("icc spike", ACTION_RAID + 3), nullptr)));
triggers.push_back(new TriggerNode("icc lm",
NextAction::array(0, new NextAction("icc lm tank position", ACTION_RAID + 5),
new NextAction("icc spike", ACTION_RAID + 3), nullptr)));
//Lady Deathwhisper
triggers.push_back(new TriggerNode("icc dark reckoning",
NextAction::array(0, new NextAction("icc dark reckoning", ACTION_MOVE + 5), nullptr)));
triggers.push_back(new TriggerNode("icc ranged position lady deathwhisper",
NextAction::array(0, new NextAction("icc ranged position lady deathwhisper", ACTION_MOVE + 2), nullptr)));
triggers.push_back(new TriggerNode("icc lady deathwhisper",
NextAction::array(0, new NextAction("icc ranged position lady deathwhisper", ACTION_MOVE + 2),
new NextAction("icc adds lady deathwhisper", ACTION_RAID + 3),
new NextAction("icc shade lady deathwhisper", ACTION_RAID + 4), nullptr)));
triggers.push_back(new TriggerNode("icc adds lady deathwhisper",
NextAction::array(0, new NextAction("icc adds lady deathwhisper", ACTION_RAID + 3), nullptr)));
triggers.push_back(new TriggerNode("icc shade lady deathwhisper",
NextAction::array(0, new NextAction("icc shade lady deathwhisper", ACTION_MOVE + 5), nullptr)));
//Gunship Battle
triggers.push_back(new TriggerNode("icc rotting frost giant tank position",
NextAction::array(0, new NextAction("icc rotting frost giant tank position", ACTION_RAID + 5), nullptr)));
@@ -41,22 +35,20 @@ void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
NextAction::array(0, new NextAction("icc gunship teleport horde", ACTION_RAID + 4), nullptr)));
//DBS
triggers.push_back(new TriggerNode("icc dbs tank position",
NextAction::array(0, new NextAction("icc dbs tank position", ACTION_RAID + 3), nullptr)));
triggers.push_back(new TriggerNode("icc dbs",
NextAction::array(0, new NextAction("icc dbs tank position", ACTION_RAID + 3),
new NextAction("icc adds dbs", ACTION_RAID + 5), nullptr)));
triggers.push_back(new TriggerNode("icc dbs main tank rune of blood",
NextAction::array(0, new NextAction("taunt spell", ACTION_EMERGENCY + 4), nullptr)));
triggers.push_back(new TriggerNode("icc adds dbs",
NextAction::array(0, new NextAction("icc adds dbs", ACTION_RAID + 5), nullptr)));
//DOGS
triggers.push_back(new TriggerNode("icc stinky precious main tank mortal wound",
NextAction::array(0, new NextAction("taunt spell", ACTION_EMERGENCY + 4), nullptr)));
//FESTERGUT
triggers.push_back(new TriggerNode("icc festergut tank position",
NextAction::array(0, new NextAction("icc festergut tank position", ACTION_MOVE + 4), nullptr)));
triggers.push_back(new TriggerNode("icc festergut group position",
NextAction::array(0, new NextAction("icc festergut group position", ACTION_MOVE + 4), nullptr)));
triggers.push_back(new TriggerNode("icc festergut main tank gastric bloat",
NextAction::array(0, new NextAction("taunt spell", ACTION_EMERGENCY + 6), nullptr)));
@@ -85,18 +77,15 @@ void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
NextAction::array(0, new NextAction("icc putricide growing ooze puddle", ACTION_RAID + 3), nullptr)));
triggers.push_back(new TriggerNode("icc putricide main tank mutated plague",
NextAction::array(0, new NextAction("taunt spell", ACTION_RAID + 6), nullptr)));
NextAction::array(0, new NextAction("taunt spell", ACTION_RAID + 10), nullptr)));
triggers.push_back(new TriggerNode("icc putricide malleable goo",
NextAction::array(0, new NextAction("avoid malleable goo", ACTION_RAID + 2), nullptr)));
NextAction::array(0, new NextAction("icc putricide avoid malleable goo", ACTION_RAID + 2), nullptr)));
//BPC
triggers.push_back(new TriggerNode("icc bpc keleseth tank",
NextAction::array(0, new NextAction("icc bpc keleseth tank", ACTION_RAID + 1), nullptr)));
triggers.push_back(new TriggerNode("icc bpc nucleus",
NextAction::array(0, new NextAction("icc bpc nucleus", ACTION_RAID + 2), nullptr)));
triggers.push_back(new TriggerNode("icc bpc main tank",
NextAction::array(0, new NextAction("icc bpc main tank", ACTION_RAID + 3), nullptr)));
@@ -105,10 +94,13 @@ void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("icc bpc kinetic bomb",
NextAction::array(0, new NextAction("icc bpc kinetic bomb", ACTION_RAID + 6), nullptr)));
triggers.push_back(new TriggerNode("icc bpc ball of flame",
NextAction::array(0, new NextAction("icc bpc ball of flame", ACTION_RAID + 7), nullptr)));
//BQL
triggers.push_back(new TriggerNode("icc bql tank position",
NextAction::array(0, new NextAction("icc bql tank position", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode("icc bql group position",
NextAction::array(0, new NextAction("icc bql group position", ACTION_RAID), nullptr)));
triggers.push_back(new TriggerNode("icc bql pact of darkfallen",
NextAction::array(0, new NextAction("icc bql pact of darkfallen", ACTION_RAID +1), nullptr)));
@@ -116,25 +108,30 @@ void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("icc bql vampiric bite",
NextAction::array(0, new NextAction("icc bql vampiric bite", ACTION_EMERGENCY + 5), nullptr)));
//VDW
//Sister Svalna
triggers.push_back(new TriggerNode("icc valkyre spear",
NextAction::array(0, new NextAction("icc valkyre spear", ACTION_EMERGENCY + 5), nullptr)));
triggers.push_back(new TriggerNode("icc sister svalna",
NextAction::array(0, new NextAction("icc sister svalna", ACTION_RAID + 5), nullptr)));
//VDW
triggers.push_back(new TriggerNode("icc valithria group",
NextAction::array(0, new NextAction("icc valithria group", ACTION_RAID + 1), nullptr)));
triggers.push_back(new TriggerNode("icc valithria portal",
NextAction::array(0, new NextAction("icc valithria portal", ACTION_RAID + 5), nullptr)));
triggers.push_back(new TriggerNode("icc valithria heal",
NextAction::array(0, new NextAction("icc valithria heal", ACTION_RAID+1), nullptr)));
NextAction::array(0, new NextAction("icc valithria heal", ACTION_RAID+2), nullptr)));
triggers.push_back(new TriggerNode("icc valithria dream cloud",
NextAction::array(0, new NextAction("icc valithria dream cloud", ACTION_RAID + 4), nullptr)));
//SINDRAGOSA
triggers.push_back(new TriggerNode("icc sindragosa tank position",
NextAction::array(0, new NextAction("icc sindragosa tank position", ACTION_RAID + 1), nullptr)));
triggers.push_back(new TriggerNode("icc sindragosa group position",
NextAction::array(0, new NextAction("icc sindragosa group position", ACTION_RAID + 1), nullptr)));
triggers.push_back(new TriggerNode("icc sindragosa frost beacon",
NextAction::array(0, new NextAction("icc sindragosa frost beacon", ACTION_RAID + 5), nullptr)));
@@ -181,18 +178,10 @@ void RaidIccStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
multipliers.push_back(new IccDogsMultiplier(botAI));
multipliers.push_back(new IccFestergutMultiplier(botAI));
multipliers.push_back(new IccRotfaceMultiplier(botAI));
//multipliers.push_back(new IccRotfaceGroupPositionMultiplier(botAI));
multipliers.push_back(new IccAddsPutricideMultiplier(botAI));
multipliers.push_back(new IccBpcAssistMultiplier(botAI));
multipliers.push_back(new IccBqlPactOfDarkfallenMultiplier(botAI));
multipliers.push_back(new IccBqlVampiricBiteMultiplier(botAI));
multipliers.push_back(new IccBqlMultiplier(botAI));
multipliers.push_back(new IccValithriaDreamCloudMultiplier(botAI));
multipliers.push_back(new IccSindragosaTankPositionMultiplier(botAI));
multipliers.push_back(new IccSindragosaFrostBeaconMultiplier(botAI));
//multipliers.push_back(new IccSindragosaFlyingMultiplier(botAI));
multipliers.push_back(new IccSindragosaMysticBuffetMultiplier(botAI));
multipliers.push_back(new IccSindragosaBlisteringColdPriorityMultiplier(botAI));
multipliers.push_back(new IccSindragosaFrostBombMultiplier(botAI));
multipliers.push_back(new IccLichKingNecroticPlagueMultiplier(botAI));
multipliers.push_back(new IccSindragosaMultiplier(botAI));
multipliers.push_back(new IccLichKingAddsMultiplier(botAI));
}

View File

@@ -10,46 +10,55 @@ class RaidIccTriggerContext : public NamedObjectContext<Trigger>
public:
RaidIccTriggerContext()
{
creators["icc lm tank position"] = &RaidIccTriggerContext::icc_lm_tank_position;
creators["icc spike near"] = &RaidIccTriggerContext::icc_spike_near;
creators["icc lm"] = &RaidIccTriggerContext::icc_lm;
creators["icc dark reckoning"] = &RaidIccTriggerContext::icc_dark_reckoning;
creators["icc ranged position lady deathwhisper"] = &RaidIccTriggerContext::icc_ranged_position_lady_deathwhisper;
creators["icc adds lady deathwhisper"] = &RaidIccTriggerContext::icc_adds_lady_deathwhisper;
creators["icc shade lady deathwhisper"] = &RaidIccTriggerContext::icc_shade_lady_deathwhisper;
creators["icc lady deathwhisper"] = &RaidIccTriggerContext::icc_lady_deathwhisper;
creators["icc rotting frost giant tank position"] = &RaidIccTriggerContext::icc_rotting_frost_giant_tank_position;
creators["icc in cannon"] = &RaidIccTriggerContext::icc_in_cannon;
creators["icc gunship cannon near"] = &RaidIccTriggerContext::icc_gunship_cannon_near;
creators["icc gunship teleport ally"] = &RaidIccTriggerContext::icc_gunship_teleport_ally;
creators["icc gunship teleport horde"] = &RaidIccTriggerContext::icc_gunship_teleport_horde;
creators["icc dbs tank position"] = &RaidIccTriggerContext::icc_dbs_tank_position;
creators["icc dbs"] = &RaidIccTriggerContext::icc_dbs;
creators["icc dbs main tank rune of blood"] = &RaidIccTriggerContext::icc_dbs_main_tank_rune_of_blood;
creators["icc adds dbs"] = &RaidIccTriggerContext::icc_adds_dbs;
creators["icc stinky precious main tank mortal wound"] = &RaidIccTriggerContext::icc_stinky_precious_main_tank_mortal_wound;
creators["icc festergut tank position"] = &RaidIccTriggerContext::icc_festergut_tank_position;
creators["icc festergut group position"] = &RaidIccTriggerContext::icc_festergut_group_position;
creators["icc festergut main tank gastric bloat"] = &RaidIccTriggerContext::icc_festergut_main_tank_gastric_bloat;
creators["icc festergut spore"] = &RaidIccTriggerContext::icc_festergut_spore;
creators["icc rotface tank position"] = &RaidIccTriggerContext::icc_rotface_tank_position;
creators["icc rotface group position"] = &RaidIccTriggerContext::icc_rotface_group_position;
creators["icc rotface move away from explosion"] = &RaidIccTriggerContext::icc_rotface_move_away_from_explosion;
creators["icc putricide volatile ooze"] = &RaidIccTriggerContext::icc_putricide_volatile_ooze;
creators["icc putricide gas cloud"] = &RaidIccTriggerContext::icc_putricide_gas_cloud;
creators["icc putricide growing ooze puddle"] = &RaidIccTriggerContext::icc_putricide_growing_ooze_puddle;
creators["icc putricide main tank mutated plague"] = &RaidIccTriggerContext::icc_putricide_main_tank_mutated_plague;
creators["icc putricide malleable goo"] = &RaidIccTriggerContext::icc_putricide_malleable_goo;
creators["icc bpc keleseth tank"] = &RaidIccTriggerContext::icc_bpc_keleseth_tank;
creators["icc bpc nucleus"] = &RaidIccTriggerContext::icc_bpc_nucleus;
creators["icc bpc main tank"] = &RaidIccTriggerContext::icc_bpc_main_tank;
creators["icc bpc empowered vortex"] = &RaidIccTriggerContext::icc_bpc_empowered_vortex;
creators["icc bpc kinetic bomb"] = &RaidIccTriggerContext::icc_bpc_kinetic_bomb;
creators["icc bql tank position"] = &RaidIccTriggerContext::icc_bql_tank_position;
creators["icc bpc ball of flame"] = &RaidIccTriggerContext::icc_bpc_ball_of_flame;
creators["icc bql group position"] = &RaidIccTriggerContext::icc_bql_group_position;
creators["icc bql pact of darkfallen"] = &RaidIccTriggerContext::icc_bql_pact_of_darkfallen;
creators["icc bql vampiric bite"] = &RaidIccTriggerContext::icc_bql_vampiric_bite;
creators["icc valkyre spear"] = &RaidIccTriggerContext::icc_valkyre_spear;
creators["icc sister svalna"] = &RaidIccTriggerContext::icc_sister_svalna;
creators["icc valithria group"] = &RaidIccTriggerContext::icc_valithria_group;
creators["icc valithria portal"] = &RaidIccTriggerContext::icc_valithria_portal;
creators["icc valithria heal"] = &RaidIccTriggerContext::icc_valithria_heal;
creators["icc valithria dream cloud"] = &RaidIccTriggerContext::icc_valithria_dream_cloud;
creators["icc sindragosa tank position"] = &RaidIccTriggerContext::icc_sindragosa_tank_position;
creators["icc sindragosa group position"] = &RaidIccTriggerContext::icc_sindragosa_group_position;
creators["icc sindragosa frost beacon"] = &RaidIccTriggerContext::icc_sindragosa_frost_beacon;
creators["icc sindragosa blistering cold"] = &RaidIccTriggerContext::icc_sindragosa_blistering_cold;
creators["icc sindragosa unchained magic"] = &RaidIccTriggerContext::icc_sindragosa_unchained_magic;
@@ -58,6 +67,7 @@ public:
creators["icc sindragosa main tank mystic buffet"] = &RaidIccTriggerContext::icc_sindragosa_main_tank_mystic_buffet;
creators["icc sindragosa frost bomb"] = &RaidIccTriggerContext::icc_sindragosa_frost_bomb;
creators["icc sindragosa tank swap position"] = &RaidIccTriggerContext::icc_sindragosa_tank_swap_position;
creators["icc lich king shadow trap"] = &RaidIccTriggerContext::icc_lich_king_shadow_trap;
creators["icc lich king necrotic plague"] = &RaidIccTriggerContext::icc_lich_king_necrotic_plague;
creators["icc lich king winter"] = &RaidIccTriggerContext::icc_lich_king_winter;
@@ -65,46 +75,55 @@ public:
}
private:
static Trigger* icc_lm_tank_position(PlayerbotAI* ai) { return new IccLmTankPositionTrigger(ai); }
static Trigger* icc_spike_near(PlayerbotAI* ai) { return new IccSpikeNearTrigger(ai); }
static Trigger* icc_lm(PlayerbotAI* ai) { return new IccLmTrigger(ai); }
static Trigger* icc_dark_reckoning(PlayerbotAI* ai) { return new IccDarkReckoningTrigger(ai); }
static Trigger* icc_ranged_position_lady_deathwhisper(PlayerbotAI* ai) { return new IccRangedPositionLadyDeathwhisperTrigger(ai); }
static Trigger* icc_adds_lady_deathwhisper(PlayerbotAI* ai) { return new IccAddsLadyDeathwhisperTrigger(ai); }
static Trigger* icc_shade_lady_deathwhisper(PlayerbotAI* ai) { return new IccShadeLadyDeathwhisperTrigger(ai); }
static Trigger* icc_lady_deathwhisper(PlayerbotAI* ai) { return new IccLadyDeathwhisperTrigger(ai); }
static Trigger* icc_rotting_frost_giant_tank_position(PlayerbotAI* ai) { return new IccRottingFrostGiantTankPositionTrigger(ai); }
static Trigger* icc_in_cannon(PlayerbotAI* ai) { return new IccInCannonTrigger(ai); }
static Trigger* icc_gunship_cannon_near(PlayerbotAI* ai) { return new IccGunshipCannonNearTrigger(ai); }
static Trigger* icc_gunship_teleport_ally(PlayerbotAI* ai) { return new IccGunshipTeleportAllyTrigger(ai); }
static Trigger* icc_gunship_teleport_horde(PlayerbotAI* ai) { return new IccGunshipTeleportHordeTrigger(ai); }
static Trigger* icc_dbs_tank_position(PlayerbotAI* ai) { return new IccDbsTankPositionTrigger(ai); }
static Trigger* icc_dbs(PlayerbotAI* ai) { return new IccDbsTrigger(ai); }
static Trigger* icc_dbs_main_tank_rune_of_blood(PlayerbotAI* ai) { return new IccDbsMainTankRuneOfBloodTrigger(ai); }
static Trigger* icc_adds_dbs(PlayerbotAI* ai) { return new IccAddsDbsTrigger(ai); }
static Trigger* icc_stinky_precious_main_tank_mortal_wound(PlayerbotAI* ai) { return new IccStinkyPreciousMainTankMortalWoundTrigger(ai); }
static Trigger* icc_festergut_tank_position(PlayerbotAI* ai) { return new IccFestergutTankPositionTrigger(ai); }
static Trigger* icc_festergut_group_position(PlayerbotAI* ai) { return new IccFestergutGroupPositionTrigger(ai); }
static Trigger* icc_festergut_main_tank_gastric_bloat(PlayerbotAI* ai) { return new IccFestergutMainTankGastricBloatTrigger(ai); }
static Trigger* icc_festergut_spore(PlayerbotAI* ai) { return new IccFestergutSporeTrigger(ai); }
static Trigger* icc_rotface_tank_position(PlayerbotAI* ai) { return new IccRotfaceTankPositionTrigger(ai); }
static Trigger* icc_rotface_group_position(PlayerbotAI* ai) { return new IccRotfaceGroupPositionTrigger(ai); }
static Trigger* icc_rotface_move_away_from_explosion(PlayerbotAI* ai) { return new IccRotfaceMoveAwayFromExplosionTrigger(ai); }
static Trigger* icc_putricide_volatile_ooze(PlayerbotAI* ai) { return new IccPutricideVolatileOozeTrigger(ai); }
static Trigger* icc_putricide_gas_cloud(PlayerbotAI* ai) { return new IccPutricideGasCloudTrigger(ai); }
static Trigger* icc_putricide_growing_ooze_puddle(PlayerbotAI* ai) { return new IccPutricideGrowingOozePuddleTrigger(ai); }
static Trigger* icc_putricide_main_tank_mutated_plague(PlayerbotAI* ai) { return new IccPutricideMainTankMutatedPlagueTrigger(ai); }
static Trigger* icc_putricide_malleable_goo(PlayerbotAI* ai) { return new IccPutricideMalleableGooTrigger(ai); }
static Trigger* icc_bpc_keleseth_tank(PlayerbotAI* ai) { return new IccBpcKelesethTankTrigger(ai); }
static Trigger* icc_bpc_nucleus(PlayerbotAI* ai) { return new IccBpcNucleusTrigger(ai); }
static Trigger* icc_bpc_main_tank(PlayerbotAI* ai) { return new IccBpcMainTankTrigger(ai); }
static Trigger* icc_bpc_empowered_vortex(PlayerbotAI* ai) { return new IccBpcEmpoweredVortexTrigger(ai); }
static Trigger* icc_bpc_kinetic_bomb(PlayerbotAI* ai) { return new IccBpcKineticBombTrigger(ai); }
static Trigger* icc_bql_tank_position(PlayerbotAI* ai) { return new IccBqlTankPositionTrigger(ai); }
static Trigger* icc_bpc_ball_of_flame(PlayerbotAI* ai) { return new IccBpcBallOfFlameTrigger(ai); }
static Trigger* icc_bql_group_position(PlayerbotAI* ai) { return new IccBqlGroupPositionTrigger(ai); }
static Trigger* icc_bql_pact_of_darkfallen(PlayerbotAI* ai) { return new IccBqlPactOfDarkfallenTrigger(ai); }
static Trigger* icc_bql_vampiric_bite(PlayerbotAI* ai) { return new IccBqlVampiricBiteTrigger(ai); }
static Trigger* icc_valkyre_spear(PlayerbotAI* ai) { return new IccValkyreSpearTrigger(ai); }
static Trigger* icc_sister_svalna(PlayerbotAI* ai) { return new IccSisterSvalnaTrigger(ai); }
static Trigger* icc_valithria_group(PlayerbotAI* ai) { return new IccValithriaGroupTrigger(ai); }
static Trigger* icc_valithria_portal(PlayerbotAI* ai) { return new IccValithriaPortalTrigger(ai); }
static Trigger* icc_valithria_heal(PlayerbotAI* ai) { return new IccValithriaHealTrigger(ai); }
static Trigger* icc_valithria_dream_cloud(PlayerbotAI* ai) { return new IccValithriaDreamCloudTrigger(ai); }
static Trigger* icc_sindragosa_tank_position(PlayerbotAI* ai) { return new IccSindragosaTankPositionTrigger(ai); }
static Trigger* icc_sindragosa_group_position(PlayerbotAI* ai) { return new IccSindragosaGroupPositionTrigger(ai); }
static Trigger* icc_sindragosa_frost_beacon(PlayerbotAI* ai) { return new IccSindragosaFrostBeaconTrigger(ai); }
static Trigger* icc_sindragosa_blistering_cold(PlayerbotAI* ai) { return new IccSindragosaBlisteringColdTrigger(ai); }
static Trigger* icc_sindragosa_unchained_magic(PlayerbotAI* ai) { return new IccSindragosaUnchainedMagicTrigger(ai); }
@@ -113,6 +132,7 @@ private:
static Trigger* icc_sindragosa_main_tank_mystic_buffet(PlayerbotAI* ai) { return new IccSindragosaMainTankMysticBuffetTrigger(ai); }
static Trigger* icc_sindragosa_frost_bomb(PlayerbotAI* ai) { return new IccSindragosaFrostBombTrigger(ai); }
static Trigger* icc_sindragosa_tank_swap_position(PlayerbotAI* ai) { return new IccSindragosaTankSwapPositionTrigger(ai); }
static Trigger* icc_lich_king_shadow_trap(PlayerbotAI* ai) { return new IccLichKingShadowTrapTrigger(ai); }
static Trigger* icc_lich_king_necrotic_plague(PlayerbotAI* ai) { return new IccLichKingNecroticPlagueTrigger(ai); }
static Trigger* icc_lich_king_winter(PlayerbotAI* ai) { return new IccLichKingWinterTrigger(ai); }

File diff suppressed because it is too large Load Diff

View File

@@ -5,18 +5,223 @@
#include "Playerbots.h"
#include "Trigger.h"
//Lord Marrowgar
class IccLmTankPositionTrigger : public Trigger
enum CreatureIdsICC
{
public:
IccLmTankPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc lm tank position") {}
bool IsActive() override;
// Lord Marrowgar
NPC_SPIKE1 = 36619,
NPC_SPIKE2 = 38711,
NPC_SPIKE3 = 38712,
// Lady Deathwhisper
NPC_SHADE = 38222,
// Gunship Battle
NPC_KOR_KRON_BATTLE_MAGE = 37117,
NPC_KOR_KRON_AXETHROWER = 36968,
NPC_KOR_KRON_ROCKETEER = 36982,
NPC_SKYBREAKER_SORCERER = 37116,
NPC_SKYBREAKER_RIFLEMAN = 36969,
NPC_SKYBREAKER_MORTAR_SOLDIER = 36978,
NPC_IGB_HIGH_OVERLORD_SAURFANG = 36939,
NPC_IGB_MURADIN_BRONZEBEARD = 36948,
NPC_CANNONA = 36838,
NPC_CANNONH = 36839,
NPC_MURADIN_BRONZEBEARD = 36948,
NPC_HIGH_OVERLORD_SAURFANG = 36939,
// Deathbringer Saurfang
NPC_BLOOD_BEAST1 = 38508,
NPC_BLOOD_BEAST2 = 38596,
NPC_BLOOD_BEAST3 = 38597,
NPC_BLOOD_BEAST4 = 38598,
// Rotface
NPC_PUDDLE = 37013,
NPC_BIG_OOZE = 36899,
// Putricide
NPC_MALLEABLE_OOZE_STALKER = 38556,
NPC_GROWING_OOZE_PUDDLE = 37690,
NPC_CHOKING_GAS_BOMB = 38159,
// Blood Prince Council
NPC_DARK_NUCLEUS = 38369,
NPC_PRINCE_KELESETH = 37972,
NPC_PRINCE_TALDARAM = 37973,
NPC_PRINCE_VALANAR = 37970,
NPC_KINETIC_BOMB1 = 38454,
NPC_KINETIC_BOMB2 = 38775,
NPC_KINETIC_BOMB3 = 38776,
NPC_KINETIC_BOMB4 = 38777,
NPC_BALL_OF_FLAME = 38332,
NPC_BALL_OF_INFERNO_FLAME = 38451,
// Blood Queen Lana'thel
NPC_SWARMING_SHADOWS = 38163,
// Sister Svalna
NPC_SPEAR = 38248,
ITEM_SPEAR = 50307,
// Valithria Dreamwalker
NPC_VALITHRIA_DREAMWALKER = 36789,
NPC_DREAM_PORTAL = 37945,
NPC_NIGHTMARE_PORTAL = 38430,
NPC_DREAM_CLOUD = 37985,
NPC_NIGHTMARE_CLOUD = 38421,
NPC_RISEN_ARCHMAGE = 37868,
NPC_BLAZING_SKELETON = 36791,
NPC_SUPPRESSER = 37863,
NPC_BLISTERING_ZOMBIE = 37934,
NPC_GLUTTONOUS_ABOMINATION = 37886,
NPC_ROT_WORM = 37907,
NPC_COLUMN_OF_FROST = 37918,
NPC_MANA_VOID = 38068,
NPC_DREAM_PORTAL_PRE_EFFECT = 38186,
NPC_NIGHTMARE_PORTAL_PRE_EFFECT = 38429,
// Sindragosa
NPC_SINDRAGOSA = 36853,
NPC_TOMB1 = 36980,
NPC_TOMB2 = 38320,
NPC_TOMB3 = 38321,
NPC_TOMB4 = 38322,
// Lich King
NPC_THE_LICH_KING = 36597,
NPC_TERENAS_MENETHIL = 36823,
NPC_TERENAS_MENETHIL_HC = 39217,
NPC_SPIRIT_BOMB = 39189,
NPC_WICKED_SPIRIT1 = 39190,
NPC_WICKED_SPIRIT2 = 39287,
NPC_WICKED_SPIRIT3 = 39288,
NPC_WICKED_SPIRIT4 = 39289,
NPC_SHADOW_TRAP = 39137,
NPC_SHAMBLING_HORROR1 = 37698,
NPC_SHAMBLING_HORROR2 = 39299,
NPC_SHAMBLING_HORROR3 = 39300,
NPC_SHAMBLING_HORROR4 = 39301,
NPC_ICE_SPHERE1 = 36633,
NPC_ICE_SPHERE2 = 39305,
NPC_ICE_SPHERE3 = 39306,
NPC_ICE_SPHERE4 = 39307,
NPC_RAGING_SPIRIT1 = 36701,
NPC_RAGING_SPIRIT2 = 39302,
NPC_RAGING_SPIRIT3 = 39303,
NPC_RAGING_SPIRIT4 = 39304,
NPC_DRUDGE_GHOUL1 = 37695,
NPC_DRUDGE_GHOUL2 = 39309,
NPC_DRUDGE_GHOUL3 = 39310,
NPC_DRUDGE_GHOUL4 = 39311,
NPC_VALKYR_SHADOWGUARD1 = 36609,
NPC_VALKYR_SHADOWGUARD2 = 39120,
NPC_VALKYR_SHADOWGUARD3 = 39121,
NPC_VALKYR_SHADOWGUARD4 = 39122,
NPC_VILE_SPIRIT1 = 37799,
NPC_VILE_SPIRIT2 = 39284,
NPC_VILE_SPIRIT3 = 39285,
NPC_VILE_SPIRIT4 = 39286,
};
class IccSpikeNearTrigger : public Trigger
enum SpellIdsICC
{
// ICC cheat spells
SPELL_EMPOWERED_BLOOD = 70227, //70304 -->50%, 70227 /*100% more dmg, 100% more att speed*/
SPELL_EXPERIENCED = 71188, //dmg 30% 20% att speed
SPELL_NO_THREAT = 70115, //reduce threat
SPELL_SPITEFULL_FURY = 36886, //500% more threat
SPELL_NITRO_BOOSTS = 54861, //Speed
SPELL_PAIN_SUPPRESION = 69910, //40% dmg reduction
SPELL_AGEIS_OF_DALARAN = 71638, //268 all ress
SPELL_CYCLONE = 33786,
SPELL_HAMMER_OF_JUSTICE = 10308, //stun
// Lady Deathwhisper
SPELL_DARK_RECKONING = 69483,
// Gunship Battle
SPELL_DEATH_PLAGUE = 72865,
SPELL_BELOW_ZERO = 69705,
// Festergut
SPELL_GAS_SPORE = 69279,
// Rotface
SPELL_SLIME_SPRAY = 69508,
SPELL_OOZE_FLOOD = 71215,
SPELL_UNSTABLE_OOZE_EXPLOSION = 69839,
SPELL_OOZE_FLOOD_VISUAL = 69785,
// Putricide
SPELL_MALLEABLE_GOO = 70852,
SPELL_GROW_AURA = 70347,
// Blood Prince Council
SPELL_EMPOWERED_SHOCK_VORTEX1 = 72039,
SPELL_EMPOWERED_SHOCK_VORTEX2 = 73037,
SPELL_EMPOWERED_SHOCK_VORTEX3 = 73038,
SPELL_EMPOWERED_SHOCK_VORTEX4 = 73039,
// Blood Queen Lana'thel
SPELL_PACT_OF_THE_DARKFALLEN = 71340,
// Sister Svalna
SPELL_AETHER_SHIELD = 71463,
// Valithria Dreamwalker
SPELL_DREAM_STATE = 70766,
SPELL_EMERALD_VIGOR = 70873,
// Sindragosa
SPELL_FROST_BEACON = 70126,
SPELL_ICE_TOMB = 70157,
SPELL_FROST_BOMB_VISUAL = 70022,
SPELL_BLISTERING_COLD1 = 70123,
SPELL_BLISTERING_COLD2 = 71047,
SPELL_BLISTERING_COLD3 = 71048,
SPELL_BLISTERING_COLD4 = 71049,
// The Lich King
SPELL_HARVEST_SOUL_VALKYR = 68985,
SPELL_QUAKE = 72262,
SPELL_REMORSELESS_WINTER1 = 72259,
SPELL_REMORSELESS_WINTER2 = 74273,
SPELL_REMORSELESS_WINTER3 = 74274,
SPELL_REMORSELESS_WINTER4 = 74275,
SPELL_REMORSELESS_WINTER5 = 68981,
SPELL_REMORSELESS_WINTER6 = 74270,
SPELL_REMORSELESS_WINTER7 = 74271,
SPELL_REMORSELESS_WINTER8 = 74272,
};
const uint32 DEFILE_AURAS[] = {72756, 74162, 74163, 74164};
const uint32 DEFILE_CAST_ID = 72762;
const uint32 DEFILE_NPC_ID = 38757;
const size_t DEFILE_AURA_COUNT = 4;
// All fanatics and adherents entry ids Lady Deathwhisper
static const std::array<uint32, 23> addEntriesLady = {
37949, 38394, 38625, 38626, 38010, 38397, 39000, 39001,
38136, 38396, 38632, 38633, 37890, 38393, 38628, 38629,
38135, 38395, 38634, 38009, 38398, 38630, 38631};
const std::vector<uint32> spellEntriesFlood = {
69782, 69783, 69796, 69797, 69798,
69799, 69801, 69802, 69795};
const std::vector<uint32> availableTargetsGS = {
NPC_KOR_KRON_AXETHROWER, NPC_KOR_KRON_ROCKETEER, NPC_KOR_KRON_BATTLE_MAGE, NPC_IGB_HIGH_OVERLORD_SAURFANG,
NPC_SKYBREAKER_RIFLEMAN, NPC_SKYBREAKER_MORTAR_SOLDIER, NPC_SKYBREAKER_SORCERER, NPC_IGB_MURADIN_BRONZEBEARD};
static std::vector<ObjectGuid> sporeOrder;
//Lord Marrowgar
class IccLmTrigger : public Trigger
{
public:
IccSpikeNearTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc spike near") {}
IccLmTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc lm") {}
bool IsActive() override;
};
@@ -28,24 +233,10 @@ public:
bool IsActive() override;
};
class IccRangedPositionLadyDeathwhisperTrigger : public Trigger
class IccLadyDeathwhisperTrigger : public Trigger
{
public:
IccRangedPositionLadyDeathwhisperTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc ranged position lady deathwhisper") {}
bool IsActive() override;
};
class IccAddsLadyDeathwhisperTrigger : public Trigger
{
public:
IccAddsLadyDeathwhisperTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc adds lady deathwhisper") {}
bool IsActive() override;
};
class IccShadeLadyDeathwhisperTrigger : public Trigger
{
public:
IccShadeLadyDeathwhisperTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc shade lady deathwhisper") {}
IccLadyDeathwhisperTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc lady deathwhisper") {}
bool IsActive() override;
};
@@ -86,10 +277,10 @@ public:
};
//DBS
class IccDbsTankPositionTrigger : public Trigger
class IccDbsTrigger : public Trigger
{
public:
IccDbsTankPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc dbs tank position") {}
IccDbsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc dbs") {}
bool IsActive() override;
};
@@ -100,13 +291,6 @@ public:
bool IsActive() override;
};
class IccAddsDbsTrigger : public Trigger
{
public:
IccAddsDbsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc adds dbs") {}
bool IsActive() override;
};
//DOGS
class IccStinkyPreciousMainTankMortalWoundTrigger : public Trigger
{
@@ -116,10 +300,10 @@ public:
};
//FESTERGUT
class IccFestergutTankPositionTrigger : public Trigger
class IccFestergutGroupPositionTrigger : public Trigger
{
public:
IccFestergutTankPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc festergut tank position") {}
IccFestergutGroupPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc festergut group position") {}
bool IsActive() override;
};
@@ -205,13 +389,6 @@ public:
bool IsActive() override;
};
class IccBpcNucleusTrigger : public Trigger
{
public:
IccBpcNucleusTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc bpc nucleus") {}
bool IsActive() override;
};
class IccBpcMainTankTrigger : public Trigger
{
public:
@@ -233,11 +410,18 @@ public:
bool IsActive() override;
};
//Bql
class IccBqlTankPositionTrigger : public Trigger
class IccBpcBallOfFlameTrigger : public Trigger
{
public:
IccBqlTankPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc bql tank position") {}
IccBpcBallOfFlameTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc bpc ball of flame") {}
bool IsActive() override;
};
//Bql
class IccBqlGroupPositionTrigger : public Trigger
{
public:
IccBqlGroupPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc bql tank position") {}
bool IsActive() override;
};
@@ -255,7 +439,7 @@ public:
bool IsActive() override;
};
//VDW
// Sister Svalna
class IccValkyreSpearTrigger : public Trigger
{
public:
@@ -270,6 +454,16 @@ public:
bool IsActive() override;
};
// Valithria Dreamwalker
class IccValithriaGroupTrigger : public Trigger
{
public:
IccValithriaGroupTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc valithria group") {}
bool IsActive() override;
};
class IccValithriaPortalTrigger : public Trigger
{
public:
@@ -293,10 +487,10 @@ public:
//SINDRAGOSA
class IccSindragosaTankPositionTrigger : public Trigger
class IccSindragosaGroupPositionTrigger : public Trigger
{
public:
IccSindragosaTankPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc sindragosa tank position") {}
IccSindragosaGroupPositionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc sindragosa group position") {}
bool IsActive() override;
};

View File

@@ -11,6 +11,7 @@
#include "HealthTriggers.h"
#include "RangeTriggers.h"
#include "Trigger.h"
#include "Player.h"
class PlayerbotAI;
class Unit;
@@ -922,4 +923,13 @@ public:
public:
virtual Value<Unit*>* GetTargetValue();
};
class SelfResurrectTrigger : public Trigger
{
public:
SelfResurrectTrigger(PlayerbotAI* ai) : Trigger(ai, "can self resurrect") {}
bool IsActive() override { return !bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL); }
};
#endif

View File

@@ -223,6 +223,7 @@ public:
creators["near random status"] = &TriggerContext::near_random_status;
creators["near npc status"] = &TriggerContext::near_npc_status;
creators["do quest status"] = &TriggerContext::do_quest_status;
creators["can self resurrect"] = &TriggerContext::can_self_resurrect;
}
private:
@@ -420,6 +421,7 @@ private:
static Trigger* near_random_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_NEAR_RANDOM); }
static Trigger* near_npc_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_NEAR_NPC); }
static Trigger* do_quest_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_DO_QUEST); }
static Trigger* can_self_resurrect(PlayerbotAI* ai) { return new SelfResurrectTrigger(ai); }
};
#endif

View File

@@ -40,6 +40,11 @@ bool IsDeadValue::Calculate()
bool PetIsDeadValue::Calculate()
{
if ((bot->GetLevel() < 10 && bot->getClass() == CLASS_HUNTER) || bot->IsMounted())
{
return false;
}
if (!bot->GetPet())
{
uint32 ownerid = bot->GetGUID().GetCounter();

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "AfflictionWarlockStrategy.h"
#include "Playerbots.h"
// ===== Action Node Factory =====
class AfflictionWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
AfflictionWarlockStrategyActionNodeFactory()
{
creators["corruption"] = &corruption;
creators["corruption on attacker"] = &corruption;
creators["unstable affliction"] = &unstable_affliction;
creators["unstable affliction on attacker"] = &unstable_affliction;
creators["curse of agony"] = &curse_of_agony;
creators["curse of agony on attacker"] = &curse_of_agony;
creators["haunt"] = &haunt;
creators["shadow bolt"] = &shadow_bolt;
creators["drain soul"] = &drain_soul;
creators["life tap"] = &life_tap;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption on attacker"] = &seed_of_corruption;
creators["seed of corruption"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
}
private:
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* unstable_affliction(PlayerbotAI*) { return new ActionNode("unstable affliction", nullptr, nullptr, nullptr); }
static ActionNode* unstable_affliction_on_attacker(PlayerbotAI*) { return new ActionNode("unstable affliction on attacker", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*) { return new ActionNode("curse of agony", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony_on_attacker(PlayerbotAI*) { return new ActionNode("curse of agony on attacker", nullptr, nullptr, nullptr); }
static ActionNode* haunt(PlayerbotAI*) { return new ActionNode("haunt", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* drain_soul(PlayerbotAI*) { return new ActionNode("drain soul", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", nullptr, nullptr, nullptr); }
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
AfflictionWarlockStrategy::AfflictionWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new AfflictionWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** AfflictionWarlockStrategy::getDefaultActions()
{
return NextAction::array( 0,
new NextAction("corruption", 5.6f),
new NextAction("unstable affliction", 5.5f),
new NextAction("curse of agony", 5.4f),
new NextAction("haunt", 5.3f),
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void AfflictionWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
// Main DoT triggers for high uptime
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("unstable affliction on attacker", NextAction::array(0, new NextAction("unstable affliction on attacker", 19.0f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 18.5f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 18.0f), nullptr)));
triggers.push_back(new TriggerNode("unstable affliction", NextAction::array(0, new NextAction("unstable affliction", 17.5f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 17.0f), nullptr)));
triggers.push_back(new TriggerNode("haunt", NextAction::array(0, new NextAction("haunt", 16.5f), nullptr)));
// Drain Soul as execute if target is low HP // Shadow Trance for free casts
triggers.push_back(new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 16.0f), nullptr)));
triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("drain soul", 15.5f), nullptr)));
// Life Tap glyph buff, and Life Tap as filler
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 29.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
}
// ===== AoE Strategy, 3+ enemies =====
AfflictionWarlockAoeStrategy::AfflictionWarlockAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void AfflictionWarlockAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_AFFLICTIONWARLOCKSTRATEGY_H
#define _PLAYERBOT_AFFLICTIONWARLOCKSTRATEGY_H
#include "GenericWarlockStrategy.h"
#include "CombatStrategy.h"
class PlayerbotAI;
class AfflictionWarlockStrategy : public GenericWarlockStrategy
{
public:
AfflictionWarlockStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "affli"; }
NextAction** getDefaultActions() override;
};
class AfflictionWarlockAoeStrategy : public CombatStrategy
{
public:
AfflictionWarlockAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "affli aoe"; }
};
#endif

View File

@@ -0,0 +1,127 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "DemonologyWarlockStrategy.h"
#include "Playerbots.h"
// ===== Action Node Factory =====
class DemonologyWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
DemonologyWarlockStrategyActionNodeFactory()
{
creators["metamorphosis"] = &metamorphosis;
creators["demonic empowerment"] = &demonic_empowerment;
creators["curse of agony"] = &curse_of_agony;
creators["curse of agony on attacker"] = &curse_of_agony_on_attacker;
creators["corruption"] = &corruption;
creators["corruption on attacker"] = &corruption_on_attacker;
creators["immolate"] = &immolate;
creators["immolate on attacker"] = &immolate_on_attacker;
creators["incinerate"] = &incinerate;
creators["soul fire"] = &soul_fire;
creators["shadow bolt"] = &shadow_bolt;
creators["life tap"] = &life_tap;
creators["immolation aura"] = &immolation_aura;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption on attacker"] = &seed_of_corruption_on_attacker;
creators["seed of corruption"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
creators["demon charge"] = &demon_charge;
creators["shadow cleave"] = &shadow_cleave;
}
private:
static ActionNode* metamorphosis(PlayerbotAI*) { return new ActionNode("metamorphosis", nullptr, nullptr, nullptr); }
static ActionNode* demonic_empowerment(PlayerbotAI*) { return new ActionNode("demonic empowerment", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*) { return new ActionNode("curse of agony", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony_on_attacker(PlayerbotAI*) { return new ActionNode("curse of agony on attacker", nullptr, nullptr, nullptr); }
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", nullptr, nullptr, nullptr); }
static ActionNode* immolate_on_attacker(PlayerbotAI*) { return new ActionNode("immolate on attacker", nullptr, nullptr, nullptr); }
static ActionNode* incinerate(PlayerbotAI*) { return new ActionNode("incinerate", nullptr, nullptr, nullptr); }
static ActionNode* soul_fire(PlayerbotAI*) { return new ActionNode("soul fire", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* immolation_aura(PlayerbotAI*) { return new ActionNode("immolation aura", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", nullptr, nullptr, nullptr); }
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
static ActionNode* demon_charge(PlayerbotAI*) { return new ActionNode("demon charge", nullptr, nullptr, nullptr); }
static ActionNode* shadow_cleave(PlayerbotAI*) { return new ActionNode("shadow cleave", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
DemonologyWarlockStrategy::DemonologyWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new DemonologyWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** DemonologyWarlockStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("corruption", 5.6f),
new NextAction("curse of agony", 5.5f),
new NextAction("immolate", 5.4f),
new NextAction("shadow bolt", 5.3f),
new NextAction("incinerate", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void DemonologyWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
// High priority cooldowns
triggers.push_back(new TriggerNode("metamorphosis", NextAction::array(0, new NextAction("metamorphosis", 28.5f), nullptr)));
triggers.push_back(new TriggerNode("demonic empowerment", NextAction::array(0, new NextAction("demonic empowerment", 28.0f), nullptr)));
// Main DoT triggers for high uptime
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("immolate on attacker", NextAction::array(0, new NextAction("immolate on attacker", 19.0f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 18.5f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 18.0f), nullptr)));
triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 17.5f), nullptr)));
// Procs
triggers.push_back(new TriggerNode("decimation", NextAction::array(0, new NextAction("soul fire", 17.0f), nullptr)));
triggers.push_back(new TriggerNode("molten core", NextAction::array(0, new NextAction("incinerate", 16.5f), nullptr)));
// Life Tap glyph buff, and Life Tap as filler
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 29.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
}
// ===== AoE Strategy, 3+ enemies =====
DemonologyWarlockAoeStrategy::DemonologyWarlockAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void DemonologyWarlockAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("immolation aura", 26.0f),
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}
// Combat strategy to run to melee for Immolation Aura
// Enabled by default for the Demonology spec
// To enable, type "co +meta melee"
// To disable, type "co -meta melee"
MetaMeleeAoeStrategy::MetaMeleeAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void MetaMeleeAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("immolation aura active", NextAction::array(0,
new NextAction("reach melee", 25.5f),
new NextAction("demon charge", 25.0f),
new NextAction("shadow cleave", 24.5f), nullptr)));
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_DEMONOLOGYWARLOCKSTRATEGY_H
#define _PLAYERBOT_DEMONOLOGYWARLOCKSTRATEGY_H
#include "GenericWarlockStrategy.h"
#include "CombatStrategy.h"
class PlayerbotAI;
class DemonologyWarlockStrategy : public GenericWarlockStrategy
{
public:
DemonologyWarlockStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "demo"; }
NextAction** getDefaultActions() override;
};
class DemonologyWarlockAoeStrategy : public CombatStrategy
{
public:
DemonologyWarlockAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "demo aoe"; }
};
class MetaMeleeAoeStrategy : public CombatStrategy
{
public:
MetaMeleeAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "meta melee"; }
};
#endif

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "DestructionWarlockStrategy.h"
#include "Playerbots.h"
// ===== Action Node Factory =====
class DestructionWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
DestructionWarlockStrategyActionNodeFactory()
{
creators["immolate"] = &immolate;
creators["conflagrate"] = &conflagrate;
creators["chaos bolt"] = &chaos_bolt;
creators["incinerate"] = &incinerate;
creators["corruption"] = &corruption;
creators["corruption on attacker"] = &corruption_on_attacker;
creators["curse of agony"] = &curse_of_agony;
creators["curse of agony on attacker"] = &curse_of_agony_on_attacker;
creators["shadow bolt"] = &shadow_bolt;
creators["shadowburn"] = &shadowburn;
creators["life tap"] = &life_tap;
creators["shadowfury"] = &shadowfury;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption"] = &seed_of_corruption;
creators["seed of corruption on attacker"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
}
private:
static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", nullptr, nullptr, nullptr); }
static ActionNode* conflagrate(PlayerbotAI*) { return new ActionNode("conflagrate", nullptr, nullptr, nullptr); }
static ActionNode* chaos_bolt(PlayerbotAI*) { return new ActionNode("chaos bolt", nullptr, nullptr, nullptr); }
static ActionNode* incinerate(PlayerbotAI*) { return new ActionNode("incinerate", nullptr, nullptr, nullptr); }
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* corruption_on_attacker(PlayerbotAI*) { return new ActionNode("corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*) { return new ActionNode("curse of agony", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony_on_attacker(PlayerbotAI*) { return new ActionNode("curse of agony on attacker", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* shadowburn(PlayerbotAI*) { return new ActionNode("shadowburn", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* shadowfury(PlayerbotAI*) { return new ActionNode("shadowfury", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*) { return new ActionNode("seed of corruption", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption_on_attacker(PlayerbotAI*) { return new ActionNode("seed of corruption on attacker", nullptr, nullptr, nullptr); }
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
DestructionWarlockStrategy::DestructionWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new DestructionWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** DestructionWarlockStrategy::getDefaultActions()
{
return NextAction::array( 0,
new NextAction("immolate", 6.1f),
new NextAction("conflagrate", 6.0f),
new NextAction("chaos bolt", 5.9f),
new NextAction("incinerate", 5.8f),
new NextAction("corruption", 5.4f), // Note: Corruption, Curse of Agony, and Shadow Bolt won't be used after
new NextAction("curse of agony", 5.3f), // the character learns Incinerate at level 64
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void DestructionWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
// Main DoT triggers for high uptime + high priority cooldowns
triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("conflagrate", NextAction::array(0, new NextAction("conflagrate", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("chaos bolt", NextAction::array(0, new NextAction("chaos bolt", 19.0f), nullptr)));
// Note: These DoTs won't be used after the character learns Incinerate at level 64
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 5.6f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 5.5f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 5.4f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 5.3f), nullptr)));
// Shadowburn as execute if target is low HP
triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("shadowburn", 18.0f), nullptr)));
// Life Tap glyph buff, and Life Tap as filler
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 29.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 5.1f), nullptr)));
}
// ===== AoE Strategy, 3+ enemies =====
DestructionWarlockAoeStrategy::DestructionWarlockAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void DestructionWarlockAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("shadowfury", 23.0f),
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#ifndef _PLAYERBOT_DESTRUCTIONWARLOCKSTRATEGY_H
#define _PLAYERBOT_DESTRUCTIONWARLOCKSTRATEGY_H
#include "GenericWarlockStrategy.h"
#include "CombatStrategy.h"
class PlayerbotAI;
class DestructionWarlockStrategy : public GenericWarlockStrategy
{
public:
DestructionWarlockStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "destro"; }
NextAction** getDefaultActions() override;
};
class DestructionWarlockAoeStrategy : public CombatStrategy
{
public:
DestructionWarlockAoeStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "destro aoe"; }
};
#endif

View File

@@ -4,105 +4,85 @@
*/
#include "DpsWarlockStrategy.h"
#include "Playerbots.h"
// This strategy is designed for low-level Warlocks without talents.
// All of the important spells/cooldowns have been migrated to
// their respective specs.
// ===== Action Node Factory =====
class DpsWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
DpsWarlockStrategyActionNodeFactory()
{
creators["corruption"] = &corruption;
creators["curse of agony"] = &curse_of_agony;
creators["immolate"] = &immolate;
creators["shadow bolt"] = &shadow_bolt;
creators["unstable affliction"] = &unstable_affliction;
creators["unstable affliction on attacker"] = &unstable_affliction_on_attacker;
creators["life tap"] = &life_tap;
creators["shadowflame"] = &shadowflame;
creators["seed of corruption"] = &seed_of_corruption;
creators["rain of fire"] = &rain_of_fire;
creators["drain soul"] = &drain_soul;
}
private:
static ActionNode* shadow_bolt([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("shadow bolt",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("shoot"), nullptr),
/*C*/ nullptr);
}
static ActionNode* unstable_affliction([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("unstable affliction",
/*P*/ NULL,
/*A*/ NextAction::array(0, new NextAction("immolate"), NULL),
/*C*/ NULL);
}
static ActionNode* unstable_affliction_on_attacker([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("unstable affliction on attacker",
/*P*/ NULL,
/*A*/ NextAction::array(0, new NextAction("immolate on attacker"), NULL),
/*C*/ NULL);
}
static ActionNode* corruption(PlayerbotAI*) { return new ActionNode("corruption", nullptr, nullptr, nullptr); }
static ActionNode* curse_of_agony(PlayerbotAI*){return new ActionNode("curse of agony", nullptr, nullptr, nullptr);}
static ActionNode* immolate(PlayerbotAI*) { return new ActionNode("immolate", nullptr, nullptr, nullptr); }
static ActionNode* shadow_bolt(PlayerbotAI*) { return new ActionNode("shadow bolt", nullptr, nullptr, nullptr); }
static ActionNode* life_tap(PlayerbotAI*) { return new ActionNode("life tap", nullptr, nullptr, nullptr); }
static ActionNode* shadowflame(PlayerbotAI*) { return new ActionNode("shadowflame", nullptr, nullptr, nullptr); }
static ActionNode* seed_of_corruption(PlayerbotAI*){return new ActionNode("seed of corruption", nullptr, nullptr, nullptr);}
static ActionNode* rain_of_fire(PlayerbotAI*) { return new ActionNode("rain of fire", nullptr, nullptr, nullptr); }
static ActionNode* drain_soul(PlayerbotAI*) { return new ActionNode("drain soul", nullptr, nullptr, nullptr); }
};
// ===== Single Target Strategy =====
DpsWarlockStrategy::DpsWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new DpsWarlockStrategyActionNodeFactory());
}
// ===== Default Actions =====
NextAction** DpsWarlockStrategy::getDefaultActions()
{
return NextAction::array(
0, new NextAction("haunt", ACTION_DEFAULT + 0.4f), new NextAction("demonic empowerment", ACTION_DEFAULT + 0.3f),
new NextAction("shadow bolt", ACTION_DEFAULT + 0.2f), new NextAction("shoot", ACTION_DEFAULT), nullptr);
return NextAction::array(0,
new NextAction("immolate", 5.5f),
new NextAction("corruption", 5.4f),
new NextAction("curse of agony", 5.3f),
new NextAction("shadow bolt", 5.2f),
new NextAction("shoot", 5.0f), nullptr);
}
// ===== Trigger Initialization ===
void DpsWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
triggers.push_back(
new TriggerNode("backlash", NextAction::array(0, new NextAction("shadow bolt", 20.0f), nullptr)));
// Main DoT triggers for high uptime
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 19.5f), nullptr)));
triggers.push_back(new TriggerNode("immolate on attacker", NextAction::array(0, new NextAction("immolate on attacker", 19.0f), nullptr)));
triggers.push_back(new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 18.5f), nullptr)));
triggers.push_back(new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 18.0f), nullptr)));
triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 17.5f), nullptr)));
triggers.push_back(new TriggerNode("haunt", NextAction::array(0, new NextAction("haunt", 26.0f), NULL)));
// Drain Soul as execute if target is low HP
triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("drain soul", 17.0f), nullptr)));
triggers.push_back(
new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 15.0f), NULL)));
triggers.push_back(new TriggerNode("backlash", NextAction::array(0, new NextAction("shadow bolt", 15.0f), NULL)));
triggers.push_back(new TriggerNode("molten core", NextAction::array(0, new NextAction("incinerate", 15.0f), NULL)));
triggers.push_back(new TriggerNode("decimation", NextAction::array(0, new NextAction("soul fire", 16.0f), NULL)));
// cast during movement
triggers.push_back(
new TriggerNode("high mana", NextAction::array(0, new NextAction("life tap", ACTION_DEFAULT + 0.1f), nullptr)));
// Cast during movement or to activate glyph buff
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", ACTION_DEFAULT + 0.1f), nullptr)));
triggers.push_back(new TriggerNode("life tap glyph buff", NextAction::array(0, new NextAction("life tap", 28.0f), NULL)));
triggers.push_back(
new TriggerNode("metamorphosis", NextAction::array(0, new NextAction("metamorphosis", 20.0f), NULL)));
}
// ===== AoE Strategy, 3+ enemies =====
void DpsAoeWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("seed of corruption", 33.0f),
new NextAction("seed of corruption on attacker", 32.0f),
new NextAction("rain of fire", 31.0f), nullptr)));
triggers.push_back(new TriggerNode("corruption on attacker",
NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr)));
triggers.push_back(
new TriggerNode("unstable affliction on attacker",
NextAction::array(0, new NextAction("unstable affliction on attacker", 26.0f), NULL)));
triggers.push_back(
new TriggerNode("curse of agony on attacker",
NextAction::array(0, new NextAction("curse of agony on attacker", 25.0f), nullptr)));
}
void DpsWarlockDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("corruption", NextAction::array(0, new NextAction("corruption", 22.0f), nullptr)));
triggers.push_back(new TriggerNode("unstable affliction",
NextAction::array(0, new NextAction("unstable affliction", 21.0f), NULL)));
triggers.push_back(
new TriggerNode("curse of agony", NextAction::array(0, new NextAction("curse of agony", 20.0f), nullptr)));
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
new NextAction("shadowflame", 22.5f),
new NextAction("seed of corruption on attacker", 22.0f),
new NextAction("seed of corruption", 21.5f),
new NextAction("rain of fire", 21.0f), nullptr)));
}

View File

@@ -30,14 +30,4 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "aoe"; }
};
class DpsWarlockDebuffStrategy : public CombatStrategy
{
public:
DpsWarlockDebuffStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "dps debuff"; }
};
#endif

View File

@@ -4,7 +4,7 @@
*/
#include "GenericWarlockNonCombatStrategy.h"
#include "AiFactory.h"
#include "Playerbots.h"
class GenericWarlockNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
@@ -20,6 +20,10 @@ public:
creators["summon felhunter"] = &summon_felhunter;
}
// Pet skills are setup in pass-through fashion, so if one fails, it attempts to cast the next one
// The order goes Felguard -> Felhunter -> Succubus -> Voidwalker -> Imp
// Pets are summoned based on the non-combat strategy you have active, the warlock's level, and if they have a soulstone available
private:
static ActionNode* fel_armor([[maybe_unused]] PlayerbotAI* botAI)
{
@@ -36,7 +40,6 @@ private:
/*A*/ NextAction::array(0, new NextAction("demon skin"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_voidwalker([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon voidwalker",
@@ -62,7 +65,7 @@ private:
{
return new ActionNode("summon felguard",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon succubus"), nullptr),
/*A*/ NextAction::array(0, new NextAction("summon felhunter"), nullptr),
/*C*/ nullptr);
}
};
@@ -75,45 +78,133 @@ GenericWarlockNonCombatStrategy::GenericWarlockNonCombatStrategy(PlayerbotAI* bo
void GenericWarlockNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
NonCombatStrategy::InitTriggers(triggers);
triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr)));
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("fel domination", 30.0f), nullptr)));
triggers.push_back(new TriggerNode("soul link", NextAction::array(0, new NextAction("soul link", 28.0f), nullptr)));
triggers.push_back(new TriggerNode("demon armor", NextAction::array(0, new NextAction("fel armor", 27.0f), nullptr)));
triggers.push_back(new TriggerNode("no healthstone", NextAction::array(0, new NextAction("create healthstone", 26.0f), nullptr)));
triggers.push_back(new TriggerNode("no soulstone", NextAction::array(0, new NextAction("create soulstone", 25.0f), nullptr)));
triggers.push_back(new TriggerNode("life tap", NextAction::array(0, new NextAction("life tap", 23.0f), nullptr)));
triggers.push_back(
new TriggerNode("demon armor", NextAction::array(0, new NextAction("fel armor", 21.0f), nullptr)));
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr)));
triggers.push_back(
new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr)));
triggers.push_back(
new TriggerNode("no healthstone", NextAction::array(0, new NextAction("create healthstone", 15.0f), nullptr)));
triggers.push_back(
new TriggerNode("no spellstone", NextAction::array(0, new NextAction("create spellstone", 13.0f), nullptr)));
triggers.push_back(
new TriggerNode("spellstone", NextAction::array(0, new NextAction("spellstone", 13.0f), nullptr)));
}
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 60.0f),
// nullptr)));
// TODO Warlock pets
Player* bot = botAI->GetBot();
int tab = AiFactory::GetPlayerSpecTab(bot);
if (tab == 2) // Destruction uses Firestone
{
triggers.push_back(
new TriggerNode("no firestone", NextAction::array(0, new NextAction("create firestone", 24.0f), nullptr)));
triggers.push_back(
new TriggerNode("firestone", NextAction::array(0, new NextAction("firestone", 24.0f), nullptr)));
}
else // Affliction and Demonology use Spellstone
{
triggers.push_back(new TriggerNode("no spellstone",
NextAction::array(0, new NextAction("create spellstone", 24.0f), nullptr)));
triggers.push_back(
new TriggerNode("spellstone", NextAction::array(0, new NextAction("spellstone", 24.0f), nullptr)));
}
}
// Non-combat strategy for summoning a Imp
// Enabled by default for the Destruction spec
// To enable, type "nc +imp"
// To disable, type "nc -imp"
SummonImpStrategy::SummonImpStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonImpStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 11.0f), NULL)));
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 29.0f), NULL)));
}
SummonFelguardStrategy::SummonFelguardStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
// Non-combat strategy for summoning a Voidwalker
// Disabled by default
// To enable, type "nc +voidwalker"
// To disable, type "nc -voidwalker"
SummonVoidwalkerStrategy::SummonVoidwalkerStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonFelguardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
void SummonVoidwalkerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 11.0f), NULL)));
triggers.push_back(
new TriggerNode("no pet", NextAction::array(0, new NextAction("summon voidwalker", 29.0f), NULL)));
}
// Non-combat strategy for summoning a Succubus
// Disabled by default
// To enable, type "nc +succubus"
// To disable, type "nc -succubus"
SummonSuccubusStrategy::SummonSuccubusStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonSuccubusStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon succubus", 29.0f), NULL)));
}
// Non-combat strategy for summoning a Felhunter
// Enabled by default for the Affliction spec
// To enable, type "nc +felhunter"
// To disable, type "nc -felhunter"
SummonFelhunterStrategy::SummonFelhunterStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonFelhunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 11.0f), NULL)));
}
new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL)));
}
// Non-combat strategy for summoning a Felguard
// Enabled by default for the Demonology spec
// To enable, type "nc +felguard"
// To disable, type "nc -felguard"
SummonFelguardStrategy::SummonFelguardStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SummonFelguardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), NULL)));
}
// Non-combat strategy for selecting themselves to receive soulstone
// Disabled by default
// To enable, type "nc +ss self"
// To disable, type "nc -ss self"
SoulstoneSelfStrategy::SoulstoneSelfStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneSelfStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone self", 24.0f), NULL)));
}
// Non-combat strategy for selecting the master to receive soulstone
// Disabled by default
// To enable, type "nc +ss master"
// To disable, type "nc -ss master"
SoulstoneMasterStrategy::SoulstoneMasterStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneMasterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone master", 24.0f), NULL)));
}
// Non-combat strategy for selecting tanks to receive soulstone
// Disabled by default
// To enable, type "nc +ss tank"
// To disable, type "nc -ss tank"
SoulstoneTankStrategy::SoulstoneTankStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneTankStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone tank", 24.0f), NULL)));
}
// Non-combat strategy for selecting healers to receive soulstone
// Disabled by default
// To enable, type "nc +ss healer"
// To disable, type "nc -ss healer"
SoulstoneHealerStrategy::SoulstoneHealerStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
void SoulstoneHealerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("soulstone", NextAction::array(0, new NextAction("soulstone healer", 24.0f), NULL)));
}

View File

@@ -19,30 +19,31 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockPetStrategy : public Strategy
{
public:
WarlockPetStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "pet"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonImpStrategy : public NonCombatStrategy
{
public:
SummonImpStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "bhealth"; }
virtual std::string const getName() override { return "imp"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonFelguardStrategy : public NonCombatStrategy
class SummonVoidwalkerStrategy : public NonCombatStrategy
{
public:
SummonFelguardStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "bdps"; }
SummonVoidwalkerStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "voidwalker"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonSuccubusStrategy : public NonCombatStrategy
{
public:
SummonSuccubusStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "succubus"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
@@ -52,7 +53,57 @@ class SummonFelhunterStrategy : public NonCombatStrategy
{
public:
SummonFelhunterStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "bmana"; }
virtual std::string const getName() override { return "felhunter"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SummonFelguardStrategy : public NonCombatStrategy
{
public:
SummonFelguardStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "felguard"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneSelfStrategy : public NonCombatStrategy
{
public:
SoulstoneSelfStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss self"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneMasterStrategy : public NonCombatStrategy
{
public:
SoulstoneMasterStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss master"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneTankStrategy : public NonCombatStrategy
{
public:
SoulstoneTankStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss tank"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class SoulstoneHealerStrategy : public NonCombatStrategy
{
public:
SoulstoneHealerStrategy(PlayerbotAI* ai);
virtual std::string const getName() override { return "ss healer"; }
public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;

View File

@@ -4,7 +4,7 @@
*/
#include "GenericWarlockStrategy.h"
#include "Strategy.h"
#include "Playerbots.h"
class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
@@ -12,28 +12,22 @@ class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory<Action
public:
GenericWarlockStrategyActionNodeFactory()
{
// creators["summon voidwalker"] = &summon_voidwalker;
creators["banish"] = &banish;
creators["banish on cc"] = &banish_on_cc;
creators["fear on cc"] = &fear_on_cc;
creators["spell lock"] = &spell_lock;
creators["devour magic purge"] = &devour_magic_purge;
creators["devour magic cleanse"] = &devour_magic_cleanse;
}
private:
// static ActionNode* summon_voidwalker([[maybe_unused]] PlayerbotAI* botAI)
//{
// return new ActionNode ("summon voidwalker",
/*P*/ // nullptr,
/*A*/ // NextAction::array(0, new NextAction("drain soul"), nullptr),
/*C*/ // nullptr);
//}
static ActionNode* banish([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("banish",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("fear"), nullptr),
/*C*/ nullptr);
}
static ActionNode* banish_on_cc(PlayerbotAI*) { return new ActionNode("banish on cc", nullptr, nullptr, nullptr); }
static ActionNode* fear_on_cc(PlayerbotAI*) { return new ActionNode("fear on cc", nullptr, nullptr, nullptr); }
static ActionNode* spell_lock(PlayerbotAI*) { return new ActionNode("spell lock", nullptr, nullptr, nullptr); }
static ActionNode* devour_magic_purge(PlayerbotAI*) { return new ActionNode("devour magic purge", nullptr, nullptr, nullptr); }
static ActionNode* devour_magic_cleanse(PlayerbotAI*) { return new ActionNode("devour magic cleanse", nullptr, nullptr, nullptr); }
};
GenericWarlockStrategy::GenericWarlockStrategy(PlayerbotAI* botAI) : RangedCombatStrategy(botAI)
GenericWarlockStrategy::GenericWarlockStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
{
actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory());
}
@@ -42,28 +36,38 @@ NextAction** GenericWarlockStrategy::getDefaultActions() { return NextAction::ar
void GenericWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
RangedCombatStrategy::InitTriggers(triggers);
CombatStrategy::InitTriggers(triggers);
// triggers.push_back(new TriggerNode("shadow trance", NextAction::array(0, new NextAction("shadow bolt", 20.0f),
// nullptr))); triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("drain
// life", 40.0f), nullptr)));
triggers.push_back(
new TriggerNode("low mana", NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), nullptr)));
triggers.push_back(
new TriggerNode("target critical health", NextAction::array(0, new NextAction("drain soul", 30.0f), nullptr)));
// triggers.push_back(new TriggerNode("immolate", NextAction::array(0, new NextAction("immolate", 13.0f), new
// NextAction("conflagrate", 13.0f), nullptr))); triggers.push_back(new TriggerNode("enemy too close for spell",
// NextAction::array(0, new NextAction("flee", 49.0f), NULL)));
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("life tap", ACTION_EMERGENCY + 5), nullptr)));
triggers.push_back(new TriggerNode("medium threat", NextAction::array(0, new NextAction("soulshatter", 55.0f), nullptr)));
triggers.push_back(new TriggerNode("spell lock", NextAction::array(0, new NextAction("spell lock", ACTION_INTERRUPT), nullptr)));
triggers.push_back(new TriggerNode("devour magic purge", NextAction::array(0, new NextAction("devour magic purge", ACTION_DISPEL), nullptr)));
triggers.push_back(new TriggerNode("devour magic cleanse", NextAction::array(0, new NextAction("devour magic cleanse", ACTION_DISPEL), nullptr)));
}
void WarlockBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("amplify curse", NextAction::array(0, new NextAction("amplify curse", 41.0f), nullptr)));
// Placeholder for future boost triggers
}
void WarlockPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// Placeholder for future pet triggers
}
void WarlockCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("banish", NextAction::array(0, new NextAction("banish on cc", 32.0f), nullptr)));
triggers.push_back(new TriggerNode("fear", NextAction::array(0, new NextAction("fear on cc", 33.0f), nullptr)));
triggers.push_back(new TriggerNode("banish", NextAction::array(0, new NextAction("banish on cc", 33.0f), nullptr)));
triggers.push_back(new TriggerNode("fear", NextAction::array(0, new NextAction("fear on cc", 32.0f), nullptr)));
}
// Combat strategy for using Curse of the Elements
// Enabling this will turn off their use of Curse of Agony
// Enabled by default for the Destruction spec
// To enable, type "co +curse of elements"
// To disable, type "co -curse of elements"
void WarlockCurseOfTheElementsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("curse of the elements", NextAction::array(0, new NextAction("curse of the elements", 30.0f), nullptr)));
}

View File

@@ -7,11 +7,10 @@
#define _PLAYERBOT_GENERICWARLOCKSTRATEGY_H
#include "CombatStrategy.h"
#include "RangedCombatStrategy.h"
class PlayerbotAI;
class GenericWarlockStrategy : public RangedCombatStrategy
class GenericWarlockStrategy : public CombatStrategy
{
public:
GenericWarlockStrategy(PlayerbotAI* botAI);
@@ -30,6 +29,15 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockPetStrategy : public Strategy
{
public:
WarlockPetStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "pet"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCcStrategy : public Strategy
{
public:
@@ -39,4 +47,13 @@ public:
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
class WarlockCurseOfTheElementsStrategy : public Strategy
{
public:
WarlockCurseOfTheElementsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "curse of elements"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
};
#endif

View File

@@ -4,65 +4,41 @@
*/
#include "TankWarlockStrategy.h"
#include "Playerbots.h"
class GenericWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
// Combat strategy for a Warlock Tank, for certain bosses like Twin Emperors
// Priority is set to spam Searing Pain and use Shadow Ward on CD
// Disabled by default
// To enable, type "co +tank"
// To disable, type "co -tank"
// ===== Action Node Factory =====
class TankWarlockStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
GenericWarlockStrategyActionNodeFactory()
TankWarlockStrategyActionNodeFactory()
{
creators["summon voidwalker"] = &summon_voidwalker;
creators["summon felguard"] = &summon_felguard;
creators["summon succubus"] = &summon_succubus;
creators["summon felhunter"] = &summon_felhunter;
creators["shadow ward"] = &shadow_ward;
creators["searing pain"] = &searing_pain;
}
private:
static ActionNode* summon_voidwalker([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon voidwalker",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon imp"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_felguard([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon felguard",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon succubus"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_succubus([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon succubus",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon voidwalker"), nullptr),
/*C*/ nullptr);
}
static ActionNode* summon_felhunter([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("summon felhunter",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("summon imp"), nullptr),
/*C*/ nullptr);
}
static ActionNode* shadow_ward(PlayerbotAI*) { return new ActionNode("shadow ward", nullptr, nullptr, nullptr); }
static ActionNode* searing_pain(PlayerbotAI*) { return new ActionNode("searing pain", nullptr, nullptr, nullptr); }
};
// ===== Warlock Tank Combat Strategy =====
TankWarlockStrategy::TankWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrategy(botAI)
{
actionNodeFactories.Add(new GenericWarlockStrategyActionNodeFactory());
actionNodeFactories.Add(new TankWarlockStrategyActionNodeFactory());
}
NextAction** TankWarlockStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("shoot", ACTION_DEFAULT), nullptr);
// Shadow Ward is the highest priority, Searing Pain next.
return NextAction::array(0, new NextAction("shadow ward", 27.5f), new NextAction("searing pain", 27.0f), nullptr);
}
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
GenericWarlockStrategy::InitTriggers(triggers);
}

View File

@@ -5,23 +5,204 @@
#include "WarlockActions.h"
#include <string>
#include <vector>
#include "Event.h"
#include "Item.h"
#include "ObjectGuid.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "Unit.h"
bool CastDrainSoulAction::isUseful() { return AI_VALUE2(uint32, "item count", "soul shard") < 10; }
Value<Unit*>* CastBanishAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "banish"); }
bool CastBanishAction::Execute(Event event) { return botAI->CastSpell("banish", GetTarget()); }
Value<Unit*>* CastFearOnCcAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "fear"); }
bool CastFearOnCcAction::Execute(Event event) { return botAI->CastSpell("fear", GetTarget()); }
bool CastFearOnCcAction::isPossible() { return true; }
bool CastFearOnCcAction::isUseful() { return true; }
// Checks if the bot has less than 32 soul shards, and if so, allows casting Drain Soul
bool CastDrainSoulAction::isUseful() { return AI_VALUE2(uint32, "item count", "soul shard") < 32; }
// Checks if the bot's health is above a certain threshold, and if so, allows casting Life Tap
bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->lowHealth; }
Unit* UseSoulstoneAction::GetTarget() { return botAI->GetMaster(); }
// Checks if the target marked with the moon icon can be banished
bool CastBanishOnCcAction::isPossible()
{
Unit* target = GetTarget();
if (!target)
return false;
// Only possible on elementals or demons
uint32 creatureType = target->GetCreatureType();
if (creatureType != CREATURE_TYPE_DEMON && creatureType != CREATURE_TYPE_ELEMENTAL)
return false;
// Use base class to check spell available, range, etc
return CastCrowdControlSpellAction::isPossible();
}
// Checks if the target marked with the moon icon can be feared
bool CastFearOnCcAction::isPossible()
{
Unit* target = GetTarget();
if (!target)
return false;
// Fear cannot be cast on mechanical or undead creatures
uint32 creatureType = target->GetCreatureType();
if (creatureType == CREATURE_TYPE_MECHANICAL || creatureType == CREATURE_TYPE_UNDEAD)
return false;
// Use base class to check spell available, range, etc
return CastCrowdControlSpellAction::isPossible();
}
// Checks if the enemies are close enough to use Shadowflame
bool CastShadowflameAction::isUseful()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
bool facingTarget = AI_VALUE2(bool, "facing", "current target");
bool targetClose = bot->IsWithinCombatRange(target, 7.0f); // 7 yard cone
return facingTarget && targetClose;
}
// Checks if the bot knows Seed of Corruption, and prevents the use of Rain of Fire if it does
bool CastRainOfFireAction::isUseful()
{
Unit* target = GetTarget();
if (!target)
return false;
if (bot->HasSpell(27243) || bot->HasSpell(47835) || bot->HasSpell(47836)) // Seed of Corruption spell IDs
return false;
return true;
}
// Checks if the enemies are close enough to use Hellfire
bool CastHellfireAction::isUseful()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
return bot->IsWithinCombatRange(target, 5.0f); // 5 yard AoE radius
}
// Checks if the "meta melee aoe" strategy is active, OR if the bot is in melee range of the target
bool CastImmolationAuraAction::isUseful()
{
if (botAI->HasStrategy("meta melee", BOT_STATE_COMBAT))
return true;
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
if (!bot->HasAura(47241)) // 47241 is Metamorphosis spell ID (WotLK)
return false;
return bot->IsWithinCombatRange(target, 5.0f); // 5 yard AoE radius
}
// Checks if the "warlock tank" strategy is active, and if so, prevents the use of Soulshatter
bool CastSoulshatterAction::isUseful()
{
if (botAI->HasStrategy("tank", BOT_STATE_COMBAT))
return false;
return true;
}
// Checks if the target has a soulstone aura
static bool HasSoulstoneAura(Unit* unit)
{
static const std::vector<uint32> soulstoneAuraIds = {20707, 20762, 20763, 20764, 20765, 27239, 47883};
for (uint32 spellId : soulstoneAuraIds)
if (unit->HasAura(spellId))
return true;
return false;
}
// Use the soulstone item on the bot itself with nc strategy "ss self"
bool UseSoulstoneSelfAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
if (HasSoulstoneAura(bot))
return false;
bot->SetSelection(bot->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, bot);
}
// Use the soulstone item on the bot's master with nc strategy "ss master"
bool UseSoulstoneMasterAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
Player* master = botAI->GetMaster();
if (!master || HasSoulstoneAura(master))
return false;
bot->SetSelection(master->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, master);
}
// Use the soulstone item on a tank in the group with nc strategy "ss tank"
bool UseSoulstoneTankAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
Player* tank = nullptr;
Group* group = bot->GetGroup();
if (group)
{
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (member && member->IsAlive() && botAI->IsTank(member) && !HasSoulstoneAura(member))
{
tank = member;
break;
}
}
}
if (!tank)
return false;
bot->SetSelection(tank->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, tank);
}
// Use the soulstone item on a healer in the group with nc strategy "ss healer"
bool UseSoulstoneHealerAction::Execute(Event event)
{
std::vector<Item*> items = AI_VALUE2(std::vector<Item*>, "inventory items", "soulstone");
if (items.empty())
return false;
Player* healer = nullptr;
Group* group = bot->GetGroup();
if (group)
{
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (member && member->IsAlive() && botAI->IsHeal(member) && !HasSoulstoneAura(member))
{
healer = member;
break;
}
}
}
if (!healer)
return false;
bot->SetSelection(healer->GetGUID());
return UseItem(items[0], ObjectGuid::Empty, nullptr, healer);
}

View File

@@ -8,10 +8,13 @@
#include "GenericSpellActions.h"
#include "UseItemAction.h"
#include "Action.h"
class PlayerbotAI;
class Unit;
// Buff and Out of Combat Spells
class CastDemonSkinAction : public CastBuffSpellAction
{
public:
@@ -30,71 +33,67 @@ public:
CastFelArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "fel armor") {}
};
BEGIN_RANGED_SPELL_ACTION(CastShadowBoltAction, "shadow bolt")
END_SPELL_ACTION()
class CastDrainSoulAction : public CastSpellAction
class CastSoulLinkAction : public CastBuffSpellAction
{
public:
CastDrainSoulAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain soul") {}
bool isUseful() override;
CastSoulLinkAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "soul link", false, 5000) {}
std::string const GetTargetName() override { return "pet target"; }
};
class CastDrainManaAction : public CastSpellAction
class CastCreateHealthstoneAction : public CastBuffSpellAction
{
public:
CastDrainManaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain mana") {}
CastCreateHealthstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create healthstone") {}
};
class CastDrainLifeAction : public CastSpellAction
class CastCreateFirestoneAction : public CastBuffSpellAction
{
public:
CastDrainLifeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain life") {}
CastCreateFirestoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create firestone") {}
};
class CastCurseOfAgonyAction : public CastDebuffSpellAction
class CastCreateSpellstoneAction : public CastBuffSpellAction
{
public:
CastCurseOfAgonyAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of agony", true) {}
CastCreateSpellstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create spellstone") {}
};
class CastCurseOfWeaknessAction : public CastDebuffSpellAction
class CastCreateSoulstoneAction : public CastBuffSpellAction
{
public:
CastCurseOfWeaknessAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of weakness") {}
CastCreateSoulstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create soulstone") {}
};
class CastCorruptionAction : public CastDebuffSpellAction
class UseSoulstoneSelfAction : public UseSpellItemAction
{
public:
CastCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "corruption", true) {}
bool isUseful() override
{
return CastDebuffSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
UseSoulstoneSelfAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction
class UseSoulstoneMasterAction : public UseSpellItemAction
{
public:
CastCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "corruption", true) {}
bool isUseful() override
{
return CastDebuffSpellOnAttackerAction::isUseful() &&
!botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
UseSoulstoneMasterAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction
class UseSoulstoneTankAction : public UseSpellItemAction
{
public:
CastCurseOfAgonyOnAttackerAction(PlayerbotAI* botAI)
: CastDebuffSpellOnAttackerAction(botAI, "curse of agony", true)
{
}
UseSoulstoneTankAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
class UseSoulstoneHealerAction : public UseSpellItemAction
{
public:
UseSoulstoneHealerAction(PlayerbotAI* botAI) : UseSpellItemAction(botAI, "soulstone") {}
bool Execute(Event event) override;
};
// Summoning Spells
class CastSummonVoidwalkerAction : public CastBuffSpellAction
{
public:
@@ -124,41 +123,293 @@ class CastSummonSuccubusAction : public CastBuffSpellAction
public:
CastSummonSuccubusAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon succubus") {}
};
class CastCreateHealthstoneAction : public CastBuffSpellAction
class CastFelDominationAction : public CastBuffSpellAction
{
public:
CastCreateHealthstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create healthstone") {}
CastFelDominationAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "fel domination") {}
};
class CastCreateFirestoneAction : public CastBuffSpellAction
// CC and Pet Spells
class CastBanishOnCcAction : public CastCrowdControlSpellAction
{
public:
CastCreateFirestoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create firestone") {}
CastBanishOnCcAction(PlayerbotAI* botAI) : CastCrowdControlSpellAction(botAI, "banish") {}
bool isPossible() override;
};
class CastCreateSpellstoneAction : public CastBuffSpellAction
class CastFearOnCcAction : public CastCrowdControlSpellAction
{
public:
CastCreateSpellstoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create spellstone") {}
CastFearOnCcAction(PlayerbotAI* botAI) : CastCrowdControlSpellAction(botAI, "fear") {}
bool isPossible() override;
};
class CastBanishAction : public CastBuffSpellAction
class CastSpellLockAction : public CastSpellAction
{
public:
CastBanishAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "banish on cc") {}
Value<Unit*>* GetTargetValue() override;
bool Execute(Event event) override;
CastSpellLockAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "spell lock") {}
};
class CastDevourMagicPurgeAction : public CastSpellAction
{
public:
CastDevourMagicPurgeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "devour magic") {}
std::string const GetTargetName() override { return "current target"; }
};
class CastDevourMagicCleanseAction : public CastSpellAction
{
public:
CastDevourMagicCleanseAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "devour magic cleanse") {}
std::string const getName() override { return "cleanse magic on party"; }
};
// Utility Spells
class CastShadowWardAction : public CastBuffSpellAction
{
public:
CastShadowWardAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shadow ward") {}
};
class CastSoulshatterAction : public CastSpellAction
{
public:
CastSoulshatterAction(PlayerbotAI* ai) : CastSpellAction(ai, "soulshatter") {}
bool isUseful() override;
};
class CastLifeTapAction : public CastSpellAction
{
public:
CastLifeTapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "life tap") {}
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
};
class CastCurseOfWeaknessAction : public CastDebuffSpellAction
{
public:
CastCurseOfWeaknessAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of weakness") {}
};
class CastCurseOfTheElementsAction : public CastDebuffSpellAction
{
public:
CastCurseOfTheElementsAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "curse of the elements", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class DemonChargeAction : public CastSpellAction
{
public:
DemonChargeAction(PlayerbotAI* ai) : CastSpellAction(ai, "demon charge") {}
};
// Cooldown Spells
class CastMetamorphosisAction : public CastBuffSpellAction
{
public:
CastMetamorphosisAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "metamorphosis") {}
};
class CastDemonicEmpowermentAction : public CastBuffSpellAction
{
public:
CastDemonicEmpowermentAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demonic empowerment") {}
std::string const GetTargetName() override { return "pet target"; }
};
// DoT Spells
class CastCurseOfAgonyAction : public CastDebuffSpellAction
{
public:
CastCurseOfAgonyAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "curse of agony", true) {}
bool isUseful() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastCurseOfAgonyOnAttackerAction(PlayerbotAI* botAI)
: CastDebuffSpellOnAttackerAction(botAI, "curse of agony", true)
{
}
bool isUseful() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastCorruptionAction : public CastDebuffSpellAction
{
public:
CastCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "corruption", true) {}
bool isUseful() override
{
// Bypass TTL check and prevent casting if Seed of Corruption is present
return CastAuraSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "corruption", true) {}
bool isUseful() override
{
// Bypass TTL check and prevent casting if Seed of Corruption is present
return CastAuraSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CastImmolateAction : public CastDebuffSpellAction
{
public:
CastImmolateAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "immolate", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastImmolateOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastImmolateOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "immolate", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastUnstableAfflictionAction : public CastDebuffSpellAction
{
public:
CastUnstableAfflictionAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "unstable affliction", true) {}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
class CastUnstableAfflictionOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastUnstableAfflictionOnAttackerAction(PlayerbotAI* ai)
: CastDebuffSpellOnAttackerAction(ai, "unstable affliction", true)
{
}
bool isUseful() override
{
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
};
// Damage Spells
class CastShadowBoltAction : public CastSpellAction
{
public:
CastShadowBoltAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shadow bolt") {}
};
class CastDrainSoulAction : public CastSpellAction
{
public:
CastDrainSoulAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain soul") {}
bool isUseful() override;
};
class CastDrainManaAction : public CastSpellAction
{
public:
CastDrainManaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain mana") {}
};
class CastDrainLifeAction : public CastSpellAction
{
public:
CastDrainLifeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "drain life") {}
};
class CastConflagrateAction : public CastSpellAction
{
public:
CastConflagrateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "conflagrate") {}
};
class CastIncinerateAction : public CastSpellAction
{
public:
CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {}
};
class CastHauntAction : public CastSpellAction
{
public:
CastHauntAction(PlayerbotAI* ai) : CastSpellAction(ai, "haunt") {}
};
class CastSoulFireAction : public CastSpellAction
{
public:
CastSoulFireAction(PlayerbotAI* ai) : CastSpellAction(ai, "soul fire") {}
};
class CastShadowburnAction : public CastSpellAction
{
public:
CastShadowburnAction(PlayerbotAI* ai) : CastSpellAction(ai, "shadowburn") {}
};
class CastChaosBoltAction : public CastSpellAction
{
public:
CastChaosBoltAction(PlayerbotAI* ai) : CastSpellAction(ai, "chaos bolt") {}
};
class CastSearingPainAction : public CastSpellAction
{
public:
CastSearingPainAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "searing pain") {}
};
// AoE Spells
class CastSeedOfCorruptionAction : public CastDebuffSpellAction
{
public:
CastSeedOfCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "seed of corruption", true, 0) {}
bool isUseful() override
{
return CastDebuffSpellAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true);
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
};
@@ -172,7 +423,8 @@ public:
}
bool isUseful() override
{
return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true);
// Bypass TTL check
return CastAuraSpellAction::isUseful();
}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
};
@@ -182,6 +434,22 @@ class CastRainOfFireAction : public CastSpellAction
public:
CastRainOfFireAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "rain of fire") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
};
class CastHellfireAction : public CastSpellAction
{
public:
CastHellfireAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "hellfire") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
};
class CastShadowflameAction : public CastSpellAction
{
public:
CastShadowflameAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shadowflame") {}
bool isUseful() override;
};
class CastShadowfuryAction : public CastSpellAction
@@ -190,125 +458,17 @@ public:
CastShadowfuryAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shadowfury") {}
};
class CastImmolateAction : public CastDebuffSpellAction
class CastImmolationAuraAction : public CastSpellAction
{
public:
CastImmolateAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "immolate", true) {}
};
class CastImmolateOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastImmolateOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "immolate", true) {}
};
class CastConflagrateAction : public CastSpellAction
{
public:
CastConflagrateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "conflagrate") {}
};
class CastIncinirateAction : public CastSpellAction
{
public:
CastIncinirateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "incinirate") {}
};
class CastFearAction : public CastDebuffSpellAction
{
public:
CastFearAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "fear") {}
};
class CastFearOnCcAction : public CastBuffSpellAction
{
public:
CastFearOnCcAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "fear on cc") {}
Value<Unit*>* GetTargetValue() override;
bool Execute(Event event) override;
bool isPossible() override;
CastImmolationAuraAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "immolation aura") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
bool isUseful() override;
};
class CastLifeTapAction : public CastSpellAction
class ShadowCleaveAction : public CastMeleeSpellAction
{
public:
CastLifeTapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "life tap") {}
std::string const GetTargetName() override { return "self target"; }
bool isUseful() override;
};
class CastAmplifyCurseAction : public CastBuffSpellAction
{
public:
CastAmplifyCurseAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "amplify curse") {}
};
class CastSiphonLifeAction : public CastDebuffSpellAction
{
public:
CastSiphonLifeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "siphon life", true) {}
};
class CastSiphonLifeOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastSiphonLifeOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "siphon life") {}
};
class CastUnstableAfflictionAction : public CastDebuffSpellAction
{
public:
CastUnstableAfflictionAction(PlayerbotAI* ai) : CastDebuffSpellAction(ai, "unstable affliction", true) {}
};
class CastHauntAction : public CastSpellAction
{
public:
CastHauntAction(PlayerbotAI* ai) : CastSpellAction(ai, "haunt") {}
};
class CastDemonicEmpowermentAction : public CastBuffSpellAction
{
public:
CastDemonicEmpowermentAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demonic empowerment") {}
std::string const GetTargetName() override { return "pet target"; }
};
class CastMetamorphosisAction : public CastBuffSpellAction
{
public:
CastMetamorphosisAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "metamorphosis") {}
};
class CastUnstableAfflictionOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastUnstableAfflictionOnAttackerAction(PlayerbotAI* ai)
: CastDebuffSpellOnAttackerAction(ai, "unstable affliction", true)
{
}
};
class CastSoulFireAction : public CastSpellAction
{
public:
CastSoulFireAction(PlayerbotAI* ai) : CastSpellAction(ai, "soul fire") {}
};
class CastIncinerateAction : public CastSpellAction
{
public:
CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {}
};
class UseSoulstoneAction : public UseSpellItemAction
{
public:
UseSoulstoneAction(PlayerbotAI* ai) : UseSpellItemAction(ai, "soulstone") {}
Unit* GetTarget() override;
ShadowCleaveAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "shadow cleave") {}
};
#endif

View File

@@ -4,7 +4,10 @@
*/
#include "WarlockAiObjectContext.h"
#include "AfflictionWarlockStrategy.h"
#include "DemonologyWarlockStrategy.h"
#include "DestructionWarlockStrategy.h"
#include "TankWarlockStrategy.h"
#include "DpsWarlockStrategy.h"
#include "GenericTriggers.h"
#include "GenericWarlockNonCombatStrategy.h"
@@ -12,7 +15,6 @@
#include "Playerbots.h"
#include "PullStrategy.h"
#include "Strategy.h"
#include "TankWarlockStrategy.h"
#include "UseItemAction.h"
#include "WarlockActions.h"
#include "WarlockTriggers.h"
@@ -21,24 +23,40 @@ class WarlockStrategyFactoryInternal : public NamedObjectContext<Strategy>
{
public:
WarlockStrategyFactoryInternal()
{
{
creators["nc"] = &WarlockStrategyFactoryInternal::nc;
creators["pull"] = &WarlockStrategyFactoryInternal::pull;
creators["aoe"] = &WarlockStrategyFactoryInternal::aoe;
creators["dps debuff"] = &WarlockStrategyFactoryInternal::dps_debuff;
creators["boost"] = &WarlockStrategyFactoryInternal::boost;
creators["cc"] = &WarlockStrategyFactoryInternal::cc;
creators["pet"] = &WarlockStrategyFactoryInternal::pet;
creators["affli"] = &WarlockStrategyFactoryInternal::affliction;
creators["affli aoe"] = &WarlockStrategyFactoryInternal::affliction_aoe;
creators["demo"] = &WarlockStrategyFactoryInternal::demonology;
creators["demo aoe"] = &WarlockStrategyFactoryInternal::demonology_aoe;
creators["destro"] = &WarlockStrategyFactoryInternal::destruction;
creators["destro aoe"] = &WarlockStrategyFactoryInternal::destruction_aoe;
creators["meta melee"] = &WarlockStrategyFactoryInternal::meta_melee_aoe;
creators["dps"] = &WarlockStrategyFactoryInternal::dps;
creators["aoe"] = &WarlockStrategyFactoryInternal::aoe;
creators["curse of elements"] = &WarlockStrategyFactoryInternal::curse_of_elements;
}
private:
static Strategy* pet(PlayerbotAI* botAI) { return new WarlockPetStrategy(botAI); }
static Strategy* nc(PlayerbotAI* botAI) { return new GenericWarlockNonCombatStrategy(botAI); }
static Strategy* aoe(PlayerbotAI* botAI) { return new DpsAoeWarlockStrategy(botAI); }
static Strategy* dps_debuff(PlayerbotAI* botAI) { return new DpsWarlockDebuffStrategy(botAI); }
static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "shoot"); }
static Strategy* boost(PlayerbotAI* botAI) { return new WarlockBoostStrategy(botAI); }
static Strategy* cc(PlayerbotAI* botAI) { return new WarlockCcStrategy(botAI); }
static Strategy* affliction(PlayerbotAI* botAI) { return new AfflictionWarlockStrategy(botAI); }
static Strategy* affliction_aoe(PlayerbotAI* botAI) { return new AfflictionWarlockAoeStrategy(botAI); }
static Strategy* demonology(PlayerbotAI* botAI) { return new DemonologyWarlockStrategy(botAI); }
static Strategy* demonology_aoe(PlayerbotAI* botAI) { return new DemonologyWarlockAoeStrategy(botAI); }
static Strategy* destruction(PlayerbotAI* botAI) { return new DestructionWarlockStrategy(botAI); }
static Strategy* destruction_aoe(PlayerbotAI* botAI) { return new DestructionWarlockAoeStrategy(botAI); }
static Strategy* meta_melee_aoe(PlayerbotAI* botAI) { return new MetaMeleeAoeStrategy(botAI); }
static Strategy* dps(PlayerbotAI* botAI) { return new DpsWarlockStrategy(botAI); }
static Strategy* aoe(PlayerbotAI* botAI) { return new DpsAoeWarlockStrategy(botAI); }
static Strategy* curse_of_elements(PlayerbotAI* botAI) { return new WarlockCurseOfTheElementsStrategy(botAI); }
};
class WarlockCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -46,13 +64,11 @@ class WarlockCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
public:
WarlockCombatStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["dps"] = &WarlockCombatStrategyFactoryInternal::dps;
creators["tank"] = &WarlockCombatStrategyFactoryInternal::tank;
}
private:
static Strategy* tank(PlayerbotAI* botAI) { return new TankWarlockStrategy(botAI); }
static Strategy* dps(PlayerbotAI* botAI) { return new DpsWarlockStrategy(botAI); }
};
class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
@@ -60,15 +76,27 @@ class NonCombatBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
public:
NonCombatBuffStrategyFactoryInternal() : NamedObjectContext<Strategy>(false, true)
{
creators["bdps"] = &NonCombatBuffStrategyFactoryInternal::felguard;
creators["bmana"] = &NonCombatBuffStrategyFactoryInternal::felhunter;
creators["bhealth"] = &NonCombatBuffStrategyFactoryInternal::imp;
creators["imp"] = &NonCombatBuffStrategyFactoryInternal::imp;
creators["voidwalker"] = &NonCombatBuffStrategyFactoryInternal::voidwalker;
creators["succubus"] = &NonCombatBuffStrategyFactoryInternal::succubus;
creators["felhunter"] = &NonCombatBuffStrategyFactoryInternal::felhunter;
creators["felguard"] = &NonCombatBuffStrategyFactoryInternal::felguard;
creators["ss self"] = &NonCombatBuffStrategyFactoryInternal::soulstone_self;
creators["ss master"] = &NonCombatBuffStrategyFactoryInternal::soulstone_master;
creators["ss tank"] = &NonCombatBuffStrategyFactoryInternal::soulstone_tank;
creators["ss healer"] = &NonCombatBuffStrategyFactoryInternal::soulstone_healer;
}
private:
static Strategy* imp(PlayerbotAI* ai) { return new SummonImpStrategy(ai); }
static Strategy* voidwalker(PlayerbotAI* ai) { return new SummonVoidwalkerStrategy(ai); }
static Strategy* succubus(PlayerbotAI* ai) { return new SummonSuccubusStrategy(ai); }
static Strategy* felhunter(PlayerbotAI* ai) { return new SummonFelhunterStrategy(ai); }
static Strategy* felguard(PlayerbotAI* ai) { return new SummonFelguardStrategy(ai); }
static Strategy* soulstone_self(PlayerbotAI* ai) { return new SoulstoneSelfStrategy(ai); }
static Strategy* soulstone_master(PlayerbotAI* ai) { return new SoulstoneMasterStrategy(ai); }
static Strategy* soulstone_tank(PlayerbotAI* ai) { return new SoulstoneTankStrategy(ai); }
static Strategy* soulstone_healer(PlayerbotAI* ai) { return new SoulstoneHealerStrategy(ai); }
};
class WarlockTriggerFactoryInternal : public NamedObjectContext<Trigger>
@@ -78,64 +106,73 @@ public:
{
creators["shadow trance"] = &WarlockTriggerFactoryInternal::shadow_trance;
creators["demon armor"] = &WarlockTriggerFactoryInternal::demon_armor;
creators["soul link"] = &WarlockTriggerFactoryInternal::soul_link;
creators["no healthstone"] = &WarlockTriggerFactoryInternal::HasHealthstone;
creators["no firestone"] = &WarlockTriggerFactoryInternal::HasFirestone;
creators["no spellstone"] = &WarlockTriggerFactoryInternal::HasSpellstone;
creators["no soulstone"] = &WarlockTriggerFactoryInternal::HasSoulstone;
creators["firestone"] = &WarlockTriggerFactoryInternal::firestone;
creators["spellstone"] = &WarlockTriggerFactoryInternal::spellstone;
creators["soulstone"] = &WarlockTriggerFactoryInternal::soulstone;
creators["banish"] = &WarlockTriggerFactoryInternal::banish;
creators["fear"] = &WarlockTriggerFactoryInternal::fear;
creators["spell lock"] = &WarlockTriggerFactoryInternal::spell_lock;
creators["devour magic purge"] = &WarlockTriggerFactoryInternal::devour_magic_purge;
creators["devour magic cleanse"] = &WarlockTriggerFactoryInternal::devour_magic_cleanse;
creators["backlash"] = &WarlockTriggerFactoryInternal::backlash;
creators["corruption"] = &WarlockTriggerFactoryInternal::corruption;
creators["corruption on attacker"] = &WarlockTriggerFactoryInternal::corruption_on_attacker;
creators["curse of agony"] = &WarlockTriggerFactoryInternal::curse_of_agony;
creators["curse of agony on attacker"] = &WarlockTriggerFactoryInternal::curse_of_agony_on_attacker;
creators["banish"] = &WarlockTriggerFactoryInternal::banish;
creators["spellstone"] = &WarlockTriggerFactoryInternal::spellstone;
creators["backlash"] = &WarlockTriggerFactoryInternal::backlash;
creators["fear"] = &WarlockTriggerFactoryInternal::fear;
creators["immolate"] = &WarlockTriggerFactoryInternal::immolate;
creators["amplify curse"] = &WarlockTriggerFactoryInternal::amplify_curse;
creators["siphon life"] = &WarlockTriggerFactoryInternal::siphon_life;
creators["siphon life on attacker"] = &WarlockTriggerFactoryInternal::siphon_life_on_attacker;
creators["immolate on attacker"] = &WarlockTriggerFactoryInternal::immolate_on_attacker;
creators["unstable affliction"] = &WarlockTriggerFactoryInternal::unstable_affliction;
creators["unstable affliction on attacker"] = &WarlockTriggerFactoryInternal::unstable_affliction_on_attacker;
creators["haunt"] = &WarlockTriggerFactoryInternal::haunt;
creators["curse of the elements"] = &WarlockTriggerFactoryInternal::curse_of_the_elements;
creators["decimation"] = &WarlockTriggerFactoryInternal::decimation;
creators["life tap"] = &WarlockTriggerFactoryInternal::life_tap;
creators["life tap glyph buff"] = &WarlockTriggerFactoryInternal::life_tap_glyph_buff;
creators["molten core"] = &WarlockTriggerFactoryInternal::molten_core;
creators["metamorphosis"] = &WarlockTriggerFactoryInternal::metamorphosis;
creators["demonic empowerment"] = &WarlockTriggerFactoryInternal::demonic_empowerment;
creators["immolation aura active"] = &WarlockTriggerFactoryInternal::immolation_aura_active;
}
private:
static Trigger* amplify_curse(PlayerbotAI* botAI) { return new AmplifyCurseTrigger(botAI); }
static Trigger* shadow_trance(PlayerbotAI* botAI) { return new ShadowTranceTrigger(botAI); }
static Trigger* demon_armor(PlayerbotAI* botAI) { return new DemonArmorTrigger(botAI); }
static Trigger* soul_link(PlayerbotAI* botAI) { return new SoulLinkTrigger(botAI); }
static Trigger* HasHealthstone(PlayerbotAI* botAI) { return new HasHealthstoneTrigger(botAI); }
static Trigger* HasFirestone(PlayerbotAI* botAI) { return new HasFirestoneTrigger(botAI); }
static Trigger* HasSpellstone(PlayerbotAI* botAI) { return new HasSpellstoneTrigger(botAI); }
static Trigger* HasSoulstone(PlayerbotAI* botAI) { return new HasSoulstoneTrigger(botAI); }
static Trigger* firestone(PlayerbotAI* botAI) { return new FirestoneTrigger(botAI); }
static Trigger* spellstone(PlayerbotAI* botAI) { return new SpellstoneTrigger(botAI); }
static Trigger* soulstone(PlayerbotAI* botAI) { return new SoulstoneTrigger(botAI); }
static Trigger* corruption(PlayerbotAI* botAI) { return new CorruptionTrigger(botAI); }
static Trigger* corruption_on_attacker(PlayerbotAI* botAI) { return new CorruptionOnAttackerTrigger(botAI); }
static Trigger* siphon_life(PlayerbotAI* botAI) { return new SiphonLifeTrigger(botAI); }
static Trigger* siphon_life_on_attacker(PlayerbotAI* botAI) { return new SiphonLifeOnAttackerTrigger(botAI); }
static Trigger* curse_of_agony(PlayerbotAI* botAI) { return new CurseOfAgonyTrigger(botAI); }
static Trigger* curse_of_agony_on_attacker(PlayerbotAI* botAI)
{
return new CastCurseOfAgonyOnAttackerTrigger(botAI);
}
static Trigger* curse_of_agony_on_attacker(PlayerbotAI* botAI) { return new CurseOfAgonyOnAttackerTrigger(botAI); }
static Trigger* banish(PlayerbotAI* botAI) { return new BanishTrigger(botAI); }
static Trigger* spellstone(PlayerbotAI* botAI) { return new SpellstoneTrigger(botAI); }
static Trigger* backlash(PlayerbotAI* botAI) { return new BacklashTrigger(botAI); }
static Trigger* fear(PlayerbotAI* botAI) { return new FearTrigger(botAI); }
static Trigger* spell_lock(PlayerbotAI* botAI) { return new SpellLockInterruptSpellTrigger(botAI); }
static Trigger* devour_magic_purge(PlayerbotAI* botAI) { return new DevourMagicPurgeTrigger(botAI); }
static Trigger* devour_magic_cleanse(PlayerbotAI* botAI) { return new DevourMagicCleanseTrigger(botAI); }
static Trigger* backlash(PlayerbotAI* botAI) { return new BacklashTrigger(botAI); }
static Trigger* immolate(PlayerbotAI* botAI) { return new ImmolateTrigger(botAI); }
static Trigger* immolate_on_attacker(PlayerbotAI* ai) { return new ImmolateOnAttackerTrigger(ai); }
static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(ai); }
static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai)
{
return new UnstableAfflictionOnAttackerTrigger(ai);
}
static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new UnstableAfflictionOnAttackerTrigger(ai); }
static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); }
static Trigger* curse_of_the_elements(PlayerbotAI* ai) { return new CurseOfTheElementsTrigger(ai); }
static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); }
static Trigger* life_tap(PlayerbotAI* ai) { return new LifeTapTrigger(ai); }
static Trigger* life_tap_glyph_buff(PlayerbotAI* ai) { return new LifeTapGlyphBuffTrigger(ai); }
static Trigger* molten_core(PlayerbotAI* ai) { return new MoltenCoreTrigger(ai); }
static Trigger* metamorphosis(PlayerbotAI* ai) { return new MetamorphosisTrigger(ai); }
static Trigger* demonic_empowerment(PlayerbotAI* ai) { return new DemonicEmpowermentTrigger(ai); }
static Trigger* immolation_aura_active(PlayerbotAI* ai) { return new ImmolationAuraActiveTrigger(ai); }
};
class WarlockAiObjectContextInternal : public NamedObjectContext<Action>
@@ -146,104 +183,125 @@ public:
creators["fel armor"] = &WarlockAiObjectContextInternal::fel_armor;
creators["demon armor"] = &WarlockAiObjectContextInternal::demon_armor;
creators["demon skin"] = &WarlockAiObjectContextInternal::demon_skin;
creators["soul link"] = &WarlockAiObjectContextInternal::soul_link;
creators["create healthstone"] = &WarlockAiObjectContextInternal::create_healthstone;
creators["create firestone"] = &WarlockAiObjectContextInternal::create_firestone;
creators["create spellstone"] = &WarlockAiObjectContextInternal::create_spellstone;
creators["create soulstone"] = &WarlockAiObjectContextInternal::create_soulstone;
creators["firestone"] = &WarlockAiObjectContextInternal::firestone;
creators["spellstone"] = &WarlockAiObjectContextInternal::spellstone;
creators["soulstone self"] = &WarlockAiObjectContextInternal::soulstone_self;
creators["soulstone master"] = &WarlockAiObjectContextInternal::soulstone_master;
creators["soulstone tank"] = &WarlockAiObjectContextInternal::soulstone_tank;
creators["soulstone healer"] = &WarlockAiObjectContextInternal::soulstone_healer;
creators["summon voidwalker"] = &WarlockAiObjectContextInternal::summon_voidwalker;
creators["summon felguard"] = &WarlockAiObjectContextInternal::summon_felguard;
creators["summon felhunter"] = &WarlockAiObjectContextInternal::summon_felhunter;
creators["summon succubus"] = &WarlockAiObjectContextInternal::summon_succubus;
creators["summon imp"] = &WarlockAiObjectContextInternal::summon_imp;
creators["fel domination"] = &WarlockAiObjectContextInternal::fel_domination;
creators["immolate"] = &WarlockAiObjectContextInternal::immolate;
creators["immolate on attacker"] = &WarlockAiObjectContextInternal::immolate_on_attacker;
creators["corruption"] = &WarlockAiObjectContextInternal::corruption;
creators["corruption on attacker"] = &WarlockAiObjectContextInternal::corruption_on_attacker;
creators["siphon life"] = &WarlockAiObjectContextInternal::siphon_life;
creators["siphon life on attacker"] = &WarlockAiObjectContextInternal::siphon_life_on_attacker;
creators["curse of agony"] = &WarlockAiObjectContextInternal::curse_of_agony;
creators["curse of agony on attacker"] = &WarlockAiObjectContextInternal::curse_of_agony_on_attacker;
creators["shadow bolt"] = &WarlockAiObjectContextInternal::shadow_bolt;
creators["drain soul"] = &WarlockAiObjectContextInternal::drain_soul;
creators["drain mana"] = &WarlockAiObjectContextInternal::drain_mana;
creators["drain life"] = &WarlockAiObjectContextInternal::drain_life;
creators["banish"] = &WarlockAiObjectContextInternal::banish;
creators["banish on cc"] = &WarlockAiObjectContextInternal::banish_on_cc;
creators["fear on cc"] = &WarlockAiObjectContextInternal::fear_on_cc;
creators["spell lock"] = &WarlockAiObjectContextInternal::spell_lock;
creators["devour magic purge"] = &WarlockAiObjectContextInternal::devour_magic_purge;
creators["devour magic cleanse"] = &WarlockAiObjectContextInternal::devour_magic_cleanse;
creators["seed of corruption"] = &WarlockAiObjectContextInternal::seed_of_corruption;
creators["seed of corruption on attacker"] = &WarlockAiObjectContextInternal::seed_of_corruption_on_attacker;
creators["rain of fire"] = &WarlockAiObjectContextInternal::rain_of_fire;
creators["hellfire"] = &WarlockAiObjectContextInternal::hellfire;
creators["shadowfury"] = &WarlockAiObjectContextInternal::shadowfury;
creators["life tap"] = &WarlockAiObjectContextInternal::life_tap;
creators["fear"] = &WarlockAiObjectContextInternal::fear;
creators["fear on cc"] = &WarlockAiObjectContextInternal::fear_on_cc;
creators["incinirate"] = &WarlockAiObjectContextInternal::incinirate;
creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate;
creators["conflagrate"] = &WarlockAiObjectContextInternal::conflagrate;
creators["amplify curse"] = &WarlockAiObjectContextInternal::amplify_curse;
creators["immolate on attacker"] = &WarlockAiObjectContextInternal::immolate_on_attacker;
creators["unstable affliction"] = &WarlockAiObjectContextInternal::unstable_affliction;
creators["unstable affliction on attacker"] = &WarlockAiObjectContextInternal::unstable_affliction_on_attacker;
creators["haunt"] = &WarlockAiObjectContextInternal::haunt;
creators["curse of the elements"] = &WarlockAiObjectContextInternal::curse_of_the_elements;
creators["demonic empowerment"] = &WarlockAiObjectContextInternal::demonic_empowerment;
creators["metamorphosis"] = &WarlockAiObjectContextInternal::metamorphosis;
creators["soul fire"] = &WarlockAiObjectContextInternal::soul_fire;
creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate;
creators["soulstone"] = &WarlockAiObjectContextInternal::soulstone;
}
creators["demon charge"] = &WarlockAiObjectContextInternal::demon_charge;
creators["shadow cleave"] = &WarlockAiObjectContextInternal::shadow_cleave;
creators["shadowburn"] = &WarlockAiObjectContextInternal::shadowburn;
creators["shadowflame"] = &WarlockAiObjectContextInternal::shadowflame;
creators["immolation aura"] = &WarlockAiObjectContextInternal::immolation_aura;
creators["chaos bolt"] = &WarlockAiObjectContextInternal::chaos_bolt;
creators["soulshatter"] = &WarlockAiObjectContextInternal::soulshatter;
creators["searing pain"] = WarlockAiObjectContextInternal::searing_pain;
creators["shadow ward"] = &WarlockAiObjectContextInternal::shadow_ward;
}
private:
static Action* amplify_curse(PlayerbotAI* botAI) { return new CastAmplifyCurseAction(botAI); }
static Action* conflagrate(PlayerbotAI* botAI) { return new CastConflagrateAction(botAI); }
static Action* incinirate(PlayerbotAI* botAI) { return new CastIncinirateAction(botAI); }
static Action* fear_on_cc(PlayerbotAI* botAI) { return new CastFearOnCcAction(botAI); }
static Action* fear(PlayerbotAI* botAI) { return new CastFearAction(botAI); }
static Action* incinerate(PlayerbotAI* botAI) { return new CastIncinerateAction(botAI); }
static Action* immolate(PlayerbotAI* botAI) { return new CastImmolateAction(botAI); }
static Action* summon_imp(PlayerbotAI* botAI) { return new CastSummonImpAction(botAI); }
static Action* summon_succubus(PlayerbotAI* botAI) { return new CastSummonSuccubusAction(botAI); }
static Action* immolate_on_attacker(PlayerbotAI* botAI) { return new CastImmolateOnAttackerAction(botAI); }
static Action* fel_armor(PlayerbotAI* botAI) { return new CastFelArmorAction(botAI); }
static Action* demon_armor(PlayerbotAI* botAI) { return new CastDemonArmorAction(botAI); }
static Action* demon_skin(PlayerbotAI* botAI) { return new CastDemonSkinAction(botAI); }
static Action* soul_link(PlayerbotAI* botAI) { return new CastSoulLinkAction(botAI); }
static Action* create_healthstone(PlayerbotAI* botAI) { return new CastCreateHealthstoneAction(botAI); }
static Action* create_firestone(PlayerbotAI* botAI) { return new CastCreateFirestoneAction(botAI); }
static Action* create_spellstone(PlayerbotAI* botAI) { return new CastCreateSpellstoneAction(botAI); }
static Action* create_soulstone(PlayerbotAI* botAI) { return new CastCreateSoulstoneAction(botAI); }
static Action* firestone(PlayerbotAI* botAI) { return new UseSpellItemAction(botAI, "firestone", true); }
static Action* spellstone(PlayerbotAI* botAI) { return new UseSpellItemAction(botAI, "spellstone", true); }
static Action* soulstone_self(PlayerbotAI* botAI) { return new UseSoulstoneSelfAction(botAI); }
static Action* soulstone_master(PlayerbotAI* botAI) { return new UseSoulstoneMasterAction(botAI); }
static Action* soulstone_tank(PlayerbotAI* botAI) { return new UseSoulstoneTankAction(botAI); }
static Action* soulstone_healer(PlayerbotAI* botAI) { return new UseSoulstoneHealerAction(botAI); }
static Action* summon_voidwalker(PlayerbotAI* botAI) { return new CastSummonVoidwalkerAction(botAI); }
static Action* summon_felguard(PlayerbotAI* botAI) { return new CastSummonFelguardAction(botAI); }
static Action* summon_felhunter(PlayerbotAI* botAI) { return new CastSummonFelhunterAction(botAI); }
static Action* summon_imp(PlayerbotAI* botAI) { return new CastSummonImpAction(botAI); }
static Action* summon_succubus(PlayerbotAI* botAI) { return new CastSummonSuccubusAction(botAI); }
static Action* fel_domination(PlayerbotAI* botAI) { return new CastFelDominationAction(botAI); }
static Action* corruption(PlayerbotAI* botAI) { return new CastCorruptionAction(botAI); }
static Action* corruption_on_attacker(PlayerbotAI* botAI) { return new CastCorruptionOnAttackerAction(botAI); }
static Action* siphon_life(PlayerbotAI* botAI) { return new CastSiphonLifeAction(botAI); }
static Action* siphon_life_on_attacker(PlayerbotAI* botAI) { return new CastSiphonLifeOnAttackerAction(botAI); }
static Action* curse_of_agony(PlayerbotAI* botAI) { return new CastCurseOfAgonyAction(botAI); }
static Action* curse_of_agony_on_attacker(PlayerbotAI* botAI)
{
return new CastCurseOfAgonyOnAttackerAction(botAI);
}
static Action* curse_of_agony_on_attacker(PlayerbotAI* botAI) { return new CastCurseOfAgonyOnAttackerAction(botAI); }
static Action* shadow_bolt(PlayerbotAI* botAI) { return new CastShadowBoltAction(botAI); }
static Action* drain_soul(PlayerbotAI* botAI) { return new CastDrainSoulAction(botAI); }
static Action* drain_mana(PlayerbotAI* botAI) { return new CastDrainManaAction(botAI); }
static Action* drain_life(PlayerbotAI* botAI) { return new CastDrainLifeAction(botAI); }
static Action* banish(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
static Action* banish_on_cc(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
static Action* banish_on_cc(PlayerbotAI* botAI) { return new CastBanishOnCcAction(botAI); }
static Action* fear_on_cc(PlayerbotAI* botAI) { return new CastFearOnCcAction(botAI); }
static Action* spell_lock(PlayerbotAI* botAI) { return new CastSpellLockAction(botAI); }
static Action* devour_magic_purge(PlayerbotAI* botAI) { return new CastDevourMagicPurgeAction(botAI); }
static Action* devour_magic_cleanse(PlayerbotAI* botAI) { return new CastDevourMagicCleanseAction(botAI); }
static Action* seed_of_corruption(PlayerbotAI* botAI) { return new CastSeedOfCorruptionAction(botAI); }
static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI)
{
return new CastSeedOfCorruptionOnAttackerAction(botAI);
}
static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI) { return new CastSeedOfCorruptionOnAttackerAction(botAI); }
static Action* rain_of_fire(PlayerbotAI* botAI) { return new CastRainOfFireAction(botAI); }
static Action* hellfire(PlayerbotAI* botAI) { return new CastHellfireAction(botAI); }
static Action* shadowfury(PlayerbotAI* botAI) { return new CastShadowfuryAction(botAI); }
static Action* life_tap(PlayerbotAI* botAI) { return new CastLifeTapAction(botAI); }
static Action* immolate_on_attacker(PlayerbotAI* ai) { return new CastImmolateOnAttackerAction(ai); }
static Action* unstable_affliction(PlayerbotAI* ai) { return new CastUnstableAfflictionAction(ai); }
static Action* unstable_affliction_on_attacker(PlayerbotAI* ai)
{
return new CastUnstableAfflictionOnAttackerAction(ai);
}
static Action* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new CastUnstableAfflictionOnAttackerAction(ai); }
static Action* haunt(PlayerbotAI* ai) { return new CastHauntAction(ai); }
static Action* curse_of_the_elements(PlayerbotAI* ai) { return new CastCurseOfTheElementsAction(ai); }
static Action* demonic_empowerment(PlayerbotAI* ai) { return new CastDemonicEmpowermentAction(ai); }
static Action* metamorphosis(PlayerbotAI* ai) { return new CastMetamorphosisAction(ai); }
static Action* soul_fire(PlayerbotAI* ai) { return new CastSoulFireAction(ai); }
static Action* incinerate(PlayerbotAI* ai) { return new CastIncinerateAction(ai); }
static Action* soulstone(PlayerbotAI* ai) { return new UseSoulstoneAction(ai); }
static Action* demon_charge(PlayerbotAI* ai) { return new DemonChargeAction(ai); }
static Action* shadow_cleave(PlayerbotAI* ai) { return new ShadowCleaveAction(ai); }
static Action* shadowburn(PlayerbotAI* ai) { return new CastShadowburnAction(ai); }
static Action* shadowflame(PlayerbotAI* botAI) { return new CastShadowflameAction(botAI); }
static Action* immolation_aura(PlayerbotAI* botAI) { return new CastImmolationAuraAction(botAI); }
static Action* chaos_bolt(PlayerbotAI* botAI) { return new CastChaosBoltAction(botAI); }
static Action* soulshatter(PlayerbotAI* botAI) { return new CastSoulshatterAction(botAI);}
static Action* searing_pain(PlayerbotAI* botAI) { return new CastSearingPainAction(botAI); }
static Action* shadow_ward(PlayerbotAI* botAI) { return new CastShadowWardAction(botAI); }
};
WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)

View File

@@ -4,10 +4,34 @@
*/
#include "WarlockTriggers.h"
#include "GenericTriggers.h"
#include "Playerbots.h"
bool SpellstoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; }
bool FirestoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; }
bool WarlockConjuredItemTrigger::IsActive()
{
return ItemCountTrigger::IsActive() && AI_VALUE2(uint32, "item count", "soul shard") > 0;
}
// Checks if the target marked with the moon icon can be banished
bool BanishTrigger::IsActive()
{
Unit* ccTarget = context->GetValue<Unit*>("cc target", "banish")->Get();
Unit* moonTarget = context->GetValue<Unit*>("rti cc target")->Get();
return ccTarget && moonTarget && ccTarget == moonTarget && HasCcTargetTrigger::IsActive();
}
// Checks if the target marked with the moon icon can be feared
bool FearTrigger::IsActive()
{
Unit* ccTarget = context->GetValue<Unit*>("cc target", "fear")->Get();
Unit* moonTarget = context->GetValue<Unit*>("rti cc target")->Get();
return ccTarget && moonTarget && ccTarget == moonTarget && HasCcTargetTrigger::IsActive();
}
bool DemonArmorTrigger::IsActive()
{
Unit* target = GetTarget();
@@ -15,30 +39,18 @@ bool DemonArmorTrigger::IsActive()
!botAI->HasAura("fel armor", target);
}
bool SpellstoneTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(uint32, "item count", getName()) > 0; }
bool WarlockConjuredItemTrigger::IsActive()
bool SoulLinkTrigger::IsActive()
{
return ItemCountTrigger::IsActive() && AI_VALUE2(uint32, "item count", "soul shard") > 0;
Unit* target = GetTarget();
return !botAI->HasAura("soul link", target);
}
bool ImmolateOnAttackerTrigger::IsActive()
bool DemonicEmpowermentTrigger::IsActive()
{
return DebuffOnAttackerTrigger::IsActive() &&
// !botAI->HasAura("immolate", GetTarget(), false, true) &&
!botAI->HasAura("unstable affliction", GetTarget(), false, true);
}
bool UnstableAfflictionTrigger::IsActive()
{
return DebuffTrigger::IsActive() && !botAI->HasAura("immolate", GetTarget(), false, true);
// !botAI->HasAura("unstable affliction", GetTarget(), false, true);
}
bool UnstableAfflictionOnAttackerTrigger::IsActive()
{
return DebuffOnAttackerTrigger::IsActive() && !botAI->HasAura("immolate", GetTarget(), false, true);
// !botAI->HasAura("unstable affliction", GetTarget(), false, true);
Pet* pet = bot->GetPet();
if (!pet)
return false;
return !botAI->HasAura("demonic empowerment", pet);
}
bool DecimationTrigger::IsActive()
@@ -47,11 +59,51 @@ bool DecimationTrigger::IsActive()
return aura && aura->GetDuration() > 3000;
}
// Checks if the bot's mana is below 85% and health is above a low health threshold
bool LifeTapTrigger::IsActive()
{
if (AI_VALUE2(uint8, "health", "self target") <= sPlayerbotAIConfig->lowHealth)
return false;
if (!AI_VALUE2(bool, "has mana", "self target"))
return false;
if (AI_VALUE2(uint8, "mana", "self target") >= 85)
return false;
return true;
}
// Checks if the Life Tap Glyph buff is active
bool LifeTapGlyphBuffTrigger::IsActive()
{
// Check life tap glyph first
if (!botAI->HasAura(63320, bot))
return false;
return BuffTrigger::IsActive();
}
}
// Checks if the target has a conflicting debuff that is equal to Curse of the Elements
bool CurseOfTheElementsTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target || !target->IsAlive() || !target->IsInWorld())
return false;
// List of all spell IDs for Ebon Plague, Earth and Moon, and Curse of the Elements
static const uint32 CurseOfTheElementsExclusiveDebuffs[] = {// Ebon Plague
51735, 51734, 51726,
// Earth and Moon
48511, 48513, 48514,
// Curse of the Elements
1490, 11721, 11722, 27228, 47865};
// Check if target has any of the exclusive debuffs
for (uint32 spellId : CurseOfTheElementsExclusiveDebuffs)
{
if (target->HasAura(spellId))
return false;
}
// Use default BuffTrigger logic for the rest (only trigger if debuff is missing or expiring)
return BuffTrigger::IsActive();
}

View File

@@ -8,9 +8,13 @@
#include "GenericTriggers.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "CureTriggers.h"
class PlayerbotAI;
// Buff and Out of Combat Triggers
class DemonArmorTrigger : public BuffTrigger
{
public:
@@ -19,90 +23,50 @@ public:
bool IsActive() override;
};
class SoulLinkTrigger : public BuffTrigger
{
public:
SoulLinkTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "soul link") {}
bool IsActive() override;
};
class FirestoneTrigger : public BuffTrigger
{
public:
FirestoneTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "firestone") {}
bool IsActive() override;
};
class SpellstoneTrigger : public BuffTrigger
{
public:
SpellstoneTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "spellstone") {}
bool IsActive() override;
};
// DEBUFF_CHECKISOWNER_TRIGGER(CurseOfAgonyTrigger, "curse of agony");
class CurseOfAgonyTrigger : public DebuffTrigger
class HasSoulstoneTrigger : public Trigger
{
public:
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 20.0f) {}
HasSoulstoneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no soulstone") {}
bool IsActive() override { return AI_VALUE2(uint32, "item count", "soulstone") == 0; }
};
class CorruptionTrigger : public DebuffTrigger
class SoulstoneTrigger : public Trigger
{
public:
CorruptionTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "corruption", 1, true) {}
SoulstoneTrigger(PlayerbotAI* botAI) : Trigger(botAI, "soulstone") {}
bool IsActive() override
{
return DebuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
// Just check if we have a soulstone item available
return AI_VALUE2(uint32, "item count", "soulstone") > 0;
}
};
DEBUFF_CHECKISOWNER_TRIGGER(SiphonLifeTrigger, "siphon life");
class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) {}
bool IsActive() override
{
return DebuffOnAttackerTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CastCurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CastCurseOfAgonyOnAttackerTrigger(PlayerbotAI* botAI)
: DebuffOnAttackerTrigger(botAI, "curse of agony", true, 20.0f)
{
}
};
class SiphonLifeOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
SiphonLifeOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "siphon life") {}
};
DEBUFF_CHECKISOWNER_TRIGGER(ImmolateTrigger, "immolate");
class ImmolateOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
ImmolateOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "immolate") {}
virtual bool IsActive();
};
class ShadowTranceTrigger : public HasAuraTrigger
{
public:
ShadowTranceTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "shadow trance") {}
};
class BacklashTrigger : public HasAuraTrigger
{
public:
BacklashTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "backlash") {}
};
class BanishTrigger : public HasCcTargetTrigger
{
public:
BanishTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "banish") {}
};
class WarlockConjuredItemTrigger : public ItemCountTrigger
{
public:
WarlockConjuredItemTrigger(PlayerbotAI* botAI, std::string const item) : ItemCountTrigger(botAI, item, 1) {}
bool IsActive() override;
};
@@ -124,30 +88,114 @@ public:
HasHealthstoneTrigger(PlayerbotAI* botAI) : WarlockConjuredItemTrigger(botAI, "healthstone") {}
};
// CC and Pet Triggers
class BanishTrigger : public HasCcTargetTrigger
{
public:
BanishTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "banish") {}
bool IsActive() override;
};
class FearTrigger : public HasCcTargetTrigger
{
public:
FearTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "fear") {}
};
class AmplifyCurseTrigger : public BuffTrigger
{
public:
AmplifyCurseTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "amplify curse") {}
};
class UnstableAfflictionTrigger : public DebuffTrigger // SpellTrigger
{
public:
UnstableAfflictionTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "unstable affliction", 1, true) {}
bool IsActive() override;
};
class SpellLockInterruptSpellTrigger : public InterruptSpellTrigger
{
public:
SpellLockInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "spell lock") {}
};
class DevourMagicPurgeTrigger : public TargetAuraDispelTrigger
{
public:
DevourMagicPurgeTrigger(PlayerbotAI* botAI) : TargetAuraDispelTrigger(botAI, "devour magic", DISPEL_MAGIC) {}
};
class DevourMagicCleanseTrigger : public PartyMemberNeedCureTrigger
{
public:
DevourMagicCleanseTrigger(PlayerbotAI* botAI) : PartyMemberNeedCureTrigger(botAI, "devour magic", DISPEL_MAGIC) {}
};
// DoT/Debuff Triggers
class CurseOfAgonyTrigger : public DebuffTrigger
{
public:
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 0.5f) {}
bool IsActive() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
return BuffTrigger::IsActive();
}
};
class CurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CurseOfAgonyOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "curse of agony", true) {}
bool IsActive() override
{
if (botAI->HasStrategy(
"curse of elements", BOT_STATE_COMBAT)) // If Curse of the Elements strategy is active, do not cast Curse of Agony
return false;
return BuffTrigger::IsActive();
}
};
class CorruptionTrigger : public DebuffTrigger
{
public:
CorruptionTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "corruption", 1, true, 0.5f) {}
bool IsActive() override
{
return BuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) {}
bool IsActive() override
{
return BuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true);
}
};
class ImmolateTrigger : public DebuffTrigger
{
public:
ImmolateTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "immolate", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class ImmolateOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
ImmolateOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "immolate", true) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class UnstableAfflictionTrigger : public DebuffTrigger
{
public:
UnstableAfflictionTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "unstable affliction", 1, true, 0.5f) {}
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class UnstableAfflictionOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
UnstableAfflictionOnAttackerTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "unstable affliction", true) {}
bool IsActive() override;
bool IsActive() override { return BuffTrigger::IsActive(); }
};
class HauntTrigger : public DebuffTrigger
@@ -156,10 +204,20 @@ public:
HauntTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "haunt", 1, true, 0) {}
};
class DecimationTrigger : public HasAuraTrigger
class CurseOfTheElementsTrigger : public DebuffTrigger
{
public:
DecimationTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "decimation") {}
CurseOfTheElementsTrigger(PlayerbotAI* botAI)
: DebuffTrigger(botAI, "curse of the elements", 1, true, 0.5f) {}
bool IsActive() override;
};
// Proc/Cooldown Triggers
class LifeTapTrigger : public Trigger
{
public:
LifeTapTrigger(PlayerbotAI* ai) : Trigger(ai, "life tap") {}
bool IsActive() override;
};
@@ -170,15 +228,47 @@ public:
bool IsActive() override;
};
class MoltenCoreTrigger : public HasAuraTrigger
{
public:
MoltenCoreTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "molten core") {}
};
class MetamorphosisTrigger : public BoostTrigger
{
public:
MetamorphosisTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "metamorphosis") {}
};
class DemonicEmpowermentTrigger : public BuffTrigger
{
public:
DemonicEmpowermentTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "demonic empowerment") {}
bool IsActive() override;
};
class ImmolationAuraActiveTrigger : public HasAuraTrigger
{
public:
ImmolationAuraActiveTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "immolation aura") {}
};
class ShadowTranceTrigger : public HasAuraTrigger
{
public:
ShadowTranceTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "shadow trance") {}
};
class BacklashTrigger : public HasAuraTrigger
{
public:
BacklashTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "backlash") {}
};
class DecimationTrigger : public HasAuraTrigger
{
public:
DecimationTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "decimation") {}
bool IsActive() override;
};
class MoltenCoreTrigger : public HasAuraTrigger
{
public:
MoltenCoreTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "molten core") {}
};
#endif