Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
33 lines
3.8 KiB
Plaintext
33 lines
3.8 KiB
Plaintext
--- a/addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c
|
|
+++ b/addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c
|
|
@@ -238,6 +238,11 @@
|
|
if (m_State == 2)
|
|
{
|
|
if (!m_Removal || m_Removal.Result < 0) { Stop(); return; }
|
|
+ // Observed transfer ends our custody; a later nearby drop cannot restore it.
|
|
+ // Original inventory ownership may still settle after the native callback.
|
|
+ InventoryItemComponent item = InventoryItemComponent.Cast(m_Mine.FindComponent(InventoryItemComponent));
|
|
+ bool attached = m_Mine.GetParent() || (item && item.GetParentSlot());
|
|
+ if (attached && !ERR_InfantryAmmoTransfer.StoredUnder(m_Mine, m_Actor)) { Stop(); return; }
|
|
if (!m_Removal.Result || !Grounded()) return;
|
|
if (vector.DistanceXZ(m_Actor.GetOrigin(), m_Position) > 3) { Stop(); return; }
|
|
// A callback proves removal, not continued custody of a distant loose item.
|
|
--- a/tests/test_engineer_mine.py
|
|
+++ b/tests/test_engineer_mine.py
|
|
@@ -117,7 +117,14 @@
|
|
Fixture refused;refused.inventory.accepted=false;refused.Prepare();assert(refused.controller.Finished()&&refused.inventory.calls==1);refused.inventory.callback->OnComplete();refused.Drop();refused.controller.Tick(13000);assert(!refused.trigger.calls&&!refused.mine.moves);
|
|
Fixture failed;failed.Prepare();failed.inventory.callback->OnFailed();failed.inventory.callback->OnComplete();failed.Drop();failed.controller.Tick(12001);assert(failed.controller.Finished()&&failed.inventory.callback->Result==-1&&!failed.mine.moves);
|
|
// ACK alone cannot establish custody. A stolen item is never positioned/armed.
|
|
- Fixture stolen;stolen.Prepare();stolen.inventory.callback->OnComplete();stolen.mine.parent=&stolen.actor;stolen.Drop();stolen.controller.Tick(12001);assert(stolen.controller.m_State==2&&!stolen.mine.moves);stolen.controller.Tick(181000);assert(stolen.controller.Finished());
|
|
+ Fixture stolen;stolen.Prepare();stolen.inventory.callback->OnComplete();Entity thief;stolen.mine.parent=&thief;stolen.Drop();stolen.controller.Tick(12001);assert(stolen.controller.Finished()&&!stolen.mine.moves);stolen.controller.Tick(181000);assert(stolen.controller.Finished());
|
|
+ // Observed foreign custody is terminal even if the same exact item returns nearby.
|
|
+ // Exercise both an acknowledged removal and an accepted, still-pending removal.
|
|
+ for(int ack=0;ack<2;ack++)for(int slotOnly=0;slotOnly<2;slotOnly++){Fixture f;f.Prepare();f.Drop();Entity holder;if(slotOnly)f.item.slot=&holder;else f.mine.parent=&holder;f.mine.stored=true;f.mine.storageOwner=&holder;if(ack)f.inventory.callback->OnComplete();
|
|
+ f.controller.Tick(12001);assert(f.controller.Finished()&&!f.mine.moves&&!f.trigger.calls);
|
|
+ f.mine.parent=nullptr;f.Drop();f.inventory.callback->OnComplete();f.controller.Tick(12002);f.actor.position={0,0,0};f.controller.Tick(14000);assert(!f.mine.moves&&!f.trigger.calls&&f.inventory.calls==1);}
|
|
+ // Native ownership still attached to the original actor may settle normally.
|
|
+ Fixture settling;settling.Prepare();settling.inventory.callback->OnComplete();settling.controller.Tick(12001);assert(!settling.controller.Finished()&&!settling.mine.moves);settling.Drop();settling.controller.Tick(12002);assert(settling.controller.m_State==3&&settling.mine.moves==1);
|
|
// Cancellation retains callback and item tombstone and only completes own action.
|
|
Fixture stopped;stopped.Prepare();SCR_AIBehaviorBase unrelated;stopped.utility.actions.Insert(&unrelated);auto owned=stopped.controller.m_Action;stopped.controller.Stop();stopped.controller.Stop();stopped.Drop();stopped.inventory.callback->OnComplete();stopped.controller.Tick(13000);assert(owned->completed==1&&!unrelated.completed&&!stopped.mine.moves&&!stopped.trigger.calls&&stopped.attempted.Contains(&stopped.mine));
|
|
// Original identity changes abort before irreversible work, including replacement
|