Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b6af40e
Restore Naxx Strategies Rebases
Wishmaster117 Jan 18, 2026
11d79ff
codestyle
Wishmaster117 Jan 18, 2026
f213527
Update include path for RaidNaxxBossHelper.h
Wishmaster117 Jan 18, 2026
990863e
remove folder
Wishmaster117 Jan 19, 2026
8d9efb8
Restore folder
Wishmaster117 Jan 19, 2026
0485ae3
Update AiObjectContext.cpp
Wishmaster117 Jan 20, 2026
30dccf5
Move Naxx Folder
Wishmaster117 Jan 20, 2026
3d467ce
Added some additional defense checks around isHostile and unit/target…
hermensbas Jan 24, 2026
378254a
Fix Assistant Assignment Functions (#1930)
brighton-chi Jan 24, 2026
5365ba8
Added PR template (#2063)
hermensbas Jan 25, 2026
7abd836
Update PULL_REQUEST_TEMPLATE.md (#2064)
hermensbas Jan 25, 2026
c59a02e
Update PULL_REQUEST_TEMPLATE.md (#2065)
hermensbas Jan 25, 2026
43e8e31
Update PULL_REQUEST_TEMPLATE.md (#2066)
hermensbas Jan 25, 2026
f5711dc
FIX Onyxia Crash (#2062)
gutoukuaiken Jan 25, 2026
2c8f8f8
Improve Saphiron Bots Strat
Wishmaster117 Jan 28, 2026
8d68253
Merge branch 'mod-playerbots:master' into Restore-Naxx-Strategies-Reb…
Wishmaster117 Jan 28, 2026
b9d64cf
Update RaidNaxxBossHelper.h
Wishmaster117 Jan 28, 2026
3640c58
Improve Kelthuzad bots strategie
Wishmaster117 Jan 28, 2026
941ee0f
Update RaidNaxxActions_Kelthuzad.cpp
Wishmaster117 Jan 28, 2026
8693825
Add strat Noth the Plaguebringer
Wishmaster117 Jan 28, 2026
ff7af10
Codestyle
Wishmaster117 Jan 28, 2026
a928860
Summon Logic Tweaks (#2049)
dillyns Jan 29, 2026
47dfeea
Implement Loatheb strategie + New folder structure
Wishmaster117 Jan 30, 2026
94926b1
Update RaidNaxxActions_Loatheb.cpp
Wishmaster117 Jan 30, 2026
42743ea
Improve Anubrekhan bots strategies
Wishmaster117 Jan 30, 2026
37aa78c
Implement Grand Widow Faerlina bots strategie
Wishmaster117 Jan 30, 2026
1ad327e
Implement Maexxna raid bots strategie
Wishmaster117 Jan 30, 2026
34da26d
Implement Gothik the Harvester Bots Strategy
Wishmaster117 Jan 30, 2026
13fff46
Improper singletons migration to clean Meyer's singletons (cherry-pic…
hermensbas Jan 30, 2026
caae524
Minor flightMasterCache fix. (#2085)
Celandriel Jan 30, 2026
00d19db
Fix Destro Warlock Glyphs (#2084)
brighton-chi Jan 30, 2026
e6eae3f
Merge branch 'mod-playerbots:master' into Restore-Naxx-Strategies-Reb…
Wishmaster117 Jan 30, 2026
3632723
Fix Fuc**** compil error
Wishmaster117 Jan 31, 2026
9546363
Hotfix for OnBotLoginOperation() Crash (#2089)
brighton-chi Jan 31, 2026
772b5ac
Merge branch 'mod-playerbots:master' into Restore-Naxx-Strategies-Reb…
Wishmaster117 Jan 31, 2026
6ee1684
Fix WSG graveyard camping by flag carrier (#2086)
brighton-chi Jan 31, 2026
8529654
Correction after singleton PR (#2095)
hermensbas Feb 1, 2026
2b2f9e8
Merge branch 'mod-playerbots:master' into Restore-Naxx-Strategies-Reb…
Wishmaster117 Feb 1, 2026
2c915b3
Adjustments for KT and Saphiron 25
Wishmaster117 Feb 1, 2026
cafb95e
Create check_pr_source.yml (#2098)
hermensbas Feb 1, 2026
8e316cd
fix (#2099)
hermensbas Feb 1, 2026
8c2a27b
Update check_pr_source.yml (#2101)
hermensbas Feb 1, 2026
ba83525
New whisper command "pvp stats" that allows players to ask a bot to r…
Wishmaster117 Feb 2, 2026
c86032f
Convert PlayerBots tables to InnoDB (#2083)
elderbit Feb 2, 2026
31765c7
Update PULL_REQUEST_TEMPLATE.md (#2114)
hermensbas Feb 3, 2026
666b4a0
Merge branch 'master' into Restore-Naxx-Strategies-Rebased
hermensbas Feb 3, 2026
add33f5
Remove commented code
Wishmaster117 Feb 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/check_pr_source.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Enforce test-staging → main

on:
pull_request:
branches:
- master

jobs:
require-test-staging:
runs-on: ubuntu-22.04
steps:
- name: Ensure PR source is test-staging
run: |
echo "Base: ${{ github.event.pull_request.base.ref }}"
echo "Head: ${{ github.event.pull_request.head.ref }}"
if [ "${{ github.event.pull_request.head.ref }}" != "test-staging" ]; then
echo "✖ Pull request must come from test-staging"
exit 1
fi
136 changes: 136 additions & 0 deletions PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Pull Request

Describe what this change does and why it is needed...

---

## Design Philosophy

We prioritize **stability, performance, and predictability** over behavioral realism.
Complex player-mimicking logic is intentionally limited due to its negative impact on scalability, maintainability, and
long-term robustness.

Excessive processing overhead can lead to server hiccups, increased CPU usage, and degraded performance for all
participants. Because every action and
decision tree is executed **per bot and per trigger**, even small increases in logic complexity can scale poorly and
negatively affect both players and
world (random) bots. Bots are not expected to behave perfectly, and perfect simulation of human decision-making is not a
project goal. Increased behavioral
realism often introduces disproportionate cost, reduced predictability, and significantly higher maintenance overhead.

Every additional branch of logic increases long-term responsibility. All decision paths must be tested, validated, and
maintained continuously as the system evolves.
If advanced or AI-intensive behavior is introduced, the **default configuration must remain the lightweight decision
model**. More complex behavior should only be
available as an **explicit opt-in option**, clearly documented as having a measurable performance cost.

Principles:

- **Stability before intelligence**
A stable system is always preferred over a smarter one.

- **Performance is a shared resource**
Any increase in bot cost affects all players and all bots.

- **Simple logic scales better than smart logic**
Predictable behavior under load is more valuable than perfect decisions.

- **Complexity must justify itself**
If a feature cannot clearly explain its cost, it should not exist.

- **Defaults must be cheap**
Expensive behavior must always be optional and clearly communicated.

- **Bots should look reasonable, not perfect**
The goal is believable behavior, not human simulation.

Before submitting, confirm that this change aligns with those principles.

---

## Feature Evaluation

Please answer the following:

- Describe the **minimum logic** required to achieve the intended behavior?
- Describe the **cheapest implementation** that produces an acceptable result?
- Describe the **runtime cost** when this logic executes across many bots?

---

## How to Test the Changes

- Step-by-step instructions to test the change
- Any required setup (e.g. multiple players, bots, specific configuration)
- Expected behavior and how to verify it

## Complexity & Impact

Does this change add new decision branches?
```
[ ] No
[ ] Yes (**explain below**)
```

Does this change increase per-bot or per-tick processing?
```
[ ] No
[ ] Yes (**describe and justify impact**)
```

Could this logic scale poorly under load?
```
[ ] No
[ ] Yes (**explain why**)
```
---

## Defaults & Configuration

Does this change modify default bot behavior?
```
[ ] No
[ ] Yes (**explain why**)
```

If this introduces more advanced or AI-heavy logic:
```
[ ] Lightweight mode remains the default
[ ] More complex behavior is optional and thereby configurable
```
---

## AI Assistance

Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change?
```
[ ] No
[ ] Yes (**explain below**)
```

If yes, please specify:

- AI tool or model used (e.g. ChatGPT, GPT-4, Claude, etc.)
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation)
- Which parts of the change were influenced or generated
- Whether the result was manually reviewed and adapted

AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
Any AI-influenced changes must be verified against existing CORE and PB logic. We expect contributors to be honest
about what they do and do not understand.

---

## Final Checklist

- [ ] Stability is not compromised
- [ ] Performance impact is understood, tested, and acceptable
- [ ] Added logic complexity is justified and explained
- [ ] Documentation updated if needed

---

## Notes for Reviewers

Anything that significantly improves realism at the cost of stability or performance should be carefully discussed
before merging.
8 changes: 4 additions & 4 deletions conf/playerbots.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,8 @@ AiPlayerbot.AutoGearQualityLimit = 3
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
# TBC
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
# Wotlk
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
# WotLK
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
# Default: 0 (no limit)
Expand Down Expand Up @@ -736,7 +736,7 @@ AiPlayerbot.RandomGearQualityLimit = 3
# TBC
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
# Wotlk
# WotLK
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
# Default: 0 (no limit)
Expand Down Expand Up @@ -1624,7 +1624,7 @@ AiPlayerbot.PremadeSpecLink.9.1.60 = -003203301135112530135201051
AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55
AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005
AiPlayerbot.PremadeSpecName.9.2 = destro pve
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,50077,43394,43393,42454
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,42454,43394,43393,45785
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151
AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351
AiPlayerbot.PremadeSpecName.9.3 = affli pvp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Temporarily disables innodb_strict_mode for the session to allow the script to complete even if legacy table definitions contain InnoDB-incompatible attributes
SET SESSION innodb_strict_mode = 0;

-- Change the tables to InnoDB
ALTER TABLE playerbots_guild_names ENGINE=InnoDB;
ALTER TABLE playerbots_names ENGINE=InnoDB;

-- Re-enables innodb_strict_mode
SET SESSION innodb_strict_mode = 1;
18 changes: 18 additions & 0 deletions data/sql/playerbots/updates/2026_01_30_00_change_to_InnoDB.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-- Temporarily disables innodb_strict_mode for the session to allow the script to complete even if legacy table definitions contain InnoDB-incompatible attributes
SET SESSION innodb_strict_mode = 0;

-- Change the tables to InnoDB
ALTER TABLE playerbots_dungeon_suggestion_abbrevation ENGINE=InnoDB;
ALTER TABLE playerbots_dungeon_suggestion_definition ENGINE=InnoDB;
ALTER TABLE playerbots_dungeon_suggestion_strategy ENGINE=InnoDB;
ALTER TABLE playerbots_equip_cache ENGINE=InnoDB;
ALTER TABLE playerbots_item_info_cache ENGINE=InnoDB;
ALTER TABLE playerbots_rarity_cache ENGINE=InnoDB;
ALTER TABLE playerbots_rnditem_cache ENGINE=InnoDB;
ALTER TABLE playerbots_tele_cache ENGINE=InnoDB;
ALTER TABLE playerbots_travelnode ENGINE=InnoDB;
ALTER TABLE playerbots_travelnode_link ENGINE=InnoDB;
ALTER TABLE playerbots_travelnode_path ENGINE=InnoDB;

-- Re-enables innodb_strict_mode
SET SESSION innodb_strict_mode = 1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
-- #########################################################
-- Playerbots - Add PVP / Arena texts for TellPvpAction
-- Localized for all WotLK locales (koKR, frFR, deDE, zhCN,
-- zhTW, esES, esMX, ruRU)
-- #########################################################

-- ---------------------------------------------------------
-- pvp_currency
-- [PVP] Arena points: %arena_points | Honor Points: %honor_points
-- ---------------------------------------------------------
INSERT INTO `ai_playerbot_texts`
(`name`, `text`, `say_type`, `reply_type`,
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
SELECT
'pvp_currency',
'[PVP] Arena points: %arena_points | Honor Points: %honor_points',
0, 0,
-- koKR
'[PVP] 투기장 점수: %arena_points | 명예 점수: %honor_points',
-- frFR
'[PVP] Points d''arène : %arena_points | Points d''honneur : %honor_points',
-- deDE
'[PVP] Arenapunkte: %arena_points | Ehrenpunkte: %honor_points',
-- zhCN
'[PVP] 竞技场点数:%arena_points | 荣誉点数:%honor_points',
-- zhTW
'[PVP] 競技場點數:%arena_points | 榮譽點數:%honor_points',
-- esES
'[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points',
-- esMX
'[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points',
-- ruRU
'[PVP] Очки арены: %arena_points | Очки чести: %honor_points'
WHERE NOT EXISTS (
SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_currency'
);

-- ---------------------------------------------------------
-- pvp_arena_team
-- [PVP] %bracket: <%team_name> (rating %team_rating)
-- ---------------------------------------------------------
INSERT INTO `ai_playerbot_texts`
(`name`, `text`, `say_type`, `reply_type`,
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
SELECT
'pvp_arena_team',
'[PVP] %bracket: <%team_name> (rating %team_rating)',
0, 0,
-- koKR
'[PVP] %bracket: <%team_name> (평점 %team_rating)',
-- frFR
'[PVP] %bracket : <%team_name> (cote %team_rating)',
-- deDE
'[PVP] %bracket: <%team_name> (Wertung %team_rating)',
-- zhCN
'[PVP] %bracket: <%team_name> (评分 %team_rating)',
-- zhTW
'[PVP] %bracket: <%team_name> (評分 %team_rating)',
-- esES
'[PVP] %bracket: <%team_name> (índice %team_rating)',
-- esMX
'[PVP] %bracket: <%team_name> (índice %team_rating)',
-- ruRU
'[PVP] %bracket: <%team_name> (рейтинг %team_rating)'
WHERE NOT EXISTS (
SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_arena_team'
);

-- ---------------------------------------------------------
-- pvp_no_arena_team
-- [PVP] I have no Arena Team.
-- ---------------------------------------------------------
INSERT INTO `ai_playerbot_texts`
(`name`, `text`, `say_type`, `reply_type`,
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
SELECT
'pvp_no_arena_team',
'[PVP] I have no Arena Team.',
0, 0,
-- koKR
'[PVP] 투기장 팀이 없습니다.',
-- frFR
'[PVP] Je n''ai aucune équipe d''arène.',
-- deDE
'[PVP] Ich habe kein Arenateam.',
-- zhCN
'[PVP] 我没有竞技场战队。',
-- zhTW
'[PVP] 我沒有競技場隊伍。',
-- esES
'[PVP] No tengo equipo de arena.',
-- esMX
'[PVP] No tengo equipo de arena.',
-- ruRU
'[PVP] У меня нет команды арены.'
WHERE NOT EXISTS (
SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_no_arena_team'
);
1 change: 1 addition & 0 deletions src/Ai/Base/ActionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "OutfitAction.h"
#include "PositionAction.h"
#include "DropQuestAction.h"
#include "RaidNaxxActions.h"
#include "RandomBotUpdateAction.h"
#include "ReachTargetActions.h"
#include "ReleaseSpiritAction.h"
Expand Down
6 changes: 3 additions & 3 deletions src/Ai/Base/Actions/AcceptInvitationAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,18 @@ bool AcceptInvitationAction::Execute(Event event)
if (!bot->GetGroup() || !bot->GetGroup()->IsMember(inviter->GetGUID()))
return false;

if (sRandomPlayerbotMgr->IsRandomBot(bot))
if (sRandomPlayerbotMgr.IsRandomBot(bot))
botAI->SetMaster(inviter);
// else
// sPlayerbotRepository->Save(botAI);
// PlayerbotRepository::instance().Save(botAI);

botAI->ResetStrategies();
botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT);
botAI->Reset();

botAI->TellMaster("Hello");

if (sPlayerbotAIConfig->summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig->sightDistance)
if (sPlayerbotAIConfig.summonWhenGroup && bot->GetDistance(inviter) > sPlayerbotAIConfig.sightDistance)
{
Teleport(inviter, bot, true);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Ai/Base/Actions/AreaTriggerAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ bool ReachAreaTriggerAction::Execute(Event event)
/*forceDestination*/ false);

float distance = bot->GetDistance(at->x, at->y, at->z);
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay;
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig.reactDelay;
botAI->TellError("Wait for me");
botAI->SetNextCheckDelay(delay);
context->GetValue<LastMovement&>("last area trigger")->Get().lastAreaTrigger = triggerId;
Expand Down
6 changes: 3 additions & 3 deletions src/Ai/Base/Actions/AttackAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
// Check if bot OR target is in prohibited zone/area (skip for duels)
if ((target->IsPlayer() || target->IsPet()) &&
(!bot->duel || bot->duel->Opponent != target) &&
(sPlayerbotAIConfig->IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) ||
sPlayerbotAIConfig->IsPvpProhibited(target->GetZoneId(), target->GetAreaId())))
(sPlayerbotAIConfig.IsPvpProhibited(bot->GetZoneId(), bot->GetAreaId()) ||
sPlayerbotAIConfig.IsPvpProhibited(target->GetZoneId(), target->GetAreaId())))
{
if (verbose)
botAI->TellError("I cannot attack other players in PvP prohibited areas.");
Expand Down Expand Up @@ -160,7 +160,7 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
}

if (botAI->CanMove() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target))
sServerFacade->SetFacingTo(bot, target);
ServerFacade::instance().SetFacingTo(bot, target);

botAI->ChangeEngine(BOT_STATE_COMBAT);

Expand Down
Loading