MrDoge124 Posted April 8, 2020 Share Posted April 8, 2020 I had a character that can glow in the dark, I though of an idea where they could use this light to stun enemies. I've looked at examples but I couldn't quite get it right. I wanted to make it so when he activates it his light will be gone for 8 minutes (a day) and he'll get a sanity penalty. (About -10 to -15 maybe?) I was going to make it activated by a key press by I couldn't quite figure it out. Any help would be appreciated. Link to comment Share on other sites More sharing options...
Ultroman Posted April 8, 2020 Share Posted April 8, 2020 Take a look at this If you think of the "inst" as the instance of an entity you've found, which you want to inflict a (de)buff on, i.e., your stun, and use the movement speed example to give them a movementspeed multiplier of 0, they should at least stop moving on their own volition, but still be affected by physics. But that code is for an aura-buff. Gimme a sec. Link to comment Share on other sites More sharing options...
Ultroman Posted April 8, 2020 Share Posted April 8, 2020 (edited) IGNORE Edited April 8, 2020 by Ultroman Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 8, 2020 Author Share Posted April 8, 2020 So far I have this, inst.lightstunisapplied = false local applybuff = function(inst) -- Apply all your buff stuff here inst.components.locomotor:SetExternalSpeedMultiplier(inst, "lightstunkey", 0) end local removebuff = function(inst) -- Remove all your buff stuff here inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "lightstunkey") end inst:DoPeriodicTask(0.5, function(inst) if inst == nil or not inst:IsValid() or inst.components.health:IsDead() then -- If the player instance is invalid or they're dead, then we don't want to do anything. return end -- If our buff is applied and our measurements say it should not be applied anymore, we remove it. -- Else, if our buff is not applied and our measurements say it should be, we apply it. if inst.lightstunisapplied and inst.components.sanity:GetPercentWithPenalty() > 0.07 then removebuff(inst) elseif not inst.lightstunisapplied and inst.components.sanity:GetPercentWithPenalty() <= 0.07 then applybuff(inst) end end) This seems to slow him down when on 7% sanity. I'm not sure how to find an entity and slow them down with the inst thing and I am not sure how I would activate this with a key press. I do know however that I'll need a keyhandler.lua as other mods use this when dealing with key inputs. Link to comment Share on other sites More sharing options...
Ultroman Posted April 8, 2020 Share Posted April 8, 2020 That other code is for aura-buffs and doesn't handle duplicate buffs (woopsie!). I made this for you. It's a better way of handling timed buffs. Â Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 9, 2020 Author Share Posted April 9, 2020 I've been using this code to activate the buff TheInput:AddKeyDownHandler(KEY_Z, function() ApplyBuff(Buffs["stunbuff"], inst) end) However this seems to target me and nothing else. I'm not sure how to target things around me and not myself. I also need a way of adding a cool down so that I can't just use it constantly. Here is what the rest of the code looks like. Spoiler -- This function is rather complicated. You don't need to change anything in here. local function ApplyBuff(buffData, instToBuff)    local buffUniqueName = buffData.uniqueName       -- Cancel any existing duplicate timed buff.    if instToBuff[buffUniqueName.."Task"] ~= nil then       buffData.removeFunction(instToBuff)       instToBuff[buffUniqueName.."Task"]:Cancel()       instToBuff[buffUniqueName.."Task"] = nil    end       -- Make sure that our buff is removed BEFORE the entity is saved (the server is closed or player quits).    -- This is only necessary if you change variables which are saved, like current health, health-penalty, etc.    -- Without it, you could apply a max-health buff, quit before it ran out, rejoin, and you would have kept    -- the extra max health!    local buffOnSave = function(self, inst, data)       if inst[buffUniqueName.."Task"] ~= nil then          buffData.removeFunction(inst)          inst[buffUniqueName.."Task"]:Cancel()          inst[buffUniqueName.."Task"] = nil       end    end       if instToBuff.OnSave ~= nil then       local oldOnSave = instToBuff.OnSave       instToBuff.OnSave = function(self, inst, data)          buffOnSave(self, inst, data)          oldOnSave(self, inst, data)       end    else       instToBuff.OnSave = buffOnSave    end       -- Apply the buff.    buffData.applyFunction(instToBuff)       -- Set up removal after a certain amount of time.    instToBuff[buffUniqueName.."Task"] = instToBuff:DoTaskInTime(buffData.duration, function(inst)       buffData.removeFunction(inst)       inst[buffUniqueName.."Task"] = nil    end) end -- Now to make some buffs and put them in a Buffs-dictionary. local Buffs = {} -- This function creates a new buff-data object and adds it to the Buffs-dictionary -- with the uniqueName as key. local function CreateBuff(uniqueName, duration, applyFunction, removeFunction)    local newBuff = {}    newBuff.uniqueName = uniqueName    newBuff.duration = duration    newBuff.applyFunction = applyFunction    newBuff.removeFunction = removeFunction    Buffs[uniqueName] = newBuff end -- This is an example of how to use the CreateBuff() function to create a new buff. CreateBuff("stunbuff", 5.0,    function(inst)       -- Apply all your buff code here       -- Remember to always check whether the components you want to change are actually present on the       -- entity before you try to mess with them.-- Store the current maxhealth in a variable.       -- Add 0% speed boost in all situations       inst.components.locomotor:SetExternalSpeedMultiplier(inst, "stunkey", 0)    end,    function(inst)       -- Revert your buff code here       -- Remember to always check whether the components you want to change are actually present on the       -- entity before you try to mess with them.    -- Remove speed bonus.    inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "stunkey")    end ) TheInput:AddKeyDownHandler(KEY_Z, function()    ApplyBuff(Buffs["stunbuff"], inst) end)   Link to comment Share on other sites More sharing options...
Ultroman Posted April 10, 2020 Share Posted April 10, 2020 Well, that's because you're casting it on yourself. If you put that code in a character, then "inst" is the character. You need to trigger the function with a listener or something. Use the tutorials here to familiarize yourself with how to do things in the code. Check out the perk/buff tutorials. Â Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 11, 2020 Author Share Posted April 11, 2020 (edited) I think I'm missing something, because I get this error when I press the key [00:01:43]: [string "../mods/Green/modmain.lua"]:198: attempt to index local 'instToBuff' (a nil value) LUA ERROR stack traceback: ../mods/Green/modmain.lua:198 in (upvalue) ApplyBuff (Lua) <194-234> buffData = table: 4B41C1D0 instToBuff = nil buffUniqueName = stunbuff ../mods/Green/modmain.lua:273 in (field) fn (Lua) <272-274> scripts/events.lua:46 in (method) HandleEvent (Lua) <42-49> self = events = table: 29B1A1C0 event = 122 arg = nil handlers = table: 4B41C2C0 k = table: 4B41C270 v = true scripts/input.lua:187 in (method) OnRawKey (Lua) <184-191> self = onkeyup = table: 29B1A3F0 entitiesundermouse = table: 8E1BCF40 onmousebutton = table: 29B19F40 controllerid_cached = 0 onkey = table: 29B1A3C8 enabledebugtoggle = true ongesture = table: 29B1A418 mouse_enabled = true ontextinput = table: 29B1A648 position = table: 29B1A760 onkeydown = table: 29B1A198 oncontrol = table: 29B1A8C8 key = 122 down = true scripts/input.lua:396 in () ? (Lua) <395-397> key = 122 is_up = true [00:01:43]: [string "../mods/Green/modmain.lua"]:198: attempt to index local 'instToBuff' (a nil value) LUA ERROR stack traceback: ../mods/Green/modmain.lua:198 in (upvalue) ApplyBuff (Lua) <194-234> ../mods/Green/modmain.lua:273 in (field) fn (Lua) <272-274> scripts/events.lua:46 in (method) HandleEvent (Lua) <42-49> scripts/input.lua:187 in (method) OnRawKey (Lua) <184-191> scripts/input.lua:396 in () ? (Lua) <395-397> I think I'm just being stupid here, but I'm not sure what is wrong. Spoiler -- This function is rather complicated. You don't need to change anything in here. local function ApplyBuff(buffData, instToBuff) local buffUniqueName = buffData.uniqueName -- Cancel any existing duplicate timed buff. if instToBuff[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(instToBuff) instToBuff[buffUniqueName.."Task"]:Cancel() instToBuff[buffUniqueName.."Task"] = nil end -- Make sure that our buff is removed BEFORE the entity is saved (the server is closed or player quits). -- This is only necessary if you change variables which are saved, like current health, health-penalty, etc. -- Without it, you could apply a max-health buff, quit before it ran out, rejoin, and you would have kept -- the extra max health! local buffOnSave = function(self, inst, data) if inst[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(inst) inst[buffUniqueName.."Task"]:Cancel() inst[buffUniqueName.."Task"] = nil end end if instToBuff.OnSave ~= nil then local oldOnSave = instToBuff.OnSave instToBuff.OnSave = function(self, inst, data) buffOnSave(self, inst, data) oldOnSave(self, inst, data) end else instToBuff.OnSave = buffOnSave end -- Apply the buff. buffData.applyFunction(instToBuff) -- Set up removal after a certain amount of time. instToBuff[buffUniqueName.."Task"] = instToBuff:DoTaskInTime(buffData.duration, function(inst) buffData.removeFunction(inst) inst[buffUniqueName.."Task"] = nil end) end -- Now to make some buffs and put them in a Buffs-dictionary. local Buffs = {"stunbuff",} -- This function creates a new buff-data object and adds it to the Buffs-dictionary -- with the uniqueName as key. local function CreateBuff(uniqueName, duration, applyFunction, removeFunction) local newBuff = {} newBuff.uniqueName = uniqueName newBuff.duration = duration newBuff.applyFunction = applyFunction newBuff.removeFunction = removeFunction Buffs[uniqueName] = newBuff end -- This is an example of how to use the CreateBuff() function to create a new buff. CreateBuff("stunbuff", 5.0, function(inst) -- Apply all your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them.-- Store the current maxhealth in a variable. -- Add 0% speed boost in all situations inst.components.locomotor:SetExternalSpeedMultiplier(inst, "stunkey", 0) end, function(inst) -- Revert your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them. -- Remove speed bonus. inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "stunkey") end ) TheInput = GLOBAL.TheInput local KEY_Z = GLOBAL.KEY_Z TheInput:AddKeyDownHandler(KEY_Z, function() ApplyBuff(Buffs["stunbuff"], inst) end)   Edited April 11, 2020 by MrDoge124 Added code Link to comment Share on other sites More sharing options...
Ultroman Posted April 12, 2020 Share Posted April 12, 2020 14 hours ago, MrDoge124 said: I think I'm missing something, because I get this error when I press the key I think I'm just being stupid here, but I'm not sure what is wrong.  Hide contents TheInput:AddKeyDownHandler(KEY_Z, function() ApplyBuff(Buffs["stunbuff"], inst) end)   In a keyhandler function like this, there is no inst in the scope. You need to educate yourself on scopes, if you want to understand what's happening here. When you want to use a variable, it has to be available in the scope you're currently working in. In this case, you're using a keyhandler-function which takes a key and a function, The function cannot have any parameters, so the only things you have access to in there are any local variables you might have next to it. In modmain there is no inst. This code is not meant for modmain. Not in the way you've used it, at least. It's supposed to go in the Lua file for your character/item. Take a step back, educate yourself on scopes and perhaps revisit the Lua Crash Course you can find in the newcomer post and perhaps just read some of the tutorials. The ones about character perks are very informative. Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 13, 2020 Author Share Posted April 13, 2020 So I got it to find other things and the basics work Here is what I did to get it to work. (It probably isn't very efficient.) Spoiler -- This is an example of how to use the CreateBuff() function to create a new buff. CreateBuff("stunbuff", 5.0, function(inst) -- Apply all your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them.-- Store the current maxhealth in a variable. -- Add 0% speed boost in all situations local x, y, z = inst.Transform:GetWorldPosition() local range = 5 local ents = TheSim:FindEntities(x, y, z, range, { "_combat"}, { "player", "structure", "INLIMBO", "NOCLICK" }, {"hostile", "pig"}) for i, ent in ipairs(ents) do --local ds = ent.entity:GetDebugString() --local tagsstr = string.match(ds, "Tags: ([^\n]+)\n") --print(tagsstr) ent.components.locomotor:SetExternalSpeedMultiplier(inst, "stunkey", 0) end end, function(inst) -- Revert your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them. -- Remove speed bonus. local x, y, z = inst.Transform:GetWorldPosition() local range = 45 local ents = TheSim:FindEntities(x, y, z, range, { "_combat"}, { "player", "structure", "INLIMBO", "NOCLICK" }, { "hostile", "pig"}) for i, ent in ipairs(ents) do --local ds = ent.entity:GetDebugString() --local tagsstr = string.match(ds, "Tags: ([^\n]+)\n") --print(tagsstr) ent.components.locomotor:RemoveExternalSpeedMultiplier(inst, "stunkey") end end ) Â I'm not sure how to get cool downs to work and the effects to the character. (Turning off the light and the sanity penalty.) Link to comment Share on other sites More sharing options...
Ultroman Posted April 14, 2020 Share Posted April 14, 2020 You're approaching this the wrong way. Perhaps I didn't explain properly. The CreateBuff function just adds a single timed buff effect on a single entity. You should not be looking for entities around you inside the ApplyBuff function. That function ONLY has to apply the buff, and ONLY to the inst given to the CreateBuff. What you're supposed to do, is where you attack or wherever you want to trigger this buff, you do a FindEntities-call, and then call CreateBuff on the entities that are eligible for it. Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 16, 2020 Author Share Posted April 16, 2020 Ok I got it to work with some help from a friend. Here is the code Spoiler -- This function is rather complicated. You don't need to change anything in here. local function ApplyBuff(buffData, instToBuff, ents) --print(ents) local buffUniqueName = buffData.uniqueName -- Cancel any existing duplicate timed buff. if instToBuff[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(instToBuff, ents) instToBuff[buffUniqueName.."Task"]:Cancel() instToBuff[buffUniqueName.."Task"] = nil end -- Make sure that our buff is removed BEFORE the entity is saved (the server is closed or player quits). -- This is only necessary if you change variables which are saved, like current health, health-penalty, etc. -- Without it, you could apply a max-health buff, quit before it ran out, rejoin, and you would have kept -- the extra max health! local buffOnSave = function(self, inst, data) if inst[buffUniqueName.."Task"] ~= nil then buffData.removeFunction(inst, ents) inst[buffUniqueName.."Task"]:Cancel() inst[buffUniqueName.."Task"] = nil end end if instToBuff.OnSave ~= nil then local oldOnSave = instToBuff.OnSave instToBuff.OnSave = function(self, inst, data) buffOnSave(self, inst, data) oldOnSave(self, inst, data) end else instToBuff.OnSave = buffOnSave end -- Apply the buff. buffData.applyFunction(instToBuff, ents) -- Set up removal after a certain amount of time. instToBuff[buffUniqueName.."Task"] = instToBuff:DoTaskInTime(buffData.duration, function(inst) buffData.removeFunction(inst, ents) inst[buffUniqueName.."Task"] = nil end) end -- Now to make some buffs and put them in a Buffs-dictionary. local Buffs = {"stunbuff",} -- This function creates a new buff-data object and adds it to the Buffs-dictionary -- with the uniqueName as key. local function CreateBuff(uniqueName, duration, applyFunction, removeFunction) local newBuff = {} newBuff.uniqueName = uniqueName newBuff.duration = duration newBuff.applyFunction = applyFunction newBuff.removeFunction = removeFunction Buffs[uniqueName] = newBuff end -- This is an example of how to use the CreateBuff() function to create a new buff. CreateBuff("stunbuff", 5.0, function(inst, ents) -- Apply all your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them.-- Store the current maxhealth in a variable. -- Add 0% speed boost in all situations for i, ent in ipairs(ents) do --local ds = ent.entity:GetDebugString() --local tagsstr = string.match(ds, "Tags: ([^\n]+)\n") --print(tagsstr) ent.components.locomotor:SetExternalSpeedMultiplier(inst, "stunkey", 0) if ent.brain then ent.brain:Stop() end end end, function(inst, ents) -- Revert your buff code here -- Remember to always check whether the components you want to change are actually present on the -- entity before you try to mess with them. -- Remove speed bonus. for i, ent in ipairs(ents) do ent.components.locomotor:RemoveExternalSpeedMultiplier(inst, "stunkey") if ent.brain then ent.brain:Start() end end end ) TheInput:AddKeyDownHandler(KEY_Z, function() local x, y, z = inst.Transform:GetWorldPosition() local range = 5 local ents = TheSim:FindEntities(x, y, z, range, { "_combat"}, { "player", "structure", "INLIMBO", "NOCLICK" }, {"hostile", "pig"}) --Find Entity nearby if not chargeincooldown and inst.components.sanity.current > 10 and table.getn(ents) > 0 then --If chargeincooldown is false and current sanity is larger than 10 and there is more that 0 entities nearby chargeincooldown = true --Disable the move by starting the cooldown ApplyBuff(Buffs["stunbuff"], inst, ents) --Run the apply buff function, inputting the entity table. God only knows how the rest of the function works. inst.components.sanity.current = inst.components.sanity.current - 10 --Remove 10 sanity inst.SoundEmitter:PlaySound("dontstarve/characters/green/stun") inst.Light:SetIntensity(0.75) inst.Light:SetFalloff(.1) inst.Light:SetRadius(1.5)--Deal with lighting inst:DoTaskInTime(0.2, function() inst.Light:Enable (false)--Hide light after 1 second end) --Reset everything after 15 seconds inst:DoTaskInTime(480, function() inst.Light:SetIntensity(.75) inst.Light:SetFalloff(.5) inst.Light:SetRadius(0.8) inst.Light:Enable (true) chargeincooldown = false end) end end) end  Also the keyhandler.lua which goes in a components folder in scripts. Spoiler local KeyHandler = Class(function(self, inst) self.inst = inst self.handler = TheInput:AddKeyHandler(function(key, down) self:OnRawKey(key, down) end ) end) function KeyHandler:OnRawKey(key, down) local player = ThePlayer if (key and not down) and not IsPaused() then player:PushEvent("keypressed", {inst = self.inst, player = player, key = key}) elseif key and down and not IsPaused() then player:PushEvent("keydown", {inst = self.inst, player = player, key = key}) end end function KeyHandler:AddActionListener(Namespace, Key, Action) self.inst:ListenForEvent("keypressed", function(inst, data) if data.inst == ThePlayer then if data.key == Key then if TheWorld.ismastersim then ThePlayer:PushEvent("keyaction"..Namespace..Action, { Namespace = Namespace, Action = Action, Fn = MOD_RPC_HANDLERS[Namespace][MOD_RPC[Namespace][Action].id] }) else SendModRPCToServer( MOD_RPC[Namespace][Action] ) end end end end) if TheWorld.ismastersim then self.inst:ListenForEvent("keyaction"..Namespace..Action, function(inst, data) if not data.Action == Action and not data.Namespace == Namespace then return end data.Fn(inst) end, self.inst) end end return KeyHandler  Thank you for the help! I'm sorry if i was being a pain. 1 Link to comment Share on other sites More sharing options...
Ultroman Posted April 16, 2020 Share Posted April 16, 2020 Looks about right  Good job! 1 Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 18, 2020 Author Share Posted April 18, 2020 Sorry to bother you but it doesn't seem to work when I enable caves. I think this might be because I don't have any networking code and I have no idea how to do that... Any help would be appreciated. Link to comment Share on other sites More sharing options...
Ultroman Posted April 24, 2020 Share Posted April 24, 2020 Look at the character mod tutorials. You have to make sure that no Add***PostInit functions are called on clients, and that no components are added to entities on clients. Look through the character and item tutorials to see how it works. Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 25, 2020 Author Share Posted April 25, 2020 I'm not sure what to do. I've looked at other aoe attacks and they seem to have stuff like "SendRPCToServer" and the code mentions actions. I've attached the code I'm using right now if you need it. green.lua Link to comment Share on other sites More sharing options...
Ultroman Posted April 26, 2020 Share Posted April 26, 2020 I can't really help without knowing what error it encountered and having the full file (because the errors are logged with line numbers). Also, the indentation of your code makes it difficult to read, so the only thing I'm seeing that's out of place, is that you add the "green" tag in the master_postinit, and tags should usually be added in the common_postinit, so they get added on both the server and the client. I don't know why the other AoE attacks use SendRPCToServer. Maybe they set up completely new actions for their attacks and do some syncing using RPCs. I don't know. I don't think you'll need that for this. Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 26, 2020 Author Share Posted April 26, 2020 (edited) When I enable caves it does nothing, no errors. Nothing is printed even if I tell it to print something. I think something isn't being triggered properly. My best guess is the "TheInput:AddKeyDownHandler(KEY_Z, function()" part isn't working right as nothing happens when I press Z. I might have to add an action for the attack, but I'm not sure how that works. I've found an example where actions are used and it seems to work fine. Edited April 26, 2020 by MrDoge124 Added information Link to comment Share on other sites More sharing options...
Ultroman Posted April 26, 2020 Share Posted April 26, 2020 The AddKeyDownHandler-part should only happen on the client or if the host is not a dedicated server. I haven't seen your modmain.lua file, so I can't tell you what's wrong with it. Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 26, 2020 Author Share Posted April 26, 2020 Ok I'll send you the modmain.lua modmain.lua Link to comment Share on other sites More sharing options...
Ultroman Posted April 26, 2020 Share Posted April 26, 2020 Since your keyhandler is in master_postinit, it is only added on the server. I'm not too knowledgeable on keyhandlers and where to put them, so try looking at other character mods which have keyhandlers, to see how and where they add these keyhandlers so they work correctly. Link to comment Share on other sites More sharing options...
MrDoge124 Posted April 26, 2020 Author Share Posted April 26, 2020 I've looked at other examples and they all seem to use an action handler. I'm going to have to look into this and either figure out how these things work or try to find another way to do it. Link to comment Share on other sites More sharing options...
Ultroman Posted April 26, 2020 Share Posted April 26, 2020 Try looking into it, but otherwise make a new thread for this specific problem. I'm sure someone else will come along and help. This thread looks to other people like it's already being handled. 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