X2CommunityCore / X2WOTCCommunityHighlander

https://steamcommunity.com/workshop/filedetails/?id=1134256495
MIT License
60 stars 68 forks source link

Updated OnUnitDied to properly kill gremlins when their owner dies #1362

Open BlackDog86 opened 1 month ago

BlackDog86 commented 1 month ago

Fixes #367

Tested under 4 standard conditions:

Gremlin attached to specialist 1 - Kill specialist 1 - Gremlin dies Gremlin attached to another unit - Kill other unit - Gremlin returns to specialist 1 Gremlin attached to another unit - Kill specialist 1 - Gremlin dies Gremlin attached to specialist 1 - Kill other unit - No effect

And 4 non-standard conditions:

Specialist 1 uses aid protocol on specialist 2 - Kill specialist 2 - Gremlin 1 returns to Specialist 1, Gremlin 2 dies Specialist 1 uses aid protocol on specialist 2 - Kill specialist 1 - Gremlin 1 dies, Gremlin 2 no effect Specialist 1 & 2 use aid protocol on each other - Kill both specialists at once - Both gremlins die Specialist 1 & 2 use aid protocol on 2 different units - Kill both units at once - Both gremlins return

BlackDog86 commented 1 month ago

Should be sorted

Iridar commented 19 hours ago

I've refactored the code, could you please redo your four tests with this code?

function EventListenerReturn OnUnitDied(Object EventData, Object EventSource, XComGameState GameState, Name Event, Object CallbackData)
{
    local XComGameStateHistory History;
    local XComGameState_Unit UnitState, CosmeticUnit;
    local XComGameState NewGameState;
    local XComGameState_Item ItemState;
    local vector NewLocation;
    local XComGameStateContext_ChangeContainer ChangeContext;

    // Variable for Issue #367
    local XComGameState_Unit OwnerUnitState;

    // Start Issue #367
    /// HL-Docs: ref:Bugfixes; issue:367
    /// Gremlins now correctly die when the Gremlin's owner dies while the Gremlin is attached to another unit.

    UnitState = XComGameState_Unit(EventData);
    if (UnitState == none)
        return ELR_NoInterrupt;

    if (UnitState.ObjectID == OwnerStateObject.ObjectID)
    {
        // Owner of the Gremlin died, kill the Gremlin.

        History = `XCOMHISTORY;
        CosmeticUnit = XComGameState_Unit(History.GetGameStateForObjectID(CosmeticUnitRef.ObjectID));

        if (CosmeticUnit != none)
        {
            NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Owner Unit Died");
            ChangeContext = XComGameStateContext_ChangeContainer(NewGameState.GetContext());
            ChangeContext.BuildVisualizationFn = ItemOwnerDeathVisualization;
            CosmeticUnit = XComGameState_Unit(NewGameState.ModifyStateObject(CosmeticUnit.Class, CosmeticUnit.ObjectID));
            CosmeticUnit.SetCurrentStat(eStat_HP, 0);
            `GAMERULES.SubmitGameState(NewGameState);
        }
    }
    else if (UnitState.ObjectID == AttachedUnitRef.ObjectID)
    {
        // Unit to whom the Gremlin is attached to has died, recall the Gremlin and re-attach to its owner.

        History = `XCOMHISTORY;
        CosmeticUnit = XComGameState_Unit(History.GetGameStateForObjectID(CosmeticUnitRef.ObjectID));
        OwnerUnitState = XComGameState_Unit(History.GetGameStateForObjectID(OwnerStateObject.ObjectID));

        if (OwnerUnitState != none && CosmeticUnit != none)
        {
            NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Attached Unit Died");
            ItemState = XComGameState_Item(NewGameState.ModifyStateObject(Class, ObjectID));
            ItemState.AttachedUnitRef = OwnerStateObject;
            `GAMERULES.SubmitGameState(NewGameState);

            if (CosmeticUnit.TileLocation != OwnerUnitState.TileLocation)
            {
                NewLocation = `XWORLD.GetPositionFromTileCoordinates(OwnerUnitState.TileLocation);
                XGUnit(CosmeticUnit.GetVisualizer()).MoveToLocation(NewLocation);
            }
        }
    }
    // End Issue #367

    return ELR_NoInterrupt;
}

The bug with the original code happened mostly because it was convoluted and hard to read. Bad code. I don't doubt that the code you submitted fixes the bug, but it's still hard to read, so I've simplified it as much as possible.