Compare commits

..

8 Commits

Author SHA1 Message Date
bashermens
6cf7f1aaef [CHORE] Util classes format and simple cleanup with generated resources (#2028)
- Did some basic formatting
- Some generated docs
- Cleaned header/impl Helper.css
- Moved PerfMonitor from util to bot/handler/command

Still a freaking mess though, but its a start i guess. Cant ask ppl to
add more or make use of those when its so messy.
2026-01-18 00:43:44 +01:00
bashermens
9f54d7e702 Removed the expansion folder from dungeons (#2027)
In order to make consistent with raids but also to shorten max used
length directory for windows builds
2026-01-17 21:55:08 +01:00
bashermens
aeaaee15da [FIX] Finalized structure! (do not start fixing PR merge structure conflict till this is merged) (#2025)
Finalized
2026-01-17 14:38:12 +01:00
bashermens
a1137dbddc [FIX] Folder restructure (#2018)
As requested

Poll
```
1. Yes
2. Yes
3. Maybe, but yes
```

---------

Co-authored-by: Celandriel <22352763+Celandriel@users.noreply.github.com>
2026-01-17 10:34:58 +01:00
bashermens
2eb98c3233 [BUILD] Windows shorter build path (#2021) 2026-01-16 17:39:12 +01:00
Keleborn
29613e29b7 Bug - Selfbot can trigger crash in printstats (#2013)
Adding a guard against bots that may be registered in `playerBots`
variable as selfbot have appeared to crash here.

Edit: The exact circumstances that caused the incorrect registration are
under investigation as it seems to be 'atypical' behavior.
2026-01-15 00:42:37 +01:00
privatecore
e2c203a35e Fix the duplicate spells issue during randomization (#2014)
**Original issue:**
Bots/Characters received duplicate spells during randomization process.

**Root cause:**
When `PlayerbotFactory::Randomize` is processed, `InitSkills` is called
AFTER `InitAvailableSpells`, which causes the duplicate spells issue
because the skillline ability spell is already learned when processing
spells from trainers (`InitAvailableSpells`).

We simply need to change the order of the randomization process: skills
should be handled first, then spells. An alternative approach would be
to adjust the skillline abilities and check each spell for every skill,
but that seems redundant since we already have checks for the trainer's
spells.

`InitSkills` -> `SetRandomSkill` -> `SetSkill` ->
`learnSkillRewardedSpells` -> `learnSpell` -> duplicate error...

**Steps to reproduce:**
1. create common character and login with it
2. set level for this character eq. 80 (`.set level 79`)
3. create and run macro:
```
/g .playerbots bot initself
/g .saveall
```
4. logout -> login and run macro again

**Note:**
Also added checks for the trainer's spells since `GetSpell` can return
nullptr. Updated `LearnQuestSpells` after recent changes and used the
same logic and implementation from `Player::learnQuestRewardedSpells`.

Yes, we need to cast spells, or we should handle all spell effects that
quests/trainers have (for ex.: `SPELL_EFFECT_SKILL_STEP`,
`SPELL_EFFECT_UNLEARN_SPECIALIZATION`, `SPELL_EFFECT_BIND`).
2026-01-15 00:42:19 +01:00
bashermens
1b1ed18a23 Minor fix (#2015) 2026-01-15 00:42:09 +01:00
1165 changed files with 704 additions and 484 deletions

View File

@@ -25,21 +25,25 @@ jobs:
with: with:
repository: 'mod-playerbots/azerothcore-wotlk' repository: 'mod-playerbots/azerothcore-wotlk'
ref: 'Playerbot' ref: 'Playerbot'
path: 'ac'
- name: Checkout Playerbot Module - name: Checkout Playerbot Module
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
repository: 'mod-playerbots/mod-playerbots' repository: 'mod-playerbots/mod-playerbots'
path: 'modules/mod-playerbots' #path: 'modules/mod-playerbots'
path: ac/modules/mod-playerbots
- name: ccache - name: ccache
uses: hendrikmuhs/ccache-action@v1.2.13 uses: hendrikmuhs/ccache-action@v1.2.13
- name: Configure OS - name: Configure OS
shell: bash shell: bash
working-directory: ac
env: env:
CONTINUOUS_INTEGRATION: true CONTINUOUS_INTEGRATION: true
run: | run: |
./acore.sh install-deps ./acore.sh install-deps
- name: Build - name: Build
shell: bash shell: bash
working-directory: ac
run: | run: |
export CTOOLS_BUILD=all export CTOOLS_BUILD=all
./acore.sh compiler build ./acore.sh compiler build

View File

@@ -49,7 +49,7 @@ bool AcceptInvitationAction::Execute(Event event)
if (sRandomPlayerbotMgr->IsRandomBot(bot)) if (sRandomPlayerbotMgr->IsRandomBot(bot))
botAI->SetMaster(inviter); botAI->SetMaster(inviter);
// else // else
// sPlayerbotDbStore->Save(botAI); // sPlayerbotRepository->Save(botAI);
botAI->ResetStrategies(); botAI->ResetStrategies();
botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+follow,-lfg,-bg", BOT_STATE_NON_COMBAT);

View File

@@ -75,19 +75,17 @@ void AutoMaintenanceOnLevelupAction::LearnSpells(std::ostringstream* out)
void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* out) void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* out)
{ {
PlayerbotFactory factory(bot, bot->GetLevel()); PlayerbotFactory factory(bot, bot->GetLevel());
factory.InitSkills();
factory.InitClassSpells(); factory.InitClassSpells();
factory.InitAvailableSpells(); factory.InitAvailableSpells();
factory.InitSkills();
factory.InitPet(); factory.InitPet();
} }
void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out) void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
{ {
// CreatureTemplate const* co = sCreatureStorage.LookupEntry<CreatureTemplate>(id);
ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates(); ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates();
for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i) for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i)
{ {
//uint32 questId = i->first; //not used, line marked for removal.
Quest const* quest = i->second; Quest const* quest = i->second;
// only process class-specific quests to learn class-related spells, cuz // only process class-specific quests to learn class-related spells, cuz
@@ -104,15 +102,53 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
!bot->SatisfyQuestSkill(quest, false)) !bot->SatisfyQuestSkill(quest, false))
continue; continue;
if (quest->GetRewSpellCast() > 0) // RewardSpell - expected route // use the same logic and impl from Player::learnQuestRewardedSpells
int32 spellId = quest->GetRewSpellCast();
if (!spellId)
continue;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
continue;
// xinef: find effect with learn spell and check if we have this spell
bool found = false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{ {
LearnSpell(quest->GetRewSpellCast(), out); if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
} !bot->HasSpell(spellInfo->Effects[i].TriggerSpell))
else if (quest->GetRewSpell() > 0) // RewardDisplaySpell - fallback
{ {
LearnSpell(quest->GetRewSpell(), out); // pusywizard: don't re-add profession specialties!
if (SpellInfo const* triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell))
if (triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
break; // pussywizard: break and not cast the spell (found is false)
found = true;
break;
} }
} }
// xinef: we know the spell, continue
if (!found)
continue;
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();
if (rewSpellId)
{
if (SpellInfo const* rewSpellInfo = sSpellMgr->GetSpellInfo(rewSpellId))
{
*out << FormatSpell(rewSpellInfo) << ", ";
continue;
}
}
*out << FormatSpell(spellInfo) << ", ";
}
} }
std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* sInfo) std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* sInfo)
@@ -128,41 +164,6 @@ std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* s
return out.str(); return out.str();
} }
void AutoMaintenanceOnLevelupAction::LearnSpell(uint32 spellId, std::ostringstream* out)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
return;
SpellInfo const* triggeredInfo;
// find effect with learn spell and check if we have this spell
bool found = false;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
!bot->HasSpell(spellInfo->Effects[i].TriggerSpell))
{
triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell);
// do not learn profession specialties!
if (!triggeredInfo || triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
break;
found = true;
break;
}
}
if (!found)
return;
// NOTE: When rewarding quests, core casts spells instead of learning them,
// but we sacrifice safe cast checks here in favor of performance/speed
bot->learnSpell(triggeredInfo->Id);
*out << FormatSpell(triggeredInfo) << ", ";
}
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip() void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
{ {
if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot))

View File

@@ -28,7 +28,6 @@ protected:
void LearnSpells(std::ostringstream* out); void LearnSpells(std::ostringstream* out);
void LearnTrainerSpells(std::ostringstream* out); void LearnTrainerSpells(std::ostringstream* out);
void LearnQuestSpells(std::ostringstream* out); void LearnQuestSpells(std::ostringstream* out);
void LearnSpell(uint32 spellId, std::ostringstream* out);
std::string const FormatSpell(SpellInfo const* sInfo); std::string const FormatSpell(SpellInfo const* sInfo);
}; };

View File

@@ -6,7 +6,7 @@
#include "ChangeStrategyAction.h" #include "ChangeStrategyAction.h"
#include "Event.h" #include "Event.h"
#include "PlayerbotDbStore.h" #include "PlayerbotRepository.h"
#include "Playerbots.h" #include "Playerbots.h"
bool ChangeCombatStrategyAction::Execute(Event event) bool ChangeCombatStrategyAction::Execute(Event event)
@@ -24,7 +24,7 @@ bool ChangeCombatStrategyAction::Execute(Event event)
case '+': case '+':
case '-': case '-':
case '~': case '~':
sPlayerbotDbStore->Save(botAI); sPlayerbotRepository->Save(botAI);
break; break;
case '?': case '?':
break; break;
@@ -62,7 +62,7 @@ bool ChangeNonCombatStrategyAction::Execute(Event event)
case '+': case '+':
case '-': case '-':
case '~': case '~':
sPlayerbotDbStore->Save(botAI); sPlayerbotRepository->Save(botAI);
break; break;
case '?': case '?':
break; break;

Some files were not shown because too many files have changed in this diff Show More