Jump to content

Way to disable all actions except moving?


Recommended Posts

Hello, if someone can help me with this that'd be great :)!

So, I'd like to know if there's a way I can disable the player from preforming any actions like attacking, picking up items, ect.. & all they can do is move around? Basically like how the player ghost acts? Is there someway to disable all player actions except locomoting?

Thanks for reading my question, have a good day/night :D!

Link to comment
Share on other sites

@IronHunter Thanks!! I looked through woodie.lua & now I know how disable actions with

Spoiler

local function Nothing(inst)
end

local function RemovePlayerActions(inst, enable)
    if enable then
        if inst.components.playercontroller ~= nil then
            inst.components.playercontroller.actionbuttonoverride = Nothing
        end
        if inst.components.playeractionpicker ~= nil then
            inst.components.playeractionpicker.leftclickoverride = Nothing
            inst.components.playeractionpicker.rightclickoverride = Nothing
        end
    else
        if inst.components.playercontroller ~= nil then
            inst.components.playercontroller.actionbuttonoverride = nil
        end
        if inst.components.playeractionpicker ~= nil then
            inst.components.playeractionpicker.leftclickoverride = nil
            inst.components.playeractionpicker.rightclickoverride = nil
        end
    end
end

 

Now the only problems left is my character can still force_attack & I looked through playercontroller.lua & woodie.lua & couldn't find out how to stop that from working :confused:.. I found these but they seem to have nothing to do with force_attack since he still would do force attack even when I disable them

inst.components.playercontroller.controller_attack_override = nil
inst.components.playercontroller.attack_buffer = nil
inst.components.playercontroller.force_target = nil

 

Also, does someone know if there's a code that checks if the character's picking or wants to pick up/harvest something? Then I can make my action not work if the player is trying to pickup an item since my character gets glitchy cause he tries to do both actions at the same time..

And thanks for your help :wilson_flower:!! 

Edited by SuperDavid
Link to comment
Share on other sites

2 hours ago, ZupaleX said:

For the force attack you might find what you want in playercontroller component.

I already looked through there & couldn't find any attackoverride thing.

2 hours ago, ZupaleX said:

For the second point I am not sure I understand. 

I want to know if there's some code like "inst:WantsToPickupItem()" then I can put a if check for my jump action to not happen if the character is trying to pickup or walking towards an item to pick it up.

Link to comment
Share on other sites

Well it's not a real, real action..it's just a action that plays a state when you press a key since I don't know how to add real, real actions :wilson_dorky:.. & it's in modmain.lua

Spoiler

local function jump(act)
	if act.target.gelid_mode == true or act.target.heavy_armor == true then return end
	if act.target.jump == nil and not act.target.sg:HasStateTag("busy") and not act.target.components.rider:IsRiding() then
		if act.target.components.locomotor:WantsToMoveForward() then
			act.target.sg:GoToState("run_jump")
		elseif not act.target.components.locomotor:WantsToMoveForward() and act.target:IsOnValidGround() then
			act.target.sg:GoToState("jump")
		end
	end
end

 

Edited by SuperDavid
Link to comment
Share on other sites

The issue that you have is that you need to define your jump as an action so the game can actually prioritize them.

You can find example on how to do that in various mods. Again, I am not advertising my mod, but you can see a working example in my "Archery Mod" on the workshop, which add several custom actions. You can find other mods doing it but I don't know them.

It has not been updated in a while though so it is using a deprecated function to add ACTION but it is still working and the new way is almost exactly the same (save for one line). If you decide to take a look into the code and have questions let me know. If you would rather get help step by step to do it without an example, I guess we can work something out as well, it will just take more time probably.

Edited by ZupaleX
Link to comment
Share on other sites

Okay, so I do something like this.. is this correct way? I have no idea what I'm doing really xD...

jump_action.priority = 10

local function jump(act)
	local JUMPACTION = ACTIONS.JUMP
	actions = act.target:SortActionList({JUMPACTION})
	return actions
end

local jump_action = AddAction("JUMP", "Jump", function(act)
	if act.target.gelid_mode == true or act.target.heavy_armor == true then return end
	if act.target.jump == nil and not act.target.sg:HasStateTag("busy") and not act.target.components.rider:IsRiding() then
		if act.target.components.locomotor:WantsToMoveForward() then
			act.target.sg:GoToState("run_jump")
		elseif not act.target.components.locomotor:WantsToMoveForward() and act.target:IsOnValidGround() then
			act.target.sg:GoToState("jump")
		end
	end
end)

local JUMP = GLOBAL.Action()
JUMP.str = "Jump"
JUMP.id = "JUMP"
JUMP.fn = function(act)
	jump(act)
end
AddAction(JUMP)

 

Edited by SuperDavid
Link to comment
Share on other sites

1 minute ago, ZupaleX said:

Not quite, you need to define the action before adding it.

Look at the items GLOBAL.Action(...)

I don't really know what that mean by this cause I'm dumb, sorry xD!

 

From your modmain.lua I see this action

local ARMCROSSBOW = GLOBAL.Action(	5,		-- priority
									nil,	-- instant (set to not instant)
									true,	-- right mouse button
									nil,	-- distance check
									nil,	-- ghost valid (set to not ghost valid)
									nil,	-- ghost exclusive
									nil,	-- can force action
									nil)	-- Range check function

And you say my action need priority to not be able to preform other action while doing it, right?

So, in my action I see it's similar to your archery action thing, so I put 10 priority which's more than yours but my character still can do other actions while in jump(act) :confused:!

local JUMP = GLOBAL.Action(10)
JUMP.str = "Jump"
JUMP.id = "JUMP"
JUMP.fn = function(act)
	jump(act)
end
AddAction(JUMP)

 

Did I do something wrong? And thanks for your help :)!

Link to comment
Share on other sites

Okay, I found this in your archery modmain.lua

AddComponentAction("USEITEM", "zupalexsrangedweapons", bow_attack_useitem)

But I have no idea what to do with it? I'm guessing the first thing I put my JUMP action?

local JUMP = GLOBAL.Action(10)
JUMP.str = "Jump"
JUMP.id = "JUMP"
JUMP.fn = function(act)
	jump(act)
end
AddAction(JUMP)
AddComponentAction("JUMP", "zupalexsrangedweapons", bow_attack_useitem)

I don't know what the other 2 things mean though :confused:

 

EDIT: Okay, I think the last one is the name of the function you're doing? So I would just put my "jump"(act) function, but I have no idea what the middle one is & thanks for your help man :D!!

Edited by SuperDavid
Link to comment
Share on other sites

So you have several types of predefined Component Actions:

SCENE: clicking on something on the screen while not having any active item

USEITEM: clicking on something else on the surounding area with an object "in hand" (active item, appearing under your cursor)

POINT: same as USEITEM but clicking on anywhere on the screen (like when you use the blinkstaff)

EQUIPPED: if the item is equipped

INVENTORY: right clicking it in your inventory

Each of these types apply in specific situations when you want to use an item.

AddComponentAction takes several arguments. The first one is which type of action you want to deal with and must belong to the list above.

Second argument is which component you want to attach this new action.

Third is a function saying which specific action you want to have as a choice and under which circumstances.

Try to read again that part in my modmain and see if it makes more sense.

 

Now you want to be able to jump while you use a special item or it's just that your character is supposed to be able to jump by default?

Link to comment
Share on other sites

I was hoping to make the character jump when I press spacebar since that's how it's like for most games. Which's also why it conflicts with picking up items so much xD..

Also, what if I don't have any component related to this jump action? Can I just put it "nil" or do I have to make a component?

Link to comment
Share on other sites

If it is not linked to a item but to the player locomotor and playeractionpicker component. It is not so trivial anymore but doable.

@SuperDavid: so I looked a bit more into it because it's not something I've really done before (I worked with custom actions but always linked to an item).

This will be in playeractionpicker.lua and playercontroller.lua

You have in playeractionpicker.lua a function which is called each "tick" (each time the game refresh everything) to sort through the possible actions and pick the one which has the highest priority.

Spoiler

function PlayerActionPicker:GetLeftClickActions(position, target)
    if self.leftclickoverride ~= nil then
        local actions, usedefault = self.leftclickoverride(self.inst, target, position)
        if not usedefault or (actions ~= nil and #actions > 0) then
            return actions or {}
        end
    end

    local actions = nil
    local useitem = self.inst.replica.inventory:GetActiveItem()
    local equipitem = self.inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)
    local ispassable = self.map:IsPassableAtPoint(position:Get())

    --if we're specifically using an item, see if we can use it on the target entity
    if useitem ~= nil then
        if useitem:IsValid() then
            if target == self.inst then
                actions = self:GetInventoryActions(useitem)
            elseif target ~= nil then
                actions = self:GetUseItemActions(target, useitem)
            elseif ispassable then
                actions = self:GetPointActions(position, useitem)
            end
        end
    elseif target ~= nil and target ~= self.inst then
        --if we're clicking on a scene entity, see if we can use our equipped object on it, or just use it
        if self.inst.components.playercontroller:IsControlPressed(CONTROL_FORCE_INSPECT) and
            target:HasTag("inspectable") and
            (self.inst.CanExamine == nil or self.inst:CanExamine()) and
            (self.inst.sg == nil or self.inst.sg:HasStateTag("moving") or self.inst.sg:HasStateTag("idle") or self.inst.sg:HasStateTag("channeling")) and
            (self.inst:HasTag("moving") or self.inst:HasTag("idle") or self.inst:HasTag("channeling")) then
            actions = self:SortActionList({ ACTIONS.LOOKAT }, target, nil)
        elseif self.inst.components.playercontroller:IsControlPressed(CONTROL_FORCE_ATTACK) and target.replica.combat ~= nil and self.inst.replica.combat:CanTarget(target) then
            actions = self:SortActionList({ ACTIONS.ATTACK }, target, nil)
        elseif equipitem ~= nil and equipitem:IsValid() then
            actions = self:GetEquippedItemActions(target, equipitem)
        end

        if actions == nil or #actions == 0 then
            actions = self:GetSceneActions(target)
        end
    end

    if actions == nil and target == nil and equipitem ~= nil and equipitem:IsValid() and ispassable then
        --can we use our equipped item at the point?
        actions = self:GetPointActions(position, equipitem)
        --this is to make it so you don't auto-drop equipped items when you left click the ground. kinda ugly.
        if actions ~= nil then
            for i, v in ipairs(actions) do
                if v.action == ACTIONS.DROP then
                    table.remove(actions, i)
                    break
                end
            end
        end
    end

    return actions or {}
end

 

You need to insert your action in the table which is sorted, and give it a priority which is high enough that it ends up being the first one.

PICKUP action has priority 1 so anything above will be executed first. PICK doesn't have a priority specified so in this case it will be 0.

(from actions.lua)

Spoiler

ACTIONS =
{
    REPAIR = Action({ mount_valid=true, encumbered_valid=true }),
    READ = Action({ mount_valid=true }),
    DROP = Action({ priority=-1, mount_valid=true, encumbered_valid=true }),
    TRAVEL = Action(),
    CHOP = Action(),
    ATTACK = Action({ priority=2, canforce=true, mount_valid=true }), -- No custom range check, attack already handles that
    EAT = Action({ mount_valid=true }),
    PICK = Action({ canforce=true, rangecheckfn=DefaultRangeCheck }),
    PICKUP = Action({ priority=1 }),
    MINE = Action(),
    DIG = Action({ rmb=true }),
    GIVE = Action({ mount_valid=true, canforce=true, rangecheckfn=DefaultRangeCheck }),
    GIVETOPLAYER = Action({ priority=3, canforce=true, rangecheckfn=DefaultRangeCheck }),
    GIVEALLTOPLAYER = Action({ priority=3, canforce=true, rangecheckfn=DefaultRangeCheck }),
    FEEDPLAYER = Action({ priority=3, rmb=true, canforce=true, rangecheckfn=DefaultRangeCheck }),
    DECORATEVASE = Action(),
    COOK = Action({ priority=1, mount_valid=true }),
    FILL = Action(),
    DRY = Action(),
    ADDFUEL = Action({ mount_valid=true }),
    ADDWETFUEL = Action({ mount_valid=true }),
    LIGHT = Action({ priority=-4 }),
    EXTINGUISH = Action({ priority=0 }),
    LOOKAT = Action({ priority=-3, instant=true, ghost_valid=true, mount_valid=true, encumbered_valid=true }),
    TALKTO = Action({ priority=3, instant=true, mount_valid=true, encumbered_valid=true }),
    WALKTO = Action({ priority=-4, ghost_valid=true, mount_valid=true, encumbered_valid=true }),
    BAIT = Action(),
    CHECKTRAP = Action({ priority=2 }),
    BUILD = Action({ mount_valid=true }),
    PLANT = Action(),
    HARVEST = Action(),
    GOHOME = Action(),
    SLEEPIN = Action(),
    CHANGEIN = Action({ priority=-1 }),
    EQUIP = Action({ priority=0,instant=true, mount_valid=true, encumbered_valid=true }),
    UNEQUIP = Action({ priority=-2,instant=true, mount_valid=true, encumbered_valid=true }),
    --OPEN_SHOP = Action(),
    SHAVE = Action({ mount_valid=true }),
    STORE = Action(),
    RUMMAGE = Action({ priority=-1, mount_valid=true }),
    DEPLOY = Action({ distance=1.1 }),
    PLAY = Action({ mount_valid=true }),
    CREATE = Action(),
    JOIN = Action(),
    NET = Action({ priority=3, canforce=true, rangecheckfn=DefaultRangeCheck }),
    CATCH = Action({ priority=3, distance=math.huge, mount_valid=true }),
    FISH = Action(),
    REEL = Action({ instant=true }),
    POLLINATE = Action(),
    FERTILIZE = Action(),
    SMOTHER = Action({ priority=1 }),
    MANUALEXTINGUISH = Action({ priority=1 }),
    LAYEGG = Action(),
    HAMMER = Action({ priority=3 }),
    TERRAFORM = Action(),
    JUMPIN = Action({ ghost_valid=true, encumbered_valid=true }),
    TELEPORT = Action({ rmb=true, distance=2 }),
    RESETMINE = Action({ priority=3 }),
    ACTIVATE = Action(),
    MURDER = Action({ priority=0, mount_valid=true }),
    HEAL = Action({ mount_valid=true }),
    INVESTIGATE = Action(),
    UNLOCK = Action(),
    USEKLAUSSACKKEY = Action(),
    TEACH = Action({ mount_valid=true }),
    TURNON = Action({ priority=2 }),
    TURNOFF = Action({ priority=2 }),
    SEW = Action({ mount_valid=true }),
    STEAL = Action(),
    USEITEM = Action({ priority=1, instant=true }),
    TAKEITEM = Action(),
    MAKEBALLOON = Action({ mount_valid=true }),
    CASTSPELL = Action({ priority=-1, rmb=true, distance=20, mount_valid=true }),
    BLINK = Action({ priority=10, rmb=true, distance=36, mount_valid=true }),
    COMBINESTACK = Action({ mount_valid=true }),
    TOGGLE_DEPLOY_MODE = Action({ priority=1, instant=true }),
    SUMMONGUARDIAN = Action({ rmb=false, distance=5 }),
    HAUNT = Action({ rmb=false, mindistance=2, ghost_valid=true, ghost_exclusive=true, canforce=true, rangecheckfn=DefaultRangeCheck }),
    UNPIN = Action(),
    STEALMOLEBAIT = Action({ rmb=false, distance=.75 }),
    MAKEMOLEHILL = Action({ priority=4, rmb=false, distance=0 }),
    MOLEPEEK = Action({ rmb=false, distance=1 }),
    FEED = Action({ rmb=true, mount_valid=true }),
    UPGRADE = Action({ rmb=true }),
    HAIRBALL = Action({ rmb=false, distance=3 }),
    CATPLAYGROUND = Action({ rmb=false, distance=1 }),
    CATPLAYAIR = Action({ rmb=false, distance=2 }),
    FAN = Action({ rmb=true, mount_valid=true }),
    DRAW = Action(),
    BUNDLE = Action({ rmb=true, priority=2 }),
    BUNDLESTORE = Action({ instant=true }),
    WRAPBUNDLE = Action({ instant=true }),
    UNWRAP = Action({ rmb=true, priority=2 }),
    STARTCHANNELING = Action({ distance=2.1 }),
    STOPCHANNELING = Action({ instant=true, distance=2.1 }),

    TOSS = Action({ rmb=true, distance=8, mount_valid=true }),
    NUZZLE = Action(),
    WRITE = Action(),
    ATTUNE = Action(),
    REMOTERESURRECT = Action({ rmb=false, ghost_valid=true, ghost_exclusive=true }),
    MIGRATE = Action({ rmb=false, encumbered_valid = true, ghost_valid=true }),
    MOUNT = Action({ priority=1, rmb=true, encumbered_valid=true }),
    DISMOUNT = Action({ priority=1, instant=true, rmb=true, mount_valid=true, encumbered_valid=true }),
    SADDLE = Action({ priority=1 }),
    UNSADDLE = Action({ priority=3, rmb=false }),
    BRUSH = Action({ priority=3, rmb=false }),
    ABANDON = Action({ rmb=true }),
    PET = Action(),
}

 

Then you have in playercontroller.lua the function which is executed when you left click

Spoiler

function PlayerController:OnLeftClick(down)
    if not self:UsingMouse() then
        return
    elseif not down then
        self:OnLeftUp()
        return
    end

    self.startdragtime = nil

    if not self:IsEnabled() then
        return
    elseif TheInput:GetHUDEntityUnderMouse() ~= nil then 
        self:CancelPlacement()
        return
    end

    if self.placer_recipe ~= nil and self.placer ~= nil then
        --do the placement
        if self.placer.components.placer.can_build and
            self.inst.replica.builder ~= nil and
            not self.inst.replica.builder:IsBusy() then
            self.inst.replica.builder:MakeRecipeAtPoint(self.placer_recipe, TheInput:GetWorldPosition(), self.placer:GetRotation(), self.placer_recipe_skin)
            self:CancelPlacement()
        end
        return
    end

    local act = self:GetLeftMouseAction() or BufferedAction(self.inst, nil, ACTIONS.WALKTO, nil, TheInput:GetWorldPosition())
    if act.action == ACTIONS.WALKTO then
        if act.target == nil and TheInput:GetWorldEntityUnderMouse() == nil then
            self.startdragtime = GetTime()
        end
    elseif act.action == ACTIONS.ATTACK then
        if self.inst.sg ~= nil then
            if self.inst.sg:HasStateTag("attack") then
                return
            end
        elseif self.inst:HasTag("attack") then
            return
        end
    elseif act.action == ACTIONS.LOOKAT
        and act.target ~= nil
        and act.target.components.playeravatardata ~= nil
        and self.inst.HUD ~= nil then

        local client_obj = act.target.components.playeravatardata:GetData()
        if client_obj ~= nil then
            client_obj.inst = act.target
            self.inst.HUD:TogglePlayerAvatarPopup(client_obj.name, client_obj, true)
        end
    end

    if self.ismastersim then
        self.inst.components.combat:SetTarget(nil)
    else
        local position = TheInput:GetWorldPosition()
        local mouseover = act.action ~= ACTIONS.DROP and TheInput:GetWorldEntityUnderMouse() or nil
        local controlmods = self:EncodeControlMods()
        if self.locomotor == nil then
            self.remote_controls[CONTROL_PRIMARY] = 0
            SendRPCToServer(RPC.LeftClick, act.action.code, position.x, position.z, mouseover, nil, controlmods, act.action.canforce, act.action.mod_name)
        elseif act.action ~= ACTIONS.WALKTO and self:CanLocomote() then
            act.preview_cb = function()
                self.remote_controls[CONTROL_PRIMARY] = 0
                local isreleased = not TheInput:IsControlPressed(CONTROL_PRIMARY)
                SendRPCToServer(RPC.LeftClick, act.action.code, position.x, position.z, mouseover, isreleased, controlmods, nil, act.action.mod_name)
            end
        end
    end

    self:DoAction(act)
end

 

This will execute the action which has been tagged aas having the highest priority.

BUT:

you want to perform your action when you press the space bar, which is the "ActionButton". This is again a different story but the same principle.

This time everything happens in playercontroller.lua

When you press the space bar, this is executed:

Spoiler

function PlayerController:DoActionButton()
    if self.placer == nil then
        local buffaction = self:GetActionButtonAction()
        if buffaction ~= nil then
            if self.ismastersim then
                self.locomotor:PushAction(buffaction, true)
                return
            elseif self.locomotor == nil then
                self:RemoteActionButton(buffaction)
                return
            elseif self:CanLocomote() then
                if buffaction.action ~= ACTIONS.WALKTO then
                    buffaction.preview_cb = function()
                        self:RemoteActionButton(buffaction, not TheInput:IsControlPressed(CONTROL_ACTION) or nil)
                    end
                end
                self.locomotor:PreviewAction(buffaction, true)
            end
        end
    elseif self.placer.components.placer.can_build and
        self.inst.replica.builder ~= nil and
        not self.inst.replica.builder:IsBusy() then
        --do the placement
        self.inst.replica.builder:MakeRecipeAtPoint(self.placer_recipe, self.placer:GetPosition(), self.placer:GetRotation(), self.placer_recipe_skin)
    end

    --Still need to let the server know our action button is down
    if not self.ismastersim and self.remote_controls[CONTROL_ACTION] == nil then
        self:RemoteActionButton()
    end
end

 

This function uses its own action picker which is the following

Spoiler

function PlayerController:GetActionButtonAction(force_target)
    --Don't want to spam the action button before the server actually starts the buffered action
    --Also check if playercontroller is enabled
    --Also check if force_target is still valid
    if (not self.ismastersim and (self.remote_controls[CONTROL_ACTION] or 0) > 0) or
        not self:IsEnabled() or
        (force_target ~= nil and (not force_target.entity:IsVisible() or force_target:HasTag("INLIMBO") or force_target:HasTag("NOCLICK"))) then
        --"DECOR" should never change, should be safe to skip that check
        return

    elseif self.actionbuttonoverride ~= nil then
        local buffaction, usedefault = self.actionbuttonoverride(self.inst, force_target)
        if not usedefault or buffaction ~= nil then
            return buffaction
        end

    elseif self.inst.replica.inventory:IsHeavyLifting()
        and not (self.inst.replica.rider ~= nil and self.inst.replica.rider:IsRiding()) then
        --hands are full!
        return

    elseif not self:IsDoingOrWorking() then
        local force_target_distsq = force_target ~= nil and self.inst:GetDistanceSqToInst(force_target) or nil

        if self.inst:HasTag("playerghost") then
            --haunt
            if force_target == nil then
                local target = FindEntity(self.inst, self.directwalking and 3 or 6, ValidateHaunt, nil, HAUNT_TARGET_EXCLUDE_TAGS)
                if CanEntitySeeTarget(self.inst, target) then
                    return BufferedAction(self.inst, target, ACTIONS.HAUNT)
                end
            elseif force_target_distsq <= (self.directwalking and 9 or 36) and
                not (force_target:HasTag("haunted") or force_target:HasTag("catchable")) and
                ValidateHaunt(force_target) then
                return BufferedAction(self.inst, force_target, ACTIONS.HAUNT)
            end
            return
        end

        local tool = self.inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)

        --bug catching (has to go before combat)
        if tool ~= nil and tool:HasTag(ACTIONS.NET.id.."_tool") then
            if force_target == nil then
                local target = FindEntity(self.inst, 5, ValidateBugNet, { "_health", ACTIONS.NET.id.."_workable" }, TARGET_EXCLUDE_TAGS)
                if CanEntitySeeTarget(self.inst, target) then
                    return BufferedAction(self.inst, target, ACTIONS.NET, tool)
                end
            elseif force_target_distsq <= 25 and
                force_target.replica.health ~= nil and
                ValidateBugNet(force_target) and
                force_target:HasTag(ACTIONS.NET.id.."_workable") then
                return BufferedAction(self.inst, force_target, ACTIONS.NET, tool)
            end
        end

        --catching
        if self.inst:HasTag("cancatch") then
            if force_target == nil then
                local target = FindEntity(self.inst, 10, nil, { "catchable" }, TARGET_EXCLUDE_TAGS)
                if CanEntitySeeTarget(self.inst, target) then
                    return BufferedAction(self.inst, target, ACTIONS.CATCH)
                end
            elseif force_target_distsq <= 100 and
                force_target:HasTag("catchable") then
                return BufferedAction(self.inst, force_target, ACTIONS.CATCH)
            end
        end

        --unstick
        if force_target == nil then
            local target = FindEntity(self.inst, self.directwalking and 3 or 6, nil, { "pinned" }, TARGET_EXCLUDE_TAGS)
            if CanEntitySeeTarget(self.inst, target) then
                return BufferedAction(self.inst, target, ACTIONS.UNPIN)
            end
        elseif force_target_distsq <= (self.directwalking and 9 or 36) and
            force_target:HasTag("pinned") then
            return BufferedAction(self.inst, force_target, ACTIONS.UNPIN)
        end

        --misc: pickup, tool work, smother
        if force_target == nil then
            local pickup_tags =
            {
                "_inventoryitem",
                "pickable",
                "donecooking",
                "readyforharvest",
                "notreadyforharvest",
                "harvestable",
                "trapsprung",
                "minesprung",
                "dried",
                "inactive",
                "smolder",
                "saddled",
                "brushable",
            }
            if tool ~= nil then
                for k, v in pairs(TOOLACTIONS) do
                    if tool:HasTag(k.."_tool") then
                        table.insert(pickup_tags, k.."_workable")
                    end
                end
            end
            local x, y, z = self.inst.Transform:GetWorldPosition()
            local ents = TheSim:FindEntities(x, y, z, self.directwalking and 3 or 6, nil, PICKUP_TARGET_EXCLUDE_TAGS, pickup_tags)
            for i, v in ipairs(ents) do
                if v ~= self.inst and v.entity:IsVisible() and CanEntitySeeTarget(self.inst, v) then
                    local action = GetPickupAction(self.inst, v, tool)
                    if action ~= nil then
                        return BufferedAction(self.inst, v, action, action ~= ACTIONS.SMOTHER and tool or nil)
                    end
                end
            end
        elseif force_target_distsq <= (self.directwalking and 9 or 36) then
            local action = GetPickupAction(self.inst, force_target, tool)
            if action ~= nil then
                return BufferedAction(self.inst, force_target, action, action ~= ACTIONS.SMOTHER and tool or nil)
            end
        end
    end
end

 

This last function is the one you need to modify to have your jump action returned in priority.

I will try to write a simple example which demonstrates how it would work.

Edited by ZupaleX
Link to comment
Share on other sites

Sorry for the double post but I decided that it deserve another post instead of a third edit.

Please find attached a working skeleton for a custom action not using an object and performed when pressing the space bar. You'll have to adapt it to your needs and keep it mind it will probably not work well with a gamepad (if you want to make it compatible with using a gamepad you would need to override the function corresponding to the gamepad button the same way I override the space bar in my proof of principle).

Spoiler

local CHEATYHEAL = GLOBAL.Action({priority = 10, mount_valid=true, encumbered_valid=true})
CHEATYHEAL.strfn = function(act) return "Free Heal" end
CHEATYHEAL.id = "CHEATYHEAL"
CHEATYHEAL.fn = function(act)
	local doer = act.doer
	
	print("Howdy")
	
	if GLOBAL.TheWorld.ismastersim then
		if doer.components and doer.components.health then
			doer.components.health:DoDelta(20) -- Our custom action is simple: it heals the player for 20 HP
		end
	end
	
	return true
end

AddAction(CHEATYHEAL)
AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.CHEATYHEAL, "doshortaction")) 	-- doshortaction is the default state for short actions like picking up something from the ground. 
																							--Replace that with the name of the state you want the character to go to upon performing the action
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.CHEATYHEAL, "doshortaction")) -- Don't forget to create a state for the client as well and to add the link between the action and the state for the client

local function NewGetActionButtonAction(self, force_target)
	if (not self.ismastersim and (self.remote_controls[CONTROL_ACTION] or 0) > 0) or
        not self:IsEnabled() or
        (force_target ~= nil and (not force_target.entity:IsVisible() or force_target:HasTag("INLIMBO") or force_target:HasTag("NOCLICK"))) then
        --"DECOR" should never change, should be safe to skip that check
        return
	
	elseif self.actionbuttonoverride ~= nil then -- Remove that part if you want to ignore the action button override when you are supposed to perform your special action (like if the player press CONTROL button or something like that...)
        local buffaction, usedefault = self.actionbuttonoverride(self.inst, force_target)
        if not usedefault or buffaction ~= nil then
            return buffaction
        end
		
	else
		local nearbyFlower = GLOBAL.FindEntity(self.inst, 10, nil, {"flower"}) -- check if a flower is within a radius of 10 from the player (self.inst)
		
		if nearbyFlower ~= nil then
			print("Got a flower here!")
			return GLOBAL.BufferedAction(self.inst, nil, ACTIONS.CHEATYHEAL) -- So if a flower is found within a radius on 10, the CHEATYHEAL action will be performed upon pressing the space bar
		end
	end
end

AddComponentPostInit("playercontroller", function(controller)
	local OriginalGetActionButtonAction = controller.GetActionButtonAction
	
	controller.GetActionButtonAction = function(self, force_target)
		local buffAction = NewGetActionButtonAction(self, force_target)
		
		if buffAction ~= nil then return buffAction end
		
		-- If the function did not return yet, then it means our custom action cannot be performed right now, so we return the original function to get the valid actions (PICKUP, PICK, CHOP, etc...)
		return OriginalGetActionButtonAction(self, force_target)
	end
end)

 

This can go directly in your modmain.lua if you want to test it out.

Cheers

Link to comment
Share on other sites

Wow, thanks very much @ZupaleX now spacebar is jump button with no glitches :D!! Though, my character can still force_attack while doing this action :shock:! Maybe I messed something in the code up??

Spoiler

local JUMP_ADAM = GLOBAL.Action({priority = 10, mount_valid=nil, encumbered_valid=nil})
JUMP_ADAM.strfn = function(act) return "Jump" end
JUMP_ADAM.id = "JUMP_ADAM"
JUMP_ADAM.fn = function(act)
	jump(act)
	return true
end

local RUN_JUMP_ADAM = GLOBAL.Action({priority = 10, mount_valid=nil, encumbered_valid=nil})
RUN_JUMP_ADAM.strfn = function(act) return "Jump" end
RUN_JUMP_ADAM.id = "RUN_JUMP_ADAM"
RUN_JUMP_ADAM.fn = function(act)
	run_jump(act)
	return true
end

AddAction(JUMP_ADAM)
AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.JUMP_ADAM))
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.JUMP_ADAM))

AddAction(RUN_JUMP_ADAM)
AddStategraphActionHandler("wilson", ActionHandler(ACTIONS.RUN_JUMP_ADAM))
AddStategraphActionHandler("wilson_client", ActionHandler(ACTIONS.RUN_JUMP_ADAM))

local function NewGetActionButtonAction(self, force_target)
	RemovePlayerActions(self.inst, true)
	RemovePlayerActions(self.inst, false)
	
	if (not self.ismastersim and (self.remote_controls[CONTROL_ACTION] or 0) > 0) or
        not self:IsEnabled() or
        (force_target ~= nil and (not force_target.entity:IsVisible() or force_target:HasTag("INLIMBO") or force_target:HasTag("NOCLICK"))) then
        --"DECOR" should never change, should be safe to skip that check
        return
	
	elseif self.actionbuttonoverride ~= nil then -- Remove that part if you want to ignore the action button override when you are supposed to perform your special action (like if the player press CONTROL button or something like that...)
        local buffaction, usedefault = self.actionbuttonoverride(self.inst, force_target)
        if not usedefault or buffaction ~= nil then
            return buffaction
        end
		
	elseif self.inst.components.locomotor:WantsToMoveForward() then
		return GLOBAL.BufferedAction(self.inst, nil, ACTIONS.RUN_JUMP_ADAM)
	else
		return GLOBAL.BufferedAction(self.inst, nil, ACTIONS.JUMP_ADAM)
	end
end

AddComponentPostInit("playercontroller", function(controller)
	local OriginalGetActionButtonAction = controller.GetActionButtonAction
	
	controller.GetActionButtonAction = function(self, force_target)
		local buffAction = NewGetActionButtonAction(self, force_target)
		
		if buffAction ~= nil then
			return buffAction
		end
		
		return OriginalGetActionButtonAction(self, force_target)
	end
end)

 

One more thing can you maybe tell me what this code does? Cause I don't really understand what it does :wilson_dorky:..

Spoiler

elseif self.actionbuttonoverride ~= nil then -- Remove that part if you want to ignore the action button override when you are supposed to perform your special action (like if the player press CONTROL button or something like that...)
        local buffaction, usedefault = self.actionbuttonoverride(self.inst, force_target)
        if not usedefault or buffaction ~= nil then
            return buffaction
        end

 

I don't want to bother you anymore with this force_attack stuff so I think maybe I can solve it by just editing the attack state to not do a attack with some values (though the character would still go up to the entity probably).

 

And thanks a lot for your help man, I definitely wouldn't be able to make spacebar be jump button without your help :wilson_flower:!!!

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...