Files
Viano-Core/tests/clientless/test_adventure_talent_templates.py
T
Nico a758239da9
clang PCH / build (push) Canceled after 0s
GCC PCH / build (push) Canceled after 0s
Implement AdventureBot class rotations, group roles and instance encounters
2026-10-28 22:37:18 +01:00

47 lines
2.6 KiB
Python

"""Exercise real PvE templates against 4.3.4 DBC rank, tree and dependency gates."""
from pathlib import Path
import json,subprocess,tempfile
root=Path(__file__).resolve().parents[2]
data=json.loads((Path(__file__).parent/'fixtures/cata_pve_talents.json').read_text())
rows=','.join('{'+k+',{'+','.join(map(str,v))+'}}' for k,v in data['talents'].items())
tabs=','.join('{'+k+',{'+','.join(map(str,v))+'}}' for k,v in data['tabs'].items())
code=r'''
#include "AdventureTalentPolicy.h"
#include "AdventureRotationPolicy.h"
#include <map>
#include <cassert>
struct Talent{unsigned tab,tier,ranks,dependency,dependencyRank;};
struct Tab{unsigned mask,order;};
std::map<unsigned,Talent> talents={ROWS};std::map<unsigned,Tab> tabs={TABS};
int main(){
for(unsigned klass:{1,2,3,4,5,6,7,8,9,11})for(unsigned spec=0;spec<3;++spec)for(bool tank:{false,true}){
auto build=AdventureTalentPolicy::Build(klass,spec,tank);if(build.empty())continue;
unsigned primary=0;for(auto const& t:tabs)if(t.second.mask==(1u<<(klass-1)) && t.second.order==spec)primary=t.first;
assert(primary);unsigned total=0;
for(auto t:build){assert(talents.count(t.Id));auto d=talents.at(t.Id);assert(t.Ranks<=d.ranks);assert(tabs.at(d.tab).mask==(1u<<(klass-1)));total+=t.Ranks;}
assert(total==41);
for(unsigned budget=1;budget<=41;++budget){
std::map<unsigned,unsigned> known;unsigned left=budget;
auto learn=[&](unsigned id,unsigned rank){
auto d=talents.at(id);if(known[id]>rank || rank>=d.ranks)return false;
auto cost=rank+1-known[id];if(cost>left)return false;
if(d.dependency && known[d.dependency]<=d.dependencyRank)return false;
unsigned spent=0,main=0;for(auto p:known){if(talents.at(p.first).tab==d.tab)spent+=p.second;if(talents.at(p.first).tab==primary)main+=p.second;}
if(spent<d.tier*5 || (d.tab!=primary && main<31))return false;
known[id]=rank+1;left-=cost;return true;
};
assert(AdventureTalentPolicy::Spend(build,learn,[&]{return left;}));assert(!left);
if(budget==41)for(auto t:build)assert(known[t.Id]==t.Ranks);
}
}
for(unsigned klass:{1,2,3,4,5,6,7,8,9,11})for(unsigned seed=0;seed<100;++seed){
auto spec=AdventureRotationPolicy::SoloSpec(klass,seed);assert(!AdventureTalentPolicy::Build(klass,spec).empty());
}
}
'''.replace('ROWS',rows).replace('TABS',tabs)
with tempfile.TemporaryDirectory() as d:
p=Path(d);(p/'test.cpp').write_text(code)
subprocess.run(['g++','-std=c++17','-I',str(root/'src/server/game/World'),str(p/'test.cpp'),'-o',str(p/'test')],check=True)
subprocess.run([str(p/'test')],check=True)
print('Canonical Cata PvE builds: 4.3.4 class/tree/rank/prerequisite gates, all 1..41 point budgets, solo selection coverage passed')