(occasionally I will repost a journal entry from the DMK repo here if I think they might be of some general interest. This is one)

I took a break from my task list to try something silly— making pac-man in DMK. As a result some bugs got fixed related to the player actor inheriting stats it shouldn’t, and some new features got added. Actors without any inventory won’t pick stuff up (treasure doesn’t take up inventory space so they could still get that before). There’s now a melee immunity attribute that came in handy for a power-pill invincibility state. The actor random color attribute that used to just be used for color-matched doors and keys etc. can now also just randomly color actors for variety. There are also now some new win conditions, like killing all actors of a type or collecting all items of a type.

I am always torn between trying to make it so the project can make “any” kind of turn based game and making it too complex (it already is too complex!) and wanting to sort of stretch and flex it as much as I can and see where it breaks and see what assumptions I have about the code are actually wrong.

One thing this prototype surfaced was how hard it was to add another animated sprite to the small collection that exist (fire, mist, liquid) since I didn’t want to have a lot of animated sprites initially, but some felt important from the start. Instead of having these be data driven by sprites, they were hard coded in a bunch of places that made adding more a chore. I don’t know if I want to encourage adding a bunch of custom animated sprites to prototypes but I see no reason why I shouldn’t make it possible and relatively easy. So there you go. One day there may be a database of common assets that designers can upload assets to for custom animations and prototype-level listings will facilitate this. For the forseeable future though I really like providing a lego-box of assets and letting designers experiment within those constraints, keeping a unifying look and feel to prototypes, but with a big space for variation within that.

Another pain-point that the prototype exposed (even though I knew it was there already) was the fact that the state actor tints (when you are in a bleeding state you turn red, etc) was only turned on for dark levels. Tinting had initially been used to blend together lights on dark levels, but then I used it to also add state effects that could blend, as well as blend together the tints of adjacent liquids over time (something that is still the biggest performance suck in the project, and which needs to be attended to). On light levels every turn tint calculations needed for blending didn’t occur, so state tints were skipped. Those work now (via updateEntityStateTints()) while the darkness level tint blending remains unchanged. They also use a different blending mode so they’re more effective than the multiply blending that works best for tinted lights.

Finally I found one behavior that was pretty intrinsic to DMK prototypes that I had to override, that a collision between two one-hit-to-kill actors would be decided by who moves first, which seems like a perfectly good default assuming games like checkers are our starting place. But what Pac-Man, where a weak piece always loses except in a special state? Or how about a game like Animals Chess (Jungle) where there is a hierarchy of pieces that takes precidence? Animals chess also has an even more exotic exception- instead of a item/time based state of imperviousness, it has an area on the board where hierarchy is suspended and we return to first-to-attack wins rules.

Both of these turned out to be variations of the same fix. The engine already had melee_immune, which says “this actor can’t be hurt in melee” — the power pill grants it. What was missing was melee_harmless, checked on the attacker instead of the target, now Pac has it as a base state. Ghosts always win the exchange, and the impervious state suppresses it while granting melee_immune, flipping who eats whom for twenty turns and flipping back cleanly when it lapses. That needed one more small thing: states could only ever add attributes via grants_attribute, so I added suppresses_attribute as its counterpart. It wins over any granted state, which felt like the right precedence.

Animals Chess was a surprisingly easy extra get while doing this work. A prototype can now declare rank_order, an array of actor ids weakest to strongest, and captures follow it: higher takes lower, equal ranks trade, and the first entry takes the last. Rank is membership in that list rather than a number stapled to each actor, which I like better than integers scattered across files — inserting a piece mid-hierarchy is a one-line edit, and because the ends of the list are derived rather than hardcoded, the rat-takes-elephant wrap-around isn’t a special case at all. It’s just “first beats last,” and a prototype gets it wherever it decides to put the boundaries. None of it does anything unless rank_order is declared, and unranked actors are exempt, so a rank game can still have ordinary monsters wandering around in it.

What I didn’t build is the half that’s actually specific to Jungle: the trap squares where hierarchy is suspended, the water only the rat may enter, the dens. Those are all tile rules rather than actor rules, and they’re the bigger share of that game and would require their own work sprint. The trap square is interesting though, because it’s the same shape as the power pill from the other direction — a temporary suspension of the normal rule, except triggered by position instead of by an item. If I ever build it I suspect it wants to be a state applied on entering a tile, which would make the two mechanics literally the same machinery. This could be pretty useful in a roguelike, say where anyone in a web or quicksand gets instakilled by an attacker (maybe that’s not a good comparison since those actors also put you in a helpless stuck state, which makes the “who moves first” part moot since you can’t move at all for a while.)

The other thing worth noting: this only gates damage, not what the AI decides to do. Target selection goes through isEnemyOf, which is flat faction membership and knows nothing about rank, so a ranked AI will happily throw its cat at your elephant every turn and bounce off. Making that smart is behavior-library work. It’s a good reminder that “can I hurt this” and “should I attack this” are genuinely different questions and I’ve only answered one of them. Some reusable chunk that lets npc actors know when they are outmatched would be really useful to add to personalities, and could even reuse the player-controlled actor attribute tactician and give it a meaning for npc’s.