64 lines
3.2 KiB
Python
64 lines
3.2 KiB
Python
"""Exercise the actual free-slot branch used by Player::SetSkill."""
|
|
from pathlib import Path
|
|
import subprocess,tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
s=(root/'src/server/game/Entities/Player/Player.cpp').read_text()
|
|
a=s.index('uint16 skillSlot = PLAYER_MAX_SKILLS;',s.index('void Player::SetSkill('))
|
|
b=s.index(' if (skillEntry->CategoryID',a)
|
|
code=r'''
|
|
#include <array>
|
|
#include <cassert>
|
|
using uint16=unsigned short;using uint32=unsigned;
|
|
constexpr unsigned PLAYER_MAX_SKILLS=128,PLAYER_SKILL_LINEID_0=0;
|
|
#define TC_LOG_ERROR(...) ((void)0)
|
|
std::array<unsigned,128> fields;
|
|
unsigned GetUInt16Value(unsigned f,unsigned offset){return fields[2*f+offset];}
|
|
int selected=-1;
|
|
void add(){
|
|
'''+s[a:b]+r'''
|
|
selected=skillSlot;
|
|
}
|
|
int main(){fields.fill(1);fields[0]=0;add();assert(selected==0);
|
|
fields.fill(1);fields[127]=0;add();assert(selected==127);
|
|
fields.fill(1);selected=-1;add();assert(selected==-1);}
|
|
'''
|
|
with tempfile.TemporaryDirectory()as d:
|
|
p=Path(d);(p/'test.cpp').write_text(code)
|
|
subprocess.run(['c++','-std=c++17',str(p/'test.cpp'),'-o',str(p/'test')],check=True)
|
|
subprocess.run([str(p/'test')],check=True)
|
|
print('Native riding/profession allocation accepts slot zero and last slot, rejects a full skill array')
|
|
|
|
# Exercise recursive rewarded-spell learning on an initialized zero-rank placeholder.
|
|
a=s.index(' // update step',s.index('void Player::SetSkill('))
|
|
b=s.index(' // archaeology handling',a)
|
|
activation=r'''
|
|
#include <map>
|
|
#include <cassert>
|
|
using uint16=unsigned short;using uint32=unsigned;
|
|
enum {SKILL_UNCHANGED,SKILL_NEW,SKILL_CHANGED,SKILL_DELETED};
|
|
enum {SKILL_CATEGORY_PROFESSION=11,SKILL_RIDING=762,PLAYER_PROFESSION_SKILL_LINE_1=3,
|
|
ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL=4,ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL=5};
|
|
struct State {unsigned pos=0,uState=SKILL_UNCHANGED;};
|
|
struct Entry{unsigned CategoryID=0;} entry;
|
|
std::map<unsigned,State> states{{762,{}}};unsigned value=0;bool recursing=false;
|
|
void SetSkillStep(unsigned,unsigned){}void SetSkillRank(unsigned,unsigned v){value=v;}
|
|
void SetSkillMaxRank(unsigned,unsigned){}unsigned GetUInt32Value(unsigned){return 0;}
|
|
void SetUInt32Value(unsigned,unsigned){}void refreshSkillBonusAuras(){}
|
|
void UpdateSkillEnchantments(unsigned,unsigned,unsigned){}void UpdateMountCapability(){}
|
|
void UpdateAchievementCriteria(unsigned,unsigned){}
|
|
void activate(unsigned newVal);
|
|
void LearnSkillRewardedSpells(unsigned,unsigned v){if(!recursing){recursing=true;activate(v);recursing=false;}}
|
|
void activate(unsigned newVal){unsigned currVal=value,step=3,maxVal=225,id=762;
|
|
auto itr=states.find(id);auto skillEntry=&entry;
|
|
'''+s[a:b]+r'''
|
|
}
|
|
int main(){activate(225);assert(states[762].uState==SKILL_NEW);
|
|
states[762].uState=SKILL_UNCHANGED;activate(300);assert(states[762].uState==SKILL_CHANGED);
|
|
states[762].uState=SKILL_DELETED;value=0;activate(225);assert(states[762].uState==SKILL_CHANGED);}
|
|
'''
|
|
with tempfile.TemporaryDirectory() as d:
|
|
p=Path(d);(p/'activation.cpp').write_text(activation)
|
|
subprocess.run(['c++','-std=c++17',str(p/'activation.cpp'),'-o',str(p/'activation')],check=True)
|
|
subprocess.run([str(p/'activation')],check=True)
|
|
print('Native recursive skill activation preserves INSERT for new placeholders and UPDATE for saved skills')
|