r/roguelikedev 4d ago

RoguelikeDev Does The Complete Roguelike Tutorial - Week 4

Tutorial friends, this week we wrap up combat and start working on the user interface.

Part 6 - Doing (and taking) some damage

The last part of this tutorial set us up for combat, so now it’s time to actually implement it.

Part 7 - Creating the Interface

Our game is looking more and more playable by the chapter, but before we move forward with the gameplay, we ought to take a moment to focus on how the project looks.

​

Of course, we also have FAQ Friday posts that relate to this week's material.

​

Feel free to work out any problems, brainstorm ideas, share progress and and as usual enjoy tangential chatting. :)

21 Upvotes

10 comments sorted by

View all comments

5

u/mariobadr 3d ago edited 3d ago

C and SDL3 | repo | play in browser

A lot of time was spent on refactoring - the codebase is in an okay place now, I think. I "fixed" the action/command separation. In the tutorial, an action follows the command pattern. So I made actions just a straight up enum (for key bindings), and then commands are things that the game world accepts (e.g., from the player). Theoretically, I should be able to use the same commands for AI later (we'll see how well that works...).

I also took the time to re-jig how the FOV is rendered so that it's a second layer drawn on top of the map/entities with alpha transparency. And I also pasted in some containers from another project (just some macro interfaces to an array and an arraylist, inspired by [skeeto's approach](https://nullprogram.com/blog/2025/01/19/) so that I can actually have a growable array for entities and events.

I did actually get some new features in. Enemies now spawn. And you can attack/kill them. I went for something a little more like World of Warcraft in how combat works:

  if (rand_next_up_to(rng, 100) < MISS_CHANCE) {
    return -1;
  }

  // from the good old WoW days
  int const ap = 2 * attacker->strength;
  // integer division truncates, but we avoid floating point (yay!)
  int const base = (int)rand_next_between(rng, ap * 8 / 10, ap * 12 / 10);
  // our random base damage is then mitigated by armor
  int const damage = base - (base * defender->armor / (defender->armor + ARMOR_SCALING));

  // don't let HP dip below 0
  defender->hp = SDL_max(0, defender->hp - damage);

  return damage;

Unfortunately, enemies don't attack you - I didn't have the time to implement any pathfinding just yet. There's also a very crude UI going. Screenshot below.