59 lines
4.2 KiB
Python
59 lines
4.2 KiB
Python
"""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 <cassert>
|
|
#include <set>
|
|
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::set<unsigned>auras;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::set<unsigned>choices;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<unsigned>{2});
|
|
if(klass==1 || klass==4 || klass==7 || klass==8 || klass==11)assert((choices==std::set<unsigned>{0,1}));
|
|
if(klass==3 || klass==6)assert((choices==std::set<unsigned>{1,2}));
|
|
if(klass==9)assert((choices==std::set<unsigned>{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')
|