Forgot to submit last night. I spent a couple hours starting to implement an npc for this example quest. It was enlightening. There are still many many npc path and ai bugs that I need to either find nice workarounds for or fix properly. My goal was to have a simple dialog tree that ended with the npc walking off and hanging out in a specified area.
The behavior tree nodes setup for pathing feel much more complicated than I think they need to be, and I am pretty limited in the kinds of behavior I can easily implement. I didn't have a pre-defined behavior handy, and trying to come up with a "hanging out" behavior was taxing my brain. Editing behavior trees is hard, because I always have to remember what all of the nodes mean, which means either better naming or an editor may be in order.
I also still have a weird disconnect between the dialog system and events. I think I have talked about this before, and it's possible I need to redesign the whole thing. To implement this simple situation, I have to:
Last night I basically stopped when I got to that last step. I couldn't really think of The first set of steps took about an hour. Not terrible but not great either. There are some fairly well behaviors that are defined now that make some things easy. Picking up or doing something with an item takes only a few lines (once I remember how to do it). But anything else is a bit confusing. I think an editor would help a lot. But I think I need to redesign how behaviors, conversations, and events work in a wholistic way, because this isn't going to scale. It would be really nice if I could just open a new file, and put all of those things together line by line in a simple way:
"I'm going to go off by myself now"
char1 behavior =
if char1.distance(region(x)) < 500:
char1.movetoward(region(x))
Definitely need to spend some time creating a more cohesive and complete grammar for everything before I can get to something clean like that. But it will help so much in experimenting with such highly experimental gameplay!
I also had a bug with the response interface where the player chooses what to say. After getting fed up with behaviors, I tried to fix this and couldn't narrow down why it wasn't working, so I went to bed frustrated. I hate going to bed frustrated!
I worked on the conversation system a bit. I'm not really happy with it both in concept or code - I might redesign how it works. Until then, alongside fixing some bugs where the npc ai would take over in the middle of a conversation; I've modified how eavesdropping works. Before, I was modifying the opacity of the textbox as you got further away from the center of the conversation. It worked well enough, but I felt like fading it out wasn't quite appropriate.
First, it's not always that clear whether it's fading as part of the normal animation of the textbox, or whether it's because you are too far away. Second, even if the text has faded a lot, as a player it is still possible to read the complete content of the dialog! That's not quite what I want. I would like there to be situations where either for stealth reasons, or because of the way the environment is situated, as a player you can pick up some of the dialog but not all of it.
So I've switched it to a letter replacement system. As you get further away from the conversation, more of the letters are replaced. At a certain distance, you will see no letters at all. You had better sneak a little closer if you want to pick up that important bit of information...
Unable to use my home computer today, and missed a streak yesterday, I decided to find something simple to do for a few minutes at work. For dialog, I started with a json format for substituting variables in text. It looked like this before:
[{"random","choices":["Hello.","Why hello there","How do you do?"]},"my name is",{"v":"name"}]
There was a lot of ugly type checking (are we using substitution at all? Then just copy the string. If we are using substitution, we have to check whether each chunk is a string or keyvalue (python dictionary). It works, but it's a little sloppy, and editing this weird format as a writer isn't as freeing as it could be. So during my lunch hour, I converted the above syntax to this:
"{random/Hello./Why hello there/How do you do} my name is {v/name}"
Easier to edit and cleaner to parse. The downside is that it's a little bit more work if I want to support recursion ({if_friend_alive/Here {random/is/are} some more {random/text/words}.) But most of the things I would need recursion for will be better handled elsewhere - in the structure of the conversation system or events choosing the appropriate conversation.
For the most part, I am trying to stick to json only for all of my data formats. Earlier on for instance I converted a custom format for behavior trees into json because I kept adding new syntax and it got too complicated to quickly. But here I think that editing convenience trumps the downsides of having a specialized format. With behavior trees, some of the editing would be made smoother if I had a nice gui for them. But with text... text is just text, and the fastest way to write it is something similar to above. As long as I keep the number of special cases and commands low. Which may or may not happen knowing me.
Erik
So for Erik, I just focused on the conversations some more. I added commands for characters "entering" and "exiting" the conversation in the middle of it. When the volunteer is chosen to collect firewood, he starts walking off to do his job while the remaining characters continue conversing. I've also inched forward in making the characters appear natural. There was a silly bug where the command to have a character look at a point makes them look AWAY.
I've also made it so characters choose between running and walking depending on their distance to the target. If they are far away but summoned to a conversation they will get there as fast as they can! I'm pretty happy with the system, and less happy with my writing :P
Missing: better smarts about where characters should stand during the conversation - they should pick the nearest available logical slot rather than just randomly picking any x/y in range.
MyBacklog
For my game launcher, I worked on the steam/gog api usability. If there is an error logging into either service, a window pops up to let you check that your account information is input correctly. It feels pretty janky, but it's better than the program crashing if steam is down or you entered your gog password wrong!
For the firewood conversation, I had one character who speaks a one-off line who wasn't walking into the conversation at the start. It was odd to have the previous speaker say a line, and then sit there wondering what's going on, until finally you see the girl walk into the circle to say her throwaway line. First I thought maybe her behavior tree was getting stuck, so I opened up the behavior tree debugger. I decided since there are many ai's in the scene, to make it a bit easier to open the debugger, by simply clicking on a character, where previously you had to cycle through all of them.
Long story short, it wasn't the behavior tree. For some reason, I had it set so the conversation only tells people who are twice as far as the conversation range to come within range. I think I was going for fuzzier conversation boundaries. Anyway, the girl with the single line was far enough away from the center of the conversation circle to not see her or feel like she is a part of it; but close enough to not get the WALK command. Sigh.
It's minor, but the conversation feels a little bit better now, along with changes I made a few days ago. It's not quite what I want it to be, but it's really close. The characters directions during the conversation is the last real tweak I need to make so it doesn't look janky. Beyond that, I'd like to make them able to have a bit more movement, with characters talking while they walk somewhere - but that's going to take a slightly different approach to the current one.
Erik
I fixed some bugs from the previous update (actually some of the bugs were older, they just didn't present). I had earlier add a menu that lets you choose which items you wanted to use to fuel the fire. You can use your tent as kindling if you wish for instance (though I wouldn't recommend it). This lead to crashing though now that I had an ai character trying to interact with the campfire - ai characters don't have a menu attached, but otherwise use the same interaction code as the player. This had a simple solution - write a menu handler on into the ai and make sure when passing it a menu to give it enough context to make a decision. For the fuel, I have a list of item types and the order in which he would prefer to burn them, starting with the most obvious, the log. But if he is running his ai routine to top off the campfire and runs out of logs... who knows what might happen :)
Other bugs related to the conversation and event system. In one case, the same conversation was appearing twice, because of an delete-index-while-iterating-a-list error with events when there are two events to be executed on a frame. Luckily, I just happened to have my test conversation keyed to trigger on the same tick as another event, or I may not have caught this one!
MyBacklog
Separately I'm going to throw in updates for another project here occasionally, even forgoing Erik on some updates. For about a year I've been working on my own front end to launch games from. It imports my library from steam and gog, can launch roms in various emulators, and can also just point to any shortcut or exe. It is a unified way for me to launch games and track my playtime, which has become increasingly important to me as my game pile grows out of control. I think that it might be useful to others in the future, but the polish isn't quite there, and it's missing some features that don't bother me too much but will be tougher for others to swallow.
Today I worked on some of those missing features. One issue was that all of the external apis had my own account information and passwords hardcoded. Wouldn't want to send my gog password out in public now would I? I also have not updated how the database stores games in a while. It's... pretty messy as you might expect, with support for so many different sources of game information added haphazardly over a year. I made some tweaks to it and updated my 1200 strong game database to the new data format. Where I used to have something like this:
{"name":"Assassin's Creed IV",
"steamid":"12345",
"icon":"http://steeamicons/bf.jpg",
"gogid":""
}
I now have this:
{"name":"Assassin's Creed IV", "sources":[ {"steam":"12345","icon":""} ] }
It's a small change but is a lot easier to expand for the future. In general, I'm trying to make it more expandable, so that if I get feature request or bug reports I can more easily modify the data without end users having to run dangerous conversion scripts that might screw up their data.
Let me know if you are interested in beta testing the software, I'd really like to start with a very tiny group like this one.
No update tomorrow probably :P
I added to the conversation about where to set up the camp. If you reject the first campsite, the npc walks to a different location and asks again if it's a good spot to set up camp. It's not the full on voting that it will be, but I'm just doing the basic flow of the mechanics. Every little thing I add contentwise is still requiring quite a bit of extra coding to be done in either the event system, the conversation system, or the ai system. In this case, I had to add a way to trigger an event from the conversation (when you say "No, this is a bad spot to set up camp"), and a way for the event system to hear events triggered FROM conversation. I already had a way for events to create a new conversation - but they were always centered on a specific npc, and in this case, I needed to generate the conversation elsewhere (the location of the new camp). So I added an argument to the "create_conversation" action which will center it on a tagged location from the map editor.
It sounds more complicated than it is :P But I wonder if I have too many systems.
This is probably par for the course for the start of the game, but the goal is that by either act 2 or 3 I will mainly be adding content to the json files and not spending too much time in code.
Hey, I sat down thinking I was just going to twiddle some tickets and ended up adding a bunch of cool things.
I did twiddle some tickets though :)
I added meat you can eat to regain your endurance. The meat uses the tasks interface. You can fail, making it lose you endurance instead :P Not sure if I will keep this, but the main reason I chose to use tasks for it is because it's the best way I have right now for an action to take time, and eating should totally take time.
I added some birds that fly around and don't collide with things. They are basically just flavor. They currently do land on walls which I may change later.
I added a "drop_item" command for npcs so that I can trigger the setting up the camp scene in the act 1 I've been working on. So now, rather than the tents just starting there, the group will have a conversation about the safest place to set up. I can eventually script it so that after there is a consensus, the people who are carrying the tents will go drop them in the right spot. I'm thinking of having the group walk between two or three different potential spots, and then having a vote - where the player will get one vote. It will be split such that the players vote is actually the deciding one :P