Jump to content

Assistance with two perks


Recommended Posts

After two or so years of not playing DS, I decided to buy Hamlet, which, in turn, made me decide to get back into making custom characters. I decided to make a character, Wilkas, who is essentially a more humanoid hound enemy. I'm hoping I can get some assistance with two of his perks, one more major than the other. One of his perks is that he can befriend hounds, similar to how you can befriend pigs and bunnymen. I played with Webber's code to get what I have now and am tweaking it as I go, which... doesn't crash, which is good. The idea is you feed a hound food, hound is happy, hound follows you, hound fights for you.

The problem, however, is that the hounds don't attack Wilkas, there's no sanity drain from them, and you can feed the hounds. All things I wanted. However, after feeding the hound, the "befriending" music plays, but the hound continues running around and does not seem to really follow, which makes me wonder if they were even befriended at all. Given hounds have rather erratic behavior already, it's a bit difficult for me to tell. Also, my character seems to act like a hound too, as in they go to attack things on their own... Seems to only occur when in the vicinity of hounds?

I've included my code below. Note, the "hound.lua" is in the prefabs folder of my mod folder. I'm a complete newbie when it comes to coding, so I could be way in over my head here or be doing something far too complicated that I shouldn't.

As for my second question, is there a way to make a custom character have a Wilbur-like way of speaking, in that they make sounds instead of words? Specifically, I'd like Wilkas' way of speaking to be a series of g's, h's, and r's, like growling, instead of Wilbur's o's, e's, and a's. I've looked through the files, but all I could really find was his very few dialogue lines for bananas and being in the dark. I could have sworn I saw a topic for this some time back, but I cannot for the life of me find it. Nevermind, got it.

hound.lua

wilkas.lua

modmain.lua

Link to comment
Share on other sites

By including hound.lua in your mod, you are basically completely overwriting any changes other mods might be doing to the hounds. If those mods expect their changes to be present, they may crash or create unwanted behavior. If your mod is loaded after theirs, your mod will completely reset their changes. If Klei decide to make a change to hound.lua, then you have to manually update your mod with the new code, even if it has nothing to do with what you've actually changed. It is bad practice to completely overwrite game files.

That said, if you know you aren't using any other mods affecting or relying on hounds, and you don't plan on submitting the character to the workshop or to the public in any way (so only playing solo), then it's fine :) Otherwise, it will have a huge potential to mess up a user's playtime.

So, in order to help you best, I'd need to know if you plan on publishing the mod, or if you plan on strictly playing with it alone on your own server.

A quick thought is, I think the hounds will always run around aimlessly, due to their brain telling them to either "Wander" or "ChaseAndAttack". You'd need to make your character their leader, but even when you do that, they'll still run around you like crazy. I've never done anything like this before, and if you haven't either, I'd be looking for another mod doing the same thing. Like this one. Don't know if it still works.

If you are a newcomer to modding DST here's a link to my newcomer post. Even though you seem to have been doing a lot of non-crashing code already, you might learn something new :)

Good luck! :D I think that mod I linked is doing exactly what you want.

Link to comment
Share on other sites

@Ultroman Hello! And thank you for your response! I must admit I was nervous to ask for help, so it's nice to have a kind soul willing to help. I also apologize for not responding sooner today, as I had work and was up to my neck in dogs, lol. It kind of tires you out.

I'll tell you right now that no, I don't plan on publishing the mod. :) It's just something I wanted to do for myself for fun, and I don't intend to add any mods that edit hounds in any way. I do plan on making the character DST compatible in the future, intended to be shared with my best friend only as they're really the only person I play with, but I'll cross that bridge when and if I get to it.

And yes, thank you! That mod is exactly what I was looking for! I was able to cut hound.lua from the mod because of it. My character still joins in fights that hounds pick, but either way, I can recruit hounds as I should now. :D

I still have a few ideas for my mod, such as eating bones, occasionally shedding, resistance and susceptibility to cold and heat, etc., but these are things I can do easily. I was wondering, however, if you knew anything about this. My dear friend suggested for the mod that if you pressed a key, let's say H, for instance, in exchange for some hunger or sanity you could spawn 1-2 allied hounds. Is something like this feasible? I've poked at the Birds of the World book, Maxwell's Codex Umbra, even the varg and hound mound code to try and get an idea, but it's... confusing. Seems ambitious and dumb of me to try it, but I wanted to see if something like this was possible, and how I'd go about doing it.

Link to comment
Share on other sites

You are welcome :) And I'm happy to hear that I helped. And VERY glad you were able to cut hound.lua from your mod!

I'm not sure what can be done about your character joining in hound fights. Maybe that's how it's supposed to be? The feral instincts? :p

It is definitely possible to spawn some hounds with a key. I think the easiest way to do this, is to make the button call a function which does two SpawnPrefab("hound") calls and saves their return value (the hound instances) in two separate variables, and then immediately make them your friends (so you don't have to feed them before they're friendly).

I'll see if I can find an example of hooking up button presses.

local SpawnHounds = function()
	-- Spawn the hounds and whatever. Probably make some kind of cooldown timer.
end

GLOBAL.TheInput:AddKeyDownHandler(GLOBAL.KEY_H, SpawnHounds)

KEY_H should correspond to the H key on the keyboard.

You can make the key customizable by adding an option in the mod configuration.

local SPAWN_HOUNDS_KEY = GetModConfigData("HoundSpawnKey")

local SpawnHounds = function()
	-- Spawn the hounds and whatever. Probably make some kind of cooldown timer.
end

GLOBAL.TheInput:AddKeyDownHandler(SPAWN_HOUNDS_KEY, SpawnHounds)

Then you'd have to find the list of possible keys somewhere. I'd try to find a mod with a customizable key, and steal their configuration :)

Link to comment
Share on other sites

Thank you kindly for all the help you're giving me. :) And I hadn't thought about the "feral instincts" thing, but I think I like it. Maybe my character just can't stand to see his hound brethren getting beat up in fights, so he wants to help!

I've given it many attempts, and unfortunately, I do not seem to be able to get anything I try to work without crashing. :( I am embarrassed to admit that I do not know much about how to do something like this. My knowledge on coding is limited, and I assume I'm making a mountain out of a molehill here and overcomplicating things. A bit dumb of me to attempt something like this with such limited knowledge, I know. Would you perhaps be willing to provide an example of what to do, or point me to one, maybe?

Apologies for being a bother! :( 

Link to comment
Share on other sites

@Ultroman Thank you for your help, and again, I apologize for being such a bother. I'm still learning lua bit by bit, and I'm currently reading the crash course you linked in the newcomer post; I'm hoping it'll prove to be of a bit of help.

I've included my files, as requested, as well as the log. The problem seems to lie in line 72, and it seems to be a case of inst being a nil value. I've gotten this error a few times before in the past, but I do not remember how I fixed it. 'nil' essentially means I'm not returning anything from my function call, correct? Apologies, I'm using this as a learning experience.

 

log.txt

modmain.lua

Link to comment
Share on other sites

No. The problem is that you're using a variable called inst, but inst isn't in the scope of your function. Anything you try to use has to be available.

I'd actually not put the code to spawn hounds into your modmain. It should be in your character's lua, and the AddKeyDown thing should be called in its master_postinit. In the master_postinit you have access to an inst which is your character.

AddPrefabPostInitAny is a very bad thing to use. It forces the game to run your code on EVERY SINGLE prefab being spawned. That's incredibly overkill. Instead, make a list of the prefabs you want to affect, and call AddPrefabPostInit on them, like this (this should be in your modmain):

local prefab_list = {
	"hound",
	"firehound",
	"icehound",
	"moonhound",
	"clayhound",
}

for i,v in ipairs(prefab_list) do
	AddPrefabPostInit(v, function(inst)
		removeSanityAura(inst)
		makeHoundFriend(inst)
	end
end

 

What is this supposed to do? It just creates an empty entity with a transform and the leader component on it. You don't seem to call it anywhere. I think you should delete this.

local function fn() 
	local inst = CreateEntity()
	local trans = inst.entity:AddTransform()
	
	inst:AddComponent("leader")
	return inst
end

If you want to add the leader component to your character, do it in master_postinit. That's what it's for. It looks like you're trying to do everything from the modmain. For a character mod, most of the code should be in the character's lua.

Link to comment
Share on other sites

Ohhh, sorry. I wasn't 100% if it should go in modmain or the character lua. Guess I should've known.

The list of prefabs and AddPrefabPostInit seems to crash, as I think it's causing problems with the code for making hounds followers. Additionally, I do not have a master_postinit in my prefab. Is that DST? I think I remember seeing it when I was modding for DST some years ago. Either way, I've taken a step in the right direction, and managed to get it so hounds to spawn when my character takes damage. Not quite what I wanted, but it's a step closer to what I want. Wondering if I should just settle with this or commission somebody to code this in.

Link to comment
Share on other sites

Sorry, that's for DST, yeah. It's probably just called fn(). Anyway, it's the function that adds all the components.

I really need to see your logs if I'm to help you resolve a crash. The code should work fine. I'd rather take a look at your code than see you give up :) If you zip it all up and attach it to a reply, I can take a look at it. I'd need the whole mod, so I can test it.

If you've tried to move everything into the character's LUA, I can see 100 ways that could have gone wrong, starting with the use of GLOBAL in some of your code.

Link to comment
Share on other sites

I know I've said this like a dozen times already, but I really do appreciate you being patient with me. 

I should apologize in advance. As you can tell, lua, or just coding in general, is not my strong point at all, so my code might be a wreck. Again, thank you a lot for being patient with me. :) It eases my anxiety a lot about asking for help and making myself look like a fool.

Wilkas the Hound's Friend.zip

log.txt

Link to comment
Share on other sites

Again, you're very welcome :)

Look, m8, programming is complicated for anyone. It just is. You're not a fool, you're a newbie, and that's fine, natural and expected. I probably wouldn't get a clean note out of a trumpet for at least a year if I started practicing now. The only way to get better at difficult tasks, is to sink more time into it, and try your best. For programming, that would be to understand how to leverage the syntax and frameworks, APIs and libraries you have to work with, and in order to do that, you'll have to study those things. You can't start changing the brakes on your car, if you don't have the tools for it, or don't know how they work. Keep this in mind for everything in life. We all struggle, my friend. We are all anxious about not being good enough. Every single one. That's why we cling to doing some specific thing, when we finally find something we're innately good at or have worked ourselves towards being good at.

Let me get back to you after I've taken a look at the files you sent.

OK, firstly, I forgot a closing parenthesis.

for i,v in ipairs(prefab_list) do
	AddPrefabPostInit(v, function(inst)
		removeSanityAura(inst)
		makeHoundFriend(inst)
	end) -- <== this one
end

 

I'm gonna make some more changes to the mod, and send it back to you with a change log, so you can see what I've done.

Link to comment
Share on other sites

Thanks a bunch. <3 I have to say, it does put me at ease to hear that. Thank you for all the help you've given me, I think I'll take some time over spring break to check out some lua tutorials and crash courses and such to try and brush up on it a bit more. 

Link to comment
Share on other sites

Fixed it. It was just the parenthesis, and some reference issues. I've added several notes in modmain.lua and wilkas.lua

Enjoy, m8 :)

Wilkas the Hound's Friend.zip

LUA is a bit of a weird language to start out with, but you have to start somewhere. If you find that you're liking programming, you should look into C# (perhaps by picking up Unity and start making some small games) or C++ if you're up for the challenge of joining the big leagues in performance programming. It's an exciting world to be in, and there's a steady stream of jobs if you get good at either.

You're still very welcome, and I hope you continue on your journey with programming...but only if it feels right for you, of course ;)

Link to comment
Share on other sites

Wow, you're a lifesaver! :D Works like a charm! Thank you! The notes you made in the file were very helpful, as well. It's nice to see where I went wrong and how I went wrong. I was able to add a sanity penalty to the summon hounds key, as well, so now it's doing just what I want it to!

And yeah, I think I will continue to try and learn programming. :) It'll be difficult, no doubt, but I'm gonna make an effort. I enjoy modding, difficult as it is for me now, so I think if I were to learn more it'd be a much smoother road for me in the future. Thanks a bunch!

One last question, would this same code work for DST if I were to port it over in the future? Or would changes have to be made? I know DST has different code from regular DS, but there are a lot of overlaps between the two, iirc. Of course, it's been quite some time since I modded DST, so I could be wrong. From what I can see in your notes, since DST has more than one player, I'd imagine something different will have to be done with the summon hounds function involving GetPlayer()

Link to comment
Share on other sites

I can't remember how big the problem is concerning getting the player in that particular scope, but just spawning hounds might present a problem, as it has to be done on the server, and your character can be either server or client. When you get to it, you can try making a thread on the forum. I'm sure someone has the answer to such a question. It's probably quite common. I just haven't ever made a character, so I'm not really versed in that part.

Other than that, I think it's just the standard stuff of adding networking to your character, and making sure that the right things are not executed on the client but only on the server (adding components, and a lot of the code in your modmain.lua).

Investigate some DST character mods when you get there, and you should be able to figure out your character script. Your modmain may require some more help, though.

Cross that line when you get there. Relish in your success for now, and keep working. I only fixed some minor things. This is your work :)

I'm glad I could help! It's good to hear you're taking up the challenge :) Take in the things in the newcomer post, and yeah, the starter tutorials. Other than that, it's just a lot of reading game- and mod-code, googling LUA specifics and searching these modding forums for game-specifics. Time, time, time. You'll git gud, m8.

Link to comment
Share on other sites

Alright, thanks a bunch. <3 You really helped me out a ton, and gave me quite a bit of insight, so again, thank you!

For now, I think I'll work on trying to learn the language of lua, and I'll cross that DST bridge when I get to it. I'm sure there's a couple other mods I could take a peek at, as I think there's more mods for DST than there are for regular DS. If all else fails, I could always ask for help. For now, it's just nice to have a little success. :) With your help, of course. You have a great day, and thanks for all the help!

I'll tell you one thing, I'm already having fun with this.

Spoiler

2ivgy0.png

 

Link to comment
Share on other sites

Hahaha, that's a hilarious screenshot xD Actually made me laugh way too loud for this hour of the morning :D Thanks for that.

You take this success to heart, m8, it's yours. Asking questions is part of the work. I'll be waiting to hear from you on the forums another time ;)

Link to comment
Share on other sites

I wonder if I could trouble you for one final question? Apologies I didn't think to ask sooner! It was something I thought for sure I'd be able to do without a hitch. I'm putting the final touches into my mod before I start to work on the art, and I would like to make it so, depending upon the season, summoning the two hounds with the H key have a chance to be either blue or red hounds, increasing with likelihood the more days you've survived.

I recalled hound mounds periodically spawned blue and red hounds depending on the season, which is what I'm looking for, so to get an idea of what I should do, I took a peek at the code and found this.

Spoiler
Quote

local function GetSpecialHoundChance()
    local day = GetClock().numcycles
    local chance = 0
    for k,v in ipairs(TUNING.HOUND_SPECIAL_CHANCE) do
        if day > v.minday then
            chance = v.chance
        elseif day <= v.minday then
            return chance
        end
    end
    return chance
end
                             
local function SpawnGuardHound(inst, attacker)
    local prefab = "hound"
    if math.random() < GetSpecialHoundChance() then
        if GetSeasonManager():IsWinter() or GetSeasonManager():IsSpring() then
            prefab = "icehound"
        else
            prefab = "firehound"
        end
    end
    local defender = inst.components.childspawner:SpawnChild(attacker, prefab)
    if defender and attacker and defender.components.combat then
        defender.components.combat:SetTarget(attacker)
        defender.components.combat:BlankOutAttacks(1.5 + math.random()*2)
    end
end

 

(Put in a spoiler to avoid stretching the page too much lol.)

Just for clarification, this is the houndmound.lua for Reign of Giants. I love RoG very much, so I always play with it. I assume what I want out of this is the function GetSpecialHoundChance() and this chunk here:

Quote

    local prefab = "hound"
    if math.random() < GetSpecialHoundChance() then
        if GetSeasonManager():IsWinter() or GetSeasonManager():IsSpring() then
            prefab = "icehound"
        else
            prefab = "firehound"
        end
    end

I believe what this is saying is, "If the season is winter or spring, then look into GetSpecialHoundChance() for (TUNING.HOUND_SPECIAL_CHANCE) for the chance to spawn a blue hound. If the season is not winter or spring, do the same, but for the chance to spawn a red hound instead." ...Or something like that?

I assumed that if I were to copy and paste these into wilkas.lua, the local prefab = "hound" thing going under local SpawnHounds = function(), I may be able to do what I wanted to do. It does not crash, but also, it does not spawn special hounds, only regular ones, even when I skip to day 75 with c_skipdays(74). Day 75 being because in tuning.lua, under HOUND_SPECIAL_CHANCE, the chance to spawn a special hound apparently maxes at day 75 up with {minday=75, chance=.5}. 50% chance to spawn a special doggy sounds good to me for testing.

This turned out to be much longer than I hoped, lol, I'm sorry. I suppose what I'm asking is, what did I do incorrectly and how can I correct it? I assume it's a case of me putting it in the wrong spot or missing something, but I'm not 100% on the latter since it doesn't crash.

wilkas.lua

Link to comment
Share on other sites

I will get to the actual problems in a minute, but m8 you need to keep your indentation under control. It's super difficult to see what's going on, when the indentation is all over the place.

I think for right now, I'll just point you to the problems I'm seeing, and I'll let you fix them, instead of fixing it for you :)

  1. You're spawning several hounds now. On line 70 and 93 you spawn normal hounds. On line 76 and 78 you spawn other hounds, but you're assigning them to new local variables, and never use them in the scope that you create them.  That's not in line with the code snippet you posted. A local variable is lost when you leave the scope, so as soon as you get to lines 77 or 79, you have no reference to those hounds, and you never touch them again. Also, that means that within the scope of those if-statements, you actually lose the reference to the hound you originally created on line 70.
  2. On line 73 you declare a variable called "prefab", which made me happy because that's what I'd do, and also what was in the code snippet you posted. Have a variable defaulting to "hound" and then instead of spawning new prefabs on lines 76 and 78, just change the prefab variable to "icehound" or firehound" respectively. Then, move line 70, 71, and 72 down below the end of the GetSpecialHoundChance if-statement, and replace SpawnPrefab("hound") with SpawnPrefab(prefab). Boom, you spawn a different hound depending on the season and GetSpecialHoundChance.
  3. You seem to have copy/pasted some code several times on top of each other from line 82 and down.
  4. Your if-statements at line 82 and 88 are redundant. First of all, writing "hound.Physics" would crash the game if "hound" is not available, and inside this if-statement you later check whether "hound" is there.

I'll whip up my solution to all of this, and put it up in a minute. Try to have a go at it yourself for practice, looking at the pointers I gave, and then you can go look at my solution afterwards and see how close you got :) Or you can cheat and just use mine, I don't care ;)

Here's my solution, with a bit of notes.

Spoiler

local SpawnHounds = function()
	-- NOTE: You were using "inst" here, which isn't within the scope of this function.
	-- Since this function is called by a key-listener, it has no idea what you want
	-- to work with, so it has no parameters, so you can't make it send you an inst.
	-- Instead, we take advantage of DS being singleplayer, the there is only one player,
	-- which we can get a hold of by calling GetPlayer().
	local player = GetPlayer()

	if not IsPaused() and not TheInput:IsKeyDown(KEY_CTRL) and not TheInput:IsKeyDown(KEY_SHIFT) then
		-- We simplify things a bit, by just finding out which prefab we want to spawn.
		-- Defaulting to the "hound" prefab.
		local prefab = "hound"
		if math.random() < GetSpecialHoundChance() then
			if GetSeasonManager():IsWinter() or GetSeasonManager():IsSpring() then
				-- If it is winter or spring, we change the prefab-string to an Icehound
				prefab = "icehound"
			else
				-- If it is summer or fall, we change the prefab-string to a Firehound
				prefab = "firehound"
			end
		end
		
		-- Spawn whichever prefab we have ended up with.
		local hound = SpawnPrefab(prefab)
		
		-- You do not really need to check, because it will never mess up spawning a prefab,
		-- but if you want to be on the safe side, just do this.
		if not hound then
			-- Return just stops processing any further, and exits the function immediately.
			return
		end
		
		-- No need to check for hound.Physics. Hounds always have .Physics
		
		-- 1. You set the hound position twice. Here, you set it to the player position.
		hound.Transform:SetPosition(player.Transform:GetWorldPosition())
		player.SoundEmitter:PlaySound("dontstarve/maxwell/disappear")
		
		-- 2. And here you teleport it based on its current position.
		local x, y, z = hound.Transform:GetWorldPosition()
		hound.Physics:Teleport(x, .3, z)
		
		-- Why not just:
		-- local x, y, z = player.Transform:GetWorldPosition()
		-- y = 0.3
		-- hound.Physics:Teleport(x, y, z)
		
		
		-- You are not using the angle code for anything. Not sure why it was there.
		
		
		-- I am a bit confused by this bit. Can a hound just have the player as its leader,
		-- without you telling it to be? If not, then you do not need this if-statement.
		-- Also, even if the player is already the leader, should not it still cost hunger
		-- to spawn the hound?
		if hound.components.follower.leader ~= player then
			hound.components.follower:SetLeader(player)
			player.components.hunger:DoDelta(-25)
		end
	end
end

 

Link to comment
Share on other sites

Ooooh, okay. Yeah, I guess it is all over the place now that I look at it. It looked organized to me at the time, but I guess "organized" to me is subjective. Sorry about that.

Thank you for the pointers, and again, I thank you for being patient with me. I think I'm starting to understand it a bit better now, if just a bit, and I think I'll refrain from looking at that solution and try to fix it on my own, using the pointers you gave me. :) Like you said, I think it'd be good practice.

EDIT: Heyyy it works! Thank you for pointing out what I was doing wrong. :D If you ever want anything in return, maybe some art, all you need to do is ask. It's the least I can do.

Link to comment
Share on other sites

You're welcome :) And thanks for the offer. I might take you up on that.

Great! You got it working by yourself :D Applause! Did you end up looking at my solution to compare it to your final, then? Some of the notes might help you understand some things better.

Link to comment
Share on other sites

Great! I'm so happy to have been able to help you. It all seems to have worked out :D

Good luck with getting the graphics up and running. You're gonna need some of the tutorials on the forum here to get the sprites to line up properly etc.

See ya around!

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...