Rooms have traps. We have established that. All well and good. But trap-layers do not sprinkle their work around willy-nilly. A seasoned engineer would place his camouflaged pits, poison needle traps and swinging blocks close to the obvious points of interest, namely (a) the treasure and (b) the way out.
So far, when creating a room, we have allocated the trap (or traps) to random tiles. From now on, the closer a tile is to a treasure tile or an exit tile, the more likely it is to be trapped. Here. This diagram should clear things up.
In the digram above, the probability of a tile being trapped is shown using colour. The treasure tile and the exit tile have a high chance of being trapped. The probability of a tile being trapped decreases the further you get away from these two ‘hot areas’.
How does this affect the trap placement algorithm? I am glad you asked. If you look at the diagram above, you will see that there are 5 different levels of trap likelihood, as follows:
Now, lets attach some numbers to these 5 different levels, like so:
Very high: 1 in 5 tiles are trapped (i.e. probability of 0.2)
High: 1 in 10 tiles are trapped (i.e. probability of 0.1)
Medium: 1 in 20 tiles are trapped (i.e. probability of 0.05)
Low: 1 in 40 tiles are trapped (i.e. probability of 0.025)
Very Low: 1 in 80 tiles are trapped (i.e. probability of 0.0125)
How do we use these trap likelihood levels? I am glad you asked. Assume we have a room with 100 tiles. If every tile in this room has an equal chance of being trapped, we can do this:
Place the 100 Tile objects in a list.
Generate a random number between 0 and 99.
Select the Tile object whose index matches the random number
When the tiles in the room have an unequal chance of being trapped, we must modify this slightly. We do this by rigging the lottery in favour of the higher likelihood tiles. I will write the code tomorrow, but basically this means I would clone the Tile with a very high likelihood of being trapped, giving it 16 entries in the lottery. Tiles with a high chance would get cloned 8 times, and so on. It will work out, I promise 🙂
I am trying to write a pithy description of the game for the player’s guide. This is what I have so far:
Rogue Code is a programming game in which you script the behaviour of an adventurer who is raiding a dungeon.
The dungeon has many rooms. These rooms contain treasure, traps and guards. The adventurer wants to steal the treasure while avoiding the guards and traps.
Your adventurer progresses through the dungeon one room at a time. Each time the adventurer beats a room, the next room is unlocked.
A room always has the same contents (e.g. one guard, one trap, one treasure chest) but the location of those contents changes each time the room is created.
You prepare a rogue for a dungeon raid by writing code. Starting with a basic template, you will customise various aspects of the adventurer’s behaviour.
Once your rogue is complete, you can release him into the first room. Thereafter, the action is turn based. In his turn, the adventurer moves, fights and steals, according to the instructions in your programming. Then the environment reacts (e.g. a trap detonates, a guard moves to attack etc.)
Turn based action continues until the rogue has stolen the treasure and exited the room (thereby beating it) or he is dead.
If the rogue beats the room, he is automatically released into the next room.
Step 8 repeats until the rogue dies.
The source code for the rogue cannot be changed after the first room (i.e. no room specific ‘tuning’).
The final score for a rogue is the number of rooms he can beat before he is killed.
The rogue must raid the dungeon multiple times. This mitigates the potential unfairness that randomising room contents could introduce (e.g. you might start your raid right next to an angry guard!).
That brings us to another game rule. (3) At the start of the game, one or more guards are placed on random tiles in the room. When picking random tiles for the guards, all tiles are legal. The guard (or guards) can be placed on
An edge tile
A non-edge tile
A tile containing the exit door
A tile containing another Guard.
A tile containing treasure.
A tile containing a trap (the guard knows how to avoid it, so it will not trigger)
A tile containing the Rogue!
Our example has just one guard. More guards could be added to increase the difficulty of the room.
Points (4) and (7) uncover an important design decision, namely, that more that one character can inhabit a given tile at a given time. Characters effectively stack. There is no limit to how many of them can be on one tile at a given time. Of course, there are consequences to this sort of proximity (i.e. combat and death). More on this later.
Let’s finish off the set up. (4) At the start of the game, one or more treasures are placed on random tiles in the room. In this context, a random tile is any tile in the room except the tile currently occupied by the Rogue (no free gifts, right?). Accordingly, the treasure must be placed after the rogue has been positioned. Our example has just one treasure tile. More complicated rooms could have lots of treasure.
Finally, we get to traps. (5) At the start of the game, one or more traps are placed on random tiles in the room. In this context, a random tile is any tile in the room except the tile currently occupied by the Rogue. His/her starting tile is assumed to be safe. Therefore, the traps must be placed after the rogue has been positioned. However, traps are more likely to be found near treasure tiles (trap allocation algorithm to follow). Therefore traps must be placed after treasure. Our example has just one trap. More complicated rooms could have multiple traps.
So before I dive in and start writing code, let’s get some theory worked out. Let’s use a simple HTML table to represent the room, with the following notation for fixtures and fittings:
R stands for Rogue
E stands for exit
T stands for trap
G stands for guard
X stands for trap (x marks the stop right)
So, this is a room containing 36 tiles, set out in a 6 x 6 formation. At the start of the run, the Rogue is positioned at (4, 5). These (x, y) coordinates assume that the top left cell in the table is (0,0), and the cell at the bottom right of the table is (5,5). Game rule 1 – At the start of the game, the Rogue is placed on a random tile on the edge of a room. In the room above, there are only 20 legal start positions for the Rogue. All of the legal tiles match one of these four patterns:
Thus, for any square/rectangular room comprised of h x w tiles, there will be (2h + 2w)-2 edge tiles which can be used for the Rogue’s start position.
A similar restriction applies to the exit. Game rule 2 – At the start of the game, the exit is positioned on a random tile on the edge of a room. An exit in the middle of a room doesn’t make sense, right?
After a little playing around, I decided to stick with C# for the implementation. I want to do this pretty fast, and I don’t want to learn a new language as I go. I have dumped some code into a GitHub repo. It’s very basic. It creates a command line representation of a room (R = Rogue!). More to follow.
By the way, the Visual Studio extension for GitHub works very nicely. Microsoft are really playing well with others at the moment.