Jump to content

Seal Equip


Recommended Posts

I'm making a parasite monster that will latch to the player and it doesn't live long but is there a way to "seal" the equip, or prevent the player from unequipping the parasite until the player dies or the parasite does, whichever comes first?

I didn't see any functions like this in the components "armor", "equippable" or "inventory", so I'm assuming that a function will be needed to seal the inventory slot and another function to listen for "equipping" the parasite. Can I get some help?

Link to comment
Share on other sites

@DextersComicLaboratory

I took a look, and inventory handling is pretty spaghetti'd all over.

 

This is what I came up with that stops slurpers from getting removed:

local function HostAndParasiteAreAlive(host, parasite)
    return host and host.components.health and not host.components.health:IsDead() and parasite.components.health and not host.components.health:IsDead()
end
AddComponentPostInit(
    "inventory",
    function(inst)
        if not GLOBAL.TheWorld.ismastersim
        then
            return
        end
        local Unequip_old = inst.Unequip
        inst.Unequip = function(self, equipslot, slip, ...)
            if equipslot == GLOBAL.EQUIPSLOTS.HEAD
            then
                local current_head = self.equipslots[GLOBAL.EQUIPSLOTS.HEAD]
                if current_head and current_head.prefab == "slurper"
                then
                    if HostAndParasiteAreAlive(inst.inst, current_head)
                    then
                        return nil
                    end
                end
            end
            return Unequip_old(self, equipslot, slip, ...)
        end
        local Equip_old = inst.Equip
        inst.Equip = function(self, item, old_to_active, ...)
            if item and item.components.equippable and item.components.equippable.equipslot == GLOBAL.EQUIPSLOTS.HEAD
            then
                local current_head = self.equipslots[GLOBAL.EQUIPSLOTS.HEAD]
                if current_head and current_head.prefab == "slurper"
                then
                    if HostAndParasiteAreAlive(inst.inst, current_head)
                    then
                        return nil
                    end
                end
            end
            return Equip_old(self, item, old_to_active, ...)
        end
        local DropItem_old = inst.DropItem
        inst.DropItem = function(self, item, wholestack, randomdir, pos, ...)
            if item and item.prefab == "slurper"
            then
                if HostAndParasiteAreAlive(inst.inst, item)
                then
                    return nil
                end
            end
            return DropItem_old(self, item, wholestack, randomdir, pos, ...)
        end
    end
)

Note that this doesn't do anything to the client's end, and so you'll need to stop the client from predicting that they can manually put a hat in the inventory slot.

Right now it'll show for a bit that the hat was placed, then 'magically' reappear in the active item slot once the server and client resync.

 

Also note that if the slurper somehow magically loses all of its health, then the world will push that the thing died and won't fire the unequip callback, so the sounds remain.

You may need to do some special handling for 'killing' the parasite instead of relying on the health component.

Link to comment
Share on other sites

21 minutes ago, CarlZalph said:

@DextersComicLaboratory

I took a look, and inventory handling is pretty spaghetti'd all over.

 

This is what I came up with that stops slurpers from getting removed:


local function HostAndParasiteAreAlive(host, parasite)
    return host and host.components.health and not host.components.health:IsDead() and parasite.components.health and not host.components.health:IsDead()
end
AddComponentPostInit(
    "inventory",
    function(inst)
        if not GLOBAL.TheWorld.ismastersim
        then
            return
        end
        local Unequip_old = inst.Unequip
        inst.Unequip = function(self, equipslot, slip, ...)
            if equipslot == GLOBAL.EQUIPSLOTS.HEAD
            then
                local current_head = self.equipslots[GLOBAL.EQUIPSLOTS.HEAD]
                if current_head and current_head.prefab == "slurper"
                then
                    if HostAndParasiteAreAlive(inst.inst, current_head)
                    then
                        return nil
                    end
                end
            end
            return Unequip_old(self, equipslot, slip, ...)
        end
        local Equip_old = inst.Equip
        inst.Equip = function(self, item, old_to_active, ...)
            if item and item.components.equippable and item.components.equippable.equipslot == GLOBAL.EQUIPSLOTS.HEAD
            then
                local current_head = self.equipslots[GLOBAL.EQUIPSLOTS.HEAD]
                if current_head and current_head.prefab == "slurper"
                then
                    if HostAndParasiteAreAlive(inst.inst, current_head)
                    then
                        return nil
                    end
                end
            end
            return Equip_old(self, item, old_to_active, ...)
        end
        local DropItem_old = inst.DropItem
        inst.DropItem = function(self, item, wholestack, randomdir, pos, ...)
            if item and item.prefab == "slurper"
            then
                if HostAndParasiteAreAlive(inst.inst, item)
                then
                    return nil
                end
            end
            return DropItem_old(self, item, wholestack, randomdir, pos, ...)
        end
    end
)

Note that this doesn't do anything to the client's end, and so you'll need to stop the client from predicting that they can manually put a hat in the inventory slot.

Right now it'll show for a bit that the hat was placed, then 'magically' reappear in the active item slot once the server and client resync.

 

Also note that if the slurper somehow magically loses all of its health, then the world will push that the thing died and won't fire the unequip callback, so the sounds remain.

You may need to do some special handling for 'killing' the parasite instead of relying on the health component.

This is definitely an awesome code. Thing is right now if I use an item prefab (The player chooses to let this thing take their character), it'll dupe itself into the inventory and can't be dropped because said prefab is on their head. What should I do then?

Link to comment
Share on other sites

2 hours ago, DextersComicLaboratory said:

This is definitely an awesome code. Thing is right now if I use an item prefab (The player chooses to let this thing take their character), it'll dupe itself into the inventory and can't be dropped because said prefab is on their head. What should I do then?

AddComponentPostInit(
    "inventory",
    function(inst)
        if not GLOBAL.TheWorld.ismastersim
        then
            return
        end
        local function Check_1(slot, current_head)
            return slot == GLOBAL.EQUIPSLOTS.HEAD
        end
        local function Check_2(item, current_head)
            return item == current_head
        end
        local function Check_3(item, current_head)
            return item and item.components.equippable and item.components.equippable.equipslot == GLOBAL.EQUIPSLOTS.HEAD
        end
        local function Hook_This(checkfn, fn)
            local fn_old = inst[fn]
            inst[fn] = function(self, slotORitem, ...)
                local current_head = self.equipslots[GLOBAL.EQUIPSLOTS.HEAD]
                if current_head and current_head.prefab == "footballhat" and checkfn(slotORitem, current_head)
                then
                    local host = inst.inst
                    --local parasite = current_head
                    if (
                        host and host.components.health and not host.components.health:IsDead()
                        -- and parasite.components.health and not parasite.components.health:IsDead()
                    )
                    then
                        return nil
                    end
                end
                return fn_old(self, slotORitem, ...)
            end
        end
        Hook_This(Check_1, "SelectActiveItemFromEquipSlot")
        Hook_This(Check_1, "CombineActiveStackWithSlot")
        Hook_This(Check_1, "SelectActiveItemFromSlot")
        Hook_This(Check_1, "ReturnActiveItem")
        Hook_This(Check_1, "Unequip")
        
        Hook_This(Check_2, "DropItem")
        Hook_This(Check_2, "GiveActiveItem")
        Hook_This(Check_2, "GiveItem")
        Hook_This(Check_2, "RemoveItem")
        Hook_This(Check_2, "SetActiveItem")
        
        Hook_This(Check_3, "Equip")
    end
)

Same issue with that prediction thing with the mouse clickin' as before.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...