Home

Awesome

Legend of Swarkland

Status

Simple turn-based action fantasy puzzle sandbox. See Version History for latest updates.

How do I play it

A Windows build can be downloaded from here: https://wolfesoftware.com/legend-of-swarkland/

Here's how to build from source on Linux:

  1. Get Zig version 0.9.x from ziglang.org.
  2. Get other dependencies:
    • NixOS: nix-shell --pure -p python3 -p git -p clang -p SDL2
    • Ubuntu: sudo apt-get install python3 git clang libsdl2-dev
  3. zig build
    • Bonus points: zig test -lc src/index.zig
    • To build for Windows, add: -Dtarget=x86_64-windows-gnu -Drelease-fast=true
  4. ./zig-out/bin/legend-of-swarkland

Design goals

Legend of Swarkland aims to be an interesting, fair, complex, challenging experience. The primary inspiration for this game is the fabulous complexity of NetHack. After getting into NetHack, I became frustrated by several core aspects of its design, and this project was born as an attempt to realize what I believe is even greater potential.

  1. Client/server architecture
  2. Learning the game should not be frustrating
  3. Fabulous complexity
  4. Avoid grinding
  5. Seeded randomness
  6. Open source

Client/server architecture

A significant NetHack community grew around the alt.org servers, where players log in via Telnet and play the game in a terminal. The server facilitates leaderboards, spectating, and even some limited interaction between players.

However, because the interface was limited to a terminal using Telnet, this simultaneously created both a strong motivation for custom client interfaces and significant friction to implementing such interfaces. For example, instead of seeing all monsters as single letters like a for ant and b for blob, you might want a client with a graphical tileset where ants actually look like ants. The problem is that a is also the letter for bees, b is also for slimes, and so on. This ambiguity can be somewhat mitigated by using terminal colors to distinguish between the different variants, but that can only take you so far. There are 28 different &s, 58 different @s, and 74 )s (not counting artifact weapons). Furthermore, the terminal interface does not distinguish between unexplored squares and dark tiles (that have no items/traps/etc). In some cases the ambiguity is even intentional, such as the purple @ Wizard of Yendor summoning a purple @ elvenking as a decoy.

These ambiguities in NetHack's interface can be further mitigated with the v command, which allows you to move a cursor around the map and inspect each square. The game will give you a textual description of what you see there. So it would technically be possible for a custom client interface to constantly use the v command in the background to populate its model of the game state, but this creates tons of problems when it's not clear when the v command can be used.

(It's worth noting that a project called NetHack 4 addressed many of these concerns by creating a fork of NetHack that overhauled a significant amount of the game's core. That's a great thing they did, and I'm happy for them. But the client/server interface is only one problem I have with NetHack's design.)

Legend of Swarkland considers client/server separation as a core design principle. It's so fundamental that the official "rules" for what information is fair game is exactly the information in the network protocol. Down to the sort order of the information presented in the network packets, it's all deliberate and designed to only reveal exactly what the human player is supposed to know.

Contrast this with Minecraft, where, unlike NetHack which sends too little information, the Minecraft server sends the client too much information: full 3d terrain data in a radius around the player, including precious information about the location of nearby buried treasure. However, "X-Ray Texture Packs" that reveal the client's data to the human player are generally considered cheating.

This is even more problematic if someone were to write a fair AI that played Minecraft by using the network protocol (a project I dabbled in back in 2011). The AI would need very complex 3d ray-casting logic to restrict its knowledge to what a human is supposed to know in order to play "fairly".

Of course, simply using an AI to play Legend of Swarkland for you would be considered cheating just like if you were to do that in a game of online chess. But writing an AI sophisticated enough to outperform humans should be encouraged as a challenge, and respectfully asked to be kept out of the humans-only leaderboards. There should be separate leaderboards for AIs to compete, and both human and AI players are first-class citizens of the Legend of Swarkland community.

But of course, you shall always be able to play Legend of Swarkland offline thanks to the client program including all the code for running a server. (Running everything in a single process also helps debug the program while it's in development.)

As another convenience to server maintainers, the legend-of-swarkland.headless executable program has no dependencies on any UI-related libraries, so it can be built and run on a server without SDL or even X installed.

Learning the game should not be frustrating

One of the most delightful aspects of NetHack is how many ways there are to lose the game. You might try praying for help while in Gehennom. You might get attacked by an electric eel while hovering above water wearing a ring of levitation. You might try descending stairs while encumbered and wielding a cockatrice corpse. The NetHack wiki has an article devoted to listing hilarious ways to die.

The sting of failure makes victory even sweeter, and comedic misfortune has its place in our hearts. But when you don't know what you're doing, sudden death sucks. NetHack is brutally punishing, which is fun when you know what you're doing, and terribly frustrating when you don't.

Most beginners will turn to the wiki as a guide for learning the game. Some consider this "cheating" or not within the spirit of the game, but NetHack is so complex, cryptic, tedious, and punishing that attempting to learn the game through pure trial and error is unreasonably demanding of your time and patience. Does eating Medusa's corpse grant immunity to petrification or does it instantly stone you? Answering that question through trial and error would probably be a 4 hour investment for a beginner who manages to make it that far.

NetHack is unplayable without the wiki, but by reading the wiki, you're missing out on the joy of discovery and exploration.

Legend of Swarkland aims to solve this in two big ways.

First, Legend of Swarkland features a practice mode where you get an unlimited undo button. This is similar to how the old adventure games like Monkey Island or Return to Zork let you save the game anywhere and maintain multiple save files. Now if you want to know what happens when you eat Medusa's corpse, just try it and undo. Rather than losing 4 hours of progress, you spend 5 seconds peeking into the game's mechanics. You are rewarded for experimenting, not punished for it.

When you're ready to play competitively, play in hardcore mode, which is identical to practice mode, except that there's no undo button.

The second way Legend of Swarkland aims to discourage spoilers from a wiki is by including the wiki in the game itself. Games with enough complexity really need a wiki to organize information about the game. Wikis are useful and important and structured perfectly for navigating around to explore concepts and content. The big downside of a wiki is the spoilers, but in the builtin wiki for Legend of Swarkland, the wiki will only contain information that you have learned by playing the game. The article on Medusa won't say what happens when you eat her corpse until you try it and find out. The wiki starts out empty, and fills itself out as you explore the game.

The wiki's completion will persist across multiple playthroughs, and persist through undo. The wiki will have vacant placeholders for missing information to give you a sense of progress toward 100%. For some of the more obscure facts that could not reasonably be learned with first hand experience, there will be a variety of ways to fill in the gaps such as fortune cookies, rumours from NPCs, and literal guide books that you can find and read in game.

The UI for the wiki will probably be the system web browser, and the legend-of-swarkland binary will serve the content on localhost. Unlocking wiki content will happen client-side.

For those who really want spoilers, that's fine; there will be a 100% completed wiki readily available on the web somewhere. Legend of Swarkland is open source, so there's no point in trying to keep any secrets. The purpose of the slowly unlocking wiki is not to keep the player in the dark; it's to encourage players to experience the game the intended way without missing out on the structural features that a wiki provides.

The builtin wiki concept is similar to an in-game journal that fills itself out with journal entries as you play the game. But the problem with the journals in games like Spelunky is that they're useless. Spelunky says about the scorpion enemy "A predatory arachnid with a poisonous stringer on its tail", but does not mention that it has 2 HP and is therefore possible to sacrifice on altars, and doing so grants 4 points of favor. The wiki article mentions all of those things and more. Legend of Swarkland's in-game "journal" will actually be helpful, not worthless flavor text.

A critical aspect of wikis that has not been mentioned yet is the collaborative editing from the community. Legend of Swarkland's builtin wiki will be personalized for the player, and the player can add any notes they wish. The core of the content of the wiki, however, will come from the official, centralized source repository. Edits to the source of truth would be pull requests or some other curated submission process. There can be a feature that automates creating reviewable patches from your edits to your personalized wiki to streamline the process for non-programmers.

Fabulous complexity

Legend of Swarkland aims to have comparable complexity to the gold standard of complex game design, NetHack. Although the details of Legend of Swarkland's complexity have not yet been fully fleshed out, it will be heavily inspired by what NetHack has already accomplished.

To illustrate a glimpse of the fabulous complexity of NetHack, here is an excerpt from the wiki article on mirrors:

You can apply a mirror to a monster to scare it; this only works if they can see it (i.e. are not blind, have eyes, you and the monster are not invisible (unless the monster can see invisible), etc.). [...] Humanoid foes (and unicorns) are not fooled by a mirror and won't be frightened. A cursed mirror only works half the time, the rest of the time it will "fog up" instead.

Here is another excerpt from the guide for how to remove cursed equipment that is stuck to you:

  1. If the cursed object is armor, let an incubus or succubus remove it with their seduction attack.
  2. If the cursed object is causing you to levitate, float over a sink. You will crash to the floor, and the item will be removed.
  3. If the cursed object is armor or a weapon, polymorph into something that can't wear armor or wield weapons. Changing into were-form also works; werewolves will destroy armor they are wearing, while werejackals and wererats will shrink out of it.

This should give you a sense for just how sophisticated the simulation is in NetHack.

However, NetHack has a problem with its complexity. The game rules are almost consistent, but several rules are different for you and for enemies. While polymorphed into a vampire, you can perform the vampire's life-draining attack on your enemies, but as an incubus you cannot perform the seduction attack. When you polymorph into a nymph, you can perform the item stealing maneuver just like an enemy nymph would against you, but you cannot teleport away afterward like an enemy nymph would after stealing from you.

A clever player might think to polymorph into a nymph in order to steal an item from an enemy, and that intuition would be rewarded. But if the same player polymorphs into a nymph intending to teleport, that intuition would be punished. Why can't players teleport while polymorphed into a nymph? I don't know. It seems arbitrary and unfair.

In Legend of Swarkland, one of the most important game design principles is that everything should be fair to everyone in the game world; you are not special. Starting in version 5.0.0, the code that runs the game rules is so fair that it isn't even aware of which individual in the world is being controlled by the player. (There may end up being a few practical exceptions to this, such as only simulating the world around the player.)

To accomplish this, the server-side code is divided into two components:

  1. The facilitator, which accepts connections from player clients, creates new games, and manages the lifecycle of AI clients that control enemies.
  2. The game engine, which implements all the complex game rules, but has no concept of which individual is being controlled by which decision maker.

The player client along with the AI clients are collectively known as decision makers. They get information about what their characters can see, and then have to decide what to do next and send that decision to the server.

The server-side facilitator collects the decisions that everyone is making and sends them all to the game engine. The game engine runs a (pure) function that determines the consequences of those decisions including personalized observational information for each decision maker from their perspective. The facilitator then distributes that information back to each decision maker, and the cycle repeats. All communication with decision makers happens through a serial protocol that is the same for AI clients and the player client.

The AIs do not have privileged information about the game state; they're playing by the same rules you are. The only reason why the monsters want to attack you instead of each other, is that the AIs are programmed to attack humans and not any other species. Note that the AIs are not part of the game engine, but instead are managed by the facilitator.

One consequence of this fair design that already existed in version 5.0.0 is that the game would only unlock the stairs to the next level when all individuals but one had been killed, but that last standing individual didn't have to be you. If you got yourself killed while the last living enemy was already standing on the stairs, the game would advance that enemy to the next level. In the final level, you could even manage to see the "you win" screen with a lone enemy standing triumphant over your (not shown) dead corpse.

Legend of Swarkland's rigorous dedication to fairness will have several consequences on the game design. It will be generally good for making the game engine make sense to players, but it will also become impossible to implement several beloved features of NetHack. For example, the "conflict" effect in NetHack causes all monsters to attack everything in sight instead of just you. It's not possible to mind control the human player (without removing their agency), and so because conflict cannot be used against the player, it would not be fair to use it against the AI. An additional consideration is that super powerful abilities, like genocide, need careful balance scrutiny if monsters can use that super powerful ability against you.

In the now-deleted code of Legend of Swarkland 4.5.0, we were starting to see several good ideas emerge from the fairness oriented game design. Most of the examples involved enemies having limited perception, just like you have. Monsters (and you) can have blindness, invisibility, telepathic vision, or any combination of the above, which led to situations where monsters could be convinced to attack each other if they couldn't tell who exactly they were attacking. Additionally, item identification was fair for both the player and the monsters. You wouldn't know if the wand in your hand was a helpful or harmful wand until you observed it in action, and the same goes for the enemies. This led to situations like an ogre guessing that an unidentified wand is harmful, and angrily zapping it at you, only to find by seeing the effect on you that it's a helpful wand of speed, so the ogre then zaps themself with the wand. All these ideas worked very well in a fair game engine, and will probably return in the new code of version 5+.

There is a long list of features I'm considering adding to the game someday, but this is a discussion of design goals, and is not the place for an exhaustive list. If I formalize a list of planned features someday, I will link it here. For now, it's mostly just a bunch of ideas floating around in my head.

Avoid grinding

Grinding is defined by the player repeating an action to gain some in-game benefit. Grinding is pervasive in video game design, and it is often used to make games more compelling to play. RPGs are notorious for being rife with grindy elements, like fishing for hours trying to get that 1-in-2000 rare fish for a quest. NetHack has its own problems with grinding, but they're certainly not the worst industry has seen.

Legend of Swarkland aims to avoid grinding by design.

One red flag in game design that there might be grinding is simply having large numbers, where large means above 6 or so. Some common places for these numbers: hit points (hundreds?), gold pieces (thousands?), experience points (tens of thousands?). The trope of "weapon damage vs health bar" is so prevalent in action game design that people seem to accept that that's just the way action games should be designed. But consider instead the Mr Freeze fight in Batman: Arkham City, in which you must outsmart the enemy by using 8 or so different attacks on him. This isn't a boss encounter where you pelt bullets repeatedly until some number in memory eventually reduces to zero. Each hit on the boss is unique content; no grinding.

Legend of Swarkland currently has the ambitious goal of having no health bars anywhere.

When health bars are in an action game, they usually serve a few distinct purposes:

  1. Your health bar can enable you to make a limited number of mistakes without reaching a failure state. e.g. The Legend of Zelda, Crypt of the Necrodancer
  2. Your health bar can additionally be a resource that you spend and manage strategically. e.g. The Binding of Isaac, Slay the Spire
  3. An enemy health bar can be used to elongate the encounter while you constantly pelt the enemy with attacks. e.g. Contra, Metroid
  4. An enemy health bar can additionally function as a "level check" barrier that you cannot get past without leveling up elsewhere first. e.g. Final Fantasy, Dark Souls

Legend of Swarkland aims to achieve all those goals without relying on health bars. Here are some alternative solutions:

  1. For mistake forgiveness, a mistake may inflict you with a slow inevitable death that you can recover from by using life saving resources such as drinking potions or calling in a divine favor. In practice mode, you can always use the undo button. In hardcore mode, you don't necessarily need much mistake forgiveness.
  2. There will be plenty of resources to manage strategically that aren't a health bar.
  3. Elongating boss encounters can be done through boss design. Perhaps the first hit lops off an arm, which changes the available attacks and enrages the AI. Perhaps the goal of the boss encounter is to navigate them around obstacles toward a pit of lava and get them to fall in. And it's ok for there to be obscure powerful strategies that instakill certain bosses, like throwing cockatrice eggs.
  4. Level check barriers can be done by making an enemy simply immune to all of your available attacks. Then instead of theoretically being able to grind in place and eventually get past the enemy, you have to go looking for a weapon or trick that will get past them. This makes it more of a metroidvania or puzzle barrier than a big-numbers check.

Legend of Swarkland will have lots of 1-hit kills when the attacks are with weapons like swords or axes. More variety in combat can happen in the form of inflicting status conditions rather than outright killing opponents. Perhaps a giant mosquito infects you with a disease, and then attempts to flee. Perhaps a dog bite causes a bleeding condition, and subsequent attacks can cause limping. Perhaps getting hit with a thrown rock causes a dizzy condition.

There is also lots of opportunity for content in enemy AI design. Instead of everything being dead set on killing humans, perhaps some monsters are simply territorial, and running away deaggros them. Perhaps some monsters will retreat from attacking you if you demonstrate to them that you are a formidable threat. There can even be monsters that naturally fight each other, like a mongoose attacking a snake, or elves attacking dwarves.

By resisting the game design tropes of big number stats, Legend of Swarkland will naturally avoid boring filler content like NetHack's rock troll, which is just a troll but with bigger numbers. Every addition to the game must be justified with unique content.

Another more subtle source of grinding in games does not take the form of big numbers but of big spaces. Walking down a hallway in NetHack can cause a "Death by Boredom" if you hold down the movement key and don't react quickly enough when a floating eye shows up in the darkness just in front of you. In this example, pressing the "move to the right" button repeatedly is considered grinding.

NetHack also has a problem with Gehennom having too many long boring maze levels. A good strategy for Gehennom is to meticulously pickaxe through the walls to connect the stairs with a straight shot path. The amount of time that takes depends on the number of randomly generated maze levels in Gehennom, which is something the devs just typed into a text file. There's no difference in the amount of content between 5 maze levels and 10 maze levels. There's only a difference in the amount of time it takes a player to get through them.

Legend of Swarkland will try to avoid long corridors, and instead have smaller, more interesting spaces where every move counts.

Legend of Swarkland also intends to have a large open world design, so to avoid long boring walks, there will need to be lots of fast travel available. Teleportation is easy to implement, but I want to try to avoid teleportation for the sake of balance and fairness. Perhaps you will open Portal-style portals that connect areas that you or anyone else can walk through. (This would also mean that sufficiently capable enemies could also open such portals.)

Seeded randomness

A well established feature of modern roguelikes is seeded playthroughs. This is useful if players wish to race each other in real time and don't want the random nature of roguelikes to favor one player over another. A seeded playthrough will guarantee that both racers see the same world with the same items and enemies generated in the same places.

Legend of Swarkland will have multiple uses for randomness in the game, and they should all be deterministic from the initial world seed and the sequence of player decisions. In this way, any playthrough of the game can be recorded and replayed using only the world seed and the sequence of decisions. This means that TAS tools are effectively builtin in the form of practice mode. In the now-deleted code of Legend of Swarkland 4.5.0, this reply feature powered the mechanism for restoring saved games and even for running unit tests.

One of the notable implications of deterministic randomness and client/server separation is that enemy AIs have to be specifically programmed to be deterministic as well, especially in the event that a player in practice mode hits undo.

Open source

Legend of Swarkland is a passion project, not a business venture. I will always keep my contributions to this project free and open source.

Legend of Swarkland is licensed under the MIT License. See LICENSE.md.

Roadmap

5.7.0

Version History

5.6.1

5.6.0

5.5.0

5.4.0

5.3.0

5.2.0

5.1.0

5.0.1

5.0.0

4.6.0 (unfinished)

Why the C++ code was abandoned:

4.5.0

4.4.0

4.3.0

4.2.0

4.1.0

4.0.0

3.1.0

3.0.0

2.0.0

1.0.0