Jump to content

Need help troubleshooting a bit of code for implementing hunger cost on a custom teleport


Recommended Posts

To start off, a very brief background. I'm trying to create a custom item that uses the blinkstaff component to teleport the player on activation, except instead of consuming sanity, it burns hunger instead. The item has a few transformations and will be part of a custom character mod focused around high mobility with steep hunger costs. So far the teleport itself is functional, and for troubleshooting purposes, if I set it to decrease sanity on use, it will do so fine.

The problem is that for some reason, the code doesn't seem to properly reduce hunger or (for testing purposes) health.

These are the relevant inst code blocks. It's broken up into two functions for organization since it can morph into different forms, so it'll keep the overall code a tiny bit neater. I think you can pretty much ignore the second block, but I included it just in case.

local function panspark_commonfn() 
	local inst = CreateEntity()
	
	inst:AddTag("panspark")
	
	inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddNetwork()
    
    MakeInventoryPhysics(inst)
	
    inst.AnimState:SetBank("panspark")
    inst.AnimState:SetBuild("panspark")
    inst.AnimState:PlayAnimation("idle")
	
	-- Reticule component for teleport
	inst:AddComponent("reticule")
    inst.components.reticule.targetfn = blinkstaff_reticuletargetfn
    inst.components.reticule.ease = true
	
    inst.entity:SetPristine()

	-- Looks like the above code is just for client-side stuff?
	if not TheWorld.ismastersim then
        return inst
    end

    -------

    inst:AddComponent("inspectable")
    inst:AddComponent("tradable")

	-- Blinkstaff component for teleport
	inst:AddComponent("blinkstaff")
    inst.components.blinkstaff:SetFX("sand_puff_large_front", "sand_puff_large_back")
    inst.components.blinkstaff.onblinkfn = onblink
	
	-- Item is usable to change forms
    inst:AddComponent("useableitem")
    inst.components.useableitem:SetOnUseFn(panspark_movechange)
	
	-- Inventory display info
    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem:EnableMoisture(false)
    inst.components.inventoryitem.keepondeath = true

    return inst
end


local function panspark_base()
    local inst = panspark_commonfn()
	inst:AddTag("panspark_base")
    inst.components.inventoryitem.imagename = "panspark_base"
    inst.components.inventoryitem.atlasname = "images/inventoryimages/panspark_base.xml"
	
	-- Electric damage weapon
	inst:AddComponent("weapon")
    inst.components.weapon:SetDamage(25)
    inst.components.weapon:SetOnAttack(onattack)
    inst.components.weapon:SetElectric()
	
	-- Equippable
    inst:AddComponent("equippable")
    inst.components.equippable:SetOnEquip(onequip_base)
    inst.components.equippable:SetOnUnequip(onunequip_base)

    return inst
end

The important bit is in inst.components.blinkstaff.onblinkfn = onblink. If I'm reading the blinkstaff code correctly, this should be called when right clicking to teleport. Snippet from blinkstaff.lua.

function BlinkStaff:Blink(pt, caster)
    if not TheWorld.Map:IsAboveGroundAtPoint(pt:Get()) or TheWorld.Map:IsGroundTargetBlocked(pt) then
        return false
    end

    if self.blinktask ~= nil then
        self.blinktask:Cancel()
    end

    self:SpawnEffect(caster)
    caster.SoundEmitter:PlaySound("dontstarve/common/staff_blink")
    caster:Hide()
    if caster.DynamicShadow ~= nil then
        caster.DynamicShadow:Enable(false)
    end
    if caster.components.health ~= nil then
        caster.components.health:SetInvincible(true)
    end

    self.blinktask = caster:DoTaskInTime(.25, OnBlinked, self, pt)

    if self.onblinkfn ~= nil then
        self.onblinkfn(self.inst, pt, caster)
    end

    return true
end

 

And here is the specific onblink function, which is mostly copied from staff.lua except with a modification to reduce hunger.

local function onblink(staff, pos, caster)
    if caster.components.hunger and caster.components.hunger.current > 0 then
        caster.components.hunger:DoDelta(-10)
    end
end

local function NoHoles(pt)
    return not TheWorld.Map:IsGroundTargetBlocked(pt)
end

local function blinkstaff_reticuletargetfn()
    local player = ThePlayer
    local rotation = player.Transform:GetRotation() * DEGREES
    local pos = player:GetPosition()
    for r = 13, 1, -1 do
        local numtries = 2 * PI * r
        local offset = FindWalkableOffset(pos, rotation, r, numtries, false, true, NoHoles)
        if offset ~= nil then
            pos.x = pos.x + offset.x
            pos.y = 0
            pos.z = pos.z + offset.z
            return pos
        end
    end
end

The issue I'm running into, though, is that blinking will work, but won't reduce the caster's hunger. Likewise with components.health:DoDelta(#). But what's throwing me off is that if I substitute in the original onblink code (orange staff, or the Lazy Explorer), sanity is decreased as normal.

local function onblink(staff, pos, caster)
    if caster.components.sanity ~= nil then
        caster.components.sanity:DoDelta(-TUNING.SANITY_MED)
    end
    -- staff.components.finiteuses:Use(1) 
end

 

So to sum up, the only thing I can decrease on teleport is sanity, not hunger or health. But the character has the relevant components and they seem to be implemented properly. So... I'm stumped! Anyone have any insight for bug fixing?

panspark.lua

Edited by ShinyMoogle
Added attachment
Link to comment
Share on other sites

Try putting in print("onblink was called") just to make sure that your onblink is actually properly called. I know it sounds stupid, but it's a stupid problem :) Your code looks right. Personally, I would restrict the use of the staff, if the player doesn't have enough hunger/sanity/health to use it, and then forego this part of the if-statement in onblink

and caster.components.hunger.current > 0

...but that's not important right now. See if it prints that print() in one of your log files. I'm almost certain it won't, because your code inside onblink looks right.

It might be, that you have to make sure that your onblink function is declared before your panspark_commonfn()

Link to comment
Share on other sites

Yeah, hard stat requirement is on the radar. Working in broad strokes at the moment, planning to fine-tune everything at some point later.

Good idea with the print statement. It is printing a message in the log file so onblink is getting called properly. But print statements nested within the if statement aren't, meaning somehow caster.components.hunger and caster.components.hunger.current > 0 is returning false and skipping the if statement. But, uh... I'm 99% sure the component almost definitely exists. :v I did make sure onblink is getting declared before panspark_commonfn(), but no luck there.

The only thing I can think of now is that the caster parameter isn't passing along all of the player character's information, but I have absolutely no idea why that might be the case. The only other place components.blinkstaff:Blink is called is in actions, and it seems like everything should be there...

-- from actions.lua
ACTIONS.BLINK.fn = function(act)
    if act.invobject and act.invobject.components.blinkstaff then
        return act.invobject.components.blinkstaff:Blink(act.pos, act.doer)
    end
end

 

I went ahead and attached the full item script in case it helps with spotting something silly I missed somewhere.

Edited by ShinyMoogle
Link to comment
Share on other sites

You know, I think I must have fudged how I wrote the print statement earlier, since it's showing up now. Oops. Print results check out fine.

local function onblink(staff, pos, caster)
	print ("onblink was called")
    if caster.components.hunger and caster.components.hunger.current > 0 then
        caster.components.hunger:DoDelta(-10)
		print ("conditions valid")
    end
	
	print("Has hunger component: "..tostring(caster.components.hunger ~= nil))
	print("Current hunger: "..(caster.components.hunger.current))
	print(caster)
end

[00:01:09]: onblink was called    
[00:01:09]: conditions valid
[00:01:09]: Has hunger component: true    
[00:01:09]: Current hunger: 189.0625    
[00:01:09]: 116384 - pandora

 

So! Thanks to that I went in and double-checked hunger:DoDelta(), and wouldn't you know it...

if not ignore_invincible and self.inst.components.health.invincible or self.inst.is_teleporting then
        return
    end 

 

Right under my nose. Guess I'll have to move the hunger deduction somewhere else or make a postinit function.

Thanks for the help!! Print statements sure can be handy.

Edited by ShinyMoogle
Link to comment
Share on other sites

You don't have to do that. You can just do a DoTaskInTime and postpone it until the player has teleported.

local dosanityreduction = function(inst)
	if not inst.is_teleporting then
		if caster.components.hunger and caster.components.hunger.current > 0 then
			caster.components.hunger:DoDelta(-10)
		end
	else
		inst:DoTaskInTime(0.1, dosanityreduction)
	end
end

local function onblink(staff, pos, caster)
    dosanityreduction(caster)
end

This will keep calling the dosanityreduction function every 0.1 seconds, until it successfully applies the hunger change.

Edited by Ultroman
Link to comment
Share on other sites

That's easy just extend (not override) the Blink function in the component.

-- Store the original Blink function (this will keep it compatible with other mods which might also have extended this function,
-- and allow it to work even if Klei updates the code in it)
local old_Blink = inst.components.blinkstaff.Blink
-- Replace the Blink function with a new one. Notice that we add "self" to it, since the function is declared with a :.
inst.components.blinkstaff.Blink = function (self, pt, caster)
	if caster.components.hunger and caster.components.hunger.current < 10 then
		return
	end
	-- Run the original Blink function, if your check above has not already returned from our function.
	old_Blink(self, pt, caster)
end

 

Just add that right after your line

inst.components.blinkstaff.onblinkfn = onblink

 

Edited by Ultroman
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...