Devlog 2022-07-06

  • made enemy “AI” a little better
  • add a display of the enemy name during targeting
  • tweak a few places to change how a selection is highlighted to make it more obvious
  • some boring (to talk about) refactoring and trying things out that haven’t gotten anywhere yet
  • started on building out the village of the fae

I missed last week for personal reasons, which also led to me not getting as much done since then as I’d normally like.

Enemies

Previously, enemies had only a half-implemented partial idea for deciding what action to use, exactly. Unless they had a special script for their combat (which I use exactly once), they would always use exactly one attack; the last one they had defined. Now, though, each monster has a table of attacks they can choose from, with a weight. Here are the actions for the Gremlin monster:

"actions": [
	{ "chance": 2, "skill": "m_slam", "skill_level": 1, "target": "random" },
	{ "chance": 1, "skill": "stone_spike", "skill_level": 1, "target": "random" }
],

I do a weighted selection from the table based on the “chance” field, and then look at target. At this point, I believe every monster has all its attacks target “random”, which just means a random target. I could have it target a particular character by name and, more usefully, I intend to give myself the ability to restrict targets based on things like “has Energy left”, “the most HP”, etc. Anyway, once a skill and target is chosen, I just apply the skill (at the given skill level; any skill can scale based skill level) to the chosen target.

Weighted Selections

Actually, I want to talk a bit more about this since it’s something I’ve implemented a bunch of times. I often find myself wanting to have a table of options with different likelihoods for each thing. What I do not want to do, though, is define a bunch of percentages that all add up exactly to 100% that I then have to manually tweak each time I add something to the list. What I definitely do not want to do is wrap my head around a random selection based on iterative “rolls”, even though that would be very easy to code – this would look like “start at A and flip a coin; if it’s heads choose A, but if it’s tails then flip another coin; if it’s heads, choose B, but if it’s tails then flip another coin…”.

So instead I do this weighted choice: I just give each thing in the table a “chance”, which can be an arbitrary integer. Two entries with the same chance have the same chance of being chosen, while an entry with twice the “chance” has… twice the chance of being chosen, compared to the other. It’s very easy to reason about, and the code isn’t that hard to write. It looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    func weighted_rand_from(arr, weight_key="chance"):
        var chance_sum = 0                # start out by summing the "chance" values for the whole table
        for a in arr:
            chance_sum += a[weight_key]   # notice that we use the [weight_key] parameter so it can be called whatever you need
        var n = randi_range(chance_sum)   # generate a single random number
        for a in arr:                     # step through the array,
            n -= a[weight_key]            # subtracting the chance of each entry from the "roll"
            if n < 0:                     # once we drop below 0, we've found the one we want!
                return a
        return arr[arr.size() - 1]        # return the last thing in the array as a safe default

Yes, this does involved iterating over the whole array (potentially) twice, but unless you’re using very large arrays this shouldn’t be an issue. If it ever did, you’d be farther ahead to recalculate your table into something else for your export. I doubt I’ll end up needing to worry about this for Black Mountain.

Enemy Name Display and Highlighting

I mentioned the name of one of my monsters was named a Rumble Bee internally but had to just refer to it as “the wasp monster”, and I got a bit of feedback from a playtester that it’s nice to know what the monsters are called. I tend to agree, so I added a display for them when picking a target.

Twig Sprites are one of the first enemies you encounter and probably the easiest to defeat in the game.

Along with that you can see I’ve added an extra cursor to the list of monsters. I’ve added one to the list of party members as well.

Kiel is probably going to use First Aid on Omen or something, but who knows for sure.

I’ve also added a small tweak to the character selection in the menu, for viewing status, using items, etc etc. I bump their portrait up a bit just to make it a little more obvious who you have selected. This one was suggested by Hyptosis, and it’s small but I do think it helps with clarity.

The only way Violet will ever be taller than the other two.

Village of the Fae

The next area I’m working on filling out is the Village of the Fae.

The fairies are definitely friendly and definitely won’t feed your baby to a goat.

This is a very quick paint job (and not even finished) like the rest of my map painting. I just want it to be clear and playable for the time being – it will get much prettier in the future.