Jump to content

Recommended Posts

Hello good Users of the forum. I once again wish to ask People wiser than me for assistance. I hit another wall that i cannot break by bashing into it, nor i think it is possible to go around it with another solution.
I am currently trying to make custom action that allows to pick up frozen creatures that are normaly trapable by character with specific tag. Here is entire code for it that does not work so far.

 

AddAction("FROSTCOLLECT", "Collect", function(act)
    if act.target ~= nil and act.target.components.trappable ~= nil then
        -- Use trap code
        local prefab = act.target.components.trappable.product
        if prefab ~= nil then
            local item = GLOBAL.SpawnPrefab(prefab)
            if item ~= nil then
                if act.doer.components.inventory ~= nil then
                    act.doer.components.inventory:GiveItem(item, nil, act.doer:GetPosition())
                else
                    item.Transform:SetPosition(act.target.Transform:GetWorldPosition())
                end
                act.target:Remove()
                return true
            end
        end
    end
    return false
end)

    AddComponentAction("SCENE" ,"inventoryitem", function(inst, doer, actions, right)
        if not doer:HasTag("frozen_collect") then return end
        if inst:IsFrozen() and (inst:HasTag("canbetrapped") and not HasTag("inlimbo")) then
            table.insert(actions, GLOBAL.ACTIONS.FROSTCOLLECT)
        end
    end)
    
    AddStategraphActionHandler("wilson", GLOBAL.ActionHandler(GLOBAL.ACTIONS.FROSTCOLLECT, "dolongaction"))
    AddStategraphActionHandler("wilson_client", GLOBAL.ActionHandler(GLOBAL.ACTIONS.FROSTCOLLECT, "dolongaction"))


The component "inventoryitem" in the component section should allow to pick things like spiders that has their own inventory item, but disallow frogs for example (thought that might need explenation why not freezable)
Unfortunately for a reason unknown to me "IsFrozen()" returns a nil value wich crashes. (I only know this thanks to better crash screen mod)

If Anyone has any ideas, i am willing to test them

Thank Everyone in advance.

P.S. I am aware that spiders/birds can be picked in specific scenarios, however, i think it will be better to avoid PICKUP action becouse forcing their state to be pickable should conditions are met, might result in any Player of any character to be able to pick thoose should creature be frozen.

Edited by Klechu
3 hours ago, Klechu said:

AddComponentAction("SCENE" ,"inventoryitem", function(inst, doer, actions, right)
        if not doer:HasTag("frozen_collect") then return end
        if inst:IsFrozen() and (inst:HasTag("canbetrapped") and not HasTag("inlimbo")) then
            table.insert(actions, GLOBAL.ACTIONS.FROSTCOLLECT)
        end
    end)

There's no guarantee that the object you're marking can be frozen, which is why it returns null. Keep in mind that this code will run whenever you mark something that has the "inventoryitem" component. Therefore, you need to verify that what you want to grab has the "freezeable" component, which allows you to freeze things. This should be enough, but to make it more robust, you can also verify that it has the function you're looking for:

AddComponentAction("SCENE" ,"inventoryitem", function(inst, doer, actions, right)
    if doer and (not doer:HasTag("frozen_collect")) then return end
    if 
     	inst and -- inst exists
      	inst:HasTag("canbetrapped") and 
      	(not HasTag("inlimbo")) and
      	inst.components and -- has components
      	inst.components.freezable and -- Has freezable component
      	inst.components.freezable.IsFrozen() and -- Has IsFrozen() function
      	inst.components.freezable:IsFrozen() -- Check if is frozen
    then
      table.insert(actions, GLOBAL.ACTIONS.FROSTCOLLECT)
    end
  end)

The code may not look very elegant, but it's fine. When you use AND, if one of the conditions is false, the others will no longer be checked, since one false condition is enough to cause all ANDs to return false. This also happens with ORs: if one condition is true, the others will no longer be checked.

Now that I think about it, this code doesn't work on servers because the AddComponentAction function runs on the client, and I doubt the object has a freezeable component on the client. I think you'll have to modify the component to send an RPC to the client notifying them that the object is frozen so you can verify it.

Thank You for remarkably quick answer. As you suspected the code do not fully work, but It still does look way more promising than mine. Oddly tho it's the line that has "inlimbo" causes error now, and not one i would expect. In fact according to better crash screen HasTag manages to return a nil value... I'll work on it and thank You for the help.

You also mentioned that there is no guarantee that target migh have freezable component. That is correct, but as far as i'm aware everything that grass trap works on can be frozen, but not everything can be picked up from the trap as living creature. As i write this i rembered that there is living shadow heart that is trappable as well... Perhaps it might indeed be better if i switch it to freezable... This might even allow me to expand to netable creatures like bees.

This is a great idea. Many thanks to You. I will rewrite it.

Edited by Klechu
11 minutes ago, Klechu said:

Thank You for remarkably quick answer. As you suspected the code do not fully work, but It still does look way more promising than mine. Oddly tho it's the line that has "inlimbo" causes error now, and not one i would expect. In fact according to better crash screen HasTag manages to return a nil value... I'll work on it and thank You for the help.

Yeah, I don't know how I missed it, but HasTag isn't being applied to anything. The corrected code is:

AddComponentAction("SCENE" ,"inventoryitem", function(inst, doer, actions, right)
    if doer and (not doer:HasTag("frozen_collect")) then return end
    if 
     	inst and -- inst exists
      	inst:HasTag("canbetrapped") and 
      	(not inst:HasTag("inlimbo")) and
      	inst.components and -- has components
      	inst.components.freezable and -- Has freezable component
      	inst.components.freezable.IsFrozen() and -- Has IsFrozen() function
      	inst.components.freezable:IsFrozen() -- Check if is frozen
    then
      table.insert(actions, GLOBAL.ACTIONS.FROSTCOLLECT)
    end
  end)

Try it in an offline game without caves and it should work. Although, as I said, you'll need to make a few modifications to get your code working in multiplayer.

I have no more time to tinker today but thanks to You i have a code that seem to almost work.

AddComponentAction("SCENE" ,"freezable", function(inst, doer, actions, right)
    if doer and (not doer:HasTag("frozen_collect")) then return end
    if 
         inst and -- inst exists
          inst:HasTag("canbetrapped") and 
          not inst:HasTag("inlimbo") and
          inst.components and -- has components
          inst.components.inventoryitem and -- Has coreponding inventory item
          inst.components.freezable:IsFrozen() -- Check if is frozen
    then
      table.insert(actions, GLOBAL.ACTIONS.FROSTCOLLECT)
    end
  end)

What i mean almost work? Well if i rmb click spider it examines it like normal, however, when i freeze it, despite still prompting examine character just don't do that. In fact character does nothing at all, wich leads me to believe that this part of action DO work (please correct me if i'm wrog) and the problem lies in priority or the action itself.
Either way, it no longer crashes wich is far more than i managed myself.

Thank You again.

I see and You are probably right... I tested with the simplest possible action and unfortunately nothing has happend
AddAction("FROSTCOLLECT", "Collect", function(act)
        print("Hopefully test")
        return true
end)
Do You have any propositions?

Following Your advice, i indeed managed to get action to work as intended on the "call to it" so to speak. Now hopefully i will be able to limit its use on frozen creatures exclusively in the "work" part of action. My deepest thanks, this information prooved invaluable to me.

Try this:

-- modmain.lua
function freezetrue(inst)
  inst.isFreeze = true
end
function freezefalse(inst)
  inst.isFreeze = false
end
AddClientModRPCHandler("debugtools", "debugtoolsfreezetrue", freezetrue)
AddClientModRPCHandler("debugtools", "debugtoolsfreezefalse", freezefalse)
AddClassPostConstruct("components/freezable", function(inst)
    if inst and inst.Freeze then
      inst.OldFreeze = inst.Freeze
      inst.Freeze = function(self, freezetime)
        SendModRPCToClient(GetClientModRPC("debugtools", "debugtoolsfreezetrue"), nil, inst.inst)
        return self:OldFreeze(freezetime)
      end
    end
    if inst and inst.UnFreeze then
      inst.OldUnFreeze = inst.UnFreeze
      inst.UnFreeze = function(self, Unfreezetime)
        SendModRPCToClient(GetClientModRPC("debugtools", "debugtoolsfreezefalse"), nil, inst.inst)
        return self:OldUnFreeze(Unfreezetime)
      end
    end
  end)

AddComponentAction("SCENE" ,"freezable", function(inst, doer, actions, right)
    if doer and (not doer:HasTag("frozen_collect")) then return end
    if 
        inst and -- inst exists
        inst:HasTag("canbetrapped") and 
        not inst:HasTag("inlimbo") and
        inst.isFreeze -- Check if is freeze
    then
      table.insert(actions, ACTIONS.FROSTCOLLECT)
    end
end)

Just change the parts where it says "DebugTools" since that's the name of my mod where I test things.

Basically what the code does is override the Freeze and UnFreeze functions to add an RPC to the client so that, in the client, it adds an indicator to know if the creature is frozen or not.

Thank You for the code, i would use it, unfortunately it appears to be coliding with other functions of the character resulting in a crash. With a bit of luck i'll be able weave needed condtion into work part of action. Regardless of my convoluted code, i think Someone will eventuarly will find Your piece of code here ant it will end up doing their day. Cheers to that!

To Anyone finding that Who will want to do something similar here is the fully functional action. Please keep in mind that action is callable for even on unfrozen creatures, but only works with frozen ones since IsFrozen() limiter has to be in the work part of action, not call in part.

 

local Action = GLOBAL.Action
local ACTIONS = GLOBAL.ACTIONS

local FROSTCOLLECT = Action({priority = 5, distance = 1})

FROSTCOLLECT.str = "Collect"
FROSTCOLLECT.id = "FROSTCOLLECT"
FROSTCOLLECT.fn = function(act)
    local doer   = act.doer
    local target = act.target

    if target.components.freezable == nil or not target.components.freezable:IsFrozen() then
        return false
    end

    if target.components.inventoryitem ~= nil then
        doer.components.inventory:GiveItem(target, nil, doer:GetPosition())
    elseif target.components.trappable ~= nil and target.components.trappable.product ~= nil then
        local item = GLOBAL.SpawnPrefab(target.components.trappable.product)
        doer.components.inventory:GiveItem(item, nil, doer:GetPosition())
        target:Remove()
    end

    return true
end

AddAction(FROSTCOLLECT)

    AddComponentAction("SCENE" ,"inventoryitem", function(inst, doer, actions, right)
    if doer and (not doer:HasTag("frozen_collect")) then return end
    if 
         inst and -- inst exists
          inst:HasTag("canbetrapped") and 
          not inst:HasTag("inlimbo")
    then
      table.insert(actions, GLOBAL.ACTIONS.FROSTCOLLECT)
    end
  end)
    
    AddStategraphActionHandler("wilson", GLOBAL.ActionHandler(GLOBAL.ACTIONS.FROSTCOLLECT, "dolongaction"))
    AddStategraphActionHandler("wilson_client", GLOBAL.ActionHandler(GLOBAL.ACTIONS.FROSTCOLLECT, "dolongaction"))

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
×
  • Create New...