"""Exercise production spell conditions, resources, procs and stable solo choices.""" from pathlib import Path import subprocess,tempfile root=Path(__file__).resolve().parents[2] s=(root/'src/server/game/World/AdventureCombatMgr.cpp').read_text();a=s.index(' bool Allowed(');b=s.index('{',a);e=b+1;depth=1 while depth:depth+=(s[e]=='{')-(s[e]=='}');e+=1 method=s[a:e] code=r''' #include "AdventureRotationPolicy.h" #include #include using uint32=unsigned; constexpr unsigned CLASS_SHAMAN=7,POWER_HOLY_POWER=1; struct Aura{unsigned stacks=7,charges=7;unsigned GetStackAmount(){return stacks;}unsigned GetCharges(){return charges;}}aura; struct Unit{ std::setauras;float hp=100;bool casting=false; bool HasAura(unsigned id){return auras.count(id);}bool GetAuraApplicationOfRankedSpell(unsigned id,unsigned){return auras.count(id);} float GetHealthPct(){return hp;}bool HasUnitState(unsigned){return casting;} }; constexpr unsigned UNIT_STATE_CASTING=1; struct Player:Unit{ unsigned combo=0,holy=0,power=0,max=100,klass=1,spec=0; unsigned GetComboPoints(){return combo;}unsigned GetPower(unsigned type){return type==POWER_HOLY_POWER?holy:power;} unsigned GetPowerType(){return 2;}unsigned GetMaxPower(unsigned){return max;}unsigned getClass(){return klass;}unsigned GetGUID(){return 1;} Aura*GetAura(unsigned id){return HasAura(id)?&aura:nullptr;} }; unsigned GetPlayerSpec(Player*p){return p->spec;} struct Fighter{Player*me; '''+method+r''' }; int main(){ using namespace AdventureRotationPolicy;Player p;Unit target;Fighter fighter{&p}; for(unsigned klass:{1,2,3,4,5,6,7,8,9,11}){ std::setchoices;for(unsigned seed=0;seed<300;++seed){auto spec=SoloSpec(klass,seed);assert(spec==SoloSpec(klass,seed));choices.insert(spec);assert(!Damage(klass,spec).empty());} if(klass==2 || klass==5)assert(choices==std::set{2}); if(klass==1 || klass==4 || klass==7 || klass==8 || klass==11)assert((choices==std::set{0,1})); if(klass==3 || klass==6)assert((choices==std::set{1,2})); if(klass==9)assert((choices==std::set{0,1,2})); } assert(fighter.Allowed({45477,Condition::MissingAura,false,55095},&target));target.auras.insert(55095);assert(!fighter.Allowed({45477,Condition::MissingAura,false,55095},&target)); Action finisher{2098,Condition::Always,false,0,5};p.combo=4;assert(!fighter.Allowed(finisher,&target));p.combo=5;assert(fighter.Allowed(finisher,&target)); Action proc{11366,Condition::Always,false,0,0,48108};assert(!fighter.Allowed(proc,&target));p.auras.insert(48108);assert(fighter.Allowed(proc,&target)); assert(!fighter.Allowed({5308,Condition::Execute},&target));target.hp=20;assert(fighter.Allowed({5308,Condition::Execute},&target)); p.holy=2;assert(!fighter.Allowed({85256},&target));p.holy=3;assert(fighter.Allowed({85256},&target));p.holy=0;p.auras.insert(90174);assert(fighter.Allowed({85256},&target)); p.hp=34;assert(fighter.Allowed({871,Condition::Emergency,true},&p));p.hp=35;assert(!fighter.Allowed({871,Condition::Emergency,true},&p)); p.power=69;assert(!fighter.Allowed({78,Condition::Resource},&target));p.power=70;assert(fighter.Allowed({78,Condition::Resource},&target)); p.klass=7;p.spec=0;assert(!fighter.Allowed({8042},&target));p.auras.insert(324);assert(fighter.Allowed({8042},&target));aura.stacks=9;aura.charges=6;assert(!fighter.Allowed({8042},&target)); p.spec=1;p.auras.insert(53817);aura.stacks=4;assert(!fighter.Allowed({403},&target));aura.stacks=5;assert(fighter.Allowed({403},&target)); p.auras.insert(67483);assert(!fighter.Allowed({2912},&target));p.auras.erase(67483);assert(fighter.Allowed({2912},&target)); assert(Ranged(3,1) && Ranged(5,2) && !Ranged(1,2) && !Ranged(11,1)); for(unsigned klass:{2,5,7,11})for(float hp:{20.f,60.f,85.f})assert(!Healing(klass,klass==5?1:2,hp).empty()); } ''' 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('Production class rotations: persistent PvE solo pools, native rank aura IDs, combo/holy power/proc/execute/resource gates, Eclipse and healer coverage passed')