Heroic Fisticuffs!

Here's a place where I talk about games, applications, websites, and other things that I make for fun. Mostly roguelikes. And robots. Since my domain is hard to spell you probably came here on purpose.

Welcome to my underground lair

Hardpointe is set on the asteroid lair of an evil robotic overlord - conveniently enough these lairs are surprisingly similar to dungeons. A bit.

Level design is the great time sink of every roguelike developer. I have a system that I've developed over the years (mostly for my 2014 7DRL dungeon dual) that I call the floorplan approach, which basically smashes a bunch of rectangles together. Once you have rectangles, you can easily convert them into rectangular rooms, or other shapes (cross-rooms, ovals, etc.) that will still fit within that bounding rectangle.

For Hardpointe, I have brushed off this algorithm and cleaned it up a bit to make it less wasteful. I am rather liking the results so far.

While level design is great, what I really want to get to is 'lock and key' style puzzle rooms. Think of the key rooms in brogue, or the linked challenges in Unexplored. Or zelda. In any event, Tom Ford did a lot of work around this in his 2014 7DRL TraumaRL and then did a great talk on his approach.

In order to accomplish this, I first needed a more intelligent level designer - one that kept track of separate rooms as if they were nodes on a graph. I had to brush off a part of my brain that hadn't been used since CS classes many years ago, but got a working tree structure that should suit my needs.

I used treant.js to display the resulting graphs.



This first one corresponds with the above dungeon output.

Red nodes/rooms represent the longest (or one of the longest) paths in the level. In most cases, the entrance point will be at the top of the tree and the ending point will be at the deepest node of the tree.

Gray nodes are flagged as "dead ends" in that they have only one connecting room. This makes them great candidates for locked rooms, special challenges (and rewards) that will give the player a reason to explore the entirety of the level, should they choose to.

Here are a few more because I like them:






Heads up

Finally have a working heads up display (HUD) - one of my requirements for releasing an actual playable version of the game. I really want to keep the screen as uncluttered as possible, but at the same time allow players to get the tactical information they need. In general, all monsters have 1 hp and the behaviors are unique, so there is a lot of information that should be conveyed just from playing a few times.




Other important things to know are status effects, and whatever items or unique terrain is near you. (e.g. is that radiation?)


The code to get this working was actually really fun to write.

Other things tackled this week were 'conveyed' flags. Certain powers can now convey flags such as flight, or radiation resistance. In earlier versions I was doing this quite messily - lots of room for error when power systems were being installed or uninstalled. Now it flows quite naturally.

This is important because at some point I plan on adding 'challenge rooms' that require you to sacrifice one of your power slots for an otherwise useless power. For example, there is a really amazing item inside the next system of rooms, but the rooms are irradiated. Fortunately, there is a system near-by that conveys radiation resistance - but you'll have to temporarily sacrifice something else in order to install it. What you choose to do away will may make the next couple rooms harder, depending on what's inside of them.


Development Update: Handling the environment as a proper actor

I may try doing some smaller updates as I typically code in short bursts these days.

Recent Progress:

Doors
Added doors! (Seems silly & was easy enough to do, I just didn't have them in there)

Targeting Locks
Target lock - ranged enemies with this setting now need an extra turn before they fire. This gives you a chance to somehow block or otherwise avoid the shot (force them to move is an easy way). Even with the symmetrical FOV changes I did last week, it still felt like ranged attacks were a bit overpowered. This new mechanic has a fun feel to it - and also differentiates monster difficulty. Now I can have 'easier' ranged enemies that require a target lock - in later levels you may run into enemies that don't. Another idea is to give ranged enemies other disadvantages such as being immobile (turrets).

Environmental Effects
This is mostly behind the scenes, but I added a special 'architect' actor, who acts on behalf of environmental effects (fire, gas, features that interact with player/monsters standing on them). Because my engine is event-based, it was getting a little kludgey to have terrain/feature effects work properly.

This makes more complicated scenarios much easier to deal with. For example, if you want to have differing speeds for the player at some point (e.g. a haste or slow effect) then you want to be sure the 'environment' is behaving. If a player is trying to escape some gas or fire, and somehow speeds themselves up to escape, the fire or gas should not speed up too! Conversely, if a player somehow slowed, the gas should overwhelm them more quickly than normal.

Eventually the architect will also control things like spreading nano-materials and timed explosives.

Actual game mechanics

Lots of tiny steps this week.

I decided to spend some time rebuilding my FOV algorithm, which made it so ranged enemies weren't quite so deadly. This had some knock-on effects that caused me to clean up some more of the AI and generic 'awareness' code behind the scenes. All in all, time well spent.

A main focus of hardpointe is tactical movement, and using the terrain to your advantage. To that end, there are ways for the player to actually create terrain, through various 'nano cores'. These are basically tubes of little nano-bots, and eventually their contents will be unknown to the player until they actually try them out (much like your traditional potions & scrolls). As a placeholder, affected tiles were simply a 5-square 'cross' centered on the point of impact. For the actual gameplay mechanic, I wanted something more interesting, but also predictable. I didn't want a quasi-random plume or cloud of gas. The mechanic I settled on follows a few simple rules:
1. always covers 5 tiles
2. always covers the target tile
3. only grows in cardinal directions, in order: up, down, left, right.
4. if any of these directions are blocked (by terrain, or existing nano-materials) it will stretch in the following direction


This allows the player to (somewhat) reliably create structures that will advantage them, and disadvantage enemies. For example, one of the nano-materials makes you invulnerable for 3 turns, but this affects anyone who steps on the tile - it does not discriminate between player or monster. Combine this with both negative and positive effects and you (hopefully) get some interesting gameplay.
Default spread

Corner limits spread in 2 of 4 directions

Hallways can give you a straight line

Surprisingly (or not surprisingly?) fun so far!

Importance of Symmetry

One of the many joys of roguelike development is getting your ass kicked by your own game! However, in my case some of the deaths to ranged enemies felt like cheating. All I would do is come around the corner and blammo -- dead. Was this an example of my own reckless play style? Or an actual bug in the game?

Turns out the problem was with my Field Of View (FOV) algorithm. Since I am using the amazing rot.js library, I had been using the default recursive shadowcasting field of view implementation. After poking around on roguebasin and re-reading Jice's awesome overview of FOV algorithms, I realized my problem is that my FOV was not symmetrical.

Now, depending on who you ask, symmetrical FOV may or may not matter. In a game with only 3 hit points, every shot counts. While I am loath to ever over-optimize, I felt it would be time well spent. I came across Albert Ford's implementation of a symmetrical recursive shadowcasting and ended up coding something similar in typescript. The end result is exactly what I wanted.

Before (Non-Symmetrical): This bot can see me, but I can't see him. Which means as soon as I step over, I'll be in range and get shot.



After (Symmetrical): Neither of us can see each other. In this case, the bot will move closer to the spot where he last saw me - sacrificing some range and giving me a chance to see him one turn before he can attack.





Initial gameplay coming together

Have been making steady progress on the core gameplay elements of hardpointe. I do feel like the end result is even a little bit.. fun? (Shocking to me most of all)

Here's a longer-play gif of the game in action, with slightly less-embarrassing colors.

Current feature list:

  • All six initial powers:
    • Shield
    • Heavy Axe
    • Booster/Charge Attack (was originally jet pack?)
    • Cloak
    • Phasewalk (not sure if this one will make the cut)
    • Hack (turn enemies into allies)
  • One-off weapons (take up power slots but limited/non-rechargeable ammo)
  • Various combat effects:
    • Stun
    • Knockback (concussive)
    • EMP blast (in progress)
  • Enemy behaviors:
    • Basic melee
    • Keeps distance (ranged attack)
    • Explodes on death
    • Attacks in packs
    • Uses / recharges shield (in progress)
  • Terrain:
    • Chasms (if knocked into one you or enemies drop to the next level)
  • Combat mechanics:
    • Wall-smash
    • Corpse-tossing (heave enemy remains into other enemies)
  • Items:
    • Grenades (simple damage & effects)
    • Nanotech Cores (effects like acid and health - so far)

Whew. Seems a lot longer when I type it out. Stay tuned. 

Return of Heavy Axe

A lot of the powers/abilities in hardpointe are my favorite recycled bits from previous 7-Day Roguelikes. My favorite by far was my 2015 entry: Heavy Axe.

In any event, after some only minor tweaking to the pathfinding code, I now have a 'Heavy Axe' ability in hardpointe that functions much the same: a unique item gets thrown across the map. Use the power again to "recall" the axe, which will travel back to you and smash into any enemies along the way.

I also put a few more gifs on this Sharing Saturday thread on /r/roguelikedev if you want to see more!

Hardpointe Development Principles

I recently ready a blog post called The Slow Application Development Methodology that got me thinking about what I enjoy about hobby roguelike development, but also some frustrating parts of dealing with my own limited productivity.

Here are some brief design development principles for my current project, in the hopes stating them publicly will help me stick to them. These principles come from experience over the course of many 7-Day Roguelike Challenges (both successes and failures) and most importantly, learning my own weaknesses.

  1. Make a game YOU want to play
  2. You are not building a roguelike engine
    (no, seriously..)
  3. Don't reinvent the wheel (ROT.js is your friend)
  4. Work on small chunks at a time - no grandiose leaps into refactoring hell
  5. You really, really, really aren't building a roguelike engine
  6. Aim for a solid 'coffee break' game worth of content.
  7. When you have something that's not embarrassing to play, get some feedback from real users
  8. Expand core gameplay only after #6 is done
Looking to have #7 done by the end of this month.. we'll see! In the meantime, here is some more gameplay. I have 4 working powers, and have completely rebuilt the menu system so that it is super-easy to drop in new interfaces. This is the kind of thing that is boring to code but will make future features so much easier to add.


Hardpointe Updates

Slow but steady progress on hardpointe. While trying really hard not to fall into premature optimization, I did find myself running into a common problem that I have with animation and rot.js (javascript in general). One of the comments in that thread was to use postal.js, which seemed like overkill at first but is actually working extremely well.

At this point, the entire game is event driven, which makes inserting animation or other events in between gameplay super easy.

Here's the latest gameplay, showing one of my favorite attacks, the charge (aka rocket punch). I'm leaving aside decisions on damage aside for now, but probably they will be more lethal.

The overall idea is that the player will not have access to a lot of (direct) ranged attacks. So your best strategy will be to get up close and personal quickly, and then either (a) kill everyone in a few turns (you only have 3 hp or so), or (b) escape.


Hardpointe, a failed 7DRL

Hi everyone. Been a while.

As with every year since... 2010? I entered the Seven Day Roguelike Challenge. I thought I had enough old code lying around and enough free time to punch out something playable, but decided to pull the plug on day 5.5.

Since then, the idea has really stuck in my head and it's a great excuse to kick some of the rust off of my lackluster coding abilities. I've written this one in TypeScript, which is a joy to use along with the VS Code IDE. It makes coding for short periods of time actually possible since it takes almost no time to get back into the "flow". And of course as per usual I am using the amazing ROT.js library.

In any event, here's what the game looks like so far:
I have a few design principals for this game, called "hardpointe":
1. Tactical combat built from fun mechanics
2. Interesting enemies, with behaviors that match their abilities
3. No numbers over 3
4. Minimal buttons/input keys (4b: playable with a gamepad)

The main idea is to have the player build up a small set of powers across a restricted (3-4) number of "systems", which can be activated with limited resources. Think Mega Man but with less recharging. As close to a "one hit point" system as I can manage. Right now 3 health feels right. Enemies have 1 or 2 health. The goal will be to destroy as many as possible without getting hit by chaining together attacks, abilities, and escape mechanics.

Right now all I have is a wall-smash, which I find very satisfying. Enemies have 2 health, and the player typically does 1 damage. But, if you attack "into" a wall you will deal 2 damage and can use this tactic to take enemies out before they have a chance to scratch you.

More to come. Meanwhile go and play my favorite 2017 7DRL so far: Woozoolike.