mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Compare commits
166 Commits
eec2923076
...
5baba708e0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5baba708e0 | ||
|
|
e854e9beca | ||
|
|
fd34598e6a | ||
|
|
c61b311a1b | ||
|
|
fa3ffd13fa | ||
|
|
c4a0d01d34 | ||
|
|
0b41ab391f | ||
|
|
3f8aa0b6b3 | ||
|
|
2913db8964 | ||
|
|
59f82465e1 | ||
|
|
2bb0bc04b8 | ||
|
|
d7b29b5e73 | ||
|
|
3e1aa0c34f | ||
|
|
eada942a4e | ||
|
|
59d9bc6f78 | ||
|
|
9da99163a8 | ||
|
|
76dbf56227 | ||
|
|
1638bb1828 | ||
|
|
ba60fae9b6 | ||
|
|
f762053b79 | ||
|
|
c9dfee19d6 | ||
|
|
36a4b2a431 | ||
|
|
e820889965 | ||
|
|
9ac6dcbac6 | ||
|
|
e07f56d2a7 | ||
|
|
45a3189d4b | ||
|
|
6079863fce | ||
|
|
f90f365e94 | ||
|
|
343ab7ac30 | ||
|
|
666136ab34 | ||
|
|
b269fa3825 | ||
|
|
276d773ea9 | ||
|
|
180f45899c | ||
|
|
c194daa8a1 | ||
|
|
ac741cac80 | ||
|
|
f78e16c5d0 | ||
|
|
24b302496c | ||
|
|
0f612ab7a5 | ||
|
|
c586f141a8 | ||
|
|
f4c6177520 | ||
|
|
ee3f92c04a | ||
|
|
9bb86f35bc | ||
|
|
848bffac86 | ||
|
|
80a0e79cd2 | ||
|
|
6b6f61a89d | ||
|
|
b0324cd343 | ||
|
|
b371eff871 | ||
|
|
2d68716b24 | ||
|
|
ccfcb1dfb0 | ||
|
|
43186dac42 | ||
|
|
b446c5c3ac | ||
|
|
b187031ed2 | ||
|
|
c2df89f923 | ||
|
|
50e271c601 | ||
|
|
33aa553b71 | ||
|
|
5fcba45e80 | ||
|
|
f32ebb8f6b | ||
|
|
37b518aafe | ||
|
|
496f9cc3d5 | ||
|
|
e7e2cdae6e | ||
|
|
df97900674 | ||
|
|
0fedb5f8d9 | ||
|
|
2929b94d9a | ||
|
|
f7df64e4c2 | ||
|
|
7d507a6922 | ||
|
|
b1dc9c787a | ||
|
|
5552398e2d | ||
|
|
e4d4bb74f6 | ||
|
|
665f2a3e56 | ||
|
|
bf5d4cf047 | ||
|
|
dcecb6844f | ||
|
|
78ae50d3ba | ||
|
|
052b8de95c | ||
|
|
13b10e5d20 | ||
|
|
2f00af0352 | ||
|
|
d85d0aabbc | ||
|
|
7fcdc5d75b | ||
|
|
5436bb11c5 | ||
|
|
6ce047ab6a | ||
|
|
270689bc22 | ||
|
|
df77ea730d | ||
|
|
e57dcf50c5 | ||
|
|
f328f455ca | ||
|
|
e7870afbd9 | ||
|
|
f85e6568d0 | ||
|
|
c0e41e6ce1 | ||
|
|
905f550ca1 | ||
|
|
7ac501adb0 | ||
|
|
ec6e412f35 | ||
|
|
f656c3d9ef | ||
|
|
65bf6a0dff | ||
|
|
a460886c1c | ||
|
|
bf67e9fb6b | ||
|
|
e0d10bb8e9 | ||
|
|
6cd95d8f53 | ||
|
|
721f81a119 | ||
|
|
f868b6f96b | ||
|
|
4295f484a8 | ||
|
|
f5cd75e336 | ||
|
|
a6d691e6a7 | ||
|
|
2a8bd23272 | ||
|
|
9d3ecbab88 | ||
|
|
326f962bd7 | ||
|
|
6d6ad2412d | ||
|
|
3d7e43c1a2 | ||
|
|
e3b24aadd9 | ||
|
|
7bbcc62797 | ||
|
|
39927925e4 | ||
|
|
f9cf3c67ac | ||
|
|
9bd76103f2 | ||
|
|
7a9d5cd73d | ||
|
|
2d83396c59 | ||
|
|
537d7b0284 | ||
|
|
8a5b6d455c | ||
|
|
b1dde93827 | ||
|
|
5cf7a2e0db | ||
|
|
cb2fae7628 | ||
|
|
0d7b7bb1da | ||
|
|
5b39d1552c | ||
|
|
11db5ae821 | ||
|
|
4b4fdd26c1 | ||
|
|
da64c2cdcf | ||
|
|
7fa12be1b9 | ||
|
|
c8e98923c5 | ||
|
|
4882c7c25b | ||
|
|
d3e73cc0c0 | ||
|
|
e76c54d575 | ||
|
|
498224d5be | ||
|
|
e2d4d24e93 | ||
|
|
9395ed79ef | ||
|
|
a81c7a2761 | ||
|
|
4b3e7f24f3 | ||
|
|
662e86c687 | ||
|
|
487d12711e | ||
|
|
33dafd6ec0 | ||
|
|
1a057319c3 | ||
|
|
fd4c09d000 | ||
|
|
a1129cb301 | ||
|
|
21c981bd35 | ||
|
|
ae5f9e6ff1 | ||
|
|
762e793244 | ||
|
|
70efd4f1b9 | ||
|
|
523624c611 | ||
|
|
86f0be5b08 | ||
|
|
724b15e39f | ||
|
|
2104f1279e | ||
|
|
8033691888 | ||
|
|
c7fa1fcc4f | ||
|
|
8c110ba515 | ||
|
|
97fa6b671f | ||
|
|
6ea3fdcbcd | ||
|
|
714bb6bca3 | ||
|
|
585027fab7 | ||
|
|
571735cd57 | ||
|
|
b430118124 | ||
|
|
180be33d9d | ||
|
|
9e251dc397 | ||
|
|
92fa97c3aa | ||
|
|
ff001afd46 | ||
|
|
32d10080a4 | ||
|
|
1bbed177c8 | ||
|
|
a3ca438bef | ||
|
|
28ec9b34b8 | ||
|
|
a1f9ff4542 | ||
|
|
0afaf753c6 | ||
|
|
240bb2dfca |
88
.claude/settings.json
Normal file
88
.claude/settings.json
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(awk '-F[\\(\\),]' ' *)",
|
||||||
|
"Bash(xargs ls -lah)",
|
||||||
|
"Bash(py --version)",
|
||||||
|
"Bash(py -3 --version)",
|
||||||
|
"Bash(py scripts/import_cmangos_travel_nodes.py)",
|
||||||
|
"Read(//home/dev/azerothcore_installer/_server/azerothcore/modules/mod-playerbots/data/sql/playerbots/updates/**)",
|
||||||
|
"Bash(py scripts/fixup_id_collision.py)",
|
||||||
|
"Bash(py scripts/insert_ignore.py)",
|
||||||
|
"Bash(grep -nA 6 \"passFilter\" C:/Users/Admin/git/main/azerothcore-wotlk/deps/recastnavigation/Detour/Include/DetourNavMeshQuery.h)",
|
||||||
|
"Bash(grep -nA 5 \"dtQueryFilter::passFilter\" C:/Users/Admin/git/main/azerothcore-wotlk/deps/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp)",
|
||||||
|
"Bash(grep -nB1 -A2 \"modAlmostUnwalkableTriangles\" C:/Users/Admin/git/main/azerothcore-wotlk/src/tools/mmaps_generator/MapBuilder.cpp)",
|
||||||
|
"Bash(xargs grep -l \"MoveFarTo\\\\|ResolveMovePath\\\\|DispatchMovement\")",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" status)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" add src/server/game/Movement/MovementGenerators/PathGenerator.h)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" commit -m \"feat\\(Core/Movement\\): Expose dtQueryFilter::setAreaCost via PathGenerator\")",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" push)",
|
||||||
|
"Bash(wait)",
|
||||||
|
"Bash(git -C \"c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots\" show 3710c35a)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" show 9cccc5d26)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" add src/server/game/Movement/MovementGenerators/PathGenerator.cpp)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" commit -m \"feat\\(Core/Movement\\): Bias NAV_WATER 10x in default Player path filter\")",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" commit -m \"Revert \\\\\"feat\\(Core/Movement\\): Bias NAV_WATER 10x in default Player path filter\\\\\"\")",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" commit -m \"Revert \\\\\"feat\\(Core/Movement\\): Expose dtQueryFilter::setAreaCost via PathGenerator\\\\\"\")",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" log --oneline cf9c6e9f3353d386f398cbe7a821abfd8fe9a4b3..HEAD)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" diff cf9c6e9f3353d386f398cbe7a821abfd8fe9a4b3..HEAD --stat)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" reset --hard cf9c6e9f3353d386f398cbe7a821abfd8fe9a4b3)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" push --force-with-lease)",
|
||||||
|
"Bash(git cherry-pick *)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" status -s)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" diff --stat)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" add src/server/game/Movement/MovementGenerators/PathGenerator.cpp src/server/game/Movement/MovementGenerators/PathGenerator.h)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" commit -m \"feat\\(Core/Movement\\): Cap Player path filter at 50° + water bias under MOD_PLAYERBOTS\")",
|
||||||
|
"Bash(grep -n \"CollectIncludeDirectories\\\\|sourcePath\\\\|GLOB.*\\\\\\\\.cpp\\\\\\\\|target_include\" C:/Users/Admin/git/main/azerothcore-wotlk/modules/CMakeLists.txt)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" commit -m \"fix\\(Core/Movement\\): Gate playerbot path filter on WorldSession::IsBot\\(\\)\")",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" fetch origin fix/mmaps-config-overrides-and-aliases)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" log --oneline HEAD..origin/fix/mmaps-config-overrides-and-aliases)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" rebase origin/fix/mmaps-config-overrides-and-aliases)",
|
||||||
|
"Bash(git -C \"C:/Users/Admin/git/main/azerothcore-wotlk\" log --oneline -3)",
|
||||||
|
"Bash(grep -v \"//\")",
|
||||||
|
"Bash(grep -v \"^//\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk push --force-with-lease)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots push --force-with-lease)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk diff --stat)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk add src/server/game/Movement/MovementGenerators/PathGenerator.h src/server/game/Movement/MovementGenerators/PathGenerator.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk commit -m \"feat\\(Core/Movement\\): Apply bot filter rules in PathGenerator::CreateFilter\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"refactor\\(Core/Movement\\): Drop redundant bot filter setters at PathGenerator sites\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk log --all --oneline -- src/server/game/Movement/MovementGenerators/PathGenerator.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk show 82a544b03 -- src/server/game/Movement/MovementGenerators/PathGenerator.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk log --all --oneline -- src/tools/mmaps_generator/MapBuilder.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk log --all --oneline -S \"modAlmostUnwalkableTriangles\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots log --oneline --since=\"2026-05-25\" -- src/Ai/Base/Actions/LootAction.cpp src/Mgr/Item/LootObjectStack.cpp src/Mgr/Item/LootObjectStack.h src/Ai/World/Rpg/Action/NewRpgBaseAction.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots log --oneline -20)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots log --oneline 82a92f62 d0ba99f3 --not 82a92f62~30 -- src/Ai/Base/Actions/LootAction.cpp src/Mgr/Item/)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots log --oneline d0ba99f3..82a92f62 -- src/Ai/ src/Mgr/Item/)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots show c7b4b9aa --stat)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots log --oneline 82a92f62..origin/test-staging)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk rev-parse origin/test-staging)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"fix\\(Core/RPG\\): Drop over-strict MoveFarTo and MoveWorldObjectTo guards\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots show 3269d1a4 --stat)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"fix\\(Core/RPG\\): Align MoveFarTo, MoveWorldObjectTo, MoveRandomNear with cmangos\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk commit -m \"feat\\(Core/Movement\\): Double MAX_PATH_LENGTH to 148 under MOD_PLAYERBOTS\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"fix\\(Core/RPG\\): Drop chained probe and waypoint dispatch in MoveFarTo\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots revert 3384fa4f --no-edit)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots add src/Mgr/Travel/TravelMgr.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"fix\\(Core/Travel\\): Soft-bias STEEP at regen PathGenerator sites\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk add src/server/game/Movement/MovementGenerators/PathGenerator.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk commit -m \"fix\\(Core/Movement\\): Bot filter uses cost bias for STEEP, not hard exclude\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"feat\\(Core/Travel\\): K-nearest node search, cropPathTo reuse, cross-map pathToEnd\")",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots add src/Mgr/Travel/TravelNode.cpp src/Mgr/Travel/TravelNode.h src/Ai/Base/Actions/MovementActions.cpp)",
|
||||||
|
"Bash(git -C c:/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"feat\\(Core/Travel\\): Re-enable area-trigger, static-portal, and teleport-spell nodes\")",
|
||||||
|
"Bash(git -C /c/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots add src/Ai/Base/Actions/FollowActions.cpp src/Ai/Base/Actions/MovementActions.cpp src/Ai/Base/Actions/MovementActions.h src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp src/Ai/World/Rpg/Action/NewRpgBaseAction.cpp src/Ai/World/Rpg/Action/NewRpgOutdoorPvP.cpp)",
|
||||||
|
"Bash(git -C /c/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"refactor\\(Core/Movement\\): Drop IsWaitingForLastMove throttle\")",
|
||||||
|
"Bash(git -C /c/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots push)",
|
||||||
|
"Bash(git -C /c/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots diff --stat)",
|
||||||
|
"Bash(grep -v \"EmitDebugMove\\\\|//\")",
|
||||||
|
"Bash(git -C /c/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots add src/Mgr/Travel/TravelNode.h src/Mgr/Travel/TravelNode.cpp src/Ai/Base/Actions/MovementActions.cpp src/Ai/World/Rpg/NewRpgInfo.h src/Ai/World/Rpg/NewRpgInfo.cpp)",
|
||||||
|
"Bash(git -C /c/Users/Admin/git/main/azerothcore-wotlk/modules/mod-playerbots commit -m \"refactor\\(Core/Travel\\): Drop TravelPlan struct; GetFullPath returns TravelPath\")"
|
||||||
|
],
|
||||||
|
"additionalDirectories": [
|
||||||
|
"C:\\Users\\Admin\\git\\main\\azerothcore-wotlk\\src\\common\\Collision\\Maps",
|
||||||
|
"C:\\Users\\Admin\\git\\main\\azerothcore-wotlk\\src\\tools\\mmaps_generator",
|
||||||
|
"C:\\Users\\Admin\\git\\main\\azerothcore-wotlk\\src\\server\\game\\Movement\\MovementGenerators"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
10
README.md
10
README.md
@ -48,6 +48,16 @@ Then build the server following the platform-specific instructions in our **[Ins
|
|||||||
|
|
||||||
> **Testing branch:** A `test-staging` branch is available with the latest features and fixes before they are merged into `master`. To use it, clone with `--branch=test-staging` instead. Note that this branch may contain unstable or breaking changes — use it at your own risk and only if you are comfortable troubleshooting issues.
|
> **Testing branch:** A `test-staging` branch is available with the latest features and fixes before they are merged into `master`. To use it, clone with `--branch=test-staging` instead. Note that this branch may contain unstable or breaking changes — use it at your own risk and only if you are comfortable troubleshooting issues.
|
||||||
|
|
||||||
|
### Required server configuration
|
||||||
|
|
||||||
|
In `worldserver.conf` (AzerothCore core config), set:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
PreloadAllNonInstancedMapGrids = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
This is required for `mod-playerbots`.
|
||||||
|
|
||||||
### Detailed Guides
|
### Detailed Guides
|
||||||
|
|
||||||
| Guide | Description |
|
| Guide | Description |
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,632 @@
|
|||||||
|
-- Imported from cmangos-playerbots ai_playerbot_travelnode (wotlk)
|
||||||
|
-- 626 new nodes (cmangos has them, we didn't)
|
||||||
|
-- Matched on (name, mapId) + closest position; remaining are unique to cmangos.
|
||||||
|
|
||||||
|
INSERT INTO `playerbots_travelnode` (`id`, `name`, `map_id`, `x`, `y`, `z`, `linked`) VALUES
|
||||||
|
(3781, ' portal', 0, 3476.3600, -4493.3600, 137.4900, 1),
|
||||||
|
(3782, ' portal', 530, 6107.2600, -6990.6400, 133.3170, 1),
|
||||||
|
(3783, ' spirithealer', 609, 1886.7800, -5784.5900, 102.8610, 1),
|
||||||
|
(3784, ' spirithealer', 609, 2116.1900, -5286.9400, 81.2151, 1),
|
||||||
|
(3785, ' spirithealer', 609, 2364.4200, -5771.3200, 151.3670, 1),
|
||||||
|
(3786, 'Absalan the Pious', 623, 36.0312, 40.4600, 25.0322, 1),
|
||||||
|
(3787, 'Acherus: The Ebon Hold flightMaster', 0, 2348.6300, -5669.2900, 382.3240, 1),
|
||||||
|
(3788, 'Acherus: The Ebon Hold spirithealer', 0, 2356.6500, -5663.0600, 382.2570, 1),
|
||||||
|
(3789, 'Alliance Log Ride 01 Begin', 571, 4274.5300, -3055.5500, 319.4630, 1),
|
||||||
|
(3790, 'Alliance PVP Barracks', 449, -9.1189, -4.2670, 5.5710, 1),
|
||||||
|
(3791, 'Alterac Mountains The Headland', 0, -80.9055, -331.6660, 136.4710, 1),
|
||||||
|
(3792, 'Alterac Mountains', 0, 498.3190, -1076.6400, 195.8960, 1),
|
||||||
|
(3793, 'Arathi Highlands The Sanctum', 0, -1532.4300, -1882.5600, 69.5533, 1),
|
||||||
|
(3794, 'Arathi Highlands The Tower of Arathor', 0, -1774.4800, -1518.3900, 75.2667, 1),
|
||||||
|
(3795, 'Archmage Pentarus', 603, -718.4560, -57.1132, 429.9240, 1),
|
||||||
|
(3796, 'Area 52 innkeeper', 530, 3062.1500, 3701.8200, 142.5620, 1),
|
||||||
|
(3797, 'Area52 Transporter', 530, 3092.5800, 3644.7200, 143.1360, 1),
|
||||||
|
(3798, 'Ashenvale Kargathia Keep', 1, 2437.0600, -3543.6300, 98.3115, 1),
|
||||||
|
(3799, 'Auberdine innkeeper', 1, 6406.5100, 515.3670, 8.7257, 1),
|
||||||
|
(3800, 'Auchindoun: Auchenai Crypts', 558, 63.4074, -175.2640, 15.4378, 1),
|
||||||
|
(3801, 'Auchindoun: Mana-Tombs', 557, -220.0700, -177.6620, -0.9810, 1),
|
||||||
|
(3802, 'Auchindoun: Sethekk Halls', 556, -102.4290, 177.5860, 0.0932, 1),
|
||||||
|
(3803, 'Auchindoun: Shadow Labyrinth', 555, -272.2950, -140.0660, 8.1563, 1),
|
||||||
|
(3804, 'Balzaphon', 329, 3733.2700, -3480.1100, 131.0400, 1),
|
||||||
|
(3805, 'Blackfathom Deeps', 48, -570.3640, 0.8977, -47.1378, 1),
|
||||||
|
(3806, 'Blackrock Depths', 230, 870.1800, -239.3270, -71.6776, 1),
|
||||||
|
(3807, 'Blackrock Spire', 229, -16.0931, -392.4040, 48.5157, 1),
|
||||||
|
(3808, 'Blades Edge Mountains Circle of Blood', 530, 2879.1300, 5979.4500, 6.2402, 1),
|
||||||
|
(3809, 'Blades Edge Mountains Vimgols Circle', 530, 3279.9000, 4640.3600, 216.5280, 1),
|
||||||
|
(3810, 'Blood elf start', 530, 10349.6000, -6357.2900, 33.4026, 1),
|
||||||
|
(3811, 'Bloodmyst Isle The Hidden Reef', 530, -1148.6600, -11127.4000, -76.0074, 1),
|
||||||
|
(3812, 'Borean Tundra Coldarra', 571, 3917.0600, 6817.9200, 150.5070, 1),
|
||||||
|
(3813, 'Borean Tundra Naxxanar', 571, 3750.9300, 3583.8600, 353.1330, 1),
|
||||||
|
(3814, 'Burning Steppes Blackrock Mountain', 0, -7996.6300, -1013.4100, 131.8670, 1),
|
||||||
|
(3815, 'Cannon Charging (Port)', 530, 1920.1300, 5581.9000, 269.7220, 1),
|
||||||
|
(3816, 'Cannon Prep', 0, -9569.6000, -13.7809, 63.9459, 1),
|
||||||
|
(3817, 'Cannon Prep', 1, -1327.6600, 85.9815, 130.2070, 1),
|
||||||
|
(3818, 'Cannon Prep', 530, -1742.2500, 5457.4000, -11.9282, 1),
|
||||||
|
(3819, 'Chief Thunder-Skins', 230, 847.8390, -181.1150, -49.6707, 1),
|
||||||
|
(3820, 'Coilfang: Serpentshrine Cavern', 548, 135.1620, -488.7410, 0.8400, 1),
|
||||||
|
(3821, 'Coilfang: The Slave Pens', 547, -71.6723, -322.2440, -1.5438, 1),
|
||||||
|
(3822, 'Coilfang: The Steamvault', 545, -91.9829, -255.4900, -12.5306, 1),
|
||||||
|
(3823, 'Coilfang: The Underbog', 546, 108.0610, -198.7420, 50.1184, 1),
|
||||||
|
(3824, 'Coilskar Witch', 585, 139.1010, -104.6440, -20.9245, 1),
|
||||||
|
(3825, 'Crystalsong Forest The Azure Front', 571, 5434.6500, 729.6780, 186.6960, 1),
|
||||||
|
(3826, 'Crystalsong Forest The Great Tree', 571, 5895.1000, 1022.6900, 185.5390, 1),
|
||||||
|
(3827, 'Crystalsong Forest The Twilight Rivulet', 571, 5508.9200, 432.9360, 161.7470, 1),
|
||||||
|
(3828, 'Dalaran Portal to Caverns of Time', 1, -8164.8000, -4768.5000, 34.3000, 1),
|
||||||
|
(3829, 'Dalaran Portal to Caverns of Time', 571, 5781.4800, 841.2580, 680.3790, 1),
|
||||||
|
(3830, 'Dalaran Portal to Darnassus', 1, 9656.5400, 2518.2600, 1331.6600, 1),
|
||||||
|
(3831, 'Dalaran Portal to Darnassus', 571, 5706.1600, 730.1020, 641.7450, 1),
|
||||||
|
(3832, 'Dalaran Portal to Exodar', 571, 5699.5800, 735.4690, 641.7690, 1),
|
||||||
|
(3833, 'Dalaran Portal to Ironforge', 0, -4613.7100, -915.2870, 501.0620, 1),
|
||||||
|
(3834, 'Dalaran Portal to Ironforge', 571, 5712.6800, 724.8450, 641.7360, 1),
|
||||||
|
(3835, 'Dalaran Portal to Orgrimmar', 1, 1470.0200, -4222.5900, 59.2213, 1),
|
||||||
|
(3836, 'Dalaran Portal to Orgrimmar', 571, 5925.8500, 593.2500, 640.5630, 1),
|
||||||
|
(3837, 'Dalaran Portal to Shattrath', 530, -1824.3200, 5417.2300, -12.4277, 1),
|
||||||
|
(3838, 'Dalaran Portal to Shattrath', 530, -1902.4900, 5442.8600, -12.4280, 1),
|
||||||
|
(3839, 'Dalaran Portal to Shattrath', 571, 5697.4900, 744.9120, 641.8190, 1),
|
||||||
|
(3840, 'Dalaran Portal to Shattrath', 571, 5941.6600, 584.8870, 640.5740, 1),
|
||||||
|
(3841, 'Dalaran Portal to Silvermoon', 530, 9998.4600, -7106.5500, 47.7054, 1),
|
||||||
|
(3842, 'Dalaran Portal to Silvermoon', 571, 5946.9800, 568.4790, 640.5730, 1),
|
||||||
|
(3843, 'Dalaran Portal to Stormwind', 571, 5719.1900, 719.6810, 641.7280, 1),
|
||||||
|
(3844, 'Dalaran Portal to Thunder Bluff', 1, -967.3750, 284.8200, 110.7730, 1),
|
||||||
|
(3845, 'Dalaran Portal to Thunder Bluff', 571, 5945.8100, 577.3570, 640.5740, 1),
|
||||||
|
(3846, 'Dalaran Portal to Undercity', 571, 5934.6600, 590.6880, 640.5750, 1),
|
||||||
|
(3847, 'Dalaran Violet Citadel Balcony', 571, 5865.0800, 840.2100, 846.3330, 1),
|
||||||
|
(3848, 'Darnassus The Temple Gardens', 1, 9814.7800, 2574.2100, 1314.4700, 1),
|
||||||
|
(3849, 'Darnassus Warriors Terrace', 1, 9976.2100, 2262.3700, 1334.5000, 1),
|
||||||
|
(3850, 'Darnassus innkeeper', 1, 9951.8800, 2282.8200, 1345.1600, 1),
|
||||||
|
(3851, 'Deadwind Pass Groshgok Compound', 0, -11121.6000, -2416.2600, 108.6530, 1),
|
||||||
|
(3852, 'Deadwind Pass Karazhan', 0, -11123.3000, -2006.7700, 47.2725, 1),
|
||||||
|
(3853, 'Deadwind Pass', 0, -10377.2000, -1785.4200, 94.3243, 1),
|
||||||
|
(3854, 'Deeprun Tram', 369, 13.6699, 80.6694, -4.2973, 1),
|
||||||
|
(3855, 'Desolace Bolgans Hole', 1, -2375.9500, 2469.7600, 74.4626, 1),
|
||||||
|
(3856, 'Desolace The Veiled Sea', 1, -1869.3900, 3404.3400, -50.7694, 1),
|
||||||
|
(3857, 'Dire Maul', 429, 135.5790, 192.0480, -3.3910, 1),
|
||||||
|
(3858, 'Doodad_CF_elevatorPlatform01entry', 548, 50.0000, -0.0071, -70.9017, 1),
|
||||||
|
(3859, 'Doodad_CF_elevatorPlatform_small01entry', 548, -59.1350, -98.7966, -51.7018, 1),
|
||||||
|
(3860, 'Doodad_FactoryElevator01entry', 554, 0.5438, -1.3935, -1.7012, 1),
|
||||||
|
(3861, 'Doodad_HF_Elevator_Gate01entry', 571, 254.1330, -5892.0000, 258.4950, 1),
|
||||||
|
(3862, 'Doodad_HF_Elevator_Gate02', 571, 263.1630, -5919.2500, 167.2690, 1),
|
||||||
|
(3863, 'Doodad_HF_Elevator_Gate02', 571, 263.1630, -5919.2500, 173.3200, 1),
|
||||||
|
(3864, 'Doodad_HF_Elevator_Gate02entry', 571, 275.2000, -5918.1300, 166.4950, 1),
|
||||||
|
(3865, 'Doodad_HF_Elevator_Gate03', 571, 135.1250, -5765.3500, 291.7530, 1),
|
||||||
|
(3866, 'Doodad_HF_Elevator_Gate03', 571, 135.1250, -5765.3500, 286.0490, 1),
|
||||||
|
(3867, 'Doodad_HF_Elevator_Gate03entry', 571, 133.3330, -5756.2700, 285.5940, 1),
|
||||||
|
(3868, 'Doodad_HF_Elevator_Lift01entry', 571, 259.9700, -5893.8300, 255.8280, 1),
|
||||||
|
(3869, 'Doodad_HF_Elevator_Lift01entry', 571, 261.1220, -5910.0100, 77.0138, 1),
|
||||||
|
(3870, 'Doodad_HF_Elevator_Lift01entry', 571, 261.9400, -5918.9400, 164.0950, 1),
|
||||||
|
(3871, 'Doodad_HF_Elevator_Lift_01entry', 571, 158.9330, -5760.0000, 38.3942, 1),
|
||||||
|
(3872, 'Doodad_ID_elevator01entry', 571, 3324.2300, -5134.7400, 300.5890, 1),
|
||||||
|
(3873, 'Doodad_ID_elevator02entry', 571, 3302.5400, -5103.7300, 300.5890, 1),
|
||||||
|
(3874, 'Doodad_ID_elevator03entry', 571, 3286.7600, -5135.8800, 300.5890, 1),
|
||||||
|
(3875, 'Doodad_LogRun_PumpElevator05', 571, 4264.2300, -3276.9500, 336.1010, 1),
|
||||||
|
(3876, 'Doodad_LogRun_PumpElevator05', 571, 4264.2300, -3276.9500, 330.6150, 1),
|
||||||
|
(3877, 'Doodad_LogRun_PumpElevator05entry', 571, 4264.2300, -3276.9500, 329.3720, 1),
|
||||||
|
(3878, 'Doodad_Nexus_Elevator_BaseStructure_01entry', 571, 3556.2500, 6928.7200, 251.3120, 1),
|
||||||
|
(3879, 'Doodad_Nexus_Elevator_BaseStructure_01entry', 571, 3979.2300, 7272.5600, 256.0160, 1),
|
||||||
|
(3880, 'Doodad_Nexus_Elevator_BaseStructure_01entry', 571, 4110.2800, 6755.6900, 249.1790, 1),
|
||||||
|
(3881, 'Doodad_Nexus_Elevator_BaseStructure_01entry', 578, 1213.8600, 1339.0600, 248.2530, 1),
|
||||||
|
(3882, 'Doodad_Nexus_Elevator_BaseStructure_01entry', 578, 1343.4300, 825.8630, 242.8180, 1),
|
||||||
|
(3883, 'Doodad_Nexus_Elevator_BaseStructure_01entry', 578, 789.8890, 992.0980, 251.2600, 1),
|
||||||
|
(3884, 'Doodad_Vrykul_Gondola01entry', 571, 698.9930, -3824.2500, 269.5360, 1),
|
||||||
|
(3885, 'Doodad_Vrykul_Gondola01entryentry', 571, 700.2670, -3823.5000, 269.3790, 1),
|
||||||
|
(3886, 'Doodad_Vrykul_Gondola_01entry', 575, -557.0330, 1543.4600, -288.9820, 1),
|
||||||
|
(3887, 'Doodad_icecrown_elevator02entry', 631, 4366.6900, 2365.6200, 358.4790, 1),
|
||||||
|
(3888, 'Doodad_mushroombase_elevator01entry', 530, 285.6000, 5927.2000, 26.6102, 1),
|
||||||
|
(3889, 'Doodad_org_arena_axe_pillar01entry', 618, 768.0000, -298.6670, 28.4867, 1),
|
||||||
|
(3890, 'Doodad_org_arena_lightning_pillar01entry', 618, 768.0000, -277.3330, 28.4867, 1),
|
||||||
|
(3891, 'Draenei start', 530, -3961.6400, -13931.2000, 100.6150, 1),
|
||||||
|
(3892, 'Dragonblight Frostmourne Cavern', 571, 4736.3900, -558.6370, 166.0830, 1),
|
||||||
|
(3893, 'Dragonblight Scarlet Tower', 571, 4692.0500, -356.1290, 178.7370, 1),
|
||||||
|
(3894, 'Dragonblight The Pit of Narjun', 571, 3740.0300, 2125.2500, 43.0709, 1),
|
||||||
|
(3895, 'Dragonblight Wintergarde Crypt', 571, 3584.5200, -781.0240, 155.6860, 1),
|
||||||
|
(3896, 'Dragonblight Wintergarde Mausoleum', 571, 3650.8400, -1123.3200, 89.2307, 1),
|
||||||
|
(3897, 'Drakuramas Teleport 02', 571, 6175.5900, -2000.6700, 241.7690, 1),
|
||||||
|
(3898, 'Dun Morogh Chill Breeze Valley', 0, -5550.9700, -76.1191, 426.9310, 1),
|
||||||
|
(3899, 'Dun Morogh Thunderbrew Distillery', 0, -5595.6700, -513.5950, 409.4150, 1),
|
||||||
|
(3900, 'Durotar Burning Blade Coven', 1, -88.3030, -4285.0100, 62.0652, 1),
|
||||||
|
(3901, 'Durotar Dustwind Cave', 1, 877.9880, -4745.6200, 30.4963, 1),
|
||||||
|
(3902, 'Durotar Razor Hill Barracks', 1, 319.0970, -4812.8800, 10.6054, 1),
|
||||||
|
(3903, 'Durotar The Den', 1, -588.7030, -4144.9400, 41.1033, 1),
|
||||||
|
(3904, 'Duskwood Forlorn Rowe', 0, -10320.8000, 368.2760, 60.5037, 1),
|
||||||
|
(3905, 'Duskwood Rolands Doom', 0, -11106.5000, -1160.6700, 42.2494, 1),
|
||||||
|
(3906, 'Dustwallow Marsh Emberstrifes Den', 1, -5103.3600, -3949.5300, 41.4934, 1),
|
||||||
|
(3907, 'Dustwallow Marsh Foothold Citadel', 1, -3721.7400, -4538.6000, 25.9170, 1),
|
||||||
|
(3908, 'Dustwallow Marsh North Point Tower', 1, -2885.3400, -3419.3200, 47.2420, 1),
|
||||||
|
(3909, 'Dustwallow Marsh The Great Sea', 1, -4026.5700, -4975.8200, 8.2153, 1),
|
||||||
|
(3910, 'Dustwallow to Stormwind Teleport', 0, -9008.7900, 851.3200, 105.8900, 1),
|
||||||
|
(3911, 'Eastern Plaguelands MazraAlor', 0, 3439.2500, -4980.9600, 195.8110, 1),
|
||||||
|
(3912, 'Eastern Plaguelands Terrorweb Tunnel', 0, 2903.1100, -2614.6700, 89.8071, 1),
|
||||||
|
(3913, 'Eastern Plaguelands The Noxious Glade', 0, 2714.6600, -5421.4700, 161.4070, 1),
|
||||||
|
(3914, 'Elevatorentry', 0, -5065.6200, 437.5100, 424.1080, 1),
|
||||||
|
(3915, 'Elevatorentry', 1, 2261.3300, -5565.5600, 34.2689, 1),
|
||||||
|
(3916, 'Elevatorentry', 530, 1914.5100, 5514.0200, 280.6880, 1),
|
||||||
|
(3917, 'Elevatorentry', 571, 2872.9500, 6234.9700, 104.9120, 1),
|
||||||
|
(3918, 'Elevatorentry', 571, 2894.6900, 6244.8900, 209.1970, 1),
|
||||||
|
(3919, 'Elevatorentry', 571, 4185.2900, 5283.6200, 39.6833, 1),
|
||||||
|
(3920, 'Elwynn Forest Thunder Falls', 0, -9291.1000, 677.6830, 131.7780, 1),
|
||||||
|
(3921, 'Entangle', 531, -8003.0000, 1222.9000, -82.1000, 1),
|
||||||
|
(3922, 'Entangle', 531, -8022.3000, 1149.0000, -89.1000, 1),
|
||||||
|
(3923, 'Entangle', 531, -8043.6000, 1254.1000, -84.3000, 1),
|
||||||
|
(3924, 'Eredar Soul-Eater', 552, 285.5190, 146.1550, 22.3118, 1),
|
||||||
|
(3925, 'Escape Voltarus', 571, 5875.4300, -1981.3700, 234.6710, 1),
|
||||||
|
(3926, 'Escape to the Isle of QuelDanas', 530, 12887.6000, -6869.2100, 10.1141, 1),
|
||||||
|
(3927, 'Escape to the Isle of QuelDanas', 585, 148.4010, 203.4430, -11.9579, 1),
|
||||||
|
(3928, 'Evergrove innkeeper', 530, 3022.9000, 5435.5900, 146.7010, 1),
|
||||||
|
(3929, 'Everlook Transporter', 1, 6755.2200, -4658.0400, 724.7950, 1),
|
||||||
|
(3930, 'Everlook innkeeper', 1, 6695.1500, -4673.0400, 721.6500, 1),
|
||||||
|
(3931, 'Eversong Woods Commons Hall', 530, 9822.0000, -6694.3700, 2.5945, 1),
|
||||||
|
(3932, 'Eversong Woods Falthrien Academy', 530, 10158.0000, -6026.5000, 63.7448, 1),
|
||||||
|
(3933, 'Eversong Woods Huntress of the Sun', 530, 9699.4300, -6701.3600, -0.2076, 1),
|
||||||
|
(3934, 'Exit Portal', 571, 3877.1400, 6980.8300, 152.0400, 1),
|
||||||
|
(3935, 'Feathermoon Stronghold innkeeper', 1, -4381.5900, 3289.4500, 13.6266, 1),
|
||||||
|
(3936, 'Felwood Bloodvenom River', 1, 5288.7400, -544.2570, 328.6870, 1),
|
||||||
|
(3937, 'Felwood Irontree Cavern', 1, 6353.3200, -1696.9200, 440.0420, 1),
|
||||||
|
(3938, 'Felwood Shrine of the Deceiver', 1, 4779.2600, -572.0400, 275.8440, 1),
|
||||||
|
(3939, 'Gadgetzan Transporter', 1, -7109.1200, -3825.2100, 10.1529, 1),
|
||||||
|
(3940, 'Gadgetzan innkeeper', 1, -7158.9600, -3841.6100, 8.8481, 1),
|
||||||
|
(3941, 'Gallows End Tavern innkeeper', 0, 2269.5100, 244.9440, 34.3402, 1),
|
||||||
|
(3942, 'Gates of AhnQiraj', 1, -8233.1200, 1535.7500, -0.3744, 1),
|
||||||
|
(3943, 'Ghostlands Deatholme', 530, 6465.7700, -6433.6600, 50.4155, 1),
|
||||||
|
(3944, 'Ghostlands Thalassian Pass', 530, 6554.0200, -6811.2000, 110.6000, 1),
|
||||||
|
(3945, 'Ghostly Baker', 532, -11057.7000, -1919.8300, 77.3515, 1),
|
||||||
|
(3946, 'Gnomeregan', 90, -617.4620, 370.6960, -247.1880, 1),
|
||||||
|
(3947, 'Gravity Lapse - Center Teleport', 585, 148.5000, 181.0000, -16.7000, 1),
|
||||||
|
(3948, 'Greater Shadowbat', 532, -10935.0000, -1999.5000, 49.4748, 1),
|
||||||
|
(3949, 'Grizzly Hills - Quest - Arugal Teleport Back', 571, 3841.4000, -3426.6500, 293.1040, 1),
|
||||||
|
(3950, 'Grizzly Hills Boulder Hills', 571, 5082.6400, -4724.1900, 287.5000, 1),
|
||||||
|
(3951, 'Grizzly Hills Duskhowl Den', 571, 3992.0100, -4523.4300, 195.6070, 1),
|
||||||
|
(3952, 'Grizzly Hills Ursocs Den', 571, 4692.7100, -3863.7500, 327.3770, 1),
|
||||||
|
(3953, 'Grizzly Hills Voldrune Dwelling', 571, 3005.7300, -2610.3100, 98.5530, 1),
|
||||||
|
(3954, 'Gruuls Lair', 565, 107.8710, 282.5120, 1.9718, 1),
|
||||||
|
(3955, 'Gunship Portal', 628, 747.0000, -1075.0000, 135.0000, 1),
|
||||||
|
(3956, 'Gunship Portal', 641, 16.4763, 0.0184, 20.4162, 1),
|
||||||
|
(3957, 'Gunship Portal', 642, 12.3199, 0.0963, 34.6508, 1),
|
||||||
|
(3958, 'Heart of the Deconstructor', 603, 886.2750, -12.0545, 409.6020, 1),
|
||||||
|
(3959, 'Hellfire Citadel: The Blood Furnace', 542, 331.0690, 28.0790, 9.7047, 1),
|
||||||
|
(3960, 'Hellfire Citadel: The Shattered Halls', 540, 203.6690, 157.2020, -42.3511, 1),
|
||||||
|
(3961, 'Hellfire Peninsula The Path of Anguish', 530, -525.2730, 2066.0700, 94.5205, 1),
|
||||||
|
(3962, 'Hex Lord Malacrass', 568, 117.3630, 923.5690, 33.9726, 1),
|
||||||
|
(3963, 'Hillsbrad Foothills Durnholde Keep', 0, -489.8100, -1480.9400, 88.1965, 1),
|
||||||
|
(3964, 'HiveZara Swarmer Teleport', 509, -9757.8700, 1416.7100, 76.7664, 1),
|
||||||
|
(3965, 'HiveZara Swarmer Teleport', 509, -9778.9100, 1419.9800, 61.0743, 1),
|
||||||
|
(3966, 'HiveZara Swarmer Teleport', 509, -9805.9500, 1422.8500, 77.5852, 1),
|
||||||
|
(3967, 'HiveZara Swarmer Teleport', 509, -9827.5800, 1506.2800, 82.3052, 1),
|
||||||
|
(3968, 'HiveZara Swarmer Teleport', 509, -9829.4200, 1456.3700, 90.7015, 1),
|
||||||
|
(3969, 'Horde Log Ride 01 Begin', 571, 4313.3700, -2958.1700, 318.4630, 1),
|
||||||
|
(3970, 'Howling Fjord New Agamand Inn', 571, 456.4610, -4519.2400, 244.9780, 1),
|
||||||
|
(3971, 'Howling Fjord Utgarde Keep', 571, 855.8150, -4831.8500, -115.7170, 1),
|
||||||
|
(3972, 'Howling Fjord Westguard Keep', 571, 1385.1700, -3244.6400, 162.8370, 1),
|
||||||
|
(3973, 'Howling Fjord Wildervar Mine', 571, 2604.4700, -5019.1400, 293.8260, 1),
|
||||||
|
(3974, 'Icecrown Jotunheim', 571, 7220.9200, 4113.1400, 630.8240, 1),
|
||||||
|
(3975, 'Icecrown Kulgalar Keep', 571, 6831.2300, 3817.0800, 621.1530, 1),
|
||||||
|
(3976, 'Icecrown Nazanak: The Forgotten Depths', 571, 5853.5100, 1807.1700, -344.9310, 1),
|
||||||
|
(3977, 'Icecrown The Fleshwerks', 571, 6610.5800, 3359.6700, 660.4740, 1),
|
||||||
|
(3978, 'Indisposed II', 571, 3454.1100, -2802.3700, 202.1400, 1),
|
||||||
|
(3979, 'Ironforge The Forlorn Cavern', 0, -4636.2200, -1110.0000, 501.4110, 1),
|
||||||
|
(3980, 'Ironforge flightMaster', 0, -4821.1300, -1152.4000, 502.2950, 1),
|
||||||
|
(3981, 'Ironforge innkeeper', 0, -4840.6700, -857.0940, 501.9970, 1),
|
||||||
|
(3982, 'Ironforge innkeeper', 0, -4908.1700, -970.9860, 505.2260, 1),
|
||||||
|
(3983, 'Ironforge', 0, -4832.2700, -1069.6400, 502.2680, 1),
|
||||||
|
(3984, 'Kalecgos', 585, 197.8630, -272.7440, -8.6516, 1),
|
||||||
|
(3985, 'Lady Faltheress', 129, 2583.1800, 695.8610, 56.8033, 1),
|
||||||
|
(3986, 'Lady Liadrin', 580, 1720.0200, 643.2330, 28.1335, 1),
|
||||||
|
(3987, 'Loch Modan Stoutlager Inn', 0, -5391.7300, -2974.8800, 325.9470, 1),
|
||||||
|
(3988, 'Lord Blackwood', 289, 200.2010, 150.8390, 109.8790, 1),
|
||||||
|
(3989, 'MaiKyl', 230, 842.7150, -181.5710, -49.6700, 1),
|
||||||
|
(3990, 'Majordomo Teleport', 409, 848.9330, -812.8750, -229.6010, 1),
|
||||||
|
(3991, 'Maraudon Portal Effect', 349, 386.2700, 33.4144, -130.9340, 1),
|
||||||
|
(3992, 'Maraudon', 349, 614.7090, -206.5360, -64.2963, 1),
|
||||||
|
(3993, 'Mesa Elevator', 209, 2600.8100, 1228.7200, -40.2788, 1),
|
||||||
|
(3994, 'Mesa Elevator', 209, 2600.8100, 1228.7200, 89.0211, 1),
|
||||||
|
(3995, 'Mesa Elevator', 209, 2617.5100, 1243.9200, -40.5284, 1),
|
||||||
|
(3996, 'Mesa Elevator', 209, 2617.5100, 1243.9200, 89.0253, 1),
|
||||||
|
(3997, 'Mesa Elevatorentry', 1, -1030.1400, -32.0337, 68.2329, 1),
|
||||||
|
(3998, 'Mesa Elevatorentry', 1, -1032.6600, -26.3241, 141.1470, 1),
|
||||||
|
(3999, 'Mesa Elevatorentry', 1, -1035.1900, -45.0725, 68.2586, 1),
|
||||||
|
(4000, 'Mesa Elevatorentry', 1, -1042.0500, -47.7792, 141.1470, 1),
|
||||||
|
(4001, 'Mesa Elevatorentry', 1, -1284.7700, 185.1110, 130.3230, 1),
|
||||||
|
(4002, 'Mesa Elevatorentry', 1, -1290.7100, 188.5430, 67.4105, 1),
|
||||||
|
(4003, 'Mesa Elevatorentry', 1, -1304.5600, 186.1990, 67.5106, 1),
|
||||||
|
(4004, 'Mesa Elevatorentry', 1, -1308.1800, 180.4040, 130.2800, 1),
|
||||||
|
(4005, 'Mesa Elevatorentry', 1, -4660.6000, -1828.2700, 85.6823, 1),
|
||||||
|
(4006, 'Mesa Elevatorentry', 1, -4666.2300, -1851.2600, 85.6813, 1),
|
||||||
|
(4007, 'Mesa Elevatorentry', 1, -4666.4800, -1832.0900, -45.3171, 1),
|
||||||
|
(4008, 'Mesa Elevatorentry', 1, -4670.1200, -1845.7300, -45.1181, 1),
|
||||||
|
(4009, 'Mesa Elevatorentry', 1, -5385.2000, -2485.3300, 89.4297, 1),
|
||||||
|
(4010, 'Mesa Elevatorentry', 1, -5385.2700, -2492.0100, -41.7147, 1),
|
||||||
|
(4011, 'Mesa Elevatorentry', 1, -5395.6800, -2501.7500, -41.5869, 1),
|
||||||
|
(4012, 'Mesa Elevatorentry', 1, -5402.5700, -2501.2400, 89.4297, 1),
|
||||||
|
(4013, 'Mesa Elevatorentry', 209, 2597.4300, 1232.1000, 89.4297, 1),
|
||||||
|
(4014, 'Mesa Elevatorentry', 209, 2604.3200, 1231.5800, -41.5870, 1),
|
||||||
|
(4015, 'Mesa Elevatorentry', 209, 2614.7300, 1241.3200, -41.7145, 1),
|
||||||
|
(4016, 'Mesa Elevatorentry', 209, 2614.8000, 1248.0000, 89.4297, 1),
|
||||||
|
(4017, 'Mesa Elevatorentry', 47, 1729.8800, 1354.2700, -45.1181, 1),
|
||||||
|
(4018, 'Mesa Elevatorentry', 47, 1733.5200, 1367.9100, -45.3171, 1),
|
||||||
|
(4019, 'Mesa Elevatorentry', 47, 1733.7700, 1348.7400, 85.6813, 1),
|
||||||
|
(4020, 'Mesa Elevatorentry', 47, 1739.4000, 1371.7300, 85.6823, 1),
|
||||||
|
(4021, 'Mole Machine Port to Grim Guzzler', 230, 901.0680, -143.9390, -49.7550, 1),
|
||||||
|
(4022, 'Molten Core', 409, 889.0990, -822.9660, -227.2440, 1),
|
||||||
|
(4023, 'Move Bind Sight', 230, 824.8090, -176.1660, -49.7551, 1),
|
||||||
|
(4024, 'Mudsprocket innkeeper', 1, -4629.4300, -3176.1400, 41.2339, 1),
|
||||||
|
(4025, 'Murta Grimgut', 209, 1891.0700, 1294.7800, 48.2347, 1),
|
||||||
|
(4026, 'Nagrand Abandoned Armory', 530, -2052.0900, 7432.7600, -24.9648, 1),
|
||||||
|
(4027, 'Naxxanar portal', 571, 3692.4300, 3577.9400, 473.3200, 1),
|
||||||
|
(4028, 'Naxxanar portal', 571, 3734.1400, 3571.1200, 341.6620, 1),
|
||||||
|
(4029, 'Naxxanar portal', 571, 3738.6400, 3567.6700, 294.5220, 1),
|
||||||
|
(4030, 'Naxxanar portal', 571, 3739.5000, 3567.0000, 337.5640, 1),
|
||||||
|
(4031, 'Naxxanar portal', 571, 3739.6600, 3567.2900, 286.7850, 1),
|
||||||
|
(4032, 'Naxxanar portal', 571, 3787.5700, 3558.1100, 469.3220, 1),
|
||||||
|
(4033, 'Naxxanar portal', 571, 3801.5000, 3586.0500, 49.5700, 1),
|
||||||
|
(4034, 'Naxxramas Teleport - Sapphiron Exit', 533, 3005.7300, -3414.7600, 297.0260, 1),
|
||||||
|
(4035, 'Netherstorm Manaforge Ara', 530, 3965.9500, 3911.9700, 178.4460, 1),
|
||||||
|
(4036, 'Netherstorm The Violet Tower', 530, 2243.2600, 2243.1400, 101.5590, 1),
|
||||||
|
(4037, 'Nexus Portal', 578, 1045.5700, 1104.2400, 361.0700, 1),
|
||||||
|
(4038, 'Nexus Portal', 578, 982.1730, 1055.4500, 359.9670, 1),
|
||||||
|
(4039, 'Nijels Point innkeeper', 1, 255.6150, 1253.7600, 192.2240, 1),
|
||||||
|
(4040, 'No Mans Land -> Out of Hyjal', 1, 5010.1700, -4554.9400, 852.1460, 1),
|
||||||
|
(4041, 'Onyxias Lair', 249, -90.7180, -106.2340, -38.1972, 1),
|
||||||
|
(4042, 'Orb of the Nexus', 578, 1048.2700, 991.3100, 361.0700, 1),
|
||||||
|
(4043, 'Orgrims Hammer', 622, 23.4324, 0.0201, 33.5795, 1),
|
||||||
|
(4044, 'Orgrims Hammerdock', 668, 5223.4700, 1537.8700, 645.6480, 1),
|
||||||
|
(4045, 'Orgrimmar flightMaster', 1, 1676.2500, -4313.4500, 61.9445, 1),
|
||||||
|
(4046, 'Out of Body Experience', 0, -465.6990, 1495.9800, 17.3595, 1),
|
||||||
|
(4047, 'Port to Mazthoril', 1, 5904.2000, -4045.9000, 596.4300, 1),
|
||||||
|
(4048, 'Portal Effect: Acherus', 609, 2400.0300, -5635.0000, 377.0170, 1),
|
||||||
|
(4049, 'Portal of Immolthar', 429, -37.5643, 813.4330, -7.4382, 1),
|
||||||
|
(4050, 'Portal to Blasted Lands', 0, -11708.4000, -3168.0000, -5.0700, 1),
|
||||||
|
(4051, 'Portal to Blasted Lands', 0, -4606.4400, -928.9970, 501.0700, 1),
|
||||||
|
(4052, 'Portal to Blasted Lands', 0, -9007.5800, 871.8700, 129.6920, 1),
|
||||||
|
(4053, 'Portal to Blasted Lands', 0, 1768.7700, 55.3698, -46.3194, 1),
|
||||||
|
(4054, 'Portal to Blasted Lands', 1, -944.0640, 274.8590, 111.7100, 1),
|
||||||
|
(4055, 'Portal to Blasted Lands', 1, 1472.0900, -4214.6300, 59.2208, 1),
|
||||||
|
(4056, 'Portal to Blasted Lands', 1, 9661.8300, 2509.6000, 1331.6300, 1),
|
||||||
|
(4057, 'Portal to Blasted Lands', 530, -4039.0700, -11555.1000, -138.3370, 1),
|
||||||
|
(4058, 'Portal to Blasted Lands', 530, 9984.0300, -7108.4300, 47.7049, 1),
|
||||||
|
(4059, 'Portal to Dalaran', 571, 5807.7500, 588.3470, 661.5050, 1),
|
||||||
|
(4060, 'Portal to Dalaran', 631, -72.7031, 2282.4500, 32.8673, 1),
|
||||||
|
(4061, 'Portal to Dalaran', 712, 4.3953, 13.6833, 20.8039, 1),
|
||||||
|
(4062, 'Portal to Dalaran', 713, 22.1770, 22.9527, 35.6576, 1),
|
||||||
|
(4063, 'Portal to Orgrimmar', 1, 1321.8100, -4383.1900, 26.2300, 1),
|
||||||
|
(4064, 'Portal to Orgrimmar', 1, 1921.3700, -4149.2400, 40.4075, 1),
|
||||||
|
(4065, 'Portal to Stormwind', 0, -8446.8300, 339.9310, 121.3290, 1),
|
||||||
|
(4066, 'Portal to Stormwind', 0, -9143.5800, 375.1030, 90.6907, 1),
|
||||||
|
(4067, 'Portal to The Purple Parlor', 571, 5822.3500, 837.0760, 680.6570, 1),
|
||||||
|
(4068, 'Portal to The Purple Parlor', 571, 5848.4800, 853.7060, 843.1820, 1),
|
||||||
|
(4069, 'Portal to The Violet Citadel', 571, 5413.0100, 2868.1800, 418.6750, 1),
|
||||||
|
(4070, 'Portal to The Violet Citadel', 571, 5819.2600, 829.7740, 680.2200, 1),
|
||||||
|
(4071, 'Portal to Undercity', 0, 1774.8000, 761.1270, 55.0477, 1),
|
||||||
|
(4072, 'Portal to Undercity', 0, 1962.6900, 235.9200, 39.7700, 1),
|
||||||
|
(4073, 'Portal: Moonglade Effect', 1, 7828.8400, -2245.6500, 463.7070, 1),
|
||||||
|
(4074, 'Portal: Return from Moonglade Effect', 571, 6215.5400, -8.4001, 410.1650, 1),
|
||||||
|
(4075, 'Portal: Valley of Echoes', 571, 6390.5300, 237.0120, 395.8130, 1),
|
||||||
|
(4076, 'Quest - Port Skettis Prisoner - Location 01', 530, -4106.6400, 3029.7600, 344.8770, 1),
|
||||||
|
(4077, 'Quest - Port Skettis Prisoner - Location 02', 530, -3720.3500, 3789.9100, 302.8880, 1),
|
||||||
|
(4078, 'Quest - Port Skettis Prisoner - Location 03', 530, -3669.5700, 3386.7400, 312.9550, 1),
|
||||||
|
(4079, 'Quest - Teleport: Caverns of Time', 1, -8380.5000, -4262.5600, -207.5340, 1),
|
||||||
|
(4080, 'Quetzlun', 571, 5716.2600, -4369.3400, 385.8850, 1),
|
||||||
|
(4081, 'Ragefire Chasm', 389, -223.4540, 87.2837, -24.9351, 1),
|
||||||
|
(4082, 'Raven', 209, 1886.6400, 1299.1100, 48.3146, 1),
|
||||||
|
(4083, 'Recall', 30, -1347.0000, -292.0000, 91.0000, 1),
|
||||||
|
(4084, 'Recall', 30, 648.0000, -34.0000, 47.0000, 1),
|
||||||
|
(4085, 'Redridge Mountains Renders Rock', 0, -8737.4300, -2213.5000, 149.9600, 1),
|
||||||
|
(4086, 'Redridge Mountains Stonewatch', 0, -9392.0000, -3026.6300, 136.7700, 1),
|
||||||
|
(4087, 'Return to Temper', 530, -3286.6300, -12908.6000, 11.7562, 1),
|
||||||
|
(4088, 'Revanchion', 429, -106.3030, 551.2760, -4.3970, 1),
|
||||||
|
(4089, 'Ritual Preparation', 575, 296.6890, -346.5040, 90.5482, 1),
|
||||||
|
(4090, 'Ritual of the Sword', 575, 296.6890, -346.5040, 108.5480, 1),
|
||||||
|
(4091, 'Rizzles Escape', 1, 3697.2000, -3967.1300, 28.3115, 1),
|
||||||
|
(4092, 'Sacrifice', 429, -25.9536, -448.2270, -36.0912, 1),
|
||||||
|
(4093, 'Sacrifice', 532, -11234.2000, -1698.4600, 179.2400, 1),
|
||||||
|
(4094, 'Sacrifice', 553, 4.0000, 608.0000, -13.8165, 1),
|
||||||
|
(4095, 'Samuro', 230, 847.6740, -175.8690, -49.6706, 1),
|
||||||
|
(4096, 'Scaffold Carsentry', 0, -6889.3100, -1211.7600, 240.4440, 1),
|
||||||
|
(4097, 'Scaffold Carsentry', 0, -6895.5000, -1338.1500, 240.2840, 1),
|
||||||
|
(4098, 'Scaffold Carsentry', 0, -6899.7000, -1207.6000, 240.4100, 1),
|
||||||
|
(4099, 'Scaffold Carsentry', 0, -6903.5800, -1201.6700, 193.8930, 1),
|
||||||
|
(4100, 'Scaffold Carsentry', 0, -6905.7300, -1211.8300, 214.0430, 1),
|
||||||
|
(4101, 'Scaffold Carsentry', 469, -6889.3100, -1211.7600, 240.4440, 1),
|
||||||
|
(4102, 'Scaffold Carsentry', 469, -6895.5000, -1338.1500, 240.2840, 1),
|
||||||
|
(4103, 'Scaffold Carsentry', 469, -6899.7000, -1207.6000, 240.4100, 1),
|
||||||
|
(4104, 'Scaffold Carsentry', 469, -6903.5800, -1201.6700, 193.8930, 1),
|
||||||
|
(4105, 'Scaffold Carsentry', 469, -6905.7300, -1211.8300, 214.0430, 1),
|
||||||
|
(4106, 'Scaffold Carsentry', 530, -3292.8900, 1901.2800, 142.1590, 1),
|
||||||
|
(4107, 'Scaffold Carsentry', 530, -3297.0700, 1898.6700, 101.3760, 1),
|
||||||
|
(4108, 'Scaffold Carsentry', 530, -3300.1400, 1902.2300, 168.4120, 1),
|
||||||
|
(4109, 'Scaffold Carsentry', 530, -3301.8300, 1895.4800, 122.1590, 1),
|
||||||
|
(4110, 'Scaffold Carsentry', 530, -3306.6700, 1902.6700, 168.5590, 1),
|
||||||
|
(4111, 'Scaffold Carsentry', 571, 8115.1400, -245.3940, 900.1890, 1),
|
||||||
|
(4112, 'Scaffold Carsentry', 571, 8118.4000, -380.0000, 1027.9200, 1),
|
||||||
|
(4113, 'Scaffold Carsentry', 571, 8118.7700, -386.8160, 981.7890, 1),
|
||||||
|
(4114, 'Scaffold Carsentry', 571, 8119.4000, -256.0000, 926.3570, 1),
|
||||||
|
(4115, 'Scaffold Carsentry', 571, 8119.6800, -379.0410, 1028.0500, 1),
|
||||||
|
(4116, 'Scaffold Carsentry', 571, 8122.6000, -247.5780, 926.3930, 1),
|
||||||
|
(4117, 'Scaffold Carsentry', 571, 8123.9300, -240.0710, 880.1890, 1),
|
||||||
|
(4118, 'Scaffold Carsentry', 571, 8127.2900, -380.4440, 1001.7900, 1),
|
||||||
|
(4119, 'Scroll of Recall', 0, -103.9880, -902.7950, 55.5340, 1),
|
||||||
|
(4120, 'Scroll of Recall', 0, -10446.9000, -3261.9100, 20.1790, 1),
|
||||||
|
(4121, 'Scroll of Recall', 0, -5506.3400, -704.3480, 392.6860, 1),
|
||||||
|
(4122, 'Scroll of Recall', 0, -9470.7600, 3.9090, 49.7940, 1),
|
||||||
|
(4123, 'Scroll of Recall', 0, 1804.8400, 196.3220, 70.3990, 1),
|
||||||
|
(4124, 'Scroll of Recall', 0, 286.3140, -2184.0900, 122.6120, 1),
|
||||||
|
(4125, 'Scroll of Recall', 1, -1060.2700, 23.1370, 141.4550, 1),
|
||||||
|
(4126, 'Scroll of Recall', 1, -506.2240, -2590.0800, 113.1500, 1),
|
||||||
|
(4127, 'Scroll of Recall', 1, -7135.7200, -3787.7700, 8.7990, 1),
|
||||||
|
(4128, 'Scroll of Recall', 1, 6395.7100, 433.2560, 33.2600, 1),
|
||||||
|
(4129, 'Scryers Tier innkeeper', 530, -2184.0400, 5399.6200, 51.9658, 1),
|
||||||
|
(4130, 'Searing Gorge Blackchar Cave', 0, -7249.7500, -814.5230, 296.6230, 1),
|
||||||
|
(4131, 'Searing Gorge Blackrock Mountain', 0, -7243.0600, -1122.9400, 274.6300, 1),
|
||||||
|
(4132, 'Searing Gorge The Slag Pit', 0, -6601.6300, -1250.7500, 188.0640, 1),
|
||||||
|
(4133, 'Sewer Teleport 01', 571, 5881.2000, 666.5000, 615.7940, 1),
|
||||||
|
(4134, 'Sewer Teleport 04', 571, 5815.3000, 714.6000, 619.0980, 1),
|
||||||
|
(4135, 'Shadow Port', 33, -103.4600, 2122.1000, 155.6550, 1),
|
||||||
|
(4136, 'Shadow Port', 33, -105.6540, 2154.9800, 156.4300, 1),
|
||||||
|
(4137, 'Shadow Port', 33, -84.9900, 2151.0100, 155.6200, 1),
|
||||||
|
(4138, 'Shadowblink', 469, -7469.9300, -1227.9300, 476.7770, 1),
|
||||||
|
(4139, 'Shadowblink', 469, -7486.3600, -1194.3200, 476.8000, 1),
|
||||||
|
(4140, 'Shadowblink', 469, -7500.7000, -1249.8900, 476.7980, 1),
|
||||||
|
(4141, 'Shadowblink', 469, -7506.5800, -1165.2600, 476.7960, 1),
|
||||||
|
(4142, 'Shadowblink', 469, -7524.3600, -1219.1200, 476.7940, 1),
|
||||||
|
(4143, 'Shadowblink', 469, -7538.6300, -1273.6400, 476.8000, 1),
|
||||||
|
(4144, 'Shadowblink', 469, -7542.4700, -1191.9200, 476.3550, 1),
|
||||||
|
(4145, 'Shadowblink', 469, -7561.5400, -1244.0100, 476.8000, 1),
|
||||||
|
(4146, 'Shadowblink', 469, -7581.1100, -1216.1900, 476.8000, 1),
|
||||||
|
(4147, 'Shadowmoon Darkcaster', 540, 72.4708, 184.4520, -13.2380, 1),
|
||||||
|
(4148, 'Shadowmoon Valley Oronoks Farm', 530, -2802.3200, 1286.4600, 77.3836, 1),
|
||||||
|
(4149, 'Shattrath Banish Teleport', 530, -1500.0300, 5217.1400, 32.4600, 1),
|
||||||
|
(4150, 'Shattrath City Aldor Rise', 530, -1751.2400, 5641.2300, 129.0710, 1),
|
||||||
|
(4151, 'Shattrath City Scryers Tier', 530, -2041.2900, 5561.9700, 54.4371, 1),
|
||||||
|
(4152, 'Shattrath City innkeeper', 530, -1903.7900, 5765.7000, 131.2960, 1),
|
||||||
|
(4153, 'Shattrath Portal to Darnassus', 530, -1790.9800, 5413.9800, -12.4282, 1),
|
||||||
|
(4154, 'Shattrath Portal to Exodar', 530, -1880.2800, 5357.5300, -12.4281, 1),
|
||||||
|
(4155, 'Shattrath Portal to Exodar', 530, -4031.2400, -11569.6000, -138.2990, 1),
|
||||||
|
(4156, 'Shattrath Portal to Ironforge', 530, -1795.7900, 5399.6300, -12.4281, 1),
|
||||||
|
(4157, 'Shattrath Portal to Orgrimmar', 530, -1934.4900, 5453.4800, -12.4279, 1),
|
||||||
|
(4158, 'Shattrath Portal to Silvermoon', 530, -1894.6900, 5362.3400, -12.4282, 1),
|
||||||
|
(4159, 'Shattrath Portal to Stormwind', 0, -8998.1400, 861.2540, 29.6206, 1),
|
||||||
|
(4160, 'Shattrath Portal to Stormwind', 530, -1792.7800, 5406.5400, -12.4279, 1),
|
||||||
|
(4161, 'Shattrath Portal to Thunder Bluff', 530, -1936.3200, 5445.9500, -12.4282, 1),
|
||||||
|
(4162, 'Shattrath Portal to Undercity', 0, 1773.4200, 61.7391, -46.3215, 1),
|
||||||
|
(4163, 'Shattrath Portal to Undercity', 530, -1931.4800, 5460.4900, -12.4281, 1),
|
||||||
|
(4164, 'Ship (The Bravery)dock', 0, -8644.6400, 1333.7100, 5.7993, 1),
|
||||||
|
(4165, 'Ship (The Bravery)dock', 1, 6419.1900, 818.6660, 6.1894, 1),
|
||||||
|
(4166, 'Ship (The Lady Mehley)dock', 0, -3898.2700, -597.7260, 5.5310, 1),
|
||||||
|
(4167, 'Ship (The Lady Mehley)dock', 1, -4006.9700, -4730.3300, 5.5366, 1),
|
||||||
|
(4168, 'Ship (The Maidens Fancy)dock', 0, -14279.5000, 571.2000, 6.0777, 1),
|
||||||
|
(4169, 'Ship (The Maidens Fancy)dock', 1, -997.3520, -3830.2500, 5.5803, 1),
|
||||||
|
(4170, 'Ship, Icebreaker (Northspear)dock', 571, 584.0140, -5098.6700, -6.4857, 1),
|
||||||
|
(4171, 'Ship, Night Elf (Elunes Blessing)dock', 1, 6546.9800, 927.7040, 6.1894, 1),
|
||||||
|
(4172, 'Ship, Night Elf (Elunes Blessing)dock', 530, -4264.1400, -11328.3000, 6.0035, 1),
|
||||||
|
(4173, 'Ship, Night Elf (Feathermoon Ferry)dock', 1, -4210.9100, 3280.7300, 5.7750, 1),
|
||||||
|
(4174, 'Ship, Night Elf (Moonspray)dock', 1, 6584.1600, 773.2750, 6.0986, 1),
|
||||||
|
(4175, 'Ship, Night Elf (Moonspray)dock', 1, 8545.0900, 1016.1700, 6.2912, 1),
|
||||||
|
(4176, 'Sholazar Basin Nesingwary Base Camp', 571, 5559.1100, 5765.4300, -77.9385, 1),
|
||||||
|
(4177, 'Sholazar Basin The Seabreach Flow', 571, 5527.8500, 5348.4900, -134.4620, 1),
|
||||||
|
(4178, 'Silithus Ortells Hideout', 1, -7578.7200, 196.9140, 11.5488, 1),
|
||||||
|
(4179, 'Silithus Twilights Run', 1, -6265.9300, 41.8866, 9.0625, 1),
|
||||||
|
(4180, 'Silverpine Forest Fenris Keep', 0, 993.8510, 690.0600, 74.8984, 1),
|
||||||
|
(4181, 'Sister Mercydock', 571, 254.1330, -3752.8000, 0.2291, 1),
|
||||||
|
(4182, 'Sister Mercydock', 571, 93.8904, -3681.4100, 0.2103, 1),
|
||||||
|
(4183, 'Skadi Teleport', 575, 476.7990, -511.1670, 104.7230, 1),
|
||||||
|
(4184, 'Skarthis the Summoner', 547, -76.9917, -157.0810, -2.1064, 1),
|
||||||
|
(4185, 'Socrethar Return Portal Effect', 530, 4778.4600, 3455.3600, 104.1300, 1),
|
||||||
|
(4186, 'Stonetalon Mountains Boulderslide Ravine', 1, -97.6734, 185.5910, 96.6757, 1),
|
||||||
|
(4187, 'Stonetalon Mountains Cragpool Lake', 1, 1605.9900, 96.7067, 98.5654, 1),
|
||||||
|
(4188, 'Stonetalon Mountains Windshear Mine', 1, 935.9090, -302.7410, 0.0220, 1),
|
||||||
|
(4189, 'Storm Peaks', 571, 8974.3700, -1280.5600, 1059.0100, 1),
|
||||||
|
(4190, 'Stormwind Stockade', 34, 131.1490, 3.3395, -25.5229, 1),
|
||||||
|
(4191, 'Stormwind to Dustwallow Teleport', 1, -3722.9100, -4413.9600, 26.1300, 1),
|
||||||
|
(4192, 'Stoutlager Inn innkeeper', 0, -5377.9100, -2973.9100, 323.2520, 1),
|
||||||
|
(4193, 'Stranglethorn Vale Kurzens Compound', 0, -11571.3000, -644.0530, 31.2554, 1),
|
||||||
|
(4194, 'Stranglethorn Vale The Vile Reef', 0, -12211.5000, 644.0560, -67.1350, 1),
|
||||||
|
(4195, 'Subwayentry', 369, -1.0668, -11.3475, -3.9157, 1),
|
||||||
|
(4196, 'Subwayentry', 369, -1.0668, 2470.3000, -3.9157, 1),
|
||||||
|
(4197, 'Subwayentry', 369, -39.7335, 9.7886, -3.9157, 1),
|
||||||
|
(4198, 'Subwayentry', 369, -39.7335, -10.3899, -3.9157, 1),
|
||||||
|
(4199, 'Subwayentry', 369, -39.7335, 30.3816, -3.9157, 1),
|
||||||
|
(4200, 'Subwayentry', 369, -50.9334, 2472.9300, -3.9157, 1),
|
||||||
|
(4201, 'Subwayentry', 369, -50.9334, 2512.1500, -3.9157, 1),
|
||||||
|
(4202, 'Subwayentry', 369, -51.0097, 2492.2300, -3.9157, 1),
|
||||||
|
(4203, 'Subwayentry', 369, 10.1333, 2510.4900, -3.9157, 1),
|
||||||
|
(4204, 'Subwayentry', 369, 10.1333, 2490.7400, -3.9157, 1),
|
||||||
|
(4205, 'Subwayentry', 369, 10.1333, 8.8000, -3.9157, 1),
|
||||||
|
(4206, 'Subwayentry', 369, 10.1896, 28.7706, -3.9157, 1),
|
||||||
|
(4207, 'Summon Menagerie', 578, 1116.1100, 1075.1700, 508.3490, 1),
|
||||||
|
(4208, 'Summon Menagerie', 578, 1163.7200, 1170.9900, 527.3220, 1),
|
||||||
|
(4209, 'Summon Menagerie', 578, 968.7080, 1042.4900, 527.3220, 1),
|
||||||
|
(4210, 'Sunken Temple', 109, -455.3780, 76.5158, -93.3827, 1),
|
||||||
|
(4211, 'Surface Portal', 571, 5795.8800, 2070.8700, -344.0460, 1),
|
||||||
|
(4212, 'Surface Portal', 571, 6203.8700, 2262.1700, 497.1970, 1),
|
||||||
|
(4213, 'Surge Needle Teleporter', 571, 3444.3800, 2361.8700, 38.7409, 1),
|
||||||
|
(4214, 'Swamp of Sorrows Stagalbog Cave', 0, -10919.3000, -3673.0500, 11.0245, 1),
|
||||||
|
(4215, 'Swamp of Sorrows Stonard', 0, -10437.8000, -3307.0400, 20.4499, 1),
|
||||||
|
(4216, 'Teldrassil Banethil Barrow Den', 1, 9794.8400, 1549.1500, 1262.8000, 1),
|
||||||
|
(4217, 'Teldrassil Fel Rock', 1, 10124.0000, 1115.9100, 1322.8200, 1),
|
||||||
|
(4218, 'Teldrassil Shadowthread Cave', 1, 10889.4000, 917.5860, 1326.6400, 1),
|
||||||
|
(4219, 'Teleport - Coldarra, Transitus Shield to Amber Ledge', 571, 3594.1800, 5997.5100, 136.2150, 1),
|
||||||
|
(4220, 'Teleport - Dalaran to Wintergrasp', 571, 5325.0600, 2843.3600, 409.2850, 1),
|
||||||
|
(4221, 'Teleport Darkshire', 0, -10566.0000, -1189.0000, 28.0000, 1),
|
||||||
|
(4222, 'Teleport Defenders', 607, 1226.4300, -71.9616, 70.0842, 1),
|
||||||
|
(4223, 'Teleport Duskwood', 0, -10368.0000, -422.0000, 64.1214, 1),
|
||||||
|
(4224, 'Teleport Elwynn', 0, -9104.0000, -70.0000, 83.0000, 1),
|
||||||
|
(4225, 'Teleport Goldshire', 0, -9464.0000, 62.0000, 56.0000, 1),
|
||||||
|
(4226, 'Teleport Left', 533, 2692.0000, -3399.2700, 267.6860, 1),
|
||||||
|
(4227, 'Teleport Moonbrook', 0, -11020.0000, 1436.0000, 43.6892, 1),
|
||||||
|
(4228, 'Teleport Players on Victory', 631, -548.9830, 2211.2400, 539.2900, 1),
|
||||||
|
(4229, 'Teleport Return', 533, 2685.0600, -3502.3700, 261.3150, 1),
|
||||||
|
(4230, 'Teleport Right', 533, 2692.0000, -3321.8600, 267.6860, 1),
|
||||||
|
(4231, 'Teleport Sanctum Moon - Down', 530, 7513.6300, -6388.9300, 23.8000, 1),
|
||||||
|
(4232, 'Teleport Sanctum Sun - Down', 530, 7199.4000, -7097.3600, 66.9700, 1),
|
||||||
|
(4233, 'Teleport To Zone In', 616, 728.0550, 1329.0300, 275.0000, 1),
|
||||||
|
(4234, 'Teleport Violet Citadel Spire Down', 571, 5790.0000, 734.0000, 640.0000, 1),
|
||||||
|
(4235, 'Teleport Westfall', 0, -10643.0000, 1052.0000, 33.8437, 1),
|
||||||
|
(4236, 'Teleport and Transform', 580, 1667.6400, 633.4660, 28.0500, 1),
|
||||||
|
(4237, 'Teleport back to Main Room', 603, 1970.6100, -25.5988, 324.5500, 1),
|
||||||
|
(4238, 'Teleport from Azshara Tower', 1, 3641.0000, -4702.0000, 121.0000, 1),
|
||||||
|
(4239, 'Teleport to Ashtongue NPCs', 564, 702.2200, 200.3000, 125.0100, 1),
|
||||||
|
(4240, 'Teleport to Center', 568, -34.3160, 1149.6400, 19.1550, 1),
|
||||||
|
(4241, 'Teleport to Chamber Illusion', 603, 2043.1200, -25.6981, 239.7210, 1),
|
||||||
|
(4242, 'Teleport to CoT Stratholme Phase 4', 595, 2071.5500, 1287.6800, 141.6870, 1),
|
||||||
|
(4243, 'Teleport to Council', 564, 603.4200, 305.9820, 271.9000, 1),
|
||||||
|
(4244, 'Teleport to Final Chamber Effect DND', 531, -8632.8400, 2055.8700, 108.8600, 1),
|
||||||
|
(4245, 'Teleport to Gnomeregan', 0, -5095.0000, 757.0000, 261.0000, 1),
|
||||||
|
(4246, 'Teleport to Hall of Command', 0, 2402.6200, -5633.2800, 377.0210, 1),
|
||||||
|
(4247, 'Teleport to Heart of Acherus', 609, 2419.9100, -5620.4800, 420.6440, 1),
|
||||||
|
(4248, 'Teleport to Icecrown Illusion', 603, 1949.1300, -80.6744, 239.9900, 1),
|
||||||
|
(4249, 'Teleport to Inside Violet Hold', 608, 1857.2400, 803.8770, 44.0085, 1),
|
||||||
|
(4250, 'Teleport to Lake Wintergrasp', 571, 4561.5800, 2835.3300, 389.7900, 1),
|
||||||
|
(4251, 'Teleport to Lake Wintergrasp', 571, 5025.7100, 3673.4100, 362.6870, 1),
|
||||||
|
(4252, 'Teleport to Lake Wintergrasp', 571, 5094.6700, 2170.3300, 365.6010, 1),
|
||||||
|
(4253, 'Teleport to Lake Wintergrasp', 571, 5386.0500, 2840.9700, 418.6750, 1),
|
||||||
|
(4254, 'Teleport to Molten Core DND', 409, 1080.0000, -483.0000, -108.0000, 1),
|
||||||
|
(4255, 'Teleport to Stormwind Illusion', 603, 1954.1400, 21.5220, 239.7180, 1),
|
||||||
|
(4256, 'Teleport to Sunwell Plateau', 580, 1861.4500, 495.1250, 82.9059, 1),
|
||||||
|
(4257, 'Teleport to Twin Emps Effect DND', 531, -8971.8100, 1321.4700, -104.2490, 1),
|
||||||
|
(4258, 'Teleport to Violet Stand', 571, 5724.6200, 1013.1700, 174.4800, 1),
|
||||||
|
(4259, 'Teleport to the Silvermoon', 530, 10021.1000, -7014.8700, 49.7100, 1),
|
||||||
|
(4260, 'Teleport to the Undercity', 0, 1805.9300, 335.6600, 70.3900, 1),
|
||||||
|
(4261, 'Teleport', 1, -3891.8000, -4609.9700, 9.5011, 1),
|
||||||
|
(4262, 'Teleport', 409, 736.5160, -1176.3500, -119.0060, 1),
|
||||||
|
(4263, 'Teleport', 531, -8306.6800, 2060.8400, 133.0620, 1),
|
||||||
|
(4264, 'Teleport', 531, -8330.6300, 2123.1400, 133.0620, 1),
|
||||||
|
(4265, 'Teleport', 533, 2633.4900, -3529.5600, 274.1110, 1),
|
||||||
|
(4266, 'Teleport', 533, 2905.6300, -3769.9600, 273.6200, 1),
|
||||||
|
(4267, 'Teleport', 571, 3574.2200, 6652.1300, 195.1850, 1),
|
||||||
|
(4268, 'Teleport', 571, 3646.7400, 5893.2000, 174.4830, 1),
|
||||||
|
(4269, 'Teleport', 571, 4590.9400, -5711.2400, 184.5070, 1),
|
||||||
|
(4270, 'Teleport', 576, 504.7420, 88.9122, -16.1245, 1),
|
||||||
|
(4271, 'Teleport', 578, 1103.4700, 1049.5700, 512.0000, 1),
|
||||||
|
(4272, 'Teleport', 600, -369.0000, -601.0000, 2.0000, 1),
|
||||||
|
(4273, 'Teleport: Argent Tournament', 571, 8480.5500, 1092.9000, 554.4850, 1),
|
||||||
|
(4274, 'Teleport: Black Temple', 530, -3560.5200, 583.3530, 10.9431, 1),
|
||||||
|
(4275, 'Teleport: Darnassus', 1, 9664.1400, 2526.3600, 1332.6900, 1),
|
||||||
|
(4276, 'Teleport: Moonglade', 1, 7992.6200, -2680.0400, 512.0990, 1),
|
||||||
|
(4277, 'Teleport: Shattrath', 530, -1842.0700, 5497.1700, -12.4306, 1),
|
||||||
|
(4278, 'Teleport: Stonard', 0, -10469.0000, -3331.5400, 25.4716, 1),
|
||||||
|
(4279, 'Teleport: Theramore', 1, -3748.1100, -4440.2100, 30.5688, 1),
|
||||||
|
(4280, 'Tempest Keep', 550, 411.4090, -39.8267, 20.1802, 1);
|
||||||
|
INSERT INTO `playerbots_travelnode` (`id`, `name`, `map_id`, `x`, `y`, `z`, `linked`) VALUES
|
||||||
|
(4281, 'Tempest Keep: The Arcatraz', 552, 278.6480, -12.6903, 22.4479, 1),
|
||||||
|
(4282, 'Tempest Keep: The Botanica', 553, 17.5470, 404.8610, -27.1645, 1),
|
||||||
|
(4283, 'Tempest Keep: The Mechanar', 554, 169.2420, -12.2941, -0.0010, 1),
|
||||||
|
(4284, 'Terokkar Forest Skettis', 530, -3944.9300, 3664.0900, 287.9900, 1),
|
||||||
|
(4285, 'Terokkar Forest Terokks Rest', 530, -3868.3500, 3521.8800, 278.5610, 1),
|
||||||
|
(4286, 'Test of Lore', 1, -2354.0300, -1902.0700, 95.7800, 1),
|
||||||
|
(4287, 'The Barrens Baeldun Keep', 1, -4071.7300, -2381.6400, 126.2140, 1),
|
||||||
|
(4288, 'The Barrens Dreadmist Den', 1, 318.8870, -2225.7300, 212.5040, 1),
|
||||||
|
(4289, 'The Chilled Quagmire spiritguide', 571, 5103.1300, 3462.1300, 368.5680, 1),
|
||||||
|
(4290, 'The Chilled Quagmire spirithealer', 571, 5099.0300, 3469.6700, 368.4850, 1),
|
||||||
|
(4291, 'The Nexus', 576, 545.9580, -125.9330, -24.9367, 1),
|
||||||
|
(4292, 'The Skybreaker', 623, 5.2403, 0.2579, 20.8691, 1),
|
||||||
|
(4293, 'The Storm Peaks Frostfloe Deep', 571, 8300.4300, -2564.8600, 1153.5900, 1),
|
||||||
|
(4294, 'The Storm Peaks Frostgrips Hollow', 571, 6956.1400, -2.5143, 808.5300, 1),
|
||||||
|
(4295, 'The Storm Peaks Gimoraks Den', 571, 7920.2400, -1625.2100, 910.8520, 1),
|
||||||
|
(4296, 'The Storm Peaks Hibernal Cavern', 571, 7241.0300, -2075.5900, 763.0780, 1),
|
||||||
|
(4297, 'The Storm Peaks Plain of Echoes', 571, 8109.8900, -2815.7900, 1135.3200, 1),
|
||||||
|
(4298, 'The Storm Peaks The Forlorn Mine', 571, 6929.4000, -1315.7700, 831.3460, 1),
|
||||||
|
(4299, 'The Storm Peaks The Frozen Mine', 571, 7768.5000, -16.3215, 864.4010, 1),
|
||||||
|
(4300, 'The Storm Peaks', 571, 7268.5100, -2125.3800, 778.1580, 1),
|
||||||
|
(4301, 'The Sunken Ring spiritguide', 571, 5104.7500, 2300.9500, 368.5680, 1),
|
||||||
|
(4302, 'The Zephyrdock', 1, -1026.8600, 358.4000, 133.3400, 1),
|
||||||
|
(4303, 'The Zephyrdock', 1, 1139.7300, -4142.9300, 52.0080, 1),
|
||||||
|
(4304, 'Thousand Needles Darkcloud Pinnacle', 1, -4904.6700, -1970.1300, 86.8811, 1),
|
||||||
|
(4305, 'Thousand Needles Roguefeather Den', 1, -5533.0400, -1602.8800, 29.1719, 1),
|
||||||
|
(4306, 'Thousand Needles Splithoof Hold', 1, -4952.9400, -2337.3000, -56.5321, 1),
|
||||||
|
(4307, 'Thousand Needles The Weathered Nook', 1, -5217.6500, -2788.9900, -7.4459, 1),
|
||||||
|
(4308, 'Thrall', 0, 1953.8400, 233.8350, 41.8800, 1),
|
||||||
|
(4309, 'Thrall', 1, 1920.0100, -4123.9500, 43.6300, 1),
|
||||||
|
(4310, 'Thunderbrew Distillery innkeeper', 0, -5601.6000, -531.2030, 399.7370, 1),
|
||||||
|
(4311, 'Tirisfal Glades Agamand Family Crypt', 0, 3043.6500, 681.8670, 67.0126, 1),
|
||||||
|
(4312, 'Tirisfal Glades Gallows End Tavern', 0, 2262.2600, 244.2570, 33.7170, 1),
|
||||||
|
(4313, 'To Icecrown Airship - Player - Aura - Teleport to Dalaran Trigger', 571, 5831.5300, 497.0880, 657.4660, 1),
|
||||||
|
(4314, 'Toshleys Station Transporter', 530, 2054.0500, 5569.1600, 263.5710, 1),
|
||||||
|
(4315, 'Translocate', 0, 1805.0000, 327.0000, 70.5000, 1),
|
||||||
|
(4316, 'Translocate', 530, -2259.7400, 3215.0300, -4.0500, 1),
|
||||||
|
(4317, 'Translocate', 530, -2307.3500, 3123.9200, 13.6900, 1),
|
||||||
|
(4318, 'Translocate', 530, -589.0000, 4079.0000, 143.3000, 1),
|
||||||
|
(4319, 'Translocate', 530, 12780.9000, -6877.5000, 22.7861, 1),
|
||||||
|
(4320, 'Translocate', 530, 9334.5000, -7880.7600, 74.9094, 1),
|
||||||
|
(4321, 'Translocation', 530, -594.0000, 4079.0000, 94.0000, 1),
|
||||||
|
(4322, 'Trespasser!', 571, 5773.0000, 703.5000, 641.6000, 1),
|
||||||
|
(4323, 'Trespasser!', 571, 5846.5000, 605.5000, 650.9000, 1),
|
||||||
|
(4324, 'Trespasser!', 571, 8460.0000, 700.0000, 547.4000, 1),
|
||||||
|
(4325, 'Trespasser!', 571, 8573.0000, 703.9000, 547.3000, 1),
|
||||||
|
(4326, 'Turtle (Green Island)dock', 571, 2649.6000, 844.8000, 1.7773, 1),
|
||||||
|
(4327, 'Turtle (Walker of Waves)dock', 571, 2638.1300, 938.4000, 1.7773, 1),
|
||||||
|
(4328, 'Uldaman', 70, -42.3058, 263.8750, -48.9355, 1),
|
||||||
|
(4329, 'Ulduar spirithealer', 571, 9025.6600, -1178.5700, 1060.0800, 1),
|
||||||
|
(4330, 'Undervatorentry', 0, 1552.8000, 240.7730, 55.4904, 1),
|
||||||
|
(4331, 'Undervatorentry', 0, 1596.1500, 283.2000, 55.4904, 1),
|
||||||
|
(4332, 'Undervatorentry', 0, 1596.2000, 197.1040, 55.4904, 1),
|
||||||
|
(4333, 'Undervatorentryentry', 0, 1564.0000, 240.6560, 55.7571, 1),
|
||||||
|
(4334, 'Undervatorentryentry', 0, 1595.3800, 197.7060, 55.4904, 1),
|
||||||
|
(4335, 'Undervatorentryentry', 0, 1595.3800, 213.3330, 57.8905, 1),
|
||||||
|
(4336, 'Undervatorentryentry', 0, 1595.6500, 271.8890, 55.7571, 1),
|
||||||
|
(4337, 'Use Legion Teleporter', 530, -2833.0900, 1949.8900, 201.2560, 1),
|
||||||
|
(4338, 'Vampiric Shadowbat', 532, -10930.9000, -1995.7500, 49.4768, 1),
|
||||||
|
(4339, 'Vanish', 309, -11516.1000, -1605.3100, 41.3000, 1),
|
||||||
|
(4340, 'Vator2entry', 90, -800.3290, 314.9250, -272.4900, 1),
|
||||||
|
(4341, 'Vatorentry', 0, -5163.7700, 655.3050, 348.5880, 1),
|
||||||
|
(4342, 'Vatorentry', 0, -5164.2400, 650.3540, 247.9780, 1),
|
||||||
|
(4343, 'Vortex', 616, 755.0000, 1301.0000, 280.0000, 1),
|
||||||
|
(4344, 'Watery Grave', 548, 337.6900, -732.8700, -13.7400, 1),
|
||||||
|
(4345, 'Watery Grave', 548, 365.5300, -737.1200, -14.0000, 1),
|
||||||
|
(4346, 'Watery Grave', 548, 366.2700, -709.4000, -13.9200, 1),
|
||||||
|
(4347, 'Watery Grave', 548, 372.8500, -690.8400, -13.9100, 1),
|
||||||
|
(4348, 'Weegli Blastfuse', 209, 1881.0500, 1297.3600, 48.4190, 1),
|
||||||
|
(4349, 'Western Plaguelands Mardenholde Keep', 0, 2936.4100, -1395.9000, 166.0270, 1),
|
||||||
|
(4350, 'Westfall The Cooper Residence', 0, -11023.1000, 1547.4800, 44.4936, 1),
|
||||||
|
(4351, 'Winterspring Everlook', 1, 6768.3400, -4668.5200, 723.7480, 1),
|
||||||
|
(4352, 'Winterspring Moon Horror Den', 1, 7124.2700, -4637.7800, 639.6550, 1),
|
||||||
|
(4353, 'Wyrmrest Temple flightMaster', 571, 3647.2600, 244.0510, 52.3397, 1),
|
||||||
|
(4354, 'Wyrmrest Temple spirithealer', 571, 3546.8600, 272.9880, 45.5817, 1),
|
||||||
|
(4355, 'Zeppelin (The Iron Eagle)dock', 0, -12452.0000, 221.0670, 31.7681, 1),
|
||||||
|
(4356, 'Zeppelin (The Iron Eagle)dock', 1, 1359.5700, -4632.2000, 53.6569, 1),
|
||||||
|
(4357, 'Zeppelin (The Purple Princess)dock', 0, -12407.5000, 211.8380, 31.5014, 1),
|
||||||
|
(4358, 'Zeppelin (The Purple Princess)dock', 0, 2061.4200, 235.5580, 100.1520, 1),
|
||||||
|
(4359, 'Zeppelin (The Thundercaller)dock', 0, 2064.2400, 291.6030, 97.0904, 1),
|
||||||
|
(4360, 'Zeppelin (The Thundercaller)dock', 1, 1319.3200, -4658.0900, 53.8358, 1),
|
||||||
|
(4361, 'Zeppelindock', 571, 1412.9900, -3092.5800, 166.2270, 1),
|
||||||
|
(4362, 'ZulDrak Amphitheater of Anguish', 571, 5715.7900, -2945.0100, 296.5510, 1),
|
||||||
|
(4363, 'ZulDrak ZimTorga', 571, 5756.5800, -3567.6300, 387.0390, 1),
|
||||||
|
(4364, '[PH] Teleport to Auberdine', 1, 6581.0500, 767.5000, 5.7843, 1),
|
||||||
|
(4365, '[PH] Teleport to Booty Bay', 0, -14457.0000, 496.4500, 39.1392, 1),
|
||||||
|
(4366, '[PH] Teleport to Felwood', 1, 5483.9000, -749.8810, 334.6210, 1),
|
||||||
|
(4367, '[PH] Teleport to GromGol', 0, -12415.0000, 207.6180, 31.5017, 1),
|
||||||
|
(4368, '[PH] Teleport to Menethil Harbor', 0, -3752.8100, -851.5580, 10.1153, 1),
|
||||||
|
(4369, '[PH] Teleport to Orgrimmar', 1, 1552.5000, -4420.6600, 8.9480, 1),
|
||||||
|
(4370, '[PH] Teleport to Theramore', 1, -3615.4900, -4467.3400, 21.6032, 1),
|
||||||
|
(4371, 'c-Maraudon', 1, -1424.0400, 2945.0100, 134.5400, 1),
|
||||||
|
(4372, 'c-Tauren start', 1, -3034.7000, 144.0400, 70.8700, 1),
|
||||||
|
(4373, 'c1-Blackfathom Deeps', 1, 4158.0100, 877.6000, -20.6800, 1),
|
||||||
|
(4374, 'c1-Blackrock Mountain', 0, -7502.2000, -1152.9800, 269.5500, 1),
|
||||||
|
(4375, 'c1-Coilfang', 530, 571.1000, 6938.9700, -16.8100, 1),
|
||||||
|
(4376, 'c1-Deadmine exit', 0, -11367.5000, 1617.1000, 71.2200, 1),
|
||||||
|
(4377, 'c1-Dire Maul', 1, -3626.3900, 917.3700, 150.1300, 1),
|
||||||
|
(4378, 'c1-Ebon Hold', 609, 2390.0200, -5640.9100, 377.0900, 1),
|
||||||
|
(4379, 'c1-Sunken Temple', 0, -10416.5000, -3832.5300, -36.9200, 1),
|
||||||
|
(4380, 'c1-The Noxious Pass', 609, 2528.2200, -5580.4400, 162.0200, 1),
|
||||||
|
(4381, 'c1-Timbermaw Hold', 1, 7016.7500, -2153.8400, 595.0900, 1),
|
||||||
|
(4382, 'c1-Wailing Caverns', 1, -588.5300, -2037.6900, 57.6000, 1),
|
||||||
|
(4383, 'c2-Blackfathom Deeps', 1, 4156.6000, 909.8900, -20.9700, 1),
|
||||||
|
(4384, 'c2-Blackrock Mountain', 0, -7591.3100, -1114.4400, 249.9100, 1),
|
||||||
|
(4385, 'c2-Coilfang', 530, 571.1000, 6938.9700, -15.2000, 1),
|
||||||
|
(4386, 'c2-Deadmine exit', 0, -11367.1000, 1610.4800, 76.6300, 1),
|
||||||
|
(4387, 'c2-Dire Maul', 1, -3628.0800, 919.5500, 137.8400, 1),
|
||||||
|
(4388, 'c2-Ebon Hold', 609, 2383.6500, -5645.2000, 420.7700, 1),
|
||||||
|
(4389, 'c2-Sunken Temple', 0, -10408.7000, -3834.2900, -44.6900, 1),
|
||||||
|
(4390, 'c2-The Noxious Pass', 609, 2538.3500, -5573.0500, 162.4600, 1),
|
||||||
|
(4391, 'c3-Blackfathom Deeps', 1, 4157.4600, 916.4400, -17.4000, 1),
|
||||||
|
(4392, 'c3-Coilfang', 530, 651.0700, 6865.3700, -82.3400, 1),
|
||||||
|
(4393, 'c3-Deadmine exit', 0, -11381.5000, 1584.1100, 82.1000, 1),
|
||||||
|
(4394, 'c3-Ebon Hold', 609, 2325.0300, -5659.6000, 382.2400, 1),
|
||||||
|
(4395, 'c3-Scarlet Enclave', 609, 2409.0900, -5722.3700, 154.0000, 1),
|
||||||
|
(4396, 'c3-Sunken Temple', 0, -10325.2000, -3865.8600, -44.4500, 1),
|
||||||
|
(4397, 'c3-The Noxious Pass', 609, 2546.6100, -5563.8900, 162.8800, 1),
|
||||||
|
(4398, 'c4-Coilfang', 530, 607.1700, 6908.6800, -49.2000, 1),
|
||||||
|
(4399, 'c4-Deadmine exit', 0, -11379.6000, 1578.7900, 87.8400, 1),
|
||||||
|
(4400, 'c4-Ebon Hold', 609, 2348.5800, -5695.3500, 382.2400, 1),
|
||||||
|
(4401, 'c4-Scarlet Enclave', 609, 2402.8600, -5727.0300, 154.0000, 1),
|
||||||
|
(4402, 'c4-The Noxious Pass', 609, 2563.5200, -5547.7900, 163.2700, 1),
|
||||||
|
(4403, 'c5-Coilfang', 530, 574.6800, 6942.9300, -37.7200, 1),
|
||||||
|
(4404, 'c5-Deadmine exit', 0, -11340.2000, 1571.6100, 94.4400, 1),
|
||||||
|
(4405, 'c6-Coilfang', 530, 723.7400, 6865.7800, -74.1000, 1),
|
||||||
|
(4406, 'c7-Coilfang', 530, 731.5700, 6866.0100, -70.4700, 1);
|
||||||
File diff suppressed because it is too large
Load Diff
143899
data/sql/playerbots/updates/2026_05_09_03_travelnode_path_cmangos_import.sql
Normal file
143899
data/sql/playerbots/updates/2026_05_09_03_travelnode_path_cmangos_import.sql
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@
|
|||||||
|
-- Manual travelnode coverage for the Aldrassil ramp in Shadowglen
|
||||||
|
-- (Teldrassil, map 1, zone 141). Adds 9 anchor nodes along the spiral
|
||||||
|
-- ramp (base -> intermediate ramp waypoints -> top platform near
|
||||||
|
-- Tenaron Stormgrip). All nodes are `linked = 0` so
|
||||||
|
-- `.playerbots travel generatenode` will iterate them and let mmap
|
||||||
|
-- compute the actual walk paths between consecutive nodes. Splitting
|
||||||
|
-- the climb into short segments (~30y each) gives mmap a much better
|
||||||
|
-- chance of resolving each piece than a single 300y end-to-end probe.
|
||||||
|
--
|
||||||
|
-- TEMPORARILY DISABLED: isolating generatenode behaviour on the OG
|
||||||
|
-- (cmangos-imported) graph. Re-enable by removing the comment prefix
|
||||||
|
-- once the regen flow is verified stable.
|
||||||
|
|
||||||
|
-- SET @n1 := (SELECT IFNULL(MAX(id), 0) + 1 FROM playerbots_travelnode);
|
||||||
|
-- SET @n2 := @n1 + 1;
|
||||||
|
-- SET @n3 := @n1 + 2;
|
||||||
|
-- SET @n4 := @n1 + 3;
|
||||||
|
-- SET @n5 := @n1 + 4;
|
||||||
|
-- SET @n6 := @n1 + 5;
|
||||||
|
-- SET @n7 := @n1 + 6;
|
||||||
|
-- SET @n8 := @n1 + 7;
|
||||||
|
-- SET @n9 := @n1 + 8;
|
||||||
|
|
||||||
|
-- INSERT INTO playerbots_travelnode (id, name, map_id, x, y, z, linked) VALUES
|
||||||
|
-- (@n1, 'Aldrassil Ramp 1 (base)', 1, 10413.756, 887.97363, 1319.3668, 0),
|
||||||
|
-- (@n2, 'Aldrassil Ramp 2', 1, 10440.520, 870.32320, 1328.9324, 0),
|
||||||
|
-- (@n3, 'Aldrassil Ramp 3', 1, 10497.001, 854.46014, 1345.1770, 0),
|
||||||
|
-- (@n4, 'Aldrassil Ramp 4', 1, 10517.199, 821.48640, 1354.7914, 0),
|
||||||
|
-- (@n5, 'Aldrassil Ramp 5', 1, 10477.926, 847.88855, 1372.1685, 0),
|
||||||
|
-- (@n6, 'Aldrassil Ramp 6', 1, 10455.358, 831.34240, 1380.9377, 0),
|
||||||
|
-- (@n7, 'Aldrassil Ramp 7', 1, 10460.220, 800.71716, 1388.3368, 0),
|
||||||
|
-- (@n8, 'Aldrassil Ramp 8', 1, 10507.434, 793.30420, 1397.2166, 0),
|
||||||
|
-- (@n9, 'Aldrassil Ramp 9 (top)', 1, 10495.496, 804.67700, 1397.2662, 0);
|
||||||
|
|
||||||
|
SELECT 1; -- no-op so the file is still valid SQL for the updater
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
DELETE FROM ai_playerbot_texts WHERE name IN (
|
||||||
|
'send_mail_disabled'
|
||||||
|
);
|
||||||
|
|
||||||
|
DELETE FROM ai_playerbot_texts_chance WHERE name IN (
|
||||||
|
'send_mail_disabled'
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO ai_playerbot_texts (id, name, text, say_type, reply_type, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8) VALUES
|
||||||
|
(1899, 'send_mail_disabled', 'I cannot send mail', 0, 0, '우편을 보낼 수 없습니다', 'Je ne peux pas envoyer de courrier', 'Ich kann keine Post senden', '我不能寄送邮件', '我不能寄送郵件', 'No puedo enviar correo', 'No puedo enviar correo', 'Я не могу отправить почту');
|
||||||
|
|
||||||
|
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES
|
||||||
|
('send_mail_disabled', 100);
|
||||||
351
extract_ac_client_data.sh
Normal file
351
extract_ac_client_data.sh
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# AzerothCore client-data extraction for mod-playerbots.
|
||||||
|
# Run from anywhere — output lands in $SERVER_DATA_DIR.
|
||||||
|
# =============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ─── PATHS ──────────────────────────────────────────────────────────────────
|
||||||
|
WOW_CLIENT_DATA="/home/dev/wow_client_data"
|
||||||
|
TOOLS_DIR="/home/dev/azerothcore_installer/_server/azerothcore/env/dist/bin"
|
||||||
|
SERVER_DATA_DIR="$TOOLS_DIR"
|
||||||
|
|
||||||
|
# ─── TOGGLES ────────────────────────────────────────────────────────────────
|
||||||
|
EXTRACT_DBC_AND_MAPS=true
|
||||||
|
EXTRACT_VMAPS=true
|
||||||
|
EXTRACT_MMAPS=true
|
||||||
|
|
||||||
|
MMAP_THREADS=0 # 0 = auto-detect (each thread uses 1-2 GB RAM)
|
||||||
|
MMAP_SINGLE_MAP="" # e.g. "489" for Warsong Gulch only
|
||||||
|
|
||||||
|
# Verbatim copy of azerothcore-wotlk/master:src/tools/mmaps_generator/mmaps-config.yaml
|
||||||
|
# (also the same config the mod-playerbots fork ships).
|
||||||
|
MMAPS_CONFIG_YAML=$(cat <<'YAML_EOF'
|
||||||
|
mmapsConfig:
|
||||||
|
skipLiquid: false
|
||||||
|
skipContinents: false
|
||||||
|
skipJunkMaps: true
|
||||||
|
skipBattlegrounds: false
|
||||||
|
|
||||||
|
# Path to the directory containing navigation data files.
|
||||||
|
# This directory should contain the "maps" and "vmaps" folders,
|
||||||
|
# and is also where the "mmaps" folder will be created or located.
|
||||||
|
dataDir: "./"
|
||||||
|
|
||||||
|
meshSettings:
|
||||||
|
# Here we have global config for recast navigation.
|
||||||
|
# It's possible to override these data on map or tile level (see mapsOverrides).
|
||||||
|
|
||||||
|
# Maximum slope angle (in degrees) NPCs can walk on.
|
||||||
|
# Surfaces steeper than this will be considered unwalkable.
|
||||||
|
walkableSlopeAngle: 50
|
||||||
|
|
||||||
|
# --- Cell Size Calculation ---
|
||||||
|
# Many parameters below are defined in "cell units".
|
||||||
|
# In RecastDemo, you often work with world units instead of cell units.
|
||||||
|
# The actual generator uses (src/tools/mmaps_generator/Config.cpp:28):
|
||||||
|
#
|
||||||
|
# cellSize = MMAP::GRID_SIZE / vertexPerMapEdge
|
||||||
|
#
|
||||||
|
# Where:
|
||||||
|
# MMAP::GRID_SIZE = 533.3333f (the size of one map tile in world units)
|
||||||
|
# vertexPerMapEdge = number of vertices along one edge of the full map grid
|
||||||
|
#
|
||||||
|
# Example (AC stock):
|
||||||
|
# vertexPerMapEdge = 2000 → cellSize ≈ 533.3333 / 2000 ≈ 0.2667 yd
|
||||||
|
#
|
||||||
|
# IMPORTANT: when changing vertexPerMapEdge, the per-cell parameters
|
||||||
|
# below (walkableHeight, walkableClimb, walkableRadius) must be re-scaled
|
||||||
|
# to preserve their world-unit semantics. Doubling vertexPerMapEdge
|
||||||
|
# halves cellSize, so cell counts must double to keep the same yd value.
|
||||||
|
#
|
||||||
|
# To convert a value from cell units to world units (e.g., walkableClimb),
|
||||||
|
# multiply by cellSize. For example, a walkableClimb of 6 at 2000 resolution:
|
||||||
|
# 6 × 0.2667 ≈ 1.60 yd
|
||||||
|
|
||||||
|
# Minimum ceiling height (in cell units) NPCs need to pass under an obstacle.
|
||||||
|
# Controls how much vertical clearance is required.
|
||||||
|
# To convert to world units, multiply by cellSize (see "Cell Size Calculation").
|
||||||
|
# 6 cells × 0.2667 yd ≈ 1.60 yd — matches WoW player capsule height at
|
||||||
|
# 2000 resolution (AC stock). Preserves the 1.60 yd world-unit
|
||||||
|
# ceiling-clearance requirement.
|
||||||
|
walkableHeight: 6
|
||||||
|
|
||||||
|
# Maximum height difference (in cell units) NPCs can step up or down.
|
||||||
|
# Higher values allow walking over fences, ledges, or steps.
|
||||||
|
# To convert to world units, multiply by cellSize (see "Cell Size Calculation").
|
||||||
|
#
|
||||||
|
# Vanilla WotLK uses 6, which allows creatures to "jump" over fences.
|
||||||
|
# Classic WotLK uses 4, which forces creatures to walk around fences.
|
||||||
|
# 6 cells × 0.2667 yd ≈ 1.60 yd — Vanilla-WotLK step semantics at
|
||||||
|
# 2000 resolution. Preserves the 1.60 yd world-unit step. The mmap
|
||||||
|
# is shared with every creature, NPC patrol, escort, and quest mob;
|
||||||
|
# tightening below stock breaks patrols that cross 1.5y ledges.
|
||||||
|
walkableClimb: 4
|
||||||
|
|
||||||
|
# Minimum distance (in cell units) around walkable surfaces.
|
||||||
|
# Helps prevent NPCs from clipping into walls and narrow gaps.
|
||||||
|
# To convert to world units, multiply by cellSize (see "Cell Size Calculation").
|
||||||
|
# 2 cells × 0.2667 yd ≈ 0.53 yd — AC stock world-unit buffer at
|
||||||
|
# 2000 resolution. Tested wider (= 0.71y world units): erodes polys
|
||||||
|
# near mountains/cliffs so pathfinder routes through surviving
|
||||||
|
# (higher/worse) polys → bot climbs mountains.
|
||||||
|
walkableRadius: 2
|
||||||
|
|
||||||
|
# Number of vertices along one edge of the entire map's navmesh grid.
|
||||||
|
# Higher values increase mesh resolution but also CPU/memory usage.
|
||||||
|
# 2000 = AC stock baseline. cellSize ≈ 0.2667 yd.
|
||||||
|
vertexPerMapEdge: 2000
|
||||||
|
|
||||||
|
# Number of vertices along one edge of each tile chunk.
|
||||||
|
# Must divide vertexPerMapEdge evenly — the generator uses integer
|
||||||
|
# division: tilesPerMapEdge = vertexPerMap / vertexPerTile
|
||||||
|
# (src/tools/mmaps_generator/Config.cpp:144).
|
||||||
|
# A higher vertex count per tile means fewer total tiles,
|
||||||
|
# reducing runtime work to load, unload, and manage tiles.
|
||||||
|
# 80 = AC stock baseline. 2000 / 80 = 25 tiles per map edge, 625
|
||||||
|
# tiles per map (~21y per tile). Lots of small tiles, low per-tile
|
||||||
|
# RAM, more seams to stitch across.
|
||||||
|
vertexPerTileEdge: 80
|
||||||
|
|
||||||
|
# Tolerance for how much a polygon can deviate from the original geometry when simplified.
|
||||||
|
# Higher values produce simpler (faster) meshes but can reduce accuracy.
|
||||||
|
# 0.8 (vs the AC stock 1.8 and recast canonical 1.3) keeps polygon
|
||||||
|
# edges close to real terrain. Targets "merged step into ramp"
|
||||||
|
# simplification artifacts that produce corner-cuts and false NOPATH.
|
||||||
|
maxSimplificationError: 0.8
|
||||||
|
|
||||||
|
# You can override any global parameter for a specific map by specifying its map ID.
|
||||||
|
# Inside each map override, you can also override parameters per individual tile,
|
||||||
|
# identified by a string "tileX,tileY" (coordinates).
|
||||||
|
#
|
||||||
|
# Overrides cascade: global settings → map overrides → tile overrides.
|
||||||
|
# For example:
|
||||||
|
#
|
||||||
|
# mapsOverrides:
|
||||||
|
# "0": # Map ID 0 overrides
|
||||||
|
# walkableRadius: 5 # Override global climb height for entire map 0
|
||||||
|
#
|
||||||
|
# tilesOverrides:
|
||||||
|
# "50,70": # Tile at coordinates (50,70) on map 0
|
||||||
|
# walkableSlopeAngle: 70 # Override slope angle locally just here
|
||||||
|
# walkableClimb: 4 # Also override climb height for this tile only
|
||||||
|
#
|
||||||
|
# "51,71":
|
||||||
|
# walkableClimb: 3 # Override climb height for tile (51,71)
|
||||||
|
#
|
||||||
|
# "48,32":
|
||||||
|
# walkableClimb: 1 # Even smaller climb for tile (48,32)
|
||||||
|
#
|
||||||
|
# "1": # Map ID 1 overrides example
|
||||||
|
# walkableHeight: 8 # Increase clearance for whole map 1
|
||||||
|
#
|
||||||
|
# tilesOverrides:
|
||||||
|
# "100,100":
|
||||||
|
# maxSimplificationError: 2.5 # Looser mesh simplification for this tile only
|
||||||
|
#
|
||||||
|
# "101,101":
|
||||||
|
# walkableRadius: 1 # Smaller NPC radius here for tight corridors
|
||||||
|
#
|
||||||
|
# This approach allows very fine-grained control of navigation mesh parameters
|
||||||
|
# on a per-map and per-tile basis, optimizing pathfinding quality and performance.
|
||||||
|
#
|
||||||
|
# All parameters defined globally are eligible for override.
|
||||||
|
# Just specify the parameter name and new value in the override section.
|
||||||
|
mapsOverrides:
|
||||||
|
"562": # Blade's Edge Arena
|
||||||
|
walkableRadius: 0 # This allows walking on the ropes to the pillars
|
||||||
|
|
||||||
|
"48": # Blackfathom Deeps
|
||||||
|
cellSizeVertical: 0.5334 # ch*2 = 0.2667 * 2 ≈ 0.5334. Reduce the chance to have underground levels.
|
||||||
|
|
||||||
|
"529": # Arathi Basin
|
||||||
|
tilesOverrides:
|
||||||
|
"30,29": # Lumber Mill
|
||||||
|
# Make sure that Fear will not drop players rom cliff -
|
||||||
|
# https://github.com/azerothcore/azerothcore-wotlk/pull/22462#issuecomment-3067024680
|
||||||
|
walkableSlopeAngle: 45
|
||||||
|
|
||||||
|
"530": # Outland
|
||||||
|
tilesOverrides:
|
||||||
|
"32,30": # Dark portal
|
||||||
|
walkableSlopeAngle: 45 # https://github.com/chromiecraft/chromiecraft/issues/8404#issuecomment-3476012660
|
||||||
|
|
||||||
|
# debugOutput generates debug files in the `meshes` directory for use with RecastDemo.
|
||||||
|
# This is useful for inspecting and debugging mmap generation visually.
|
||||||
|
#
|
||||||
|
# My workflow:
|
||||||
|
# 1. Install RecastDemo. I'm building it from the source of this fork: https://github.com/jackpoz/recastnavigation
|
||||||
|
# 2. In-game, move your character to the area you want to debug.
|
||||||
|
# 3. Type `.mmap loc` in chat. This will output:
|
||||||
|
# - The current tile file name (e.g., `04832.mmtile`)
|
||||||
|
# - The Recast config values used to generate that tile
|
||||||
|
# 4. Enable `debugOutput` and regenerate mmaps (preferably just the tile from step 3).
|
||||||
|
# - To regenerate only one tile, delete it from the `mmaps` folder.
|
||||||
|
# 5. After generation, you will find debug files in the `meshes` folder, including an OBJ file (e.g., `map0004832.obj`)
|
||||||
|
# 6. Copy these debug files to the `Meshes` folder used by RecastDemo.
|
||||||
|
# - RecastDemo expects this folder to be in the same directory as its executable.
|
||||||
|
# 7. In RecastDemo:
|
||||||
|
# - Click "Input Mesh" and select the `.obj` file
|
||||||
|
# - Choose "Solo Mesh" in the Sample selector
|
||||||
|
# 8. (Optional) Reuse the Recast config values from step 3:
|
||||||
|
# - `cellSizeHorizontal` → "Cell Size"
|
||||||
|
# - `walkableSlopeAngle` → "Max Slope"
|
||||||
|
# - `walkableClimb` → "Max Climb"
|
||||||
|
# - and so on
|
||||||
|
# 9. Scroll to the bottom of RecastDemo UI and press "Build" to generate the navigation mesh
|
||||||
|
debugOutput: false
|
||||||
|
YAML_EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# ─── DO NOT EDIT BELOW ──────────────────────────────────────────────────────
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
[ -n "$SERVER_DATA_DIR" ] || { echo "SERVER_DATA_DIR is not set"; exit 1; }
|
||||||
|
[ -n "$WOW_CLIENT_DATA" ] || { echo "WOW_CLIENT_DATA is not set"; exit 1; }
|
||||||
|
mkdir -p "$SERVER_DATA_DIR"
|
||||||
|
cd "$SERVER_DATA_DIR"
|
||||||
|
|
||||||
|
# ─── SAFETY: source MPQs are READ-ONLY to this script ──────────────────────
|
||||||
|
# Resolve both paths to canonical form and refuse to run if the output dir
|
||||||
|
# is inside the source. Combined with safe_rm() below, this script cannot
|
||||||
|
# touch any file inside WOW_CLIENT_DATA.
|
||||||
|
SERVER_DATA_DIR_REAL="$(cd "$SERVER_DATA_DIR" && pwd -P)"
|
||||||
|
WOW_CLIENT_DATA_REAL="$(cd "$WOW_CLIENT_DATA" && pwd -P 2>/dev/null || echo "$WOW_CLIENT_DATA")"
|
||||||
|
case "$SERVER_DATA_DIR_REAL/" in
|
||||||
|
"$WOW_CLIENT_DATA_REAL"/|"$WOW_CLIENT_DATA_REAL"/*)
|
||||||
|
echo "ERROR: SERVER_DATA_DIR ($SERVER_DATA_DIR_REAL) is inside WOW_CLIENT_DATA — refusing." >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Refuses to remove anything outside SERVER_DATA_DIR. Resolves the parent
|
||||||
|
# to absolute path so a symlink inside cwd can't trick us into traversing
|
||||||
|
# into the source. Use this for every cleanup in this script.
|
||||||
|
safe_rm() {
|
||||||
|
local target="$1"
|
||||||
|
local parent_abs base
|
||||||
|
parent_abs="$(cd "$(dirname -- "$target")" 2>/dev/null && pwd -P)" || return 0
|
||||||
|
base="$(basename -- "$target")"
|
||||||
|
local abs="$parent_abs/$base"
|
||||||
|
case "$abs/" in
|
||||||
|
"$SERVER_DATA_DIR_REAL"/|"$SERVER_DATA_DIR_REAL"/*) ;;
|
||||||
|
*)
|
||||||
|
echo "REFUSING to rm path outside SERVER_DATA_DIR: $target → $abs" >&2
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
|
rm -rf -- "$target"
|
||||||
|
}
|
||||||
|
|
||||||
|
[ "$MMAP_THREADS" -eq 0 ] && MMAP_THREADS=$(nproc 2>/dev/null || echo 4)
|
||||||
|
|
||||||
|
echo "Working dir : $(pwd)"
|
||||||
|
echo "Tools dir : $TOOLS_DIR"
|
||||||
|
echo "Threads : $MMAP_THREADS"
|
||||||
|
echo "Steps : maps=$EXTRACT_DBC_AND_MAPS vmaps=$EXTRACT_VMAPS mmaps=$EXTRACT_MMAPS"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# ─── Symlink Data/ → MPQ source (only when extracting from client) ──────────
|
||||||
|
if [ "$EXTRACT_DBC_AND_MAPS" = true ] || [ "$EXTRACT_VMAPS" = true ]; then
|
||||||
|
has_mpqs() { find "$1" -maxdepth 1 -iname "*.mpq" -print -quit 2>/dev/null | grep -q .; }
|
||||||
|
|
||||||
|
if has_mpqs "$WOW_CLIENT_DATA"; then
|
||||||
|
MPQ_DIR="$WOW_CLIENT_DATA"
|
||||||
|
elif has_mpqs "$WOW_CLIENT_DATA/Data"; then
|
||||||
|
MPQ_DIR="$WOW_CLIENT_DATA/Data"
|
||||||
|
else
|
||||||
|
echo "ERROR: no .mpq files in $WOW_CLIENT_DATA" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
MPQ_DIR="$(cd "$MPQ_DIR" && pwd)"
|
||||||
|
|
||||||
|
# Symlink only — refuse to clobber an existing real directory.
|
||||||
|
if [ -e Data ] && [ ! -L Data ]; then
|
||||||
|
echo "ERROR: Data/ exists in $(pwd) but is not a symlink" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
ln -sfn "$MPQ_DIR" Data
|
||||||
|
echo "Data/ → $MPQ_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── STEP 1: DBCs + Maps ────────────────────────────────────────────────────
|
||||||
|
if [ "$EXTRACT_DBC_AND_MAPS" = true ]; then
|
||||||
|
echo
|
||||||
|
echo "[1/3] Extracting DBCs + Maps..."
|
||||||
|
# Clean slate — map_extractor refuses to run if these dirs already exist.
|
||||||
|
safe_rm dbc
|
||||||
|
safe_rm maps
|
||||||
|
safe_rm Cameras
|
||||||
|
# -e 7 = bitfield MAP(1)|DBC(2)|CAMERA(4) — extract everything.
|
||||||
|
# The old "-e 2" was DBC-only and skipped maps + cameras entirely.
|
||||||
|
"$TOOLS_DIR/map_extractor" -e 7 -f 0
|
||||||
|
if [ ! -d maps ] || [ -z "$(ls -A maps 2>/dev/null)" ]; then
|
||||||
|
echo "ERROR: map_extractor finished but maps/ is empty — check its output above" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── STEP 2: VMaps ──────────────────────────────────────────────────────────
|
||||||
|
if [ "$EXTRACT_VMAPS" = true ]; then
|
||||||
|
echo
|
||||||
|
echo "[2/3] Extracting VMaps..."
|
||||||
|
# Clean slate — vmap4_extractor refuses to run if these dirs already exist.
|
||||||
|
safe_rm Buildings
|
||||||
|
safe_rm vmaps
|
||||||
|
"$TOOLS_DIR/vmap4_extractor" -l -d ./Data
|
||||||
|
mkdir -p vmaps
|
||||||
|
"$TOOLS_DIR/vmap4_assembler" Buildings vmaps
|
||||||
|
safe_rm Buildings
|
||||||
|
if [ ! -d vmaps ] || [ -z "$(ls -A vmaps 2>/dev/null)" ]; then
|
||||||
|
echo "ERROR: vmap4_assembler finished but vmaps/ is empty — check output above" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── STEP 3: MMaps ──────────────────────────────────────────────────────────
|
||||||
|
if [ "$EXTRACT_MMAPS" = true ]; then
|
||||||
|
if [ ! -d maps ]; then
|
||||||
|
echo "ERROR: maps/ missing in $(pwd) — run with EXTRACT_DBC_AND_MAPS=true once" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -d vmaps ]; then
|
||||||
|
echo "ERROR: vmaps/ missing in $(pwd) — run with EXTRACT_VMAPS=true once" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3/3] Generating MMaps... (do not interrupt)"
|
||||||
|
printf '%s\n' "$MMAPS_CONFIG_YAML" > mmaps-config.yaml
|
||||||
|
|
||||||
|
# Wipe any existing tiles before regenerating. Mixed tiles from
|
||||||
|
# previous runs (different cellSize / verticesPerTileEdge / etc.)
|
||||||
|
# would otherwise be silently kept and mixed with new ones,
|
||||||
|
# producing a corrupt navmesh. Clean slate every mmap run.
|
||||||
|
safe_rm mmaps
|
||||||
|
mkdir -p mmaps
|
||||||
|
|
||||||
|
# Workaround: some mmaps_generator builds write a few tiles to /mmaps
|
||||||
|
# via an absolute path. Pre-create it so the writes don't fail, then
|
||||||
|
# fold the strays into our local mmaps/ at the end.
|
||||||
|
sudo rm -rf /mmaps
|
||||||
|
sudo mkdir -p /mmaps && sudo chmod 777 /mmaps
|
||||||
|
|
||||||
|
CMD=("$TOOLS_DIR/mmaps_generator" --config mmaps-config.yaml --threads "$MMAP_THREADS")
|
||||||
|
[ -n "$MMAP_SINGLE_MAP" ] && CMD+=("$MMAP_SINGLE_MAP")
|
||||||
|
|
||||||
|
START=$(date +%s)
|
||||||
|
"${CMD[@]}"
|
||||||
|
ELAPSED=$(( $(date +%s) - START ))
|
||||||
|
|
||||||
|
if compgen -G "/mmaps/*.mmtile" >/dev/null; then
|
||||||
|
cp /mmaps/*.mmtile mmaps/ && rm -f /mmaps/*.mmtile
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "MMap done in $((ELAPSED / 60))m $((ELAPSED % 60))s"
|
||||||
|
echo "Tiles: $(ls mmaps/*.mmtile 2>/dev/null | wc -l)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Done. Restart worldserver to pick up changes."
|
||||||
@ -12,8 +12,8 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
AutoPickTalents();
|
AutoPickTalents();
|
||||||
AutoLearnSpell();
|
AutoLearnSpell();
|
||||||
AutoUpgradeEquip();
|
|
||||||
AutoTeleportForLevel();
|
AutoTeleportForLevel();
|
||||||
|
AutoUpgradeEquip();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -21,13 +21,11 @@ bool AutoMaintenanceOnLevelupAction::Execute(Event /*event*/)
|
|||||||
void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
|
void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig.autoTeleportForLevel || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
if (!sPlayerbotAIConfig.autoTeleportForLevel || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (botAI->HasRealPlayerMaster())
|
if (botAI->HasRealPlayerMaster())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
sRandomPlayerbotMgr.RandomTeleportForLevel(bot);
|
sRandomPlayerbotMgr.RandomTeleportForLevel(bot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -89,21 +87,17 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
|
|||||||
{
|
{
|
||||||
Quest const* quest = i->second;
|
Quest const* quest = i->second;
|
||||||
|
|
||||||
// only process class-specific quests to learn class-related spells, cuz
|
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10 ||
|
||||||
// we don't want all these bunch of entries to be handled!
|
quest->GetMinLevel() > bot->GetLevel())
|
||||||
if (!quest->GetRequiredClasses())
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// skip quests that are repeatable, too low level, or above bots' level
|
|
||||||
if (quest->IsRepeatable() || quest->GetMinLevel() < 10 || quest->GetMinLevel() > bot->GetLevel())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// skip if bot doesnt satisfy class, race, or skill requirements
|
|
||||||
if (!bot->SatisfyQuestClass(quest, false) || !bot->SatisfyQuestRace(quest, false) ||
|
if (!bot->SatisfyQuestClass(quest, false) || !bot->SatisfyQuestRace(quest, false) ||
|
||||||
!bot->SatisfyQuestSkill(quest, false))
|
!bot->SatisfyQuestSkill(quest, false))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
// use the same logic and impl from Player::learnQuestRewardedSpells
|
|
||||||
|
|
||||||
int32 spellId = quest->GetRewSpellCast();
|
int32 spellId = quest->GetRewSpellCast();
|
||||||
if (!spellId)
|
if (!spellId)
|
||||||
@ -113,31 +107,26 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
|
|||||||
if (!spellInfo)
|
if (!spellInfo)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// xinef: find effect with learn spell and check if we have this spell
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||||
{
|
{
|
||||||
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
|
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
|
||||||
!bot->HasSpell(spellInfo->Effects[i].TriggerSpell))
|
!bot->HasSpell(spellInfo->Effects[i].TriggerSpell))
|
||||||
{
|
{
|
||||||
// pusywizard: don't re-add profession specialties!
|
|
||||||
if (SpellInfo const* triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell))
|
if (SpellInfo const* triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell))
|
||||||
if (triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
|
if (triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
|
||||||
break; // pussywizard: break and not cast the spell (found is false)
|
break;
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// xinef: we know the spell, continue
|
|
||||||
if (!found)
|
if (!found)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bot->CastSpell(bot, spellId, true);
|
bot->CastSpell(bot, spellId, true);
|
||||||
|
|
||||||
// Check if RewardDisplaySpell is set to output the proper spell learned
|
|
||||||
// after processing quests. Output the original RewardSpell otherwise.
|
|
||||||
uint32 rewSpellId = quest->GetRewSpell();
|
uint32 rewSpellId = quest->GetRewSpell();
|
||||||
if (rewSpellId)
|
if (rewSpellId)
|
||||||
{
|
{
|
||||||
@ -167,12 +156,11 @@ std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* s
|
|||||||
|
|
||||||
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
||||||
{
|
{
|
||||||
if (!sPlayerbotAIConfig.autoUpgradeEquip || !sRandomPlayerbotMgr.IsRandomBot(bot))
|
if (!sRandomPlayerbotMgr.IsRandomBot(bot))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||||
|
|
||||||
// Clean up old consumables before adding new ones
|
|
||||||
factory.CleanupConsumables();
|
factory.CleanupConsumables();
|
||||||
|
|
||||||
factory.InitAmmo();
|
factory.InitAmmo();
|
||||||
@ -181,9 +169,6 @@ void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
|||||||
factory.InitConsumables();
|
factory.InitConsumables();
|
||||||
factory.InitPotions();
|
factory.InitPotions();
|
||||||
|
|
||||||
if (!sPlayerbotAIConfig.equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig.equipmentPersistenceLevel)
|
if (sPlayerbotAIConfig.autoUpgradeEquip)
|
||||||
{
|
factory.InitEquipment(true);
|
||||||
if (sPlayerbotAIConfig.incrementalGearInit)
|
|
||||||
factory.InitEquipment(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -173,7 +173,7 @@ std::vector<uint32> const vFlagsIC = {GO_HORDE_BANNER,
|
|||||||
GO_HORDE_BANNER_GRAVEYARD_H,
|
GO_HORDE_BANNER_GRAVEYARD_H,
|
||||||
GO_HORDE_BANNER_GRAVEYARD_H_CONT};
|
GO_HORDE_BANNER_GRAVEYARD_H_CONT};
|
||||||
|
|
||||||
// BG Waypoints (vmangos)
|
// BG Waypoints
|
||||||
|
|
||||||
// Horde Flag Room to Horde Graveyard
|
// Horde Flag Room to Horde Graveyard
|
||||||
BattleBotPath vPath_WSG_HordeFlagRoom_to_HordeGraveyard = {
|
BattleBotPath vPath_WSG_HordeFlagRoom_to_HordeGraveyard = {
|
||||||
|
|||||||
@ -6,10 +6,10 @@
|
|||||||
#include "CheckValuesAction.h"
|
#include "CheckValuesAction.h"
|
||||||
|
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
|
#include "ObjectGuid.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
|
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "TravelNode.h"
|
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
CheckValuesAction::CheckValuesAction(PlayerbotAI* botAI) : Action(botAI, "check values") {}
|
CheckValuesAction::CheckValuesAction(PlayerbotAI* botAI) : Action(botAI, "check values") {}
|
||||||
@ -21,11 +21,6 @@ bool CheckValuesAction::Execute(Event /*event*/)
|
|||||||
botAI->Ping(bot->GetPositionX(), bot->GetPositionY());
|
botAI->Ping(bot->GetPositionX(), bot->GetPositionY());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (botAI->HasStrategy("map", BOT_STATE_NON_COMBAT) || botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT))
|
|
||||||
{
|
|
||||||
TravelNodeMap::instance().manageNodes(bot, botAI->HasStrategy("map full", BOT_STATE_NON_COMBAT));
|
|
||||||
}
|
|
||||||
|
|
||||||
GuidVector possible_targets = *context->GetValue<GuidVector>("possible targets");
|
GuidVector possible_targets = *context->GetValue<GuidVector>("possible targets");
|
||||||
GuidVector all_targets = *context->GetValue<GuidVector>("all targets");
|
GuidVector all_targets = *context->GetValue<GuidVector>("all targets");
|
||||||
GuidVector npcs = *context->GetValue<GuidVector>("nearest npcs");
|
GuidVector npcs = *context->GetValue<GuidVector>("nearest npcs");
|
||||||
|
|||||||
@ -76,7 +76,7 @@ bool DebugAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::vector<WorldPosition> beginPath, endPath;
|
std::vector<WorldPosition> beginPath, endPath;
|
||||||
TravelNodeRoute route = TravelNodeMap::instance().getRoute(botPos, *points.front(), beginPath, bot);
|
TravelNodeRoute route = TravelNodeMap::instance().FindRouteNearestNodes(botPos, *points.front(), beginPath, bot);
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "Traveling to " << dest->getTitle() << ": ";
|
out << "Traveling to " << dest->getTitle() << ": ";
|
||||||
@ -196,18 +196,18 @@ bool DebugAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
WorldPosition pos(bot);
|
WorldPosition pos(bot);
|
||||||
|
|
||||||
std::string const name = "USER:" + text.substr(9);
|
std::string suffix = text.size() > 9 ? text.substr(9) : pos.getAreaName();
|
||||||
|
std::string const name = "USER:" + suffix;
|
||||||
|
|
||||||
/* TravelNode* startNode = */ TravelNodeMap::instance().addNode(pos, name, false, false); // startNode not used, but addNode as side effect, fragment marked for removal.
|
|
||||||
|
|
||||||
for (auto& endNode : TravelNodeMap::instance().getNodes(pos, 2000))
|
|
||||||
{
|
{
|
||||||
endNode->setLinked(false);
|
std::lock_guard<std::shared_timed_mutex> lock(TravelNodeMap::instance().m_nMapMtx);
|
||||||
|
TravelNodeMap::instance().addNode(pos, name, false, true);
|
||||||
|
|
||||||
|
for (auto& endNode : TravelNodeMap::instance().getNodes(pos, 2000))
|
||||||
|
endNode->setLinked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
botAI->TellMasterNoFacing("Node " + name + " created.");
|
botAI->TellMasterNoFacing("Node " + name + " created. Use console command '.playerbots travel generatenode' to connect nodes.");
|
||||||
|
|
||||||
TravelNodeMap::instance().setHasToGen();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -223,14 +223,15 @@ bool DebugAction::Execute(Event event)
|
|||||||
if (startNode->isImportant())
|
if (startNode->isImportant())
|
||||||
{
|
{
|
||||||
botAI->TellMasterNoFacing("Node can not be removed.");
|
botAI->TellMasterNoFacing("Node can not be removed.");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TravelNodeMap::instance().m_nMapMtx.lock();
|
{
|
||||||
TravelNodeMap::instance().removeNode(startNode);
|
std::lock_guard<std::shared_timed_mutex> lock(TravelNodeMap::instance().m_nMapMtx);
|
||||||
botAI->TellMasterNoFacing("Node removed.");
|
TravelNodeMap::instance().removeNode(startNode);
|
||||||
TravelNodeMap::instance().m_nMapMtx.unlock();
|
}
|
||||||
|
|
||||||
TravelNodeMap::instance().setHasToGen();
|
botAI->TellMasterNoFacing("Node removed. Use console command '.playerbots travel generatenode' to finalize nodes.");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -247,15 +248,17 @@ bool DebugAction::Execute(Event event)
|
|||||||
node->removeLinkTo(path.first, true);
|
node->removeLinkTo(path.first, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (text.find("gen node") != std::string::npos)
|
else if (text.find("gen node") != std::string::npos ||
|
||||||
|
text.find("gen path") != std::string::npos)
|
||||||
{
|
{
|
||||||
// Pathfinder
|
// Disabled: generateAll() touches Map / grid / mmap state that is only
|
||||||
TravelNodeMap::instance().generateNodes();
|
// safe to mutate on the world thread. Running it from a detached worker
|
||||||
return true;
|
// (or from a bot tick on a MapUpdater thread) races with world updates
|
||||||
}
|
// and freezes the server. Use the console command instead, which runs
|
||||||
else if (text.find("gen path") != std::string::npos)
|
// synchronously on the world thread:
|
||||||
{
|
// .playerbots travel generatenode
|
||||||
TravelNodeMap::instance().generatePaths();
|
botAI->TellMasterNoFacing(
|
||||||
|
"Disabled in chat. Run '.playerbots travel generatenode' from the server console.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (text.find("crop path") != std::string::npos)
|
else if (text.find("crop path") != std::string::npos)
|
||||||
@ -275,7 +278,7 @@ bool DebugAction::Execute(Event event)
|
|||||||
[]
|
[]
|
||||||
{
|
{
|
||||||
TravelNodeMap::instance().removeNodes();
|
TravelNodeMap::instance().removeNodes();
|
||||||
TravelNodeMap::instance().loadNodeStore();
|
TravelNodeMap::instance().LoadNodeStore();
|
||||||
});
|
});
|
||||||
|
|
||||||
t.detach();
|
t.detach();
|
||||||
@ -297,7 +300,7 @@ bool DebugAction::Execute(Event event)
|
|||||||
|
|
||||||
// uint32 time = 60 * IN_MILLISECONDS; //not used, line marked for removal.
|
// uint32 time = 60 * IN_MILLISECONDS; //not used, line marked for removal.
|
||||||
|
|
||||||
std::vector<WorldPosition> ppath = l.second->getPath();
|
std::vector<WorldPosition> ppath = l.second->GetPath();
|
||||||
|
|
||||||
for (auto p : ppath)
|
for (auto p : ppath)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -29,6 +29,10 @@ void DestroyItemAction::DestroyItem(FindItemVisitor* visitor)
|
|||||||
std::vector<Item*> items = visitor->GetResult();
|
std::vector<Item*> items = visitor->GetResult();
|
||||||
for (Item* item : items)
|
for (Item* item : items)
|
||||||
{
|
{
|
||||||
|
// backstop: never drop an active quest item
|
||||||
|
if (bot->HasQuestForItem(item->GetTemplate()->ItemId))
|
||||||
|
continue;
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << chat->FormatItem(item->GetTemplate()) << " destroyed";
|
out << chat->FormatItem(item->GetTemplate()) << " destroyed";
|
||||||
botAI->TellMaster(out);
|
botAI->TellMaster(out);
|
||||||
@ -67,18 +71,11 @@ bool SmartDestroyItemAction::Execute(Event /*event*/)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ITEM_USAGE_QUEST is excluded — those are still-needed quest items
|
||||||
std::vector<uint32> bestToDestroy = {ITEM_USAGE_NONE}; // First destroy anything useless.
|
std::vector<uint32> bestToDestroy = {ITEM_USAGE_NONE}; // First destroy anything useless.
|
||||||
|
|
||||||
if (!AI_VALUE(bool, "can sell") &&
|
bestToDestroy.push_back(ITEM_USAGE_VENDOR);
|
||||||
AI_VALUE(
|
bestToDestroy.push_back(ITEM_USAGE_AH);
|
||||||
bool,
|
|
||||||
"should get money")) // We need money so quest items are less important since they can't directly be sold.
|
|
||||||
bestToDestroy.push_back(ITEM_USAGE_QUEST);
|
|
||||||
else // We don't need money so destroy the cheapest stuff.
|
|
||||||
{
|
|
||||||
bestToDestroy.push_back(ITEM_USAGE_VENDOR);
|
|
||||||
bestToDestroy.push_back(ITEM_USAGE_AH);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we still need room
|
// If we still need room
|
||||||
bestToDestroy.push_back(
|
bestToDestroy.push_back(
|
||||||
|
|||||||
@ -154,9 +154,11 @@ void EquipAction::EquipItem(Item* item)
|
|||||||
calculator.SetOverflowPenalty(false);
|
calculator.SetOverflowPenalty(false);
|
||||||
|
|
||||||
// Calculate item scores once and store them
|
// Calculate item scores once and store them
|
||||||
float newItemScore = calculator.CalculateItem(itemId);
|
float newItemScore = calculator.CalculateItem(itemId, item->GetItemRandomPropertyId());
|
||||||
float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f;
|
float mainHandScore = mainHandItem
|
||||||
float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f;
|
? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId, mainHandItem->GetItemRandomPropertyId()) : 0.0f;
|
||||||
|
float offHandScore = offHandItem
|
||||||
|
? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId, offHandItem->GetItemRandomPropertyId()) : 0.0f;
|
||||||
|
|
||||||
// Determine where this weapon can go
|
// Determine where this weapon can go
|
||||||
bool canGoMain = (invType == INVTYPE_WEAPON ||
|
bool canGoMain = (invType == INVTYPE_WEAPON ||
|
||||||
|
|||||||
@ -19,83 +19,8 @@
|
|||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
|
|
||||||
namespace
|
// Transport helpers (GetTransportForPosTolerant, FindBoardingPointOnTransport,
|
||||||
{
|
// BoardTransport) are now on MovementAction — inherited by FollowAction.
|
||||||
Transport* GetTransportForPosTolerant(Map* map, WorldObject* ref, uint32 phaseMask, float x, float y, float z)
|
|
||||||
{
|
|
||||||
if (!map || !ref)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
std::array<float, 4> const probes = { z, z + 0.5f, z + 1.5f, z - 0.5f };
|
|
||||||
for (float const pz : probes)
|
|
||||||
{
|
|
||||||
if (Transport* t = map->GetTransportForPos(phaseMask, x, y, pz, ref))
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to find a point on the leader's transport that is closer to the bot,
|
|
||||||
// by probing along the segment from master -> bot and returning the last point
|
|
||||||
// that is still detected as being on the expected transport.
|
|
||||||
bool FindBoardingPointOnTransport(Map* map, Transport* expectedTransport, WorldObject* ref,
|
|
||||||
float masterX, float masterY, float masterZ,
|
|
||||||
float botX, float botY, float botZ,
|
|
||||||
float& outX, float& outY, float& outZ)
|
|
||||||
{
|
|
||||||
if (!map || !expectedTransport || !ref)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32 const phaseMask = ref->GetPhaseMask();
|
|
||||||
|
|
||||||
// Ensure master is actually detected on that transport (tolerant).
|
|
||||||
if (GetTransportForPosTolerant(map, ref, phaseMask, masterX, masterY, masterZ) != expectedTransport)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// The raycast in GetTransportForPos starts at (z + 2). Probe with a safe Z.
|
|
||||||
float const probeZ = std::max(masterZ, botZ);
|
|
||||||
|
|
||||||
// Adaptive step count: small platforms need tighter sampling.
|
|
||||||
float const dx2 = botX - masterX;
|
|
||||||
float const dy2 = botY - masterY;
|
|
||||||
float const dist2d = std::sqrt(dx2 * dx2 + dy2 * dy2);
|
|
||||||
int32 const steps = std::clamp(static_cast<int32>(dist2d / 0.75f), 10, 28);
|
|
||||||
|
|
||||||
float const dx = (botX - masterX) / static_cast<float>(steps);
|
|
||||||
float const dy = (botY - masterY) / static_cast<float>(steps);
|
|
||||||
|
|
||||||
// Master must actually be on the expected transport for this to work.
|
|
||||||
if (map->GetTransportForPos(ref->GetPhaseMask(), masterX, masterY, probeZ, ref) != expectedTransport)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float lastX = masterX;
|
|
||||||
float lastY = masterY;
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
for (int32 i = 1; i <= steps; ++i)
|
|
||||||
{
|
|
||||||
float const px = masterX + dx * i;
|
|
||||||
float const py = masterY + dy * i;
|
|
||||||
|
|
||||||
Transport* const t = GetTransportForPosTolerant(map, ref, phaseMask, px, py, probeZ);
|
|
||||||
if (t != expectedTransport)
|
|
||||||
break;
|
|
||||||
|
|
||||||
lastX = px;
|
|
||||||
lastY = py;
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
outX = lastX;
|
|
||||||
outY = lastY;
|
|
||||||
outZ = masterZ; // keep deck-level Z to encourage stepping onto the platform/boat
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FollowAction::Execute(Event /*event*/)
|
bool FollowAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
@ -170,9 +95,8 @@ bool FollowAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
bool const movingAllowed = IsMovingAllowed();
|
bool const movingAllowed = IsMovingAllowed();
|
||||||
bool const dupMove = IsDuplicateMove(destX, destY, destZ);
|
bool const dupMove = IsDuplicateMove(destX, destY, destZ);
|
||||||
bool const waiting = IsWaitingForLastMove(priority);
|
|
||||||
|
|
||||||
if (movingAllowed && !dupMove && !waiting)
|
if (movingAllowed && !dupMove)
|
||||||
{
|
{
|
||||||
if (bot->IsSitState())
|
if (bot->IsSitState())
|
||||||
bot->SetStandState(UNIT_STAND_STATE_STAND);
|
bot->SetStandState(UNIT_STAND_STATE_STAND);
|
||||||
|
|||||||
@ -86,7 +86,7 @@ bool TogglePetSpellAutoCastAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
uint32 spellId = itr->first;
|
uint32 spellId = itr->first;
|
||||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
if (!spellInfo->IsAutocastable())
|
if (!spellInfo || !spellInfo->IsAutocastable())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool shouldApply = true;
|
bool shouldApply = true;
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "ItemTemplate.h"
|
#include "ItemTemplate.h"
|
||||||
@ -23,6 +24,116 @@
|
|||||||
using ai::buff::MakeAuraQualifierForBuff;
|
using ai::buff::MakeAuraQualifierForBuff;
|
||||||
using ai::spell::HasSpellOrCategoryCooldown;
|
using ai::spell::HasSpellOrCategoryCooldown;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::unordered_set<uint32> const& GetMixedTriggerTrinketSpellIds()
|
||||||
|
{
|
||||||
|
static std::unordered_set<uint32> const mixedTriggerSpellIds = []()
|
||||||
|
{
|
||||||
|
std::unordered_set<uint32> onUseSpellIds;
|
||||||
|
std::unordered_set<uint32> onEquipSpellIds;
|
||||||
|
std::unordered_set<uint32> mixedSpellIds;
|
||||||
|
|
||||||
|
auto const* itemTemplates = sObjectMgr->GetItemTemplateStore();
|
||||||
|
if (!itemTemplates)
|
||||||
|
return mixedSpellIds;
|
||||||
|
|
||||||
|
auto const markSpellId = [&](int32 spellId, uint8 spellTrigger)
|
||||||
|
{
|
||||||
|
if (spellId <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (spellTrigger == ITEM_SPELLTRIGGER_ON_USE)
|
||||||
|
{
|
||||||
|
if (onEquipSpellIds.find(spellId) != onEquipSpellIds.end())
|
||||||
|
mixedSpellIds.insert(spellId);
|
||||||
|
|
||||||
|
onUseSpellIds.insert(spellId);
|
||||||
|
}
|
||||||
|
else if (spellTrigger == ITEM_SPELLTRIGGER_ON_EQUIP)
|
||||||
|
{
|
||||||
|
if (onUseSpellIds.find(spellId) != onUseSpellIds.end())
|
||||||
|
mixedSpellIds.insert(spellId);
|
||||||
|
|
||||||
|
onEquipSpellIds.insert(spellId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const& itr : *itemTemplates)
|
||||||
|
{
|
||||||
|
ItemTemplate const& proto = itr.second;
|
||||||
|
if (proto.InventoryType != INVTYPE_TRINKET)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (uint8 spellIndex = 0; spellIndex < MAX_ITEM_PROTO_SPELLS; ++spellIndex)
|
||||||
|
{
|
||||||
|
auto const& spellData = proto.Spells[spellIndex];
|
||||||
|
markSpellId(spellData.SpellId, spellData.SpellTrigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mixedSpellIds;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return mixedTriggerSpellIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsManaRestoreEffect(SpellEffectInfo const& effectInfo)
|
||||||
|
{
|
||||||
|
return (effectInfo.Effect == SPELL_EFFECT_ENERGIZE &&
|
||||||
|
effectInfo.MiscValue == POWER_MANA) ||
|
||||||
|
(effectInfo.Effect == SPELL_EFFECT_APPLY_AURA &&
|
||||||
|
effectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_ENERGIZE &&
|
||||||
|
effectInfo.MiscValue == POWER_MANA);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsManaEfficiencyEffect(SpellEffectInfo const& effectInfo)
|
||||||
|
{
|
||||||
|
return effectInfo.Effect == SPELL_EFFECT_APPLY_AURA &&
|
||||||
|
(((effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_REGEN ||
|
||||||
|
effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_REGEN_PERCENT) &&
|
||||||
|
effectInfo.MiscValue == POWER_MANA) ||
|
||||||
|
effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_COST_SCHOOL ||
|
||||||
|
effectInfo.ApplyAuraName == SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT ||
|
||||||
|
effectInfo.ApplyAuraName == SPELL_AURA_MOD_MANA_REGEN_INTERRUPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDefensiveTankEffect(SpellEffectInfo const& effectInfo)
|
||||||
|
{
|
||||||
|
if (effectInfo.Effect != SPELL_EFFECT_APPLY_AURA)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 const tankRatingsMask =
|
||||||
|
(1u << CR_DEFENSE_SKILL) |
|
||||||
|
(1u << CR_DODGE) |
|
||||||
|
(1u << CR_PARRY) |
|
||||||
|
(1u << CR_BLOCK) |
|
||||||
|
(1u << CR_HIT_TAKEN_MELEE) |
|
||||||
|
(1u << CR_HIT_TAKEN_RANGED) |
|
||||||
|
(1u << CR_HIT_TAKEN_SPELL) |
|
||||||
|
(1u << CR_CRIT_TAKEN_MELEE) |
|
||||||
|
(1u << CR_CRIT_TAKEN_RANGED) |
|
||||||
|
(1u << CR_CRIT_TAKEN_SPELL);
|
||||||
|
|
||||||
|
switch (effectInfo.ApplyAuraName)
|
||||||
|
{
|
||||||
|
case SPELL_AURA_MOD_RESISTANCE:
|
||||||
|
return (effectInfo.MiscValue & SPELL_SCHOOL_MASK_NORMAL) != 0;
|
||||||
|
case SPELL_AURA_MOD_RATING:
|
||||||
|
return (effectInfo.MiscValue & tankRatingsMask) != 0;
|
||||||
|
case SPELL_AURA_MOD_INCREASE_HEALTH:
|
||||||
|
case SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT:
|
||||||
|
case SPELL_AURA_MOD_PARRY_PERCENT:
|
||||||
|
case SPELL_AURA_MOD_DODGE_PERCENT:
|
||||||
|
case SPELL_AURA_MOD_BLOCK_PERCENT:
|
||||||
|
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
|
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
|
||||||
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell) {}
|
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell) {}
|
||||||
|
|
||||||
@ -429,52 +540,109 @@ bool UseTrinketAction::UseTrinket(Item* item)
|
|||||||
|
|
||||||
uint8 bagIndex = item->GetBagSlot();
|
uint8 bagIndex = item->GetBagSlot();
|
||||||
uint8 slot = item->GetSlot();
|
uint8 slot = item->GetSlot();
|
||||||
// uint8 spell_index = 0; //not used, line marked for removal.
|
|
||||||
uint8 cast_count = 1;
|
uint8 cast_count = 1;
|
||||||
ObjectGuid item_guid = item->GetGUID();
|
ObjectGuid item_guid = item->GetGUID();
|
||||||
uint32 glyphIndex = 0;
|
uint32 glyphIndex = 0;
|
||||||
uint8 castFlags = 0;
|
uint8 castFlags = 0;
|
||||||
uint32 targetFlag = TARGET_FLAG_NONE;
|
uint32 targetFlag = TARGET_FLAG_NONE;
|
||||||
uint32 spellId = 0;
|
uint32 spellId = 0;
|
||||||
|
int32 itemSpellCooldown = 0;
|
||||||
|
uint32 itemSpellCategory = 0;
|
||||||
|
int32 itemSpellCategoryCooldown = 0;
|
||||||
|
|
||||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||||
{
|
{
|
||||||
if (item->GetTemplate()->Spells[i].SpellId > 0 &&
|
if (item->GetTemplate()->Spells[i].SpellId > 0 &&
|
||||||
item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
|
item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
|
||||||
{
|
{
|
||||||
spellId = item->GetTemplate()->Spells[i].SpellId;
|
spellId = item->GetTemplate()->Spells[i].SpellId;
|
||||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
itemSpellCooldown = item->GetTemplate()->Spells[i].SpellCooldown;
|
||||||
|
itemSpellCategory = item->GetTemplate()->Spells[i].SpellCategory;
|
||||||
|
itemSpellCategoryCooldown = item->GetTemplate()->Spells[i].SpellCategoryCooldown;
|
||||||
|
uint64 const itemCooldownKey = (static_cast<uint64>(item->GetEntry()) << 32) | spellId;
|
||||||
|
uint32 const now = getMSTime();
|
||||||
|
|
||||||
|
if (itemSpellCooldown > 0)
|
||||||
|
{
|
||||||
|
auto const itemCooldownItr = trinketItemCooldownExpiries.find(itemCooldownKey);
|
||||||
|
if (itemCooldownItr != trinketItemCooldownExpiries.end())
|
||||||
|
{
|
||||||
|
if (itemCooldownItr->second > now)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
trinketItemCooldownExpiries.erase(itemCooldownItr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemSpellCategory && itemSpellCategoryCooldown > 0)
|
||||||
|
{
|
||||||
|
auto const categoryCooldownItr = trinketCategoryCooldownExpiries.find(itemSpellCategory);
|
||||||
|
if (categoryCooldownItr != trinketCategoryCooldownExpiries.end())
|
||||||
|
{
|
||||||
|
if (categoryCooldownItr->second > now)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
trinketCategoryCooldownExpiries.erase(categoryCooldownItr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
if (!spellInfo || !spellInfo->IsPositive())
|
if (!spellInfo || !spellInfo->IsPositive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool applyAura = false;
|
bool applyAura = false;
|
||||||
|
bool restoresMana = false;
|
||||||
|
bool improvesManaEfficiency = false;
|
||||||
|
bool defensiveTankEffect = false;
|
||||||
for (int i = 0; i < MAX_SPELL_EFFECTS; i++)
|
for (int i = 0; i < MAX_SPELL_EFFECTS; i++)
|
||||||
{
|
{
|
||||||
const SpellEffectInfo& effectInfo = spellInfo->Effects[i];
|
const SpellEffectInfo& effectInfo = spellInfo->Effects[i];
|
||||||
if (effectInfo.Effect == SPELL_EFFECT_APPLY_AURA)
|
if (effectInfo.Effect == SPELL_EFFECT_APPLY_AURA)
|
||||||
{
|
|
||||||
applyAura = true;
|
applyAura = true;
|
||||||
break;
|
|
||||||
|
restoresMana = restoresMana || IsManaRestoreEffect(effectInfo);
|
||||||
|
improvesManaEfficiency = improvesManaEfficiency || IsManaEfficiencyEffect(effectInfo);
|
||||||
|
defensiveTankEffect = defensiveTankEffect || IsDefensiveTankEffect(effectInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!applyAura && !restoresMana)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (restoresMana || improvesManaEfficiency)
|
||||||
|
{
|
||||||
|
if (!AI_VALUE2(bool, "has mana", "self target"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8 const manaPct = AI_VALUE2(uint8, "mana", "self target");
|
||||||
|
if ((restoresMana && manaPct >= sPlayerbotAIConfig.mediumMana) ||
|
||||||
|
manaPct >= sPlayerbotAIConfig.highMana)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!applyAura)
|
if (defensiveTankEffect)
|
||||||
|
{
|
||||||
|
uint8 const healthPct = AI_VALUE2(uint8, "health", "self target");
|
||||||
|
if (healthPct > sPlayerbotAIConfig.lowHealth)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& mixedTriggerTrinketSpellIds = GetMixedTriggerTrinketSpellIds();
|
||||||
|
// Exclude trinkets that expose the same spell as both ON_EQUIP and ON_USE across
|
||||||
|
// item templates. Those are equip/proc effects leaking into the active-use path,
|
||||||
|
// as seen with the error versions of Oracle Talisman of Ablution (44870) and
|
||||||
|
// Frenzyheart Insignia of Fury (44869).
|
||||||
|
if (mixedTriggerTrinketSpellIds.find(spellId) != mixedTriggerTrinketSpellIds.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32 spellProcFlag = spellInfo->ProcFlags;
|
if (!botAI->CanCastSpell(spellId, bot, false, nullptr, item))
|
||||||
|
|
||||||
// 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;
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spellId)
|
if (!spellId)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -483,7 +651,25 @@ bool UseTrinketAction::UseTrinket(Item* item)
|
|||||||
|
|
||||||
targetFlag = TARGET_FLAG_NONE;
|
targetFlag = TARGET_FLAG_NONE;
|
||||||
packet << targetFlag << bot->GetPackGUID();
|
packet << targetFlag << bot->GetPackGUID();
|
||||||
|
|
||||||
bot->GetSession()->HandleUseItemOpcode(packet);
|
bot->GetSession()->HandleUseItemOpcode(packet);
|
||||||
|
|
||||||
|
uint32 const now = getMSTime();
|
||||||
|
uint32 const cooldownDelay = bot->GetSpellCooldownDelay(spellId);
|
||||||
|
if (cooldownDelay > 0)
|
||||||
|
{
|
||||||
|
if (itemSpellCooldown > 0)
|
||||||
|
{
|
||||||
|
uint64 const itemCooldownKey = (static_cast<uint64>(item->GetEntry()) << 32) | spellId;
|
||||||
|
trinketItemCooldownExpiries[itemCooldownKey] = now + static_cast<uint32>(itemSpellCooldown);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemSpellCategory && itemSpellCategoryCooldown > 0)
|
||||||
|
{
|
||||||
|
trinketCategoryCooldownExpiries[itemSpellCategory] = now + static_cast<uint32>(itemSpellCategoryCooldown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -334,6 +334,10 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool UseTrinket(Item* trinket);
|
bool UseTrinket(Item* trinket);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<uint64, uint32> trinketItemCooldownExpiries;
|
||||||
|
std::unordered_map<uint32, uint32> trinketCategoryCooldownExpiries;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastSpellOnEnemyHealerAction : public CastSpellAction
|
class CastSpellOnEnemyHealerAction : public CastSpellAction
|
||||||
|
|||||||
@ -124,7 +124,6 @@ bool GoAction::Execute(Event event)
|
|||||||
if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT))
|
if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT))
|
||||||
{
|
{
|
||||||
PathGenerator path(bot);
|
PathGenerator path(bot);
|
||||||
|
|
||||||
path.CalculatePath(x, y, z, false);
|
path.CalculatePath(x, y, z, false);
|
||||||
|
|
||||||
Movement::Vector3 end = path.GetEndPosition();
|
Movement::Vector3 end = path.GetEndPosition();
|
||||||
|
|||||||
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#include "LootAction.h"
|
#include "LootAction.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include "Bag.h"
|
||||||
#include "ChatHelper.h"
|
#include "ChatHelper.h"
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "GuildMgr.h"
|
#include "GuildMgr.h"
|
||||||
@ -76,7 +79,11 @@ bool OpenLootAction::Execute(Event /*event*/)
|
|||||||
bool result = DoLoot(lootObject);
|
bool result = DoLoot(lootObject);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
AI_VALUE(LootObjectStack*, "available loot")->Remove(lootObject.guid);
|
// MarkCompleted (not Remove) — "add all loot" reads
|
||||||
|
// "nearest corpses" without a lootable filter, so a plain
|
||||||
|
// Remove lets the same corpse re-enter the stack on the next
|
||||||
|
// tick. The completed set blocks re-add for ~5 min.
|
||||||
|
AI_VALUE(LootObjectStack*, "available loot")->MarkCompleted(lootObject.guid);
|
||||||
context->GetValue<LootObject>("loot target")->Set(LootObject());
|
context->GetValue<LootObject>("loot target")->Set(LootObject());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -139,8 +146,9 @@ bool OpenLootAction::DoLoot(LootObject& lootObject)
|
|||||||
if (go && (go->GetGoState() != GO_STATE_READY))
|
if (go && (go->GetGoState() != GO_STATE_READY))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// This prevents dungeon chests like Tribunal Chest (Halls of Stone) from being ninja'd by the bots
|
// Block event-gated chests (Tribunal Chest, Gunship Armory) but allow
|
||||||
if (go && go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND))
|
// wild quest GOs (Moonpetal Lily etc.) when the bot is on the quest.
|
||||||
|
if (go && go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND) && !lootObject.isNeededQuestItem)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// This prevents raid chests like Gunship Armory (ICC) from being ninja'd by the bots
|
// This prevents raid chests like Gunship Armory (ICC) from being ninja'd by the bots
|
||||||
@ -377,6 +385,12 @@ bool StoreLootAction::Execute(Event event)
|
|||||||
// bot->GetSession()->HandleLootMoneyOpcode(packet);
|
// bot->GetSession()->HandleLootMoneyOpcode(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// one make-room destroy per loot packet — CanStoreNewItem after a junk
|
||||||
|
// destroy can still report full while CMSG_AUTOSTORE_LOOT_ITEM is
|
||||||
|
// queued, so a multi-quest-item packet would otherwise destroy more
|
||||||
|
// junk than necessary
|
||||||
|
bool destroyedThisPacket = false;
|
||||||
|
|
||||||
for (uint8 i = 0; i < items; ++i)
|
for (uint8 i = 0; i < items; ++i)
|
||||||
{
|
{
|
||||||
uint32 itemid;
|
uint32 itemid;
|
||||||
@ -402,7 +416,9 @@ bool StoreLootAction::Execute(Event event)
|
|||||||
if (!proto)
|
if (!proto)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!botAI->HasActivePlayerMaster() && AI_VALUE(uint8, "bag space") > 80)
|
// bags >80%: skip non-stackable junk (quest items exempt)
|
||||||
|
if (!botAI->HasActivePlayerMaster() && AI_VALUE(uint8, "bag space") > 80 &&
|
||||||
|
!bot->HasQuestForItem(itemid))
|
||||||
{
|
{
|
||||||
uint32 maxStack = proto->GetMaxStackSize();
|
uint32 maxStack = proto->GetMaxStackSize();
|
||||||
if (maxStack == 1)
|
if (maxStack == 1)
|
||||||
@ -438,6 +454,55 @@ bool StoreLootAction::Execute(Event event)
|
|||||||
GuildTaskMgr::instance().CheckItemTask(itemid, itemcount, ref->GetSource(), bot);
|
GuildTaskMgr::instance().CheckItemTask(itemid, itemcount, ref->GetSource(), bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bags full + quest item: make room by dropping cheapest junk
|
||||||
|
if (!destroyedThisPacket && bot->HasQuestForItem(itemid))
|
||||||
|
{
|
||||||
|
ItemPosCountVec dest;
|
||||||
|
InventoryResult can =
|
||||||
|
bot->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, itemcount);
|
||||||
|
if (can == EQUIP_ERR_INVENTORY_FULL || can == EQUIP_ERR_BAG_FULL)
|
||||||
|
{
|
||||||
|
// picked by usage, not quality — high-level bots have no grays
|
||||||
|
Item* victim = nullptr;
|
||||||
|
uint32 minPrice = std::numeric_limits<uint32>::max();
|
||||||
|
auto consider = [&](uint8 bag, uint8 slot)
|
||||||
|
{
|
||||||
|
Item* it = bot->GetItemByPos(bag, slot);
|
||||||
|
if (!it)
|
||||||
|
return;
|
||||||
|
ItemTemplate const* tpl = it->GetTemplate();
|
||||||
|
if (!tpl)
|
||||||
|
return;
|
||||||
|
if (bot->HasQuestForItem(tpl->ItemId))
|
||||||
|
return;
|
||||||
|
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", tpl->ItemId);
|
||||||
|
if (usage != ITEM_USAGE_NONE && usage != ITEM_USAGE_VENDOR &&
|
||||||
|
usage != ITEM_USAGE_BAD_EQUIP && usage != ITEM_USAGE_BROKEN_EQUIP)
|
||||||
|
return;
|
||||||
|
if (tpl->SellPrice < minPrice)
|
||||||
|
{
|
||||||
|
minPrice = tpl->SellPrice;
|
||||||
|
victim = it;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot)
|
||||||
|
consider(INVENTORY_SLOT_BAG_0, slot);
|
||||||
|
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
||||||
|
{
|
||||||
|
Bag* pBag = bot->GetBagByPos(bag);
|
||||||
|
if (!pBag)
|
||||||
|
continue;
|
||||||
|
for (uint32 slot = 0; slot < pBag->GetBagSize(); ++slot)
|
||||||
|
consider(bag, static_cast<uint8>(slot));
|
||||||
|
}
|
||||||
|
if (victim)
|
||||||
|
{
|
||||||
|
bot->DestroyItem(victim->GetBagSlot(), victim->GetSlot(), true);
|
||||||
|
destroyedThisPacket = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WorldPacket* packet = new WorldPacket(CMSG_AUTOSTORE_LOOT_ITEM, 1);
|
WorldPacket* packet = new WorldPacket(CMSG_AUTOSTORE_LOOT_ITEM, 1);
|
||||||
*packet << itemindex;
|
*packet << itemindex;
|
||||||
bot->GetSession()->QueuePacket(packet);
|
bot->GetSession()->QueuePacket(packet);
|
||||||
@ -453,7 +518,7 @@ bool StoreLootAction::Execute(Event event)
|
|||||||
BroadcastHelper::BroadcastLootingItem(botAI, bot, proto);
|
BroadcastHelper::BroadcastLootingItem(botAI, bot, proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
AI_VALUE(LootObjectStack*, "available loot")->Remove(guid);
|
AI_VALUE(LootObjectStack*, "available loot")->MarkCompleted(guid);
|
||||||
|
|
||||||
// release loot
|
// release loot
|
||||||
WorldPacket* packet = new WorldPacket(CMSG_LOOT_RELEASE, 8);
|
WorldPacket* packet = new WorldPacket(CMSG_LOOT_RELEASE, 8);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "LastMovementValue.h"
|
#include "LastMovementValue.h"
|
||||||
|
#include "PathGenerator.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
@ -18,16 +19,36 @@ class Unit;
|
|||||||
class WorldObject;
|
class WorldObject;
|
||||||
class Position;
|
class Position;
|
||||||
|
|
||||||
#define ANGLE_45_DEG (static_cast<float>(M_PI) / 4.f)
|
|
||||||
#define ANGLE_90_DEG M_PI_2
|
#define ANGLE_90_DEG M_PI_2
|
||||||
#define ANGLE_120_DEG (2.f * static_cast<float>(M_PI) / 3.f)
|
#define ANGLE_120_DEG (2.f * static_cast<float>(M_PI) / 3.f)
|
||||||
|
|
||||||
|
// Default acceptable path types for GeneratePath
|
||||||
|
constexpr uint32 DEFAULT_PATH_ACCEPT_MASK = PATHFIND_NORMAL | PATHFIND_INCOMPLETE;
|
||||||
|
constexpr uint32 RELAXED_PATH_ACCEPT_MASK = PATHFIND_NORMAL | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY;
|
||||||
|
|
||||||
|
struct PathResult
|
||||||
|
{
|
||||||
|
Movement::PointsArray points;
|
||||||
|
G3D::Vector3 actualEnd;
|
||||||
|
G3D::Vector3 end;
|
||||||
|
PathType pathType;
|
||||||
|
bool reachable;
|
||||||
|
};
|
||||||
|
|
||||||
class MovementAction : public Action
|
class MovementAction : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MovementAction(PlayerbotAI* botAI, std::string const name);
|
MovementAction(PlayerbotAI* botAI, std::string const name);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Emit a one-line trace describing the imminent movement. No-op
|
||||||
|
// unless the bot has the "debug move" non-combat strategy.
|
||||||
|
// Subclasses (e.g. NewRpgBaseAction) may override to append richer
|
||||||
|
// context such as RPG status and target name. Optional `extra`
|
||||||
|
// is appended verbatim (use it to attach hop labels like
|
||||||
|
// "node:Stormwind innkeeper" or fallback reasons).
|
||||||
|
virtual void EmitDebugMove(char const* method, char const* generator, float x, float y, float z, char const* extra = nullptr);
|
||||||
|
|
||||||
bool JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
bool JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||||
bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig.contactDistance,
|
bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig.contactDistance,
|
||||||
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||||
@ -35,7 +56,54 @@ protected:
|
|||||||
bool MoveTo(uint32 mapId, float x, float y, float z, bool idle = false, bool react = false,
|
bool MoveTo(uint32 mapId, float x, float y, float z, bool idle = false, bool react = false,
|
||||||
bool normal_only = false, bool exact_waypoint = false,
|
bool normal_only = false, bool exact_waypoint = false,
|
||||||
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL, bool lessDelay = false,
|
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL, bool lessDelay = false,
|
||||||
bool backwards = false);
|
bool backwards = false, bool ignoreEnemyTargets = false);
|
||||||
|
|
||||||
|
// Path-aware funnel mirroring the reference movement implementation.
|
||||||
|
// Runs UpdateMovementState + IsMovingAllowed + WaitForTransport gates,
|
||||||
|
// applies the targetPosRecalcDistance short-stop, resolves a TravelPath
|
||||||
|
// via ResolveMovePath (which gates graph A* by sightDistance), trims
|
||||||
|
// with makeShortCut, handles special head segments
|
||||||
|
// (portal/area-trigger/transport/flight) via HandleSpecialMovement,
|
||||||
|
// clips at hostile creatures via ClipPath (unless ignoreEnemyTargets),
|
||||||
|
// and dispatches the resulting walk via DispatchMovement.
|
||||||
|
// MoveTo(mapId,...) delegates here unless an intentional bypass
|
||||||
|
// (exact_waypoint / disableMoveSplinePath / flying / swimming /
|
||||||
|
// backwards) routes the move straight to DoMovePoint.
|
||||||
|
// `react=true` opts the move out of the end-of-dispatch
|
||||||
|
// WaitForReach AI-loop block — combat callers should set this so the
|
||||||
|
// bot can keep re-evaluating mid-chase. Default false matches the
|
||||||
|
// reference's MoveTo2 default.
|
||||||
|
bool MoveTo2(WorldPosition endPos,
|
||||||
|
bool idle = false, bool react = false,
|
||||||
|
bool noPath = false, bool ignoreEnemyTargets = false,
|
||||||
|
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL,
|
||||||
|
bool lessDelay = false);
|
||||||
|
|
||||||
|
// Centralized walk dispatch. Mirrors the reference's DispatchMovement
|
||||||
|
// shape: takes a TravelPath, builds the PointsArray internally,
|
||||||
|
// applies inactive-bot teleport carve-out, masterWalking mode,
|
||||||
|
// pre-dispatch state cleanup (clear emote, stand, interrupt cast),
|
||||||
|
// transport-passenger coordinate sandwich
|
||||||
|
// (CalculatePassengerPosition → UpdateAllowedPositionZ → Offset)
|
||||||
|
// around the per-point Z snap, mm.Clear → MovePoint(last) →
|
||||||
|
// MoveSplinePath. Caches the destination + duration on lastMove.
|
||||||
|
//
|
||||||
|
// Divergence from reference: reference ends with WaitForReach(size)
|
||||||
|
// which blocks the AI loop until the move completes. AC's combat
|
||||||
|
// callers (ReachCombatTo) currently funnel through MoveTo → MoveTo2
|
||||||
|
// → DispatchMovement; blocking the AI loop here would suspend combat
|
||||||
|
// re-evaluation for the full move duration. Until combat dispatch is
|
||||||
|
// restructured to bypass MoveTo2, the WaitForReach is deliberately
|
||||||
|
// omitted.
|
||||||
|
// `react=true` skips the end-of-dispatch WaitForReach so the AI
|
||||||
|
// loop isn't blocked while the spline plays — combat callers use
|
||||||
|
// this to keep re-evaluating mid-chase.
|
||||||
|
bool DispatchMovement(TravelPath path,
|
||||||
|
WorldPosition dest,
|
||||||
|
char const* label,
|
||||||
|
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL,
|
||||||
|
bool lessDelay = false,
|
||||||
|
bool react = false);
|
||||||
bool MoveTo(WorldObject* target, float distance = 0.0f,
|
bool MoveTo(WorldObject* target, float distance = 0.0f,
|
||||||
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||||
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig.contactDistance,
|
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig.contactDistance,
|
||||||
@ -43,14 +111,25 @@ protected:
|
|||||||
float GetFollowAngle();
|
float GetFollowAngle();
|
||||||
bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance);
|
bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance);
|
||||||
bool Follow(Unit* target, float distance, float angle);
|
bool Follow(Unit* target, float distance, float angle);
|
||||||
|
// Handles the cross-transport follow case: when bot and target are
|
||||||
|
// on different transports (or one is off-transport) and within
|
||||||
|
// sight, this disembarks the bot from its current transport (if
|
||||||
|
// any), teleports it to the target's position, and boards the
|
||||||
|
// target's transport (if any). Returns true if the transport
|
||||||
|
// transition was performed this tick (caller should skip the
|
||||||
|
// engine-level follow for this tick).
|
||||||
|
bool FollowOnTransport(Unit* target);
|
||||||
bool ChaseTo(WorldObject* obj, float distance = 0.0f);
|
bool ChaseTo(WorldObject* obj, float distance = 0.0f);
|
||||||
bool ReachCombatTo(Unit* target, float distance = 0.0f);
|
bool ReachCombatTo(Unit* target, float distance = 0.0f);
|
||||||
float MoveDelay(float distance, bool backwards = false);
|
float MoveDelay(float distance, bool backwards = false);
|
||||||
void WaitForReach(float distance);
|
void WaitForReach(float distance);
|
||||||
|
// PointsArray overload: sums segment distances and calls the float
|
||||||
|
// version. Matches the reference's WaitForReach(PointsArray) used at
|
||||||
|
// the end of DispatchMovement.
|
||||||
|
void WaitForReach(Movement::PointsArray const& path);
|
||||||
void SetNextMovementDelay(float delayMillis);
|
void SetNextMovementDelay(float delayMillis);
|
||||||
bool IsMovingAllowed(WorldObject* target);
|
bool IsMovingAllowed(WorldObject* target);
|
||||||
bool IsDuplicateMove(float x, float y, float z);
|
bool IsDuplicateMove(float x, float y, float z);
|
||||||
bool IsWaitingForLastMove(MovementPriority priority);
|
|
||||||
bool IsMovingAllowed();
|
bool IsMovingAllowed();
|
||||||
bool Flee(Unit* target);
|
bool Flee(Unit* target);
|
||||||
void ClearIdleState();
|
void ClearIdleState();
|
||||||
@ -66,6 +145,42 @@ protected:
|
|||||||
bool FleePosition(Position pos, float radius, uint32 minInterval = 1000);
|
bool FleePosition(Position pos, float radius, uint32 minInterval = 1000);
|
||||||
bool CheckLastFlee(float curAngle, std::list<FleeInfo>& infoList);
|
bool CheckLastFlee(float curAngle, std::list<FleeInfo>& infoList);
|
||||||
|
|
||||||
|
PathResult GeneratePath(float x, float y, float z, uint32 acceptMask = DEFAULT_PATH_ACCEPT_MASK, bool forceDestination = false);
|
||||||
|
|
||||||
|
// Returns a unified TravelPath for the move. Mirror of the reference
|
||||||
|
// ResolveMovePath shape: 10% lastPath reuse short-circuit, choose
|
||||||
|
// graph (cross-map / >sightDistance) or live mmap probe, regression
|
||||||
|
// guard preferring cached path when no better, fall back to a
|
||||||
|
// single-point path on dest. Stateless — does not dispatch.
|
||||||
|
TravelPath ResolveMovePath(WorldPosition startPos,
|
||||||
|
WorldPosition endPos,
|
||||||
|
LastMovement& lastMove);
|
||||||
|
|
||||||
|
// Dispatches the head-of-path special segment (portal interact /
|
||||||
|
// area-trigger marker / transport boarding / flight master taxi).
|
||||||
|
// Caller is expected to first call TravelPath::UpcommingSpecialMovement
|
||||||
|
// which cuts the path so the head is the special segment. Returns
|
||||||
|
// true if a movement-consuming action was dispatched this tick.
|
||||||
|
// Returns false for AREA_TRIGGER-with-entry (caller still dispatches
|
||||||
|
// the walk into the trigger volume).
|
||||||
|
bool HandleSpecialMovement(TravelPath& path);
|
||||||
|
|
||||||
|
// Top-of-MoveFarTo gate that keeps a bot riding a transport across
|
||||||
|
// ticks. Returns true if the bot is still on the transport we last
|
||||||
|
// boarded (caller should skip the rest of MoveFarTo this tick).
|
||||||
|
// Clears lastTransportEntry and returns false if the bot has
|
||||||
|
// disembarked or is no longer on the expected transport.
|
||||||
|
bool WaitForTransport();
|
||||||
|
|
||||||
|
// Transport boarding helpers (shared by FollowAction and travel plan)
|
||||||
|
static Transport* GetTransportForPosTolerant(Map* map, WorldObject* ref,
|
||||||
|
uint32 phaseMask, float x, float y, float z);
|
||||||
|
static bool FindBoardingPointOnTransport(Map* map, Transport* transport,
|
||||||
|
WorldObject* ref, float refX, float refY, float refZ,
|
||||||
|
float botX, float botY, float botZ,
|
||||||
|
float& outX, float& outY, float& outZ);
|
||||||
|
bool BoardTransport(Transport* transport);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct CheckAngle
|
struct CheckAngle
|
||||||
{
|
{
|
||||||
@ -74,10 +189,6 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// float SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range = 20.0f, bool
|
|
||||||
// normal_only = false, float step = 8.0f);
|
|
||||||
const Movement::PointsArray SearchForBestPath(float x, float y, float z, float& modified_z, int maxSearchCount = 5,
|
|
||||||
bool normal_only = false, float step = 8.0f);
|
|
||||||
bool wasMovementRestricted = false;
|
bool wasMovementRestricted = false;
|
||||||
void DoMovePoint(Unit* unit, float x, float y, float z, bool generatePath, bool backwards);
|
void DoMovePoint(Unit* unit, float x, float y, float z, bool generatePath, bool backwards);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -44,6 +44,21 @@ bool ResetAiAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Player* master = botAI->GetMaster())
|
||||||
|
{
|
||||||
|
Group* botGroup = bot->GetGroup();
|
||||||
|
Group* masterGroup = master->GetGroup();
|
||||||
|
if (botGroup && (!masterGroup || masterGroup != botGroup))
|
||||||
|
botAI->SetMaster(nullptr);
|
||||||
|
}
|
||||||
|
if (sRandomPlayerbotMgr.IsRandomBot(bot) && !bot->InBattleground())
|
||||||
|
{
|
||||||
|
if (bot->GetGroup() && (!botAI->GetMaster() || GET_PLAYERBOT_AI(botAI->GetMaster())))
|
||||||
|
{
|
||||||
|
if (Player* newMaster = botAI->FindNewMaster())
|
||||||
|
botAI->SetMaster(newMaster);
|
||||||
|
}
|
||||||
|
}
|
||||||
PlayerbotRepository::instance().Reset(botAI);
|
PlayerbotRepository::instance().Reset(botAI);
|
||||||
botAI->ResetStrategies(false);
|
botAI->ResetStrategies(false);
|
||||||
botAI->TellMaster("AI was reset to defaults");
|
botAI->TellMaster("AI was reset to defaults");
|
||||||
|
|||||||
@ -34,24 +34,23 @@ bool SendMailAction::Execute(Event event)
|
|||||||
Player* receiver = GetMaster();
|
Player* receiver = GetMaster();
|
||||||
Player* tellTo = receiver;
|
Player* tellTo = receiver;
|
||||||
|
|
||||||
std::vector<std::string> ss = split(text, ' ');
|
|
||||||
if (ss.size() > 1)
|
|
||||||
{
|
|
||||||
if (Player* p = ObjectAccessor::FindPlayer(ObjectGuid(uint64(ss[ss.size() - 1].c_str()))))
|
|
||||||
receiver = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!receiver)
|
if (!receiver)
|
||||||
receiver = event.getOwner();
|
receiver = event.getOwner();
|
||||||
|
|
||||||
if (!receiver || receiver == bot)
|
if (!receiver || receiver == bot)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!tellTo)
|
if (!tellTo)
|
||||||
tellTo = receiver;
|
tellTo = receiver;
|
||||||
|
|
||||||
|
if (!sPlayerbotAIConfig.botSendMailEnabled)
|
||||||
|
{
|
||||||
|
bot->Whisper(PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||||
|
"send_mail_disabled", "I cannot send mail", {}),
|
||||||
|
LANG_UNIVERSAL, tellTo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mailboxFound && !randomBot)
|
if (!mailboxFound && !randomBot)
|
||||||
{
|
{
|
||||||
bot->Whisper(PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
bot->Whisper(PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||||
|
|||||||
@ -16,7 +16,7 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) }));
|
new TriggerNode("uninvite guid", { NextAction("uninvite", relevance) }));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("group set leader", { /*NextAction("leader", relevance),*/ }));
|
new TriggerNode("group set leader", { NextAction("reset botAI", relevance) }));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"not enough money", { NextAction("tell not enough money", relevance) }));
|
"not enough money", { NextAction("tell not enough money", relevance) }));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
|
|||||||
@ -11,21 +11,20 @@
|
|||||||
|
|
||||||
bool LootAvailableTrigger::IsActive()
|
bool LootAvailableTrigger::IsActive()
|
||||||
{
|
{
|
||||||
bool distanceCheck = false;
|
// Strategy is non-combat-only — the engine state separation is the
|
||||||
if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT))
|
// safety net. Don't gate on hostiles-in-sight: that locked out
|
||||||
{
|
// looting in zones with continuous respawns (e.g. cave farms).
|
||||||
distanceCheck =
|
// If a new enemy aggros mid-loot the combat engine takes over, loot
|
||||||
ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), CONTACT_DISTANCE);
|
// resumes on the next non-combat window.
|
||||||
}
|
if (!AI_VALUE(bool, "has available loot"))
|
||||||
else
|
return false;
|
||||||
{
|
|
||||||
distanceCheck = ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"),
|
|
||||||
INTERACTION_DISTANCE - 2.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if loot target if empty, always pass distance check
|
// "stay" strategy is restrictive: only loot if corpse is at our feet.
|
||||||
return AI_VALUE(bool, "has available loot") &&
|
if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT))
|
||||||
(distanceCheck || AI_VALUE(GuidVector, "all targets").empty());
|
return ServerFacade::instance().IsDistanceLessOrEqualThan(
|
||||||
|
AI_VALUE2(float, "distance", "loot target"), CONTACT_DISTANCE);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FarFromCurrentLootTrigger::IsActive()
|
bool FarFromCurrentLootTrigger::IsActive()
|
||||||
|
|||||||
@ -12,64 +12,48 @@ LastMovement::LastMovement() { clear(); }
|
|||||||
LastMovement::LastMovement(LastMovement& other)
|
LastMovement::LastMovement(LastMovement& other)
|
||||||
: taxiNodes(other.taxiNodes),
|
: taxiNodes(other.taxiNodes),
|
||||||
taxiMaster(other.taxiMaster),
|
taxiMaster(other.taxiMaster),
|
||||||
lastFollow(other.lastFollow),
|
|
||||||
lastAreaTrigger(other.lastAreaTrigger),
|
lastAreaTrigger(other.lastAreaTrigger),
|
||||||
lastMoveToX(other.lastMoveToX),
|
|
||||||
lastMoveToY(other.lastMoveToY),
|
|
||||||
lastMoveToZ(other.lastMoveToZ),
|
|
||||||
lastMoveToOri(other.lastMoveToOri),
|
|
||||||
lastFlee(other.lastFlee)
|
lastFlee(other.lastFlee)
|
||||||
{
|
{
|
||||||
lastMoveShort = other.lastMoveShort;
|
lastMoveShort = other.lastMoveShort;
|
||||||
nextTeleport = other.nextTeleport;
|
nextTeleport = other.nextTeleport;
|
||||||
lastPath = other.lastPath;
|
lastPath = other.lastPath;
|
||||||
priority = other.priority;
|
priority = other.priority;
|
||||||
|
lastTransportEntry = other.lastTransportEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastMovement::clear()
|
void LastMovement::clear()
|
||||||
{
|
{
|
||||||
lastMoveShort = WorldPosition();
|
lastMoveShort = WorldPosition();
|
||||||
lastPath.clear();
|
lastPath.clear();
|
||||||
lastMoveToMapId = 0;
|
|
||||||
lastMoveToX = 0;
|
|
||||||
lastMoveToY = 0;
|
|
||||||
lastMoveToZ = 0;
|
|
||||||
lastMoveToOri = 0;
|
|
||||||
lastFollow = nullptr;
|
|
||||||
lastAreaTrigger = 0;
|
lastAreaTrigger = 0;
|
||||||
lastFlee = 0;
|
lastFlee = 0;
|
||||||
nextTeleport = 0;
|
nextTeleport = 0;
|
||||||
msTime = 0;
|
msTime = 0;
|
||||||
lastdelayTime = 0;
|
|
||||||
priority = MovementPriority::MOVEMENT_NORMAL;
|
priority = MovementPriority::MOVEMENT_NORMAL;
|
||||||
|
lastTransportEntry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastMovement::Set(Unit* follow)
|
void LastMovement::Set([[maybe_unused]] Unit* follow)
|
||||||
{
|
{
|
||||||
|
// Legacy signature — `follow` is ignored (lastFollow field removed).
|
||||||
|
// The function still serves callers that want a soft-reset:
|
||||||
|
// clears short + path, resets msTime/priority via the chain below.
|
||||||
Set(0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
Set(0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
setShort(WorldPosition());
|
setShort(WorldPosition());
|
||||||
setPath(TravelPath());
|
setPath(TravelPath());
|
||||||
lastFollow = follow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float delayTime, MovementPriority pri)
|
void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float delayTime, MovementPriority pri)
|
||||||
{
|
{
|
||||||
lastMoveToMapId = mapId;
|
|
||||||
lastMoveToX = x;
|
|
||||||
lastMoveToY = y;
|
|
||||||
lastMoveToZ = z;
|
|
||||||
lastMoveToOri = ori;
|
|
||||||
lastFollow = nullptr;
|
|
||||||
lastMoveShort = WorldPosition(mapId, x, y, z, ori);
|
lastMoveShort = WorldPosition(mapId, x, y, z, ori);
|
||||||
msTime = getMSTime();
|
msTime = getMSTime();
|
||||||
lastdelayTime = delayTime;
|
|
||||||
priority = pri;
|
priority = pri;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastMovement::setShort(WorldPosition point)
|
void LastMovement::setShort(WorldPosition point)
|
||||||
{
|
{
|
||||||
lastMoveShort = point;
|
lastMoveShort = point;
|
||||||
lastFollow = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastMovement::setPath(TravelPath path) { lastPath = path; }
|
void LastMovement::setPath(TravelPath path) { lastPath = path; }
|
||||||
|
|||||||
@ -33,12 +33,12 @@ public:
|
|||||||
{
|
{
|
||||||
taxiNodes = other.taxiNodes;
|
taxiNodes = other.taxiNodes;
|
||||||
taxiMaster = other.taxiMaster;
|
taxiMaster = other.taxiMaster;
|
||||||
lastFollow = other.lastFollow;
|
|
||||||
lastAreaTrigger = other.lastAreaTrigger;
|
lastAreaTrigger = other.lastAreaTrigger;
|
||||||
lastMoveShort = other.lastMoveShort;
|
lastMoveShort = other.lastMoveShort;
|
||||||
lastPath = other.lastPath;
|
lastPath = other.lastPath;
|
||||||
nextTeleport = other.nextTeleport;
|
nextTeleport = other.nextTeleport;
|
||||||
priority = other.priority;
|
priority = other.priority;
|
||||||
|
lastTransportEntry = other.lastTransportEntry;
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,21 +52,17 @@ public:
|
|||||||
|
|
||||||
std::vector<uint32> taxiNodes;
|
std::vector<uint32> taxiNodes;
|
||||||
ObjectGuid taxiMaster;
|
ObjectGuid taxiMaster;
|
||||||
Unit* lastFollow;
|
|
||||||
uint32 lastAreaTrigger;
|
uint32 lastAreaTrigger;
|
||||||
time_t lastFlee;
|
time_t lastFlee;
|
||||||
uint32 lastMoveToMapId;
|
|
||||||
float lastMoveToX;
|
|
||||||
float lastMoveToY;
|
|
||||||
float lastMoveToZ;
|
|
||||||
float lastMoveToOri;
|
|
||||||
float lastdelayTime;
|
|
||||||
WorldPosition lastMoveShort;
|
WorldPosition lastMoveShort;
|
||||||
uint32 msTime;
|
uint32 msTime;
|
||||||
MovementPriority priority;
|
MovementPriority priority;
|
||||||
TravelPath lastPath;
|
TravelPath lastPath;
|
||||||
time_t nextTeleport;
|
time_t nextTeleport;
|
||||||
std::future<TravelPath> future;
|
// Entry of the transport the bot is currently aboard mid-journey,
|
||||||
|
// used by WaitForTransport to resume a transport segment if the
|
||||||
|
// bot is still on it next tick (e.g. boat in motion). 0 = none.
|
||||||
|
uint32 lastTransportEntry{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
class LastMovementValue : public ManualSetValue<LastMovement&>
|
class LastMovementValue : public ManualSetValue<LastMovement&>
|
||||||
|
|||||||
@ -47,7 +47,13 @@ public:
|
|||||||
{
|
{
|
||||||
if (allowedGOFlags.empty())
|
if (allowedGOFlags.empty())
|
||||||
{
|
{
|
||||||
|
// questgivers for accept/turn-in; rest for quest progression
|
||||||
|
// (chests, runes, altars, moonwells, lily piles, …)
|
||||||
allowedGOFlags.push_back(GAMEOBJECT_TYPE_QUESTGIVER);
|
allowedGOFlags.push_back(GAMEOBJECT_TYPE_QUESTGIVER);
|
||||||
|
allowedGOFlags.push_back(GAMEOBJECT_TYPE_CHEST);
|
||||||
|
allowedGOFlags.push_back(GAMEOBJECT_TYPE_GOOBER);
|
||||||
|
allowedGOFlags.push_back(GAMEOBJECT_TYPE_SPELL_FOCUS);
|
||||||
|
allowedGOFlags.push_back(GAMEOBJECT_TYPE_GENERIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -161,9 +161,7 @@ void ShamanAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
}
|
}
|
||||||
else if (tab == SHAMAN_TAB_ENHANCEMENT)
|
else if (tab == SHAMAN_TAB_ENHANCEMENT)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("medium aoe",{ NextAction("magma totem", 24.0f),
|
triggers.push_back(new TriggerNode("medium aoe",{ NextAction("fire nova", 23.0f), }));
|
||||||
NextAction("fire nova", 23.0f), }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("maelstrom weapon 5 and medium aoe", { NextAction("chain lightning", 22.0f), }));
|
triggers.push_back(new TriggerNode("maelstrom weapon 5 and medium aoe", { NextAction("chain lightning", 22.0f), }));
|
||||||
triggers.push_back(new TriggerNode("maelstrom weapon 4 and medium aoe", { NextAction("chain lightning", 21.0f), }));
|
triggers.push_back(new TriggerNode("maelstrom weapon 4 and medium aoe", { NextAction("chain lightning", 21.0f), }));
|
||||||
triggers.push_back(new TriggerNode("enemy within melee", { NextAction("fire nova", 5.1f), }));
|
triggers.push_back(new TriggerNode("enemy within melee", { NextAction("fire nova", 5.1f), }));
|
||||||
|
|||||||
@ -112,6 +112,7 @@ std::vector<NextAction> ArmsWarriorStrategy::getDefaultActions()
|
|||||||
return {
|
return {
|
||||||
NextAction("bladestorm", ACTION_DEFAULT + 0.2f),
|
NextAction("bladestorm", ACTION_DEFAULT + 0.2f),
|
||||||
NextAction("mortal strike", ACTION_DEFAULT + 0.1f),
|
NextAction("mortal strike", ACTION_DEFAULT + 0.1f),
|
||||||
|
NextAction("sunder armor", ACTION_DEFAULT + 0.05f),
|
||||||
NextAction("melee", ACTION_DEFAULT)
|
NextAction("melee", ACTION_DEFAULT)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "WarriorActions.h"
|
#include "WarriorActions.h"
|
||||||
|
|
||||||
|
#include "AiFactory.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
bool CastBerserkerRageAction::isPossible()
|
bool CastBerserkerRageAction::isPossible()
|
||||||
@ -36,6 +37,27 @@ bool CastBerserkerRageAction::isUseful()
|
|||||||
|
|
||||||
bool CastSunderArmorAction::isUseful()
|
bool CastSunderArmorAction::isUseful()
|
||||||
{
|
{
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!botAI->IsTank(bot, false))
|
||||||
|
{
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || member == bot || !member->IsAlive() || !member->IsInWorld() ||
|
||||||
|
member->GetMapId() != bot->GetMapId())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (member->getClass() == CLASS_WARRIOR &&
|
||||||
|
botAI->IsTank(member, false))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Aura* aura = botAI->GetAura("sunder armor", GetTarget(), false, true);
|
Aura* aura = botAI->GetAura("sunder armor", GetTarget(), false, true);
|
||||||
return !aura || aura->GetStackAmount() < 5 || aura->GetDuration() <= 6000;
|
return !aura || aura->GetStackAmount() < 5 || aura->GetDuration() <= 6000;
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "AuchenaiCryptsActions.h"
|
#include "ACActions.h"
|
||||||
|
|
||||||
class TbcDungeonAuchenaiCryptsActionContext : public NamedObjectContext<Action>
|
class TbcDungeonAuchenaiCryptsActionContext : public NamedObjectContext<Action>
|
||||||
{
|
{
|
||||||
@ -1,7 +1,7 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "AiFactory.h"
|
#include "AiFactory.h"
|
||||||
#include "AuchenaiCryptsTriggers.h"
|
#include "ACTriggers.h"
|
||||||
#include "AuchenaiCryptsActions.h"
|
#include "ACActions.h"
|
||||||
|
|
||||||
// Shirrak the Dead Watcher
|
// Shirrak the Dead Watcher
|
||||||
|
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "AttackAction.h"
|
#include "AttackAction.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
#include "AuchenaiCryptsTriggers.h"
|
#include "ACTriggers.h"
|
||||||
|
|
||||||
// Shirrak the Dead Watcher
|
// Shirrak the Dead Watcher
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#include "AuchenaiCryptsMultipliers.h"
|
#include "ACMultipliers.h"
|
||||||
#include "AuchenaiCryptsActions.h"
|
#include "ACActions.h"
|
||||||
#include "AuchenaiCryptsTriggers.h"
|
#include "ACTriggers.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
#include "ReachTargetActions.h"
|
#include "ReachTargetActions.h"
|
||||||
#include "FollowActions.h"
|
#include "FollowActions.h"
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#include "AuchenaiCryptsTriggers.h"
|
#include "ACTriggers.h"
|
||||||
#include "AuchenaiCryptsStrategy.h"
|
#include "ACStrategy.h"
|
||||||
#include "AuchenaiCryptsMultipliers.h"
|
#include "ACMultipliers.h"
|
||||||
|
|
||||||
void TbcDungeonAuchenaiCryptsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void TbcDungeonAuchenaiCryptsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
#include "TriggerContext.h"
|
#include "TriggerContext.h"
|
||||||
#include "AuchenaiCryptsTriggers.h"
|
#include "ACTriggers.h"
|
||||||
|
|
||||||
class TbcDungeonAuchenaiCryptsTriggerContext : public NamedObjectContext<Trigger>
|
class TbcDungeonAuchenaiCryptsTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "AuchenaiCryptsTriggers.h"
|
#include "ACTriggers.h"
|
||||||
#include "AiObject.h"
|
#include "AiObject.h"
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "OldKingdomActions.h"
|
#include "AKActions.h"
|
||||||
|
|
||||||
class WotlkDungeonOKActionContext : public NamedObjectContext<Action>
|
class WotlkDungeonOKActionContext : public NamedObjectContext<Action>
|
||||||
{
|
{
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "OldKingdomActions.h"
|
#include "AKActions.h"
|
||||||
|
|
||||||
bool AttackNadoxGuardianAction::Execute(Event /*event*/)
|
bool AttackNadoxGuardianAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
@ -5,7 +5,7 @@
|
|||||||
#include "AttackAction.h"
|
#include "AttackAction.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "OldKingdomTriggers.h"
|
#include "AKTriggers.h"
|
||||||
|
|
||||||
class AttackNadoxGuardianAction : public AttackAction
|
class AttackNadoxGuardianAction : public AttackAction
|
||||||
{
|
{
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#include "OldKingdomMultipliers.h"
|
#include "AKMultipliers.h"
|
||||||
#include "OldKingdomActions.h"
|
#include "AKActions.h"
|
||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
#include "ChooseTargetActions.h"
|
#include "ChooseTargetActions.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
#include "OldKingdomTriggers.h"
|
#include "AKTriggers.h"
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
|
|
||||||
float ElderNadoxMultiplier::GetValue(Action* action)
|
float ElderNadoxMultiplier::GetValue(Action* action)
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "OldKingdomStrategy.h"
|
#include "AKStrategy.h"
|
||||||
#include "OldKingdomMultipliers.h"
|
#include "AKMultipliers.h"
|
||||||
|
|
||||||
void WotlkDungeonOKStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
void WotlkDungeonOKStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||||
{
|
{
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
#include "OldKingdomTriggers.h"
|
#include "AKTriggers.h"
|
||||||
|
|
||||||
class WotlkDungeonOKTriggerContext : public NamedObjectContext<Trigger>
|
class WotlkDungeonOKTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "OldKingdomTriggers.h"
|
#include "AKTriggers.h"
|
||||||
#include "AiObject.h"
|
#include "AiObject.h"
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "AzjolNerubActions.h"
|
#include "ANActions.h"
|
||||||
|
|
||||||
class WotlkDungeonANActionContext : public NamedObjectContext<Action>
|
class WotlkDungeonANActionContext : public NamedObjectContext<Action>
|
||||||
{
|
{
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "AzjolNerubActions.h"
|
#include "ANActions.h"
|
||||||
|
|
||||||
bool AttackWebWrapAction::isUseful() { return !botAI->IsHeal(bot); }
|
bool AttackWebWrapAction::isUseful() { return !botAI->IsHeal(bot); }
|
||||||
bool AttackWebWrapAction::Execute(Event /*event*/)
|
bool AttackWebWrapAction::Execute(Event /*event*/)
|
||||||
@ -5,7 +5,7 @@
|
|||||||
#include "AttackAction.h"
|
#include "AttackAction.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "AzjolNerubTriggers.h"
|
#include "ANTriggers.h"
|
||||||
|
|
||||||
class AttackWebWrapAction : public AttackAction
|
class AttackWebWrapAction : public AttackAction
|
||||||
{
|
{
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#include "AzjolNerubMultipliers.h"
|
#include "ANMultipliers.h"
|
||||||
#include "AzjolNerubActions.h"
|
#include "ANActions.h"
|
||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
#include "ChooseTargetActions.h"
|
#include "ChooseTargetActions.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
#include "AzjolNerubTriggers.h"
|
#include "ANTriggers.h"
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
|
|
||||||
float KrikthirMultiplier::GetValue(Action* action)
|
float KrikthirMultiplier::GetValue(Action* action)
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "AzjolNerubStrategy.h"
|
#include "ANStrategy.h"
|
||||||
#include "AzjolNerubMultipliers.h"
|
#include "ANMultipliers.h"
|
||||||
|
|
||||||
void WotlkDungeonANStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
void WotlkDungeonANStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||||
{
|
{
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
#include "AzjolNerubTriggers.h"
|
#include "ANTriggers.h"
|
||||||
|
|
||||||
class WotlkDungeonANTriggerContext : public NamedObjectContext<Trigger>
|
class WotlkDungeonANTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "AzjolNerubTriggers.h"
|
#include "ANTriggers.h"
|
||||||
#include "AiObject.h"
|
#include "AiObject.h"
|
||||||
#include "AiObjectContext.h"
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user