Files
Viano-Core/tests/clientless/test_empty_spell_effect.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

46 lines
2.8 KiB
Python

"""Lock and Load correction clears effect 2: never scale an empty effect."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
h=(root/'src/server/game/Spells/SpellInfo.h').read_text()
a=h.index(' SpellEffectInfo() :');b=h.index('{ }',a)+3;constructor=h[a:b]
s=(root/'src/server/game/Spells/Spell.cpp').read_text();a=s.index('SpellValue::SpellValue(');b=s.index('{',a);e=b+1;depth=1
while depth:depth+=(s[e]=='{')-(s[e]=='}');e+=1
code=r'''
#include <cassert>
#include <cstring>
#include <new>
using uint32=unsigned;constexpr int MAX_SPELL_EFFECTS=3,MECHANIC_NONE=0;
struct WorldObject{};
struct SpellEffectInfo{
void const*_spellInfo;unsigned _effIndex,Effect,ApplyAuraName,AuraPeriod,DieSides;
float RealPointsPerLevel,BasePoints,PointsPerComboPoint,Amplitude,DamageMultiplier,BonusMultiplier;
int MiscValue,MiscValueB,Mechanic;void const*TargetARadiusEntry;void const*TargetBRadiusEntry;
unsigned ChainTarget,ItemType,TriggerSpell;void*ImplicitTargetConditions;
struct{float Coefficient,Variance,ComboPointsCoefficient;}Scaling;
'''+constructor+r'''
bool IsEffect()const{return Effect!=0;}
int CalcBaseValue(WorldObject const*,void const*)const{assert(_spellInfo && IsEffect());return int(BasePoints);}
};
struct SpellInfo{SpellEffectInfo Effects[3];unsigned MaxAffectedTargets=0;};
struct SpellValue{int EffectBasePoints[3];unsigned CustomBasePointsMask,MaxAffectedTargets;float RadiusMod,AuraStackAmount,CriticalChance;SpellValue(SpellInfo const*,WorldObject const*);};
'''+s[a:e]+r'''
int main(){
alignas(SpellEffectInfo) unsigned char memory[sizeof(SpellEffectInfo)];memset(memory,0xA5,sizeof(memory));
auto empty=new(memory)SpellEffectInfo;
assert(!empty->_spellInfo && !empty->Effect && empty->Scaling.Coefficient==0 && empty->Scaling.Variance==0 && empty->Scaling.ComboPointsCoefficient==0);
SpellInfo spell;spell.Effects[0]._spellInfo=&spell;spell.Effects[0].Effect=1;spell.Effects[0].BasePoints=7;
spell.Effects[1]._spellInfo=&spell;spell.Effects[1].Effect=2;spell.Effects[1].BasePoints=12;
// Exact state produced by the 56342 native correction.
spell.Effects[2]=SpellEffectInfo();SpellValue value(&spell,nullptr);
assert(value.EffectBasePoints[0]==7 && value.EffectBasePoints[1]==12 && value.EffectBasePoints[2]==0);
spell.Effects[0]=SpellEffectInfo();spell.Effects[1]=SpellEffectInfo();SpellValue allEmpty(&spell,nullptr);
for(auto points:allEmpty.EffectBasePoints)assert(points==0);
}
'''
with tempfile.TemporaryDirectory() as d:
p=Path(d);(p/'test.cpp').write_text(code)
subprocess.run(['g++','-std=c++17',str(p/'test.cpp'),'-o',str(p/'test')],check=True)
subprocess.run([str(p/'test')],check=True)
print('Native empty spell effects: poisoned-memory scaling initialization, Lock and Load cleared slot, active effect values and all-empty spell values passed')