Implement AdventureBot profiles, daily planning and population management
clang PCH / build (push) Canceled after 0s
GCC PCH / build (push) Canceled after 0s

This commit is contained in:
Nico committed 2026-10-28 18:22:13 +01:00
1 parent d6fea6ee68
commit d3273c677e
61 files changed
+2280 -116

No files matched your search

+58 -2
View File
@@ -8,6 +8,7 @@
#include "AdventureInteractionMgr.h"
#include "AdventureGroupMgr.h"
#include "AdventureGeneratorMgr.h"
#include "AdventurePopulationMgr.h"
#include "AdventureSupplyMgr.h"
#include "AdventureSocialActions.h"
#include "Config.h"
@@ -16,6 +17,7 @@
#include "Random.h"
#include <lua.hpp>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <filesystem>
@@ -201,7 +203,7 @@ std::vector<ClientlessWeightedMount> ReadMountDictionary(lua_State* L, int movem
{
lua_Integer id = lua_tointeger(L, -2);
lua_Number weight = lua_tonumber(L, -1);
if (id > 0 && id <= 0xFFFFFFFFll && weight > 0.0)
if (id > 0 && id <= 0xFFFFFFFFll && std::isfinite(weight) && weight > 0.0 && weight <= 1000000.0)
mounts.push_back({ uint32(id), uint32(std::max<lua_Number>(1.0, weight)) });
}
lua_pop(L, 1);
@@ -220,11 +222,13 @@ public:
sClientlessLuaEngine->ExecuteAdventureScript(player);
sAdventureBehaviorMgr->Online(player);
sAdventureSupplyMgr->Online(player);
sAdventurePopulationMgr->Online(player);
}
void OnIntentChanged(Player* player, ClientlessIntent const* intent) override
{ sAdventureBehaviorMgr->IntentChanged(player, intent); }
void Update(Player* player, uint32 diff) override
{
sAdventurePopulationMgr->Maintain(player,diff);
if(sAdventureSupplyMgr->Update(player,diff,sAdventureCombatMgr->Busy(player)))return;
if(!sAdventureCombatMgr->Update(player,diff) && !sAdventureInteractionMgr->Update(player,diff))
sAdventureBehaviorMgr->Update(player,diff);
@@ -238,7 +242,7 @@ public:
void OnDamageTaken(Player* player, Unit* attacker, uint32 damage) override
{ sAdventureCombatMgr->DamageTaken(player, attacker, damage); }
void OnPlayerLogout(Player* player) override
{ sAdventureInteractionMgr->Offline(player); sAdventureSupplyMgr->Offline(player); sAdventureCombatMgr->Offline(player); sAdventureBehaviorMgr->Offline(player); }
{ sAdventurePopulationMgr->Offline(player); sAdventureInteractionMgr->Offline(player); sAdventureSupplyMgr->Offline(player); sAdventureCombatMgr->Offline(player); sAdventureBehaviorMgr->Offline(player); }
};
}
@@ -394,6 +398,19 @@ bool ClientlessLuaEngine::LoadAdventureProfile(Player* player)
profile.HomeRegion = ReadStringField(_state, -1, "home_region");
profile.Background = ReadStringField(_state, -1, "background");
profile.Vocation = ReadStringField(_state, -1, "vocation");
profile.ProfileVersion = uint32(std::clamp(ReadFloatField(_state,-1,"profile_version",0),0.0f,100.0f));
profile.Level = uint32(std::clamp(ReadFloatField(_state,-1,"level",0),0.0f,85.0f));
profile.Class = uint32(std::clamp(ReadFloatField(_state,-1,"class",0),0.0f,11.0f));
profile.Specialization = uint32(std::clamp(ReadFloatField(_state,-1,"specialization",0),0.0f,2.0f));
lua_getfield(_state,-1,"seed");
if(lua_isinteger(_state,-1)){auto value=lua_tointeger(_state,-1);if(value>=0 && value<=0xFFFFFFFFll)profile.Seed=uint32(value);}
lua_pop(_state,1);
profile.Role = ReadStringField(_state,-1,"role","damage");
if(profile.Role!="tank" && profile.Role!="healer" && profile.Role!="damage")profile.Role="damage";
profile.HomeZone = uint32(std::max(0.0f,ReadFloatField(_state,-1,"home_zone",0)));
profile.HomeCapital = uint32(std::max(0.0f,ReadFloatField(_state,-1,"home_capital",0)));
profile.FavoriteZone = uint32(std::max(0.0f,ReadFloatField(_state,-1,"favorite_zone",0)));
profile.FavoriteRegion = ReadStringField(_state,-1,"favorite_region");
}
lua_pop(_state, 1);
@@ -408,11 +425,38 @@ bool ClientlessLuaEngine::LoadAdventureProfile(Player* player)
profile.GroundMounts = ReadMountDictionary(_state, -1);
profile.CanFreeFly = ReadBoolField(_state, -1, "can_free_fly", false);
profile.FlightMounts = ReadMountDictionary(_state, -1, "flight_mounts");
profile.Companions = ReadMountDictionary(_state,-1,"companions");
profile.CompanionSpell = uint32(std::max(0.0f, ReadFloatField(_state, -1, "companion_spell", 0)));
profile.CompanionLeashItem = uint32(std::max(0.0f, ReadFloatField(_state, -1, "companion_leash_item", 0)));
}
lua_pop(_state, 1);
lua_getfield(_state,rootTable,"inventory");
if(lua_istable(_state,-1))
{
lua_getfield(_state,-1,"keep_items");
if(lua_istable(_state,-1))for(size_t i=1;i<=lua_rawlen(_state,-1);++i)
{
lua_rawgeti(_state,-1,i);auto id=lua_tointeger(_state,-1);
if(id>0 && id<=0xFFFFFFFFll)profile.KeepItems.insert(uint32(id));
lua_pop(_state,1);
}
lua_pop(_state,1);
}
lua_pop(_state,1);
lua_getfield(_state,rootTable,"zone_affinity");
if(lua_istable(_state,-1))
{
lua_pushnil(_state);
while(lua_next(_state,-2))
{
auto id=lua_tointeger(_state,-2);auto weight=lua_tonumber(_state,-1);
if(lua_isinteger(_state,-2) && lua_isnumber(_state,-1) && id>0 && id<=0xFFFFFFFFll && std::isfinite(weight))
profile.ZoneAffinity[uint32(id)]=float(std::clamp(weight,0.0,100.0));
lua_pop(_state,1);
}
}
lua_pop(_state,1);
profile.Personality = ReadFloatDictionary(_state, rootTable, "personality");
profile.RegionAffinity = ReadFloatDictionary(_state, rootTable, "region_affinity");
profile.ActivityAffinity = ReadFloatDictionary(_state, rootTable, "activity_affinity");
@@ -501,6 +545,18 @@ uint32 ClientlessLuaEngine::SelectGroundMountDisplayId(uint32 characterGuid) con
return profile->GroundMounts.back().DisplayId;
}
uint32 ClientlessLuaEngine::SelectCompanionSpell(uint32 guid) const
{
auto profile=GetAdventureProfile(guid);
if(!profile)return 0;
uint32 total=0;
for(auto const& pet:profile->Companions)total+=pet.Weight;
if(!total)return profile->CompanionSpell;
auto roll=urand(1,total);
for(auto const& pet:profile->Companions){if(roll<=pet.Weight)return pet.DisplayId;roll-=pet.Weight;}
return 0;
}
bool ClientlessLuaEngine::PrepareGroundMount(Player* player, float travelDistance, char const* context)
{
if (!player || !player->IsInWorld())