Delta-Eos - ASCII Text-Heavy Murder Mystery Game
Tags: ruby, gamedev, showdev
Published: 2019-10-30 15:35:44

---
title: Delta-Eos - ASCII Text-Heavy Murder Mystery Game
published: true
description: 
tags: ruby, gamedev, showdev
series: delta-eos
---

## I can do better, he thought. 🤔 

After a long day of coding, I thought I would unwind and do some leisure programming. I had recently played [Disco Elysium](https://en.wikipedia.org/wiki/Disco_Elysium) which is a text-heavy adventure game where you are an amnesiac detective trying to solve a murder. While I had initially enjoyed the game because it appeared the story could play out differently based on your choices, it turns out your choices didn't really matter. The murder was a random actor and the game left no clues or means for you to solve the mystery through your own actions.

Like all projects, I always think "I can do better". I know very well I will not complete this game or likely spend any more time on it, but its a fun endeavour to run with something for an hour or so before bedtime.

I thought I would share the code and introspective on what I had produced here in this post, instead of dumping this knowledge in the nearby trash.

## Defining the Pillars 🏛️

I knew if I wanted to make a truly successful game I needed to define my Pillars of Success.

1. **Underbelly** Every character no matter how seemingly insignificant, through your own actions, should unveil a dark underbelly that contributes to the story. eg. Turns out the shoeshine boy was actually a spy
1. **Forks** The world should change based on key decisions that will remove/add or change characters and locations. We will call this story forking where it's a serious challenge to stay neutral (of course through great means you should be able to stay neutral). eg. Which side do you choose to be on? The axis or the allies?
1. **Senses** Dialogue choices are not your only options here. We want a rich world of interaction.
1. **Tic-Tock** There is a deadline that can be sped up or slow downed based on your actions. The game could end on day 2, 3 or 7. It up to you. You need to maintain something daily or the game could end abruptly. eg. pay your hotel room per day

## World Architecting 🌎

Now knowing some of our own high-level rules how can we achieve this?
If we want a rich and forking story with many possible interactions then we need to define the scope of our world and characters.

### How many characters?
In Disco Elysium I could count from memory around ~35 characters. I would say only ~12 characters were of any true importance. So we could say here 12/35. I think I would like my game to be more 24/35.

### Dividing the world?
In Disco Elysium on your third day, another half of the map was opened to you. I do like the gating of areas in games. What I didn't like about Disco Elysium was this second world was vast and empty. This caused the second half of the game to be a grind of running long distances to talk to characters at opposite ends. 

I think for my game I would like to gate the world into 4 areas. I would want an in-game fast travel system eg. Trolly or Elevator. Also, I would want to avoid map design where you have two far points and more of a circular map design where one area always leads to another. You can always make your way back to the center. I guess you could say like the spokes on a bike wheel.

### Where are we?

I watch a lot of Star Trek, so dreaming up a Science-Fiction would come naturally. Also, this means I won't have to research in detail the police procedures since this a fiction world I can make up any rules I see fit and give an in-universe explanation.

I want the boundaries of my world well defined so I think a large spaceship would be a well-suited setting. It is also really easy to define all the components (rooms) you'd expect in a starship.

## Who are we?

An amnesiac detective. Unoriginal? Yes, but it works so well.

## Building the game 🔧

I first thought I could make a game with [Stardew Valley](https://www.stardewvalley.net/) like quality graphics, but at this point what is going to get me most excited is the interactions of characters and rooms.

I was considering making the game entirely like a MUD but I really hate having to type `look for x`, `describe y`, `talk to z`. So I thought it would be better just to present all the choices like a select box.

While coding my select box functionality within my terminal, I could not capture single keypresses with ruby just using `gets` which requires you to hit enter after input and so I decided to use the Ruby implementation of [Curses](https://github.com/ruby/curses)

Then I came [across this article](https://www.linuxjournal.com/content/programming-color-ncurses) by chance while trying to figure out how to colour the background of a character. In this article, someone was building an ASCII map with a character (see image below).

![](https://thepracticaldev.s3.amazonaws.com/i/m684zoe664qlaioveg1x.png)

And so from that point I thought, I can make my world out of ASCII characters.

## Creating the Rooms

I needed an easy way to create the rooms, and so I found this very nice editor which would save me a considerable amount of time.

![](https://thepracticaldev.s3.amazonaws.com/i/wzemmbh4wzq43831eh49.png)

## Building the Game

Since I've built games before I decided to ensure my Classes hold no state because it makes writing test code very painful down the road.

All the data for my game is held within one hash for now.

```ruby
data = {
  running: true,
  player: {
    position: {
      room: 'hall',
      x: 5,
      y: 5
    }
  },
  rooms: {
    hall: {
      data: File.read('rooms/hall.txt'),
      position: {
        x: 0,
        y: 1
      }
    }
  }
}
```

All classes do is preform operations on the passed in data and output which is then stored back in the data hash. So take the up here as an example. When we press left, we pass in the data and assign its output.

```ruby
ch = getch
case ch
  when 'h' # left
    x = Player.left data[:player][:position][:x]
    data[:player][:position][:x] = x
end


class Player
  def self.up y
    y-1
  end
end
```

My rooms are all going to be defined by a text file accompanied by metadata about the room possibly a JSON file. So next I need to break up each room and set collision detection and interaction with objects.


So far I can render out a single room, which is centred in my terminal and I can move the player around.

![](https://thepracticaldev.s3.amazonaws.com/i/p3gfe8d8u2ytehxnd6i4.png)


Here's the code if you're interested:

{% github  https://github.com/omenking/delta-eos %}