Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
56 lines
5.4 KiB
Python
56 lines
5.4 KiB
Python
from pathlib import Path
|
|
import hashlib,json,subprocess
|
|
P=Path('/tmp/erri-launcher-resupply-1140');R=Path('/home/jakub/devel/escapistsrereintroduced');D=P/'addons/core/Scripts/Game/ERR/10_AI';rel='addons/core/Scripts/Game/ERR/10_AI/ERR_HQAmmoSampler.c';s=(R/rel).read_text();(P/'baseline'/rel).write_text(s)
|
|
b=json.loads((P/'baseline.json').read_text());b[rel]={'working_sha256':hashlib.sha256((R/rel).read_bytes()).hexdigest(),'index_sha256':hashlib.sha256(subprocess.check_output(['git','show',':'+rel],cwd=R)).hexdigest()};(P/'baseline.json').write_text(json.dumps(b,indent=2)+'\n')
|
|
s=s.replace(' int LauncherRounds;',' int LauncherMuzzles;\n int LauncherRounds;').replace('copy.LauncherRounds = LauncherRounds;', 'copy.LauncherMuzzles = LauncherMuzzles; copy.LauncherRounds = LauncherRounds;')
|
|
s=s.replace(' if (LauncherRounds < 0', ' if (LauncherMuzzles < 0 || LauncherMuzzles > Members * 32) return false;\n if (LauncherRounds < 0')
|
|
s=s.replace('else launchers.Insert(muzzle);', '''else
|
|
{
|
|
launchers.Insert(muzzle);
|
|
if (muzzle.GetMagazineWell() && !muzzle.IsDisposable()) result.LauncherMuzzles++;
|
|
else result.LauncherComplete = false;
|
|
}''');(P/rel).write_text(s)
|
|
p=D/'ERR_InfantryResupply.c';s=p.read_text().replace('A zero aggregate without a supported physical magazine is not launcher evidence.', 'Only positively sampled reloadable magazine-well muzzles establish launcher demand.')
|
|
s=s.replace('entry.AmmoState.LauncherMagazines > 0','entry.AmmoState.LauncherMuzzles > 0').replace('local.LauncherMagazines <= 0','local.LauncherMuzzles <= 0');p.write_text(s)
|
|
p=D/'ERR_InfantryAmmoTransfer.c';s=p.read_text();s=s.replace(''' // Projectile-only/disposable and entirely missing magazine configurations
|
|
// are outside this finite magazine slice; never synthesize a projectile.
|
|
BaseMagazineComponent loaded = muzzle.GetMagazine();
|
|
if (!loaded || !loaded.GetOwner() || !loaded.GetMagazineWell() || loaded.GetMaxAmmoCount() <= 0) continue;
|
|
InventoryItemComponent loadedItem = InventoryItemComponent.Cast(loaded.GetOwner().FindComponent(InventoryItemComponent));
|
|
if (!loadedItem || !loadedItem.GetParentSlot()) continue;
|
|
InventoryStorageSlot loadedSlot = loadedItem.GetParentSlot();
|
|
if (loadedSlot.GetParentContainer() != muzzle || loadedSlot.GetAttachedEntity() != loaded.GetOwner()) continue;
|
|
if (loaded.GetMagazineWell().Type() != muzzle.GetMagazineWell().Type()) continue;''', ''' // An expended single-round item may no longer exist. The real reloadable
|
|
// muzzle/well proves capability; existing loaded items need exact custody.
|
|
if (muzzle.IsDisposable()) continue;
|
|
BaseMagazineComponent loaded = muzzle.GetMagazine();
|
|
if (loaded)
|
|
{
|
|
if (!loaded.GetOwner() || !loaded.GetMagazineWell() || loaded.GetMaxAmmoCount() <= 0) continue;
|
|
InventoryItemComponent loadedItem = InventoryItemComponent.Cast(loaded.GetOwner().FindComponent(InventoryItemComponent));
|
|
if (!loadedItem || !loadedItem.GetParentSlot()) continue;
|
|
InventoryStorageSlot loadedSlot = loadedItem.GetParentSlot();
|
|
if (loadedSlot.GetParentContainer() != muzzle || loadedSlot.GetAttachedEntity() != loaded.GetOwner()) continue;
|
|
if (loaded.GetMagazineWell().Type() != muzzle.GetMagazineWell().Type()) continue;
|
|
}''');p.write_text(s)
|
|
for name in ('test_infantry_ammo_transfer.py','test_infantry_resupply_planning.py'):
|
|
p=P/'tests'/name;s=p.read_text().replace('LauncherMagazines=1,','LauncherMuzzles=1,LauncherMagazines=1,')
|
|
if name=='test_infantry_ammo_transfer.py':
|
|
s=s.replace('struct Muzzle{Magazine*', 'struct Muzzle{bool disposable=false;bool IsDisposable(){return disposable;}Magazine*')
|
|
s=s.replace('if(bad==2)f.muzzle.loaded=nullptr;', 'if(bad==2)f.muzzle.disposable=true;')
|
|
s=s.replace('int main(){', '''int main(){
|
|
{LauncherFixture f;f.muzzle.loaded=nullptr;assert(ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity,true));f.c.Transfer(0);assert(f.source.calls==1&&f.c.m_Move->Submitted());}
|
|
''',1)
|
|
else:s=s.replace('if(bad==1)f.ammo.LauncherMagazines=0;', 'if(bad==1)f.ammo.LauncherMuzzles=0;').replace('f.ammo.SmallArmsRounds=999;assert(!f.Plan());', 'f.ammo.SmallArmsRounds=999;f.ammo.LauncherMagazines=0;assert(!f.Plan());')
|
|
p.write_text(s)
|
|
name='test_hq_ammo_sampler.py';s=(R/'tests'/name).read_text();(P/'baseline/tests'/name).write_text(s)
|
|
s=s.replace('struct Muzzle{Well*', 'struct Muzzle{bool disposable=false;bool IsDisposable(){return disposable;}Well*')
|
|
s=s.replace('assert(mixed.LauncherMagazines==1&&mixed.KnownSmallArmsEmpty());', '''assert(mixed.LauncherMagazines==1&&mixed.LauncherMuzzles==1&&mixed.KnownSmallArmsEmpty());
|
|
auto launcherWire=mixed.Snapshot();mixed.LauncherMuzzles=0;assert(launcherWire->LauncherMuzzles==1);
|
|
launcher.magazine=nullptr;inv.items.clear();auto expended=Fresh();ERR_HQAmmoSampler::Inspect(&actor,&group,&expended);
|
|
assert(expended.LauncherComplete&&expended.LauncherMuzzles==1&&expended.LauncherRounds==0&&expended.LauncherMagazines==0);
|
|
launcher.disposable=true;auto disposable=Fresh();ERR_HQAmmoSampler::Inspect(&actor,&group,&disposable);assert(!disposable.LauncherComplete&&disposable.LauncherMuzzles==0);launcher.disposable=false;
|
|
launcher.magazine=&unrelated;inv.items={&loadedEntity,&spareEntity,&unrelatedEntity};''')
|
|
# names above depend on existing exact fixture names; use original variable spelling.
|
|
print([l for l in s.splitlines() if 'Entity actor' in l or 'Entity loaded' in l]);(P/'tests'/name).write_text(s)
|