ShinyMoogle Posted January 1, 2019 Share Posted January 1, 2019 (edited) 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 January 8, 2019 by ShinyMoogle Added attachment Link to comment Share on other sites More sharing options...
Ultroman Posted January 2, 2019 Share Posted January 2, 2019 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 More sharing options...
ShinyMoogle Posted January 8, 2019 Author Share Posted January 8, 2019 (edited) 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 January 8, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
Ultroman Posted January 8, 2019 Share Posted January 8, 2019 Well, time to do more debug printing, then. print("Has hunger component: "..(caster.components.hunger ~= nil)) print("Current hunger: "..(caster.components.hunger.current)) print(caster) Link to comment Share on other sites More sharing options...
ShinyMoogle Posted January 8, 2019 Author Share Posted January 8, 2019 (edited) 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 January 8, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
Ultroman Posted January 8, 2019 Share Posted January 8, 2019 (edited) 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 January 8, 2019 by Ultroman Link to comment Share on other sites More sharing options...
ShinyMoogle Posted January 8, 2019 Author Share Posted January 8, 2019 Oh, nice. That's a much neater solution than I had in mind, thanks. I've never been great at recursive function calls. Though I suspect I'll still need to poke around the component a bit eventually to prevent use at 0 hunger. Link to comment Share on other sites More sharing options...
Ultroman Posted January 8, 2019 Share Posted January 8, 2019 (edited) 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 January 8, 2019 by Ultroman Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now