Jump to content

Recommended Posts

Hi.

I tried to search the forum first, but I couldn't find it because the English was immature. sorry.

I'm making a mod to add new magic books and science tools.

I have successfully created an animation that will come out when I use the book with the help of someone who was kind last time.

And now I want to add effects to the animation.

For example, I want to give unique ability to each animation, such as fire, wet, damage, bloodsucking, freezing, healing...

Since I don't know the lua script, I refer to data files of DST.

So I referenced several files, such as lightning and fire, but I have not found a way to add each effect I want.

Please, Could you tell me how to add effects, or can you give me a guide to help?

Thank you for reading and I look forward to your help.

Thanks again.

Can I ask why you aren't learning LUA scripting, since you're trying to make mods in LUA? That's like trying to do a Le Mans on foot. What you want to do is pretty complicated, and you're going to be messing around with game code and adding things to the game. It doesn't take many hours to get a good grasp of LUA, and maybe a few days to get a grasp of the data structures (lists etc.) and caveats. Especially if you want to offer this mod to other people e.g. on the Steam Workshop, you kind of owe it to them to do it right, and that's not going to happen if you don't learn LUA and intensely study existing and highly acclaimed mods, in order to accumulate knowledge about how things are done properly.

I highly advise you to take this LUA crash course and more tutorials like that, and read through this thread for a lot of tips on modding. Even the things you're not sure you'll need. You won't know when you'll need that information, and if you've read about it you'll probably remember that you've read about it in that thread when you run into it, and can go find it.

Also, I have no idea what you actually want to accomplish. You say you've created an animation that will come out when you use the book. Does that mean you've made the book item, and made it play the animation? What's the point of the books? Are they spellbooks which you can equip as a weapon, and then their attack is going to be a spell? Is that what you're talking about with fire, wet, damage, bloodsucking etc.?

Please give a more detailed description of the current state of your mod and exactly what you want to achieve. Perhaps start by describing one book, and start by making that. It'll make everything simpler, and then later you can duplicate that working book to make more books with other effects. It also always helps us to see what's going on, if you attach a zip-file with your mod in its current state whenever you've made changes to it and want to ask a question.

I wish you all the luck and power in your ventures :)

Edited by Ultroman
6 hours ago, Ultroman said:

Can I ask why you aren't learning LUA scripting, since you're trying to make mods in LUA? That's like trying to do a Le Mans on foot. What you want to do is pretty complicated, and you're going to be messing around with game code and adding things to the game. It doesn't take many hours to get a good grasp of LUA, and maybe a few days to get a grasp of the data structures (lists etc.) and caveats. Especially if you want to offer this mod to other people e.g. on the Steam Workshop, you kind of owe it to them to do it right, and that's not going to happen if you don't learn LUA and intensely study existing and highly acclaimed mods, in order to accumulate knowledge about how things are done properly.

I highly advise you to take this LUA crash course and more tutorials like that, and read through this thread for a lot of tips on modding. Even the things you're not sure you'll need. You won't know when you'll need that information, and if you've read about it you'll probably remember that you've read about it in that thread when you run into it, and can go find it.

Also, I have no idea what you actually want to accomplish. You say you've created an animation that will come out when you use the book. Does that mean you've made the book item, and made it play the animation? What's the point of the books? Are they spellbooks which you can equip as a weapon, and then their attack is going to be a spell? Is that what you're talking about with fire, wet, damage, bloodsucking etc.?

Please give a more detailed description of the current state of your mod and exactly what you want to achieve. Perhaps start by describing one book, and start by making that. It'll make everything simpler, and then later you can duplicate that working book to make more books with other effects. It also always helps us to see what's going on, if you attach a zip-file with your mod in its current state whenever you've made changes to it and want to ask a question.

I wish you all the luck and power in your ventures :)

Thanks for reply.

First, There is no particular reason why I didn't learn the lua script.

I just wanted to make the mod quickly.

I have received your reply and will now learn the lua script for my mod.

Now I will tell you a bit more about the question I have made.

I uploaded a video for reference.

In the video, the character uses the book, and the animation that wasn't in DST appears.

As shown in the video, I made several new animations.

But now these animations have no ability.

So I want to give each of these animations the ability.

For example, in a video, a flame animation appears, which I want to give damage to this animation and also make the enemy burn.

Like the effects of lightning.

In addition, I made various animations such as ice, wind... so I want abilities to suit them.

Regardless of the question, I will now study the lua script.

Thanks.

ex.mp4

I'm glad to hear you'll be studying LUA. Learning one coding language will make any future ones easier, I promise you. Learning to code is sort of freeing TBH. I can make my computer do whatever I want, and I can mod for basically any mod-friendly game I want; and there are a lot of them. Coding also gives you a great insight into how computers work, and will help you understand how things you use in your daily life work. It's even mentioned on a lot of job listings as a plus to have just any kind of coding or scripting experience, just because technology is creeping into more and more disciplines. It's also very rewarding to see something work, which you've built from scratch :)

That's a pretty cool video! For that effect, it'll be (almost) simple. You seem to have some code which spawns the animation at certain points. What you want to do, is:

  • Define the radius within which you wish it to apply damage
  • Determine how much damage it should apply to living things and "workable" things (buildings, rocks, trees etc.) (as a bonus, you could decrease the damage the further away the enemy is from the center of the animation; NOTE: this is not part of the example code below)
  • Define which entities should be hit by this spell. Does it only hit hostile creatures? Does it damage players? Buildings? Trees, foliage, ice-chunks, etc.?
  • Does it ignite things?
  • Is it to be labelled as an explosion? This makes it have a screenshake and damage is resisted by certain entities.

For each spawned animation, call this custom function (stolen from explosive.lua, and customized a lot). You should be able to use this for many of your effects. Lightning is another story, and a square- or cone-shaped damage area is a totally other thing. This should get you far, though. Try to study it and really understand what is going on. Just go slowly, one line at the time.

-- x, y and z -- numbers; should be filled with the position you use for placing the animations.
-- damageRange -- number; range of the explosion. For reference, the range of science machines is 4.
-- damageToLivingEntities -- number; damage to any entity with a combat-component
-- doDamageToNonCombatants -- boolean; should we also do damage to non.combatants like rabbits etc?
-- workableDamage -- number; damage to workable entities e.g. buildings, rocks, trees etc.
-- isExplosion -- boolean; should this be labelled as an explosion? Adds screen shake when the damage is applied,
-- and some entities have resistance to damage from explosions.
-- ignite -- boolean; should the damage set fire to things it hits?
-- In order to use any of the ***Tags parameters, put in a list e.g. {"firstTag", "secondTag"}. To ignore their limitations,
-- put in nil instead e.g. setting them all to nil includes all entities.

local doAreaDamage = function(x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants,
workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
	-- Description of important function:
	-- TheSim:FindEntities(x, y, z, radius, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
	-- x, y and z should be filled with the position you use for placing the animations.
	-- In order to use any of the ***Tags parameters, just replace nil for either of them with a list e.g. {"tag1", "tag2"}
	-- Putting in nil for either, completely skips the check for them, so omitting all of them simply includes all entities.
	-- In this example, we include every kind of entity, unless they have the tag "INLIMBO".
	local ents = TheSim:FindEntities(x, y, z, damageRange, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)

	-- ents is now a list of all the entities within the range, which do not have the tag "INLIMBO".
	-- Run over all these entities, and see if we should do damage to them.
	for i, v in ipairs(ents) do
		if v ~= self.inst and v:IsValid() and not v:IsInLimbo() then
			-- Do "damage" to workable things, like rocks, trees, buildings etc.
			if workableDamage > 0 and 
			v.components.workable ~= nil and v.components.workable:CanBeWorked() then
				v.components.workable:WorkedBy(self.inst, workableDamage)
			end

			-- Recheck valid after work
			if v:IsValid() and not v:IsInLimbo() then
				-- If the explosion should set things on fire, do some checks to see if the entity CAN be set on fire,
				-- and if so, call Ignite() on them.
				if ignite and
					v.components.fueled == nil and
					v.components.burnable ~= nil and
					not v.components.burnable:IsBurning() and
					not v:HasTag("burnt") then
					v.components.burnable:Ignite()
				end
				
-- Now we want to do damage to all combatants.
-- If you want to be able to hit any living entity (with a health-component), just remove v.components.combat ~= nil.
-- This will then deal damage to e.g. rabbits as well, instead of only entities which can fight back.
-- In that case, though, you need to directly remove health from them, since they don't have a combat-component to
-- call GetAttacked on. Instead you must do v.components.health:DoDelta(damageToLivingEntities, true).
-- If you want to do that, you should put in an if-statement which does it correctly for combatants, and then differently
				if v.components.health ~= nil and not v.components.health:IsDead() then
					local dmg = damageToLivingEntities
					if isExplosion and v.components.explosiveresist ~= nil then
						dmg = dmg * (1 - v.components.explosiveresist:GetResistance())
						v.components.explosiveresist:OnExplosiveDamage(dmg, self.inst)
					end
					if v.components.combat ~= nil then
						v.components.combat:GetAttacked(self.inst, dmg, nil)
					elseif doDamageToNonCombatants then
						v.components.health:DoDelta(damageToLivingEntities)
					end
				end
				if isExplosion then
					v:PushEvent("explosion", { explosive = self.inst })
				end
			end
		end
	end
end

-- Example usage:
-- Does 50 damage in a radius of 8 at position (0,0,0), doing damage to non-combatants as well, 0 damage to
-- "workables", with screenshake (isExplosion) and ignition turned on, to all entities which do not have the "INLIMBO" tag.
doAreaDamage(0, 0, 0, 8, 50, true, 0, true, true, nil, {"INLIMBO"}, nil)

 

Edited by Ultroman
  • Like 1
11 hours ago, Ultroman said:

I'm glad to hear you'll be studying LUA. Learning one coding language will make any future ones easier, I promise you. Learning to code is sort of freeing TBH. I can make my computer do whatever I want, and I can mod for basically any mod-friendly game I want; and there are a lot of them. Coding also gives you a great insight into how computers work, and will help you understand how things you use in your daily life work. It's even mentioned on a lot of job listings as a plus to have just any kind of coding or scripting experience, just because technology is creeping into more and more disciplines. It's also very rewarding to see something work, which you've built from scratch :)

That's a pretty cool video! For that effect, it'll be (almost) simple. You seem to have some code which spawns the animation at certain points. What you want to do, is:

  • Define the radius within which you wish it to apply damage
  • Determine how much damage it should apply to living things and "workable" things (buildings, rocks, trees etc.) (as a bonus, you could decrease the damage the further away the enemy is from the center of the animation; NOTE: this is not part of the example code below)
  • Define which entities should be hit by this spell. Does it only hit hostile creatures? Does it damage players? Buildings? Trees, foliage, ice-chunks, etc.?
  • Does it ignite things?
  • Is it to be labelled as an explosion? This makes it have a screenshake and damage is resisted by certain entities.

For each spawned animation, call this custom function (stolen from explosive.lua, and customized a lot). You should be able to use this for many of your effects. Lightning is another story, and a square- or cone-shaped damage area is a totally other thing. This should get you far, though. Try to study it and really understand what is going on. Just go slowly, one line at the time.


-- x, y and z -- numbers; should be filled with the position you use for placing the animations.
-- damageRange -- number; range of the explosion. For reference, the range of science machines is 4.
-- damageToLivingEntities -- number; damage to any entity with a combat-component
-- doDamageToNonCombatants -- boolean; should we also do damage to non.combatants like rabbits etc?
-- workableDamage -- number; damage to workable entities e.g. buildings, rocks, trees etc.
-- isExplosion -- boolean; should this be labelled as an explosion? Adds screen shake when the damage is applied,
-- and some entities have resistance to damage from explosions.
-- ignite -- boolean; should the damage set fire to things it hits?
-- In order to use any of the ***Tags parameters, put in a list e.g. {"firstTag", "secondTag"}. To ignore their limitations,
-- put in nil instead e.g. setting them all to nil includes all entities.

local doAreaDamage = function(x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants,
workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
	-- Description of important function:
	-- TheSim:FindEntities(x, y, z, radius, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
	-- x, y and z should be filled with the position you use for placing the animations.
	-- In order to use any of the ***Tags parameters, just replace nil for either of them with a list e.g. {"tag1", "tag2"}
	-- Putting in nil for either, completely skips the check for them, so omitting all of them simply includes all entities.
	-- In this example, we include every kind of entity, unless they have the tag "INLIMBO".
	local ents = TheSim:FindEntities(x, y, z, damageRange, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)

	-- ents is now a list of all the entities within the range, which do not have the tag "INLIMBO".
	-- Run over all these entities, and see if we should do damage to them.
	for i, v in ipairs(ents) do
		if v ~= self.inst and v:IsValid() and not v:IsInLimbo() then
			-- Do "damage" to workable things, like rocks, trees, buildings etc.
			if workableDamage > 0 and 
			v.components.workable ~= nil and v.components.workable:CanBeWorked() then
				v.components.workable:WorkedBy(self.inst, workableDamage)
			end

			-- Recheck valid after work
			if v:IsValid() and not v:IsInLimbo() then
				-- If the explosion should set things on fire, do some checks to see if the entity CAN be set on fire,
				-- and if so, call Ignite() on them.
				if ignite and
					v.components.fueled == nil and
					v.components.burnable ~= nil and
					not v.components.burnable:IsBurning() and
					not v:HasTag("burnt") then
					v.components.burnable:Ignite()
				end
				
-- Now we want to do damage to all combatants.
-- If you want to be able to hit any living entity (with a health-component), just remove v.components.combat ~= nil.
-- This will then deal damage to e.g. rabbits as well, instead of only entities which can fight back.
-- In that case, though, you need to directly remove health from them, since they don't have a combat-component to
-- call GetAttacked on. Instead you must do v.components.health:DoDelta(damageToLivingEntities, true).
-- If you want to do that, you should put in an if-statement which does it correctly for combatants, and then differently
				if v.components.health ~= nil and not v.components.health:IsDead() then
					local dmg = damageToLivingEntities
					if isExplosion and v.components.explosiveresist ~= nil then
						dmg = dmg * (1 - v.components.explosiveresist:GetResistance())
						v.components.explosiveresist:OnExplosiveDamage(dmg, self.inst)
					end
					if v.components.combat ~= nil then
						v.components.combat:GetAttacked(self.inst, dmg, nil)
					elseif doDamageToNonCombatants then
						v.components.health:DoDelta(damageToLivingEntities)
					end
				end
				if isExplosion then
					v:PushEvent("explosion", { explosive = self.inst })
				end
			end
		end
	end
end

-- Example usage:
-- Does 50 damage in a radius of 8 at position (0,0,0), doing damage to non-combatants as well, 0 damage to
-- "workables", with screenshake (isExplosion) and ignition turned on, to all entities which do not have the "INLIMBO" tag.
doAreaDamage(0, 0, 0, 8, 50, true, 0, true, true, nil, {"INLIMBO"}, nil)

 

Thanks again for the reply.

I really appreciate your kindness.

I'm studying the lua script now, but I don't know what tags and events and others exist in DST

I still don't know how to apply the script to DST modding,

But I think that if I study this more, And I find the questions in the forum, I will know how.

Now I'll tell you why I wrote again.

Before I studied the lua script, I tried using the scripts you gave me.

Since I don't know lua yet, I used it as it is.

But I got an error '<name> or '...' exported' in 'DoAreaDamage (x, y, z, damageRange...)'

I corrected the error by referring to other people's mods and DST's script files.

But there was another problem.

In the game, pigman follows the animation.

I think pigman seems to think of my animation as fire.

But my animation doesn't show any other ability.

Damage, burning, all...

I will do my best to solve the problem myself.

However, if you don't mind, I'd like to ask you a little more about my problem.

I still think I'm bothering you enough.

I'm really sorry about that.

Thanks again for your kind reply.

I have received your kindness and help, and I hope that you will be filled with good things in your path.

Below is my script.

I didn't get out of your example scripts and I modified these things.

Quote

local assets =
{
    Asset("ANIM", "anim/flameflower.zip"),
    Asset("SOUND", "sound/common.fsb"),
}

local function kill_sound(inst)
    inst.SoundEmitter:KillSound("staff_star_loop")
end

local function ontimer(inst, data)
    
    inst:ListenForEvent("animover", kill_sound)
    inst:DoTaskInTime(0.08, inst.Remove)
    
end

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddLight()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst.Transform:SetScale(1, 1, 1)

    inst.AnimState:SetLightOverride(1)
    inst.AnimState:SetBank("flameflower")
    inst.AnimState:SetBuild("flameflower")
    inst.AnimState:PlayAnimation("idle")

    inst.SoundEmitter:PlaySound("dontstarve/common/blackpowder_explo")
    
    inst:AddComponent("timer")
    inst.components.timer:StartTimer("extinguish", 0.8)
    inst:ListenForEvent("timerdone", ontimer)

    return inst
end

local function DoAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
    
    local ents = TheSim : FindEntities (0, 0, 0, 20, nil, { "INLIMBO"}, nil)
    
    for i, v in ipairs(ents) do
        if v ~= inst and v:IsValid() and not v:IsInLimbo() then
        
            if v:IsValid() and not v:IsInLimbo() then
            
                if v ~= inst and v:IsValid() and not v:IsInLimbo() then
                    if workableDamage > 0 and 
                        v.components.workable ~= nil and v.components.workable:CanBeWorked() then
                        v.components.workable:WorkedBy(inst, workableDamage, nil)
                    end
                    
                    if ignite and
                        v.components.fueled == nil and
                        v.components.burnable ~= nil and
                        not v.components.burnable:IsBurning() and
                        not v:HasTag("burnt") then
                        v.components.burnable:Ignite()
                    end
            
                    if v.components.health ~= nil and not v.components.health:IsDead() then
                        if v.components.combat ~= nil then
                        v.components.combat:GetAttacked(inst, damageToLivingEntities, nil)
                        elseif doDamageToNonCombatants then
                        v.components.health:DoDelta(inst, damageToLivingEntities, nil)
                        end
                    end
                end
            end
        end
    end
end

DoAreaDamage (0, 0, 0, 20, 100, true, 100, false, true, nil, { "INLIMBO"}, nil)
    
return Prefab("flameflower", fn, assets)

 

Yeah, you still need some LUA training :)

Give it some time. It'll be fun :D To figure out how things work, get into the language first, and then start looking at other people's mods. See how they do things. Investigate. Look at the game code. If you take the time to read the code and understand what is happening, you'll slowly get it.

This should work. I don't know why the pigs follow your flames.

local assets =
{
    Asset("ANIM", "anim/flameflower.zip"),
    Asset("SOUND", "sound/common.fsb"),
}

local function doAreaDamage(x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
    
    local ents = TheSim:FindEntities(0, 0, 0, 20, nil, {"INLIMBO"}, nil)
    
    for i, v in ipairs(ents) do
        if v ~= inst and v:IsValid() and not v:IsInLimbo() then
        
            if v:IsValid() and not v:IsInLimbo() then
            
                if v ~= inst and v:IsValid() and not v:IsInLimbo() then
                    if workableDamage > 0 and 
                        v.components.workable ~= nil and v.components.workable:CanBeWorked() then
                        v.components.workable:WorkedBy(inst, workableDamage, nil)
                    end
                    
                    if ignite and
                        v.components.fueled == nil and
                        v.components.burnable ~= nil and
                        not v.components.burnable:IsBurning() and
                        not v:HasTag("burnt") then
                        v.components.burnable:Ignite()
                    end
            
                    if v.components.health ~= nil and not v.components.health:IsDead() then
                        if v.components.combat ~= nil then
                        v.components.combat:GetAttacked(inst, damageToLivingEntities, nil)
                        elseif doDamageToNonCombatants then
                        v.components.health:DoDelta(inst, damageToLivingEntities, nil)
                        end
                    end
                end
            end
        end
    end
end

local function kill_sound(inst)
    inst.SoundEmitter:KillSound("staff_star_loop")
end

local function ontimer(inst, data)
    
    inst:ListenForEvent("animover", kill_sound)
    inst:DoTaskInTime(0.08, inst.Remove)
    
end

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddLight()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst.Transform:SetScale(1, 1, 1)

    inst.AnimState:SetLightOverride(1)
    inst.AnimState:SetBank("flameflower")
    inst.AnimState:SetBuild("flameflower")
    inst.AnimState:PlayAnimation("idle")

    inst.SoundEmitter:PlaySound("dontstarve/common/blackpowder_explo")
    
    inst:AddComponent("timer")
    inst.components.timer:StartTimer("extinguish", 0.8)
    inst:ListenForEvent("timerdone", ontimer)
	
	local x, y, z = inst.Transform:GetWorldPosition()
	doAreaDamage (x, y, z, 20, 100, true, 100, false, true, nil, { "INLIMBO"}, nil)

    return inst
end
    
return Prefab("flameflower", fn, assets)

 

I've been trying to work around your suggestion but maybe I'm totally off track here and it's not how this should be :-(. I'm making this special attack for my character, I wants it to deal AOE damage to creatures around the target when the attack hit. I have removed all the unnecessary parts about hitting workable and explosive or ignite because it's an ice attack. This is in my character.lua.

So I press a button to charge it

local function powerready(inst)
	if not inst.components.inventory.equipslots[EQUIPSLOTS.HANDS] then 
		return
	end
	local item = inst.components.inventory.equipslots[EQUIPSLOTS.HANDS].prefab
	if item ~= "boomerang"
    and item ~= "blowdart_sleep"
    and item ~= "blowdart_fire"
    and item ~= "blowdart_pipe"
    and item ~= "blowdart_yellow"
    and item ~= "blowdart_walrus"
    and item ~= "waterballoon"
    and item ~= "sleepbomb"
    then
	    inst.components.king.power = 1
		inst.powerfx = SpawnPrefab("deer_ice_charge")
	    inst.powerfx.entity:AddFollower()
	    inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 30, -150, 0)
	    if item == "umbrella" or item == "grass_umbrella" then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", -10, -380, 0)
	    end
	    if item == "shovel" or item == "goldenshovel" or item == "pitchfork" then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 0, 130, 0)
	    end
	    if item == "swordcane" then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 0, -150, 0)
	    end
	    if item == "totooriastaff1"
	    	or item == "totooriastaff2"
	    	or item == "totooriastaff3"
	    	or item == "totooriastaff4"
	    	or item == "totooriastaff5green"
	    	or item == "totooriastaff5orange"
	    	or item == "totooriastaff5yellow"
    	then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 0, -185, 0)
	    end
		inst.components.combat.damagemultiplier = inst.components.king.level*5/150 + 4
		inst.components.talker:Say("Here come the big FINALE!!")
	end
end

Then attack an enemy, This is I want it to be an AOE when hit. 

local function doAreaDamage(x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
local ents = TheSim:FindEntities(x, y, z, 6,  nil, {"INLIMBO"}, {"player"})
	for i, v in ipairs(ents) do
		if v:IsValid() and not v:IsInLimbo() then
				if v.components.health ~= nil and not v.components.health:IsDead() then
					local dmg = damageToLivingEntities
					if doDamageToNonCombatants then
						v.components.health:DoDelta(damageToLivingEntities)
					end
				end
			end
		end
	end

local function hitother(inst)
	if inst.components.king.power == 1 and inst.components.combat.target and inst.components.combat.target:IsValid() then
		if inst.components.rider:IsRiding() then return end
		inst.components.king.power = 0
	    SpawnPrefab("icing_splash_fx_full").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icing_splash_fx_med").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icing_splash_fx_low").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icing_splash_fx_melted").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("crabking_feeze").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("crabking_ring_fx").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_1").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_2").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_3").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_4").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("splash_snow_fx").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("spawn_fx_small_high").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("groundpoundring_fx").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		local x, y, z = inst.components.combat.target.Transform:GetWorldPosition()
		doAreaDamage (x, y, z, 5, 100, nil, {"INLIMBO"}, {"player"})
	    inst.powerfx:Remove()
	    inst.fxout = SpawnPrefab("deer_ice_burst")
		inst.fxout.entity:SetParent(inst.entity)
		inst.fxout.entity:AddFollower()
    	inst.fxout.Follower:FollowSymbol(inst.GUID, "swap_body", 0, 0, 0)
		inst.SoundEmitter:PlaySound("dontstarve/common/fireOut")
		inst.components.combat.damagemultiplier = 1
		if inst.components.hunger.current <= 0 then
        	inst.components.health:DoDelta(-40)
        end
		inst.components.hunger:DoDelta(-40)
		inst.components.sanity:DoDelta(-20)

	end
end

Please tell me if it's possible to do it this way or I should try other methods. I will continous to learn more. For now this code works without error but the attack stayed the same. 

Thank you for your kind reply.

On 6/11/2020 at 5:51 PM, KingAlpha said:

I've been trying to work around your suggestion but maybe I'm totally off track here and it's not how this should be :-(. I'm making this special attack for my character, I wants it to deal AOE damage to creatures around the target when the attack hit. I have removed all the unnecessary parts about hitting workable and explosive or ignite because it's an ice attack. This is in my character.lua.

So I press a button to charge it


local function powerready(inst)
	if not inst.components.inventory.equipslots[EQUIPSLOTS.HANDS] then 
		return
	end
	local item = inst.components.inventory.equipslots[EQUIPSLOTS.HANDS].prefab
	if item ~= "boomerang"
    and item ~= "blowdart_sleep"
    and item ~= "blowdart_fire"
    and item ~= "blowdart_pipe"
    and item ~= "blowdart_yellow"
    and item ~= "blowdart_walrus"
    and item ~= "waterballoon"
    and item ~= "sleepbomb"
    then
	    inst.components.king.power = 1
		inst.powerfx = SpawnPrefab("deer_ice_charge")
	    inst.powerfx.entity:AddFollower()
	    inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 30, -150, 0)
	    if item == "umbrella" or item == "grass_umbrella" then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", -10, -380, 0)
	    end
	    if item == "shovel" or item == "goldenshovel" or item == "pitchfork" then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 0, 130, 0)
	    end
	    if item == "swordcane" then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 0, -150, 0)
	    end
	    if item == "totooriastaff1"
	    	or item == "totooriastaff2"
	    	or item == "totooriastaff3"
	    	or item == "totooriastaff4"
	    	or item == "totooriastaff5green"
	    	or item == "totooriastaff5orange"
	    	or item == "totooriastaff5yellow"
    	then
	    	inst.powerfx.Follower:FollowSymbol(inst.GUID, "swap_object", 0, -185, 0)
	    end
		inst.components.combat.damagemultiplier = inst.components.king.level*5/150 + 4
		inst.components.talker:Say("Here come the big FINALE!!")
	end
end

Then attack an enemy, This is I want it to be an AOE when hit. 


local function doAreaDamage(x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
local ents = TheSim:FindEntities(x, y, z, 6,  nil, {"INLIMBO"}, {"player"})
	for i, v in ipairs(ents) do
		if v:IsValid() and not v:IsInLimbo() then
				if v.components.health ~= nil and not v.components.health:IsDead() then
					local dmg = damageToLivingEntities
					if doDamageToNonCombatants then
						v.components.health:DoDelta(damageToLivingEntities)
					end
				end
			end
		end
	end

local function hitother(inst)
	if inst.components.king.power == 1 and inst.components.combat.target and inst.components.combat.target:IsValid() then
		if inst.components.rider:IsRiding() then return end
		inst.components.king.power = 0
	    SpawnPrefab("icing_splash_fx_full").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icing_splash_fx_med").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icing_splash_fx_low").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icing_splash_fx_melted").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("crabking_feeze").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("crabking_ring_fx").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_1").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_2").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_3").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("icespike_fx_4").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("splash_snow_fx").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("spawn_fx_small_high").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		SpawnPrefab("groundpoundring_fx").Transform:SetPosition(inst.components.combat.target.Transform:GetWorldPosition())
		local x, y, z = inst.components.combat.target.Transform:GetWorldPosition()
		doAreaDamage (x, y, z, 5, 100, nil, {"INLIMBO"}, {"player"})
	    inst.powerfx:Remove()
	    inst.fxout = SpawnPrefab("deer_ice_burst")
		inst.fxout.entity:SetParent(inst.entity)
		inst.fxout.entity:AddFollower()
    	inst.fxout.Follower:FollowSymbol(inst.GUID, "swap_body", 0, 0, 0)
		inst.SoundEmitter:PlaySound("dontstarve/common/fireOut")
		inst.components.combat.damagemultiplier = 1
		if inst.components.hunger.current <= 0 then
        	inst.components.health:DoDelta(-40)
        end
		inst.components.hunger:DoDelta(-40)
		inst.components.sanity:DoDelta(-20)

	end
end

Please tell me if it's possible to do it this way or I should try other methods. I will continous to learn more. For now this code works without error but the attack stayed the same. 

Thank you for your kind reply.

I'm sorry, I seem to have missed a notification for this.

I'm not sure about the structure of your code, since it's broken up in pieces, but what you've shown so far, does not look like it has proper syntax and structure. You don't seem to end the doAreaDamage function before starting your hitother function.

If this is still relevant, please post your full code where you've tried to implement it.

On 7/9/2020 at 3:34 AM, Ultroman said:

I'm sorry, I seem to have missed a notification for this.

I'm not sure about the structure of your code, since it's broken up in pieces, but what you've shown so far, does not look like it has proper syntax and structure. You don't seem to end the doAreaDamage function before starting your hitother function.

If this is still relevant, please post your full code where you've tried to implement it.

i have some question about that, can you help me?

local function DoAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
    
    local ents = TheSim : FindEntities (0, 0, 0, 20, nil, { "INLIMBO"}, nil)
    
    for i, v in ipairs(ents) do
        if v ~= inst and v:IsValid() and not v:IsInLimbo() then
        
            if v:IsValid() and not v:IsInLimbo() then
            
                if v ~= inst and v:IsValid() and not v:IsInLimbo() then
                    if workableDamage > 0 and 
                        v.components.workable ~= nil and v.components.workable:CanBeWorked() then
                        v.components.workable:WorkedBy(inst, workableDamage, nil)
                    end
                    
                    if ignite and
                        v.components.fueled == nil and
                        v.components.burnable ~= nil and
                        not v.components.burnable:IsBurning() and
                        not v:HasTag("burnt") then
                        v.components.burnable:Ignite()
                    end
            
                    if v.components.health ~= nil and not v.components.health:IsDead() then
                        if v.components.combat ~= nil then
                        v.components.combat:GetAttacked(inst, damageToLivingEntities, nil)
                        elseif doDamageToNonCombatants then
                        v.components.health:DoDelta(inst, damageToLivingEntities, nil)
                        end
                    end
                end
            end
        end
    end

    --Key G AOE
    local function OnKeyDown(inst, data)
	    if data.inst == ThePlayer then
		    if data.key == KEY_G then
			    if data.inst.HUD and (data.inst.HUD:IsChatInputScreenOpen() or data.inst.HUD:IsConsoleScreenOpen()) then return end
		        if TheWorld.ismastersim then
				doAreaDamage(0, 0, 0, 8, 50, true, 0, true, true, nil, {"INLIMBO"}, nil)
			    end
		    end
	    end
    end

 

On 7/9/2020 at 3:34 AM, Ultroman said:

I'm sorry, I seem to have missed a notification for this.

I'm not sure about the structure of your code, since it's broken up in pieces, but what you've shown so far, does not look like it has proper syntax and structure. You don't seem to end the doAreaDamage function before starting your hitother function.

If this is still relevant, please post your full code where you've tried to implement it.

Thank you for the big help from previous replies!
I recently added this chunk under masterpostinit in character.lua.
However I can't even open the server with this command.

What I am currently trying to do is to make my character do explosion AOE when pressing a key (lets call key G here)
However, the server can't even start with this code. (I've attached the whole character.lua for convenience)

I have several question:
-Where should I add the chunks to? (I am very confused about this, character.lua? modmain.lua? under or above masterpostinit of character.lua?)
-If I don't want to make the aoe ignite, could I just remove the chunk below?

if ignite and
                        v.components.fueled == nil and
                        v.components.burnable ~= nil and
                        not v.components.burnable:IsBurning() and
                        not v:HasTag("burnt") then
                        v.components.burnable:Ignite()
                    end

gojo.lua

21 hours ago, Aurorance said:

- If I don't want to make the AoE ignite, could I just remove the chunk below?

You don't need to remove anything to make it not ignite things. If you look at the descriptions for all the function parameters, you'll find a parameter called "ignite" with the following description: ignite -- boolean; should the damage set fire to things it hits?
Simply provide a false value to that boolean parameter, and it should not ignite anything. As you can see, it exits the if-statement as early as it can, if the "ignite" parameter is set to false, so the performance hit of keeping the ignition-code in there is negligible, and you might want it later.

Your problems stem from copy/pasting code where it doesn't belong. There aren't really any clear indicators in the post I wrote about how to use it, so don't beat yourself up about not getting it :) You've also edited my doAreaDamage function to not make use of any of the parameters, so it won't work properly, and also added an OnKeyDown function inside the doAreaDamage function. You also renamed the function to have an uppercase "D", as in "DoAreaDamage" instead of "doAreaDamage", but still called it using the lowercase "d", which will also crash the game. 

I've attached a version where I moved my doAreaDamage function out of your masterpostinit, but left the OnKeyDown function in there, and fixed the naming.

I'm not sure if your OnKeyDown-implementation works, though. I usually see OnKeyDown's implemented in the modmain.lua file, but I have never done any myself, so I don't know if you can put them directly into a character-prefab like this. Make sure it is being called by using a print-statement (see the Newcomer Post if you want to learn about the basics of debugging your code using print-statements).

Note that your call to my function fires the AoE at position 0,0,0, which means you will only notice an effect if you are watching that position when testing and that there is something there that can take damage using your parameters. Note that there are no graphics included in this, just damage to living and structural entities. The best way to test, would probably be to use the current position of the player. You can do that by changing your OnKeyDown to this for testing purposes:

	local function OnKeyDown(inst, data)
		if data.inst == ThePlayer then
			if data.key == KEY_G then
				if data.inst.HUD and (data.inst.HUD:IsChatInputScreenOpen() or data.inst.HUD:IsConsoleScreenOpen()) then return end
				if TheWorld.ismastersim then
					local x,y,z = ThePlayer.Transform:GetWorldPosition()
					-- Parameter list: doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
					doAreaDamage(x, y, z, 8, 50, true, 0, true, true, nil, {"INLIMBO"}, nil)
				end
			end
		end
	end

You also feed in "nil, { "INLIMBO"}, nil" for the tags, which makes it include absolutely everything (except player ghosts), which is probably not what you will want in the end, but I understand if you want to leave it like this for testing purposes.

I hope this answers your questions and that you can make it work. Godspeed in your ventures!

Sincerely, Ultroman the Tacoman

 

gojo.lua

Edited by Ultroman
On 4/19/2021 at 8:33 AM, Ultroman said:

You don't need to remove anything to make it not ignite things. If you look at the descriptions for all the function parameters, you'll find a parameter called "ignite" with the following description: ignite -- boolean; should the damage set fire to things it hits?
Simply provide a false value to that boolean parameter, and it should not ignite anything. As you can see, it exits the if-statement as early as it can, if the "ignite" parameter is set to false, so the performance hit of keeping the ignition-code in there is negligible, and you might want it later.

Your problems stem from copy/pasting code where it doesn't belong. There aren't really any clear indicators in the post I wrote about how to use it, so don't beat yourself up about not getting it :) You've also edited my doAreaDamage function to not make use of any of the parameters, so it won't work properly, and also added an OnKeyDown function inside the doAreaDamage function. You also renamed the function to have an uppercase "D", as in "DoAreaDamage" instead of "doAreaDamage", but still called it using the lowercase "d", which will also crash the game. 

I've attached a version where I moved my doAreaDamage function out of your masterpostinit, but left the OnKeyDown function in there, and fixed the naming.

I'm not sure if your OnKeyDown-implementation works, though. I usually see OnKeyDown's implemented in the modmain.lua file, but I have never done any myself, so I don't know if you can put them directly into a character-prefab like this. Make sure it is being called by using a print-statement (see the Newcomer Post if you want to learn about the basics of debugging your code using print-statements).

Note that your call to my function fires the AoE at position 0,0,0, which means you will only notice an effect if you are watching that position when testing and that there is something there that can take damage using your parameters. Note that there are no graphics included in this, just damage to living and structural entities. The best way to test, would probably be to use the current position of the player. You can do that by changing your OnKeyDown to this for testing purposes:


	local function OnKeyDown(inst, data)
		if data.inst == ThePlayer then
			if data.key == KEY_G then
				if data.inst.HUD and (data.inst.HUD:IsChatInputScreenOpen() or data.inst.HUD:IsConsoleScreenOpen()) then return end
				if TheWorld.ismastersim then
					local x,y,z = ThePlayer.Transform:GetWorldPosition()
					-- Parameter list: doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
					doAreaDamage(x, y, z, 8, 50, true, 0, true, true, nil, {"INLIMBO"}, nil)
				end
			end
		end
	end

You also feed in "nil, { "INLIMBO"}, nil" for the tags, which makes it include absolutely everything (except player ghosts), which is probably not what you will want in the end, but I understand if you want to leave it like this for testing purposes.

I hope this answers your questions and that you can make it work. Godspeed in your ventures!

Sincerely, Ultroman the Tacoman

 

gojo.lua 6.53 kB · 0 downloads

Thank you very much for the help! 

I now understand the aoe will appear at character if I use x,y,z instead of 0,0,0


I lack understanding to the part about the tags at :

doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)

How should I edit the tags (the last 3 elements) to make my character deal damage to those living entities? (e.g. spiders, rabbits)
Or how can I know which entities belongs to which tags? 

You are very friendly, kind and helpful.
Thanks for your help!

 

Edited by Aurorance
Some coding has changed
7 hours ago, VanzDioveht said:

Hi ultra, Can you show me how to increase the damage of default tools (axe, shovel, hoe,...). Thank you.

maybe you can have a look at the in-game code about the tools, then slightly increase the tuning damage of them inside your mod.

18 hours ago, Aurorance said:

Thank you very much for the help! 

I now understand the aoe will appear at character if I use x,y,z instead of 0,0,0


I lack understanding to the part about the tags at :


doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)

How should I edit the tags (the last 3 elements) to make my character deal damage to those living entities? (e.g. spiders, rabbits)
Or how can I know which entities belongs to which tags? 

You are very friendly, kind and helpful.
Thanks for your help!

Adding the tags should be explained in the post where you found the code or in the comments in the code. It just expects a list of strings (tags) and a list of strings is made like this: {"some string 1", "some string 2", "some string 3"}

Finding out what tags to use is your main job when using this, and it is definitely the hardest, because it requires you to know how tags are used, how to figure out which prefabs have which tags (they even change depending on the state of the entity, in some cases). Tags are shared between several prefabs, so you have to make sure you choose the right tags. That said, you can discriminate on other things than tags once you have the resulting list of entities found, by checking the name of the prefab. So for example, if you only want to affect one type of bird and it doesn't have any unique tags, then you use the tag that birds use, and then using a simple if-statement saying (if this entity has the bird-tag AND its prefab name is "some prefab name", then...), to only affect that specific bird. It'll still cull (ignore) everything that isn't a bird, which is a great limiter since there aren't usually many birds in the same place at the same time.

There's sadly no better way to find the correct tags, than opening the prefab files of the entities you want to affect, search for "AddTag" in them, and see which special tags they get. Note that all entities shared a parent-script (some have an extended one, as well) which handles their animations, knows whether they are a player or not, etc., which also adds tags to the entities. These tags won't be as helpful to you, though, since they will be shared among all entities. You can check the Newcomer Post for info about where to find the Lua files from the game. Within the file structure, you will find scripts/prefabs/, which is the code for all the different types of entities in the game. Go nuts :)

Another good tag to put in the ignore-list, alongside "INLIMBO", is "FX", since that covers all entities representing graphical effects, like the fireflies or any kind of fire or spell effect.

Just out of personal interest: Did you figure out if your OnKeyDown function is being called when you press the key?

2 hours ago, Ultroman said:

Adding the tags should be explained in the post where you found the code or in the comments in the code. It just expects a list of strings (tags) and a list of strings is made like this: {"some string 1", "some string 2", "some string 3"}

Finding out what tags to use is your main job when using this, and it is definitely the hardest, because it requires you to know how tags are used, how to figure out which prefabs have which tags (they even change depending on the state of the entity, in some cases). Tags are shared between several prefabs, so you have to make sure you choose the right tags. That said, you can discriminate on other things than tags once you have the resulting list of entities found, by checking the name of the prefab. So for example, if you only want to affect one type of bird and it doesn't have any unique tags, then you use the tag that birds use, and then using a simple if-statement saying (if this entity has the bird-tag AND its prefab name is "some prefab name", then...), to only affect that specific bird. It'll still cull (ignore) everything that isn't a bird, which is a great limiter since there aren't usually many birds in the same place at the same time.

There's sadly no better way to find the correct tags, than opening the prefab files of the entities you want to affect, search for "AddTag" in them, and see which special tags they get. Note that all entities shared a parent-script (some have an extended one, as well) which handles their animations, knows whether they are a player or not, etc., which also adds tags to the entities. These tags won't be as helpful to you, though, since they will be shared among all entities. You can check the Newcomer Post for info about where to find the Lua files from the game. Within the file structure, you will find scripts/prefabs/, which is the code for all the different types of entities in the game. Go nuts :)

Another good tag to put in the ignore-list, alongside "INLIMBO", is "FX", since that covers all entities representing graphical effects, like the fireflies or any kind of fire or spell effect.

Just out of personal interest: Did you figure out if your OnKeyDown function is being called when you press the key?

Thanks for explaining the details about the tags.
I will have a look at the in-game files to search for what I want.
I now have the basic understandings about the function for AOE damage.
The chunk for aoe damage looks good and didn't crash the game. Also, after adding a file called keyhandler.lua, the game also didn't crash due to OnKeyDown function.
Unfortunately, when I pressed G, nothing happens. I think there are two possibilities : the explosion occured at 0,0,0, or the OnKeyDown function is not being called.
I am still trying to find out where the problem is.
Not sure do you need this, but I attach the current character file I am working on here. KeyHandler.lua (that prevent my game crashing) is also included.
Thanks!

gojo.lua keyhandler.lua

modmain.lua

Edited by Aurorance

Where did you get keyhandler.lua from? Is that from the game files? If so, that's a BIG no-no. You do NOT overwrite or use existing game files with your mod. I tried searching the forum about how to use OnKeyDown and the keyhandler, but I couldn't find anything for DS. You can either investigate by finding and downloading a character mod for DS that has keybinds and see how they've done it, or start a thread asking specifically about how to make keybinds for character prefabs.

11 hours ago, Ultroman said:

Where did you get keyhandler.lua from? Is that from the game files? If so, that's a BIG no-no. You do NOT overwrite or use existing game files with your mod. I tried searching the forum about how to use OnKeyDown and the keyhandler, but I couldn't find anything for DS. You can either investigate by finding and downloading a character mod for DS that has keybinds and see how they've done it, or start a thread asking specifically about how to make keybinds for character prefabs.

Not sure do you subscribe Hololive Character mods, I downloaded Amelia Watson's character mod (the character has a key bind skill) and I have a look at the file. The keyhandler is from there too.
I tried looking at in-game file but I can't find any of them related to key binds. So I use character mods from others instead.

Here is the mod (if you want to have a look) https://steamcommunity.com/sharedfiles/filedetails/?id=2411450759
However, the key bind part is very complicated for a mod starter like me (since it is mixed with many chunks like animations or other stuffs)

That's my bad then for assuming things. Sorry about that. You seem to have done the right steps, but just have trouble with the final implementation. Keybinds are nothing trivial, so don't feel bad :) The best advice I can give you, is to start a thread where you write what you have tried to do and how, and post a zip of your mod along with it, and then ask a very specific question: How do I make a character-specific keybind in DS?
That could even be the title of your thread. I haven't found any such thread, so it would be nice to have for posterity. I'm sure someone will chime in. Make sure you mention that you are a beginner, but have been through the newcomer post and have an example mod to look at (include a link, so it is easy for others to find it).

3 minutes ago, Ultroman said:

That's my bad then for assuming things. Sorry about that. You seem to have done the right steps, but just have trouble with the final implementation. Keybinds are nothing trivial, so don't feel bad :) The best advice I can give you, is to start a thread where you write what you have tried to do and how, and post a zip of your mod along with it, and then ask a very specific question: How do I make a character-specific keybind in DS?
That could even be the title of your thread. I haven't found any such thread, so it would be nice to have for posterity. I'm sure someone will chime in. Make sure you mention that you are a beginner, but have been through the newcomer post and have an example mod to look at (include a link, so it is easy for others to find it).

Sure I will do that! Thanks for the advice!

28 minutes ago, Ultroman said:

That's my bad then for assuming things. Sorry about that. You seem to have done the right steps, but just have trouble with the final implementation. Keybinds are nothing trivial, so don't feel bad :) The best advice I can give you, is to start a thread where you write what you have tried to do and how, and post a zip of your mod along with it, and then ask a very specific question: How do I make a character-specific keybind in DS?
That could even be the title of your thread. I haven't found any such thread, so it would be nice to have for posterity. I'm sure someone will chime in. Make sure you mention that you are a beginner, but have been through the newcomer post and have an example mod to look at (include a link, so it is easy for others to find it).

I hope this helps me, thanks again!

On 4/26/2021 at 10:05 PM, Ultroman said:

It's perfect! I'm sure someone will help. I haven't made any keyhandlers myself, otherwise I would have helped (if that wasn't obvious :)).

Good news, someone helped me with the keyhandler and RPC stuffs, and the mod works perfectly!
Do posting the codes here also helps too?

 

6 hours ago, Aurorance said:

Good news, someone helped me with the keyhandler and RPC stuffs, and the mod works perfectly!
Do posting the codes here also helps too?

Sure! Post the complete code as a zip and, if you feel up to it, type up whatever explanations you can give for how you made it work and which parts of the code are involved. That would be most helpful for others wanting the same feature. Even for yourself in the future.

Edited by Ultroman

Here's the code for making a key bind:
Making a key bind is very complicated because it is related to actions and RPC.
Firstly you need create a file called keyhandler.lua in the scripts/components:

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

Then you need to assign the key handler to the character prefabs. Put this inside common_postinit so the whole chunk will be:

Spoiler

-- This initializes for both the server and client. Tags can be added here.
local common_postinit = function(inst) 
    -- Minimap icon
    inst.MiniMapEntity:SetIcon( "your_character_name.tex" ) --This part is related to minimap icon, which is unique for everyone.
    -- Assign Key Handler
    inst:AddComponent("keyhandler") -- make sure it matches the name of the lua file
end

Lastly, in modmain.lua,

Spoiler

--Add RPC
local function SanityFn(player)
    if player.components.sanity.current > (85) then
        player.components.health:DoDelta(3)
    elseif player.components.sanity.current < (85) then               
        player.components.health:DoDelta(-3)                
    end
end
AddModRPCHandler(modname, "Sanity", SanityFn)

GLOBAL.TheInput:AddKeyDownHandler(GLOBAL.KEY_G, function()
    if GLOBAL.ThePlayer and GLOBAL.ThePlayer.prefab == "gojo" and GLOBAL.TheFrontEnd:GetActiveScreen() == GLOBAL.ThePlayer.HUD then
        if GLOBAL.TheWorld.ismastersim then
            SanityFn(GLOBAL.ThePlayer)
        else
            SendModRPCToServer(GetModRPC(modname, "Sanity"))
        end
    end
end)

Here's an example of gaining/reducing health depends on sanity.
You can change it to other functions if you want.

I do not understand very much about how the whole chunk works since I know a little about RPC. If there are further questions about RPC you may ask at the forum.
Note: gojo is my character name. You need to change this to your character name.

Edit: Credit to Electroely and ZeroRyuk

Edited by Aurorance
  • Thanks 1
7 hours ago, Ultroman said:

Sure! Post the complete code as a zip and, if you feel up to it, type up whatever explanations you can give for how you made it work and which parts of the code are involved. That would be most helpful for others wanting the same feature. Even for yourself in the future.

From the code above,  

  if player.components.sanity.current > (85) then
        player.components.health:DoDelta(3)
    elseif player.components.sanity.current < (85) then               
        player.components.health:DoDelta(-3)         

 this chunk is the part where I add perks to my character.
However, if I want to change it to AOE damage, should I just change this part to this?

 local x,y,z = ThePlayer.Transform:GetWorldPosition()
                    -- Parameter list: doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
doAreaDamage(x, y, z, 8, 50, true, 0, true, true, nil, {"INLIMBO"}, nil)

Also, I am not sure is this chunk needed:
 

Spoiler

local function doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)

    local ents = TheSim : FindEntities (x, y, z, 20, nil, {"INLIMBO"}, nil)

    for i, v in ipairs(ents) do
        if v ~= inst and v:IsValid() and not v:IsInLimbo() then

            if v:IsValid() and not v:IsInLimbo() then

                if v ~= inst and v:IsValid() and not v:IsInLimbo() then
                    if workableDamage > 0 and 
                        v.components.workable ~= nil and v.components.workable:CanBeWorked() then
                        v.components.workable:WorkedBy(inst, workableDamage, nil)
                    end

                    if ignite and
                        v.components.fueled == nil and
                        v.components.burnable ~= nil and
                        not v.components.burnable:IsBurning() and
                        not v:HasTag("burnt") then
                        v.components.burnable:Ignite()
                    end

                    if v.components.health ~= nil and not v.components.health:IsDead() then
                        if v.components.combat ~= nil then
                        v.components.combat:GetAttacked(inst, damageToLivingEntities, nil)
                        elseif doDamageToNonCombatants then
                        v.components.health:DoDelta(inst, damageToLivingEntities, nil)
                        end
                    end
                end
            end
        end
    end
end

 

If yes, should I put it in character prefabs or modmain?
Thanks!

modmain.lua

51 minutes ago, Aurorance said:

From the code above,  


  if player.components.sanity.current > (85) then
        player.components.health:DoDelta(3)
    elseif player.components.sanity.current < (85) then               
        player.components.health:DoDelta(-3)         

 this chunk is the part where I add perks to my character.
However, if I want to change it to AOE damage, should I just change this part to this?


 local x,y,z = ThePlayer.Transform:GetWorldPosition()
                    -- Parameter list: doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)
doAreaDamage(x, y, z, 8, 50, true, 0, true, true, nil, {"INLIMBO"}, nil)

Also, I am not sure is this chunk needed:
 

  Reveal hidden contents


local function doAreaDamage (x, y, z, damageRange, damageToLivingEntities, doDamageToNonCombatants, workableDamage, isExplosion, ignite, mustHaveTags, cantHaveTags, mustHaveOneOfTheseTags)

    local ents = TheSim : FindEntities (x, y, z, 20, nil, {"INLIMBO"}, nil)

    for i, v in ipairs(ents) do
        if v ~= inst and v:IsValid() and not v:IsInLimbo() then

            if v:IsValid() and not v:IsInLimbo() then

                if v ~= inst and v:IsValid() and not v:IsInLimbo() then
                    if workableDamage > 0 and 
                        v.components.workable ~= nil and v.components.workable:CanBeWorked() then
                        v.components.workable:WorkedBy(inst, workableDamage, nil)
                    end

                    if ignite and
                        v.components.fueled == nil and
                        v.components.burnable ~= nil and
                        not v.components.burnable:IsBurning() and
                        not v:HasTag("burnt") then
                        v.components.burnable:Ignite()
                    end

                    if v.components.health ~= nil and not v.components.health:IsDead() then
                        if v.components.combat ~= nil then
                        v.components.combat:GetAttacked(inst, damageToLivingEntities, nil)
                        elseif doDamageToNonCombatants then
                        v.components.health:DoDelta(inst, damageToLivingEntities, nil)
                        end
                    end
                end
            end
        end
    end
end

 

If yes, should I put it in character prefabs or modmain?
Thanks!

modmain.lua 4.21 kB · 0 downloads

Then you need to move the entire doAreaDamage function over into modmain.lua, outside of any other function or closure. Then exchange the code as you proposed. However, since you get the player as a parameter in your function, you should change "ThePlayer" to "player" in the line where you declare and set your x, y and z.

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