User:Duerig/Archive4

From RogueBasin
Jump to navigation Jump to search

Recursive Level Generation - Radomir 'The Sheep' Dopieralski [sheep@venus.wmid.amu.edu.pl]

Introduction.


This article contains some of my thoughts about level generation in roguelike games. It's inspired with an algorithm used in Alphaman to generate buildings, some articles red on Roguelike News and, that's a little odd, Bison and Yacc input files format. The ideas may seem a little complicated and hard to implement, but I hope the article proves useful in some way.


Overview.


The idea is to describe the level in form similar to BNF (Backus-Naur Form), used usually for describing context-free grammars.


It's natural for humans to describe large and complicated objects in terms of more simple ones. So we can describe a level. For example:

a level is either: a maze, a dungeon, a cave, a castle, etc...


a maze is a set of connected corridors and crossroads.


a corridor is a vertical or horizontal line of floor tiles, surrounded by walls on each side, opened at at least one end.


a crossroad is a single floor tile with walls around, opened in at least two directions.


a dungeon is a set of rooms, crossroads and corridors.


a room is either: a vault, a minor vault, an ordinary room. etc...


There are some rules not covered here. For example, we'd like to ensure each place of the level is reachable. It's not very easy to do, so we won't try to describe any level type, like in the example above. We'll try to only describe (and then generate) some special level type, constructed by dividing rooms.


Alphaman's buildings.


We will use an algorithm similar to this used in Alphaman. I'll first describe the original algorithm. It is quite simple:


1. Start with a large, empty room. XXXXXXXXXXXXXXXXX X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X XXXXXXXXXXXXXXXXX


2. Pick an acxis (horizontal or vertical) and a point within the room (far from walls). Let's suppose we have picked horizontal axis and point marked with '1'. XXXXXXXXXXXXXXXXX X...............X X...............X X...............X X...............X X...............X X...............X X...............X X......1........X X...............X X...............X X...............X X...............X X...............X XXXXXXXXXXXXXXXXX

3. Make a wall in selected axis, crossing the chosen point, ending at the room's walls and with door in point '1'. XXXXXXXXXXXXXXXXX X...............X X...............X X...............X X...............X X...............X X...............X X...............X X######+########X X...............X X...............X X...............X X...............X X...............X XXXXXXXXXXXXXXXXX

4. You get two new rooms. Repeat the procedure with those of them, that arte large enough. XXXXXXXXXXXXXXXXX X...............X X...............X X###########+###X X...............X X...............X X...............X X...............X X######+########X X.........#.....X X.........+.....X X.........#.....X X.........#.....X X.........#.....X XXXXXXXXXXXXXXXXX

5. You end up with set of interconnected rooms, with exactly one way between every two rooms. Something like a tree.

The procedure is simple, but the result is not very nice. It's always a labirynth of rooms and you usually have to walk a lot to explore it. We'll try to make the result better.

Adding corridors.


We can try to add some corridors, so our level will look more naturally and there will be more connections between rooms. So, instead of adding a wall, we'll add two parallel walls, making a corridor. We also add doorways at the ends of the corridors, so there will be more connections. The algorithm goes like this:

1. Start with a large, empty room. XXXXXXXXXXXXXXXXX X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X X...............X XXXXXXXXXXXXXXXXX

2. Pick an acxis (horizontal or vertical) and a point within the room (far from walls). Let's suppose we have picked horizontal axis and point marked with '1'. XXXXXXXXXXXXXXXXX X...............X X...............X X...............X X...............X X...............X X...............X X...............X X......1........X X...............X X...............X X...............X X...............X X...............X XXXXXXXXXXXXXXXXX

3. Make a corridor in selected axis, crossing the chosen point, ending at the room's walls. If the walls at it's ends are not permanent, make some doorways there. XXXXXXXXXXXXXXXXX X...............X X...............X X...............X X...............X X...............X X...............X X###############X X......1........X X###############X X...............X X...............X X...............X X...............X XXXXXXXXXXXXXXXXX

4. Make some doors along the corridor's walls. There should be at leas one door in each wall, so you make sure all the rooms are connected. XXXXXXXXXXXXXXXXX X...............X X...............X X...............X X...............X X...............X X...............X X####+######+###X X......1........X X###+###########X X...............X X...............X X...............X X...............X XXXXXXXXXXXXXXXXX

5. You get two new rooms. Repeat the procedure with those of them, that are large enough. XXXXXXXXXXXXXXXXX X...............X X###+###########X X...........2...X X#####+#####+###X X...............X X...............X X####+######+###X X......1........X X###+#####.#####X X........#3#....X X........#.+....X X........+.#....X X........#.#....X XXXXXXXXXXXXXXXXX

The result doesn't look so bad, especially if the rooms left at the end are big enough (in the example there isn't much place). But there is another problem -- how to fill the rooms with appropriate contents (that is items and monsters)? How to make sure the rooms are connected with some logic?

Level definitions.


Here's what we can do. We don't just split in two similar rooms. We will have to name these rooms and provide some rules how to split them. For example, for a scientific level in sf roguelike:

a level may: (put some probabilities here) be a scientific level;

a scientific level must: be at least SIZE large, but not larger than SIZE;

a scientific level may: consist of two scientific sections, divided (horizontally or vertically) with a scientific hall;

a scientific hall may: be a very wide corridor, with large doors at each end and at least one door at each side; there may be some plants or statues; there may be some scientific guards; there may be some scientific monsters; tehre may even be some scientific scientifists;

a scientific section may: consist of two scientific sections divided (horizontally or vertically) with a scientific corridor;

a scientific corridor may: be a wide corridor with open doorways at each end and at least one door at each side;

a scientific section must: be at least SIZE large, but not larger than SIZE;

a scientific section may: consist of two scientific labs divided (horizontally or vertically) with a scientific corridor;

a scientific lab must: be at least SIZE large, but not larger than SIZE;

a scientific lab may: consist of two scientific labs divided with a scientific wall;

a scientific wall may: be a wall with door in the middle;

a scientific lab may: be a room with tiled floor; there may be some scientific artifacts; there may be some scientific monsters; there may even be some scientific scientifists;

Building a level.


Now, let's see how to produce a random level from such an information. First, we want to build a level. So we look at the definitions and see that our level may be a scientific level with such-and-such probability. But there may be also other level definitions, so we have to choose (randomly) which level definition to choose. Let's suppose we have chosen the scientific level. We see that it has to be such-and-such big, so we provide an empty starting room of given size. Now we look into the definion and see that we have to split our level in two with a scientific hall and put a scientific section on each side. So we pick a point, pick an axis, put aour corridor in the middle and a scientific section at each side. It would be good to pay attention on the minimal size of each of the sections while picking a point to split the level. Then, we have to make our scientific sections. As we look into definitions, we see that we have two choices. So we pick randomly one of them. We can either split these sections into smaller ones, or into scientific labs. At some points, we'll have to do the second thing, because there will be no place to put a scientific section (which is supposedly larger than a lab). We continue down the tree of level fetures, until we arrive at the 'atom' ones, that is the features that doesn't consist of other features, and taht we can generate using other algorithms. Sometimes there may be need for the algorithm to 'back up' wrong decissions, because there is no way it can get to the atoms. This is because of the size limitations. It's a drawback and I don't know how to make sure it ever completes the level. But I believe it can be solved somehow.

Level representation.


With this algorithm you can use different level representations. The most common, simple two-dimensional array will do. But you can also have a linked list of features, or even a binary tree. If there were no doors at the ends of the corridors, you could even generete only these parts of the level you need at the moment, making all the fetures from the root of the tree to the node you want to know.

-- The Sheep

Finding Explorable Regions - Ross Morgan-Linial [rmorgan@jetcity.com].

This program takes a map and divides it into regions that are fully connected - that is, not split in half by walls, so the player can get anywhere in the region starting from a random point. I wrote it to determine if all of a dungeon level can be reached from the stairs, but you might find other uses for it; for example, you could use the results to find out where corridors need to be added to result in a fully connected level. Without further ado, here it is.

  1. include <stdio.h>

/*

* This program divides a set of 'grids', which can be either wall or
* floor, into connected regions. Every grid in a region is connected
* to every other square in that region by vertical or horizontal (not
* diagonal) connections, and not connected to grids in any other
* region.
*
* We maintain a map that shows which region each grid is in. To avoid
* iterating over the entire map every time we discover two candidate
* regions are joined, we use a table that maps the numbers used on
* the grid to actual region numbers. At the end of the computation,
* we renumber the grid using this table.
*/

/* Change this to 1 to see how it works */

  1. define debug 0
  1. define MAP_WIDTH 12
  2. define MAP_HEIGHT 12

/*

* Our map - 0 is wall, 1 is floor.
*
* We have to have a border of walls, or we may get strange errors.
*/

char grid[MAP_HEIGHT][MAP_WIDTH] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0}, {0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0}, {0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0}, {0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0}, {0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0}, {0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}, {0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0}, {0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};

  1. define MAX_REGIONS 16
  2. define NO_REGION 0 /* 0 is also a valid region */

int region_grid[MAP_HEIGHT][MAP_WIDTH]; int region_map[MAX_REGIONS]; int num_regions;

/*

* To reduce processing time, when two regions are found to connect
* (they're really the same region), we just mark them as the same
* without actually renumbering grids. At the end of the computation,
* or if we run out of region numbers, we use this function to update
* all grids to true region numbers. It also compacts the region
* numbers, so that afterwards all region numbers 0..num_regions-1
* are still used.
*/

void remap_regions(void) {

   int region_index[MAX_REGIONS];
   int region_index2[MAX_REGIONS];
   int new_regions;
   int x, y;
   int i;
   new_regions = 0;
   /*
    * Iterate through the regions, and assign a new number to each
    * non-remapped region so that they'll end up compacted.
    */
   for (i = 0; i < num_regions; i++)
   {
       /* Has this region not been mapped to another region? */
       if (region_map[i] == i)
       {
           /* No, it hasn't. Assign it a new region number. */
           if (debug)
           {
               printf("Mapping region: #%i -> #%i\n", i,             
                      new_regions);

}

           region_index[i] = new_regions++;
       }
       else
       {
           /* It's been renumbered. Check for processing errors. */
           if (region_map[region_map[i]] != region_map[i])
           {
               /*
                * We've encountered a bug: this region has been
                * mapped to a region that has also been mapped. Give
                * an error and abort.
                */
               fprintf(stderr, "Map %i->%i->%i\n", i, region_map[i],
                       region_map[region_map[i]]);
               abort();
           }
           /* Assign an in-bounds but otherwise meaningless value. */
           region_index[i] = NO_REGION;
       }
   }
   /*
    * Construct a table of the double-indirection through remapping
    * and compaction.
    */
   for (i = 0; i < num_regions; i++)
       region_index2[i] = region_index[region_map[i]];
   /* Renumber the grids, using the table we just computed. */
   for (y = 0; y < MAP_HEIGHT; y++)
       for (x = 0; x < MAP_WIDTH; x++)
           region_grid[y][x] = region_index2[region_grid[y][x]];
   /* Create a new do-nothing region mapping table. */
   for (i = 0; i < new_regions; i++)
       region_map[i] = i;
   /* Save the new number of regions. */
   num_regions = new_regions;

}

/*

* Join two candidate regions together. This just involves updating
* the region remapping table.
*/

void join_regions(int r1, int r2) {

   int i;
   int r1_map, r2_map;
   /* We have to operate on primary (unremapped) regions here */
   r1_map = region_map[r1];
   r2_map = region_map[r2];
   if (debug)
   {
       printf("Joining regions #%i (%i) and #%i (%i)\n", r1, r1_map,
              r2, r2_map);
   }
   /* Modify the region mapping table. */
   for (i = 0; i < num_regions; i++)
       if (region_map[i] == r2_map)
       {
           if (debug)
           {
               printf("Mapping region #%i (%i) -> #%i\n", i,
                      region_map[i], r1_map);
           }
           region_map[i] = r1_map;
       }

}

/*

* Create a new region.
*/

int new_region(void) {

   int i;
   /* If we're out of regions, compact them. */
   if (num_regions >= MAX_REGIONS)
   {
       if (debug)
           printf("Remapping regions\n");
       remap_regions();
   }
   /* If we're still out of regions, we have a problem. */
   if (num_regions >= MAX_REGIONS)
   {
       fprintf(stderr, "Too many regions\n");
       abort();
   }
   /* Allocate a new region. */
   i = num_regions++;
   region_map[i] = i;
   if (debug)
       printf("New region: #%i\n", i);
   return i;

}

void find_regions(void) {

   int x, y;
   int i;
   if (debug)
       printf("Clearing region grid\n");
   /* Clear the region grid to a valid (but meaningless) value. */
   for (y = 0; y < MAP_HEIGHT; y++)
       for (x = 0; x < MAP_WIDTH; x++)
           region_grid[y][x] = NO_REGION;
   /* Initialize the remapping table to a null map. */
   for (i = 0; i < MAX_REGIONS; i++)
       region_map[i] = i;
   /* Start with no regions. */
   num_regions = 0;
   /* Consider each grid, except the borders (leave them as walls) */
   for (y = 1; y < MAP_HEIGHT - 1; y++)
   {
       for (x = 1; x < MAP_WIDTH - 1; x++)
       {
           /* Skip wall grids. */
           if (!grid[y][x])
               continue;
           if (debug)
               printf("(%i, %i) ", x, y);
           /* 
            * Consider the possible combinations of left, above
            * grids.
            */
           if (!grid[y - 1][x])
           {
               if (!grid[y][x - 1])
               {
                   /* No floor left or above */
                   region_grid[y][x] = new_region();
               }
               else
               {
                   /* Floor left, but not above */
                   if (debug)
                   {
                       printf("Copying over #%i\n", 
                              region_grid[y][x - 1]);
                   }
                   region_grid[y][x] = region_grid[y][x - 1];
               }
           }
           else
           {
               if (!grid[y][x - 1])
               {
                   /* Floor above, but not left */
                   if (debug)
                   {
                       printf("Copying down #%i\n", 
                              region_grid[y - 1][x]);
                   }
                   region_grid[y][x] = region_grid[y - 1][x];
               }
               else
               {
                   /*
                    * Floor both left and above - are they the same 
                    * region?
                    */
                   if (region_map[region_grid[y - 1][x]] !=
                       region_map[region_grid[y][x - 1]])
                   {
                       /* No, join them. */
                       join_regions(region_grid[y - 1][x],
                                    region_grid[y][x - 1]);
                   }
                   /* They're now the same region, so copy one. */
                   if (debug)
                   {
                       printf("Copying down #%i\n", 
                              region_grid[y - 1][x]);
                   }
                   region_grid[y][x] = region_grid[y - 1][x];
               }
           }
       }
   }
   /* Do a final remapping, to make the region_grid[][] accurate. */
   remap_regions();

}

/*

* Print our results.
*/

void print_map(void) {

   int x, y;
   for (y = 1; y < MAP_HEIGHT - 1; y++)
   {
       for (x = 1; x < MAP_WIDTH - 1; x++)
       {
           if (grid[y][x])
           {
               printf("%c", 'A' + region_grid[y][x]);
           }
           else
               printf(" ");
       }
       printf("\n");
   }

}

int main(void) {

   find_regions();
   print_map();
   return 0;

}

Representing the Dungeon - Brian Bucklew [bbucklew@inteletek.com].

[Note: C++ Class Definitions Will Be Used Throughout]

Section 1 : The Question

       One of the most important things in writing a computer game of

any sort is the way in which you represent the universe the game takes place in. In a rogue-like, you will need to represent several things:

  1. 1. The Dungeon
  2. 2. The Slimy Things in The Dungeon
  3. 3. The Pointy Things with which a player kills Slimy Things
  4. 4. The Player that holds the Pointy Things
       This Article will cover #1: The Dungeon.

Section 2 : The Dungeon

       Alright, we need to find some way to represent the corridors and

rooms of The Dungeon itself. One of the easiest and most flexible methods of doing this is to create a two-dimensional array of cells. Each cell will be a wall, a floor, a door, a hideous spiked pit of death, or any number of other things we might want to represent as one tile:

class Tile {

       public:
       int Type;               // 0-Wall 1-Floor 2-Water 3-Open Door 4-Closed Door...
       unsigned int Flags;     // see below...

}

Section 2b : Bit-Flags

       One of the more important and space-saving methods of information tracking

is the use of bit-flags. As you know, a number in a computer is represented in binary, which is a series of ones and zeros... For instance the number 14 might be represented as: 00001110

Now, say we need to keep track of a number of things about a tile... Is it lit? Is it explored? Is is permenatly dark? Is it hairy?

We can use each individual bit in an integer to keep track of a true/false answer for questions like these.

So, how do you single out an individual bit? Well, bitwise operators come to save the day.

We can single out individual bits of a number by using the & (bitwise AND) operator. Each bit represents a power of two... So the first bit is 1, the second is 2 the third is 4 the fourth is 8 and so on... The & Operator takes two integers and returns an integer that only has 1 bits where the two origional integers BOTH had 1 bits... So to single out a bit, we take the variable containing the flags (Flags, in this case), and & it with the number represented by the bit we wish to read. If the returned number isn't zero, the flag is set, if it is zero the flag is not set...

This is a bit confusing, I'm sure, so here's some examples:

Example 1: (We'll use 16-bit integers to save space)

Flags : 0101000010010100

 We want This Bit-^
 It's the fifth bit, so 2^4 = 16.
 16 is 0000000000010000... so
 Flags & 16 = ?
 Flags:0101000010010100 
       &&&&&&&&&&&&&&&&
    16:0000000000010000
       ================
       0000000000010000;
 Which is greater than 0, so the flag is set...

Example 2:

Flags : 0101000010010100

 We want This Bit--^
 It's the fourth bit, so 2^3 = 8.
 8 is 0000000000001000... so
 Flags & 8 = ?
  Flags:0000000010010100
        &&&&&&&&&&&&&&&&
      8:0000000000001000
        ================
        0000000000000000;
 Which is 0, so the flag is not set...

Section 2c : Returning to The Dungeon...

       So we have our basic Tile class defined. All we need to do now is create

an array of these tiles:

       Tile Map[256][256];

Now, apply your favorite dungeon-generation method to this array of tiles and viola! You have a dungeon.

Section 3 : Positional Representation

       Anything in your Dungeon is going to have a position within the

Dungeon. This position is simply defined as an x and y coordinate within the 2D array of Tiles. If a player is at 16,19 we could look up the tile he is in using the line : Map[16][19], If the player is at 31,53 we could use Map[31][53]... So we can generalize and say that if the player had a position holding X and Y we could use the line : Map[Player.X][Player.Y];

We might also want to extend a position definition by giving it a facing...

8 1 2

\ | /
 \|/

7--*--3

 /|\
/ | \

6 5 4

So...

class Position {

       public:
       int X,Y;        // Our (X,Y) Coordinates
       int Facing;     // The direction this object is facing.

}

       Everything in your dungeon should have a position. Each Monster,

each item that is lying on the ground, and the player. This will allow you to keep track of each thing and their relations to one-another.

The Author: Brian Bucklew, 18 bbucklew@inteletek.com Current RL Project : Dungeon or "This game needs a new name"... :) Projected Beta Release : Early 98

Fun with dungeongeneration in QBasic - R.Alan Monroe.txt

I wondered what it would be like to do a random dungeon by repeatedly placing random sized "L" shaped hallways, each with a random 90 degree orientation, all over the map. Here's the results.

This method doesn't guarantee that all areas are reachable. You get a lot of cul-de-sacs, which could be good or bad depending on your game...

[fixed width font]

                                      1. ####### ######### ####### ########## # ##########
                                      2. ### ### ######## ####### ### ###### # ##########
                1. ######### ### ## ### ### ##### ### ###### # ### ######
                2. ## ## # ## ## # # ######
                3. ## # ### # ## ## ### ## # #
          1. ## # # # # #####
        1. #### # # # # ### ## ## # # #####
            1. # # # ## # # ## # # #####
        2. ## # ## # # # # #### # # # #####
          1. # ### # # ### ## # ## ##### #######
          2. ###### # # # # ## # ## ### ######
          3. ## #### # ##### ###### # #####
          4. # ############ ##### # ## # # ########### ########### #####
          5. ############## ########### # ########################## ######
            1. ########################## ############################ ######
              1. #################### ################################ #######
              2. ################ ### ### ############### ########### #######
              3. ############# ## ### ### ## #### # ##### #### ###### #######
              4. ######## ### ## ### ### ## ### ### # #### ## ### #######
      1. ####### # # ###
          1. # ### # ## ## # # # ## #####
      2. # # ## # # ## ####
    1. # #### # # ## # # ## ## # # ####
    2. # #### # ## # ## ## # # # # ########
            1. # # ## # ### # # # ########
              1. #### ## # ## #####
                      1. #### # ##### ### ###
          1. ## ##### ### ## #### # #####
                1. ## ## ###### # ### ## ####### # ### #### # # #####
                2. ##### # ###### # #### ## ####### # ###### ##### #########
                3. ####### ################## ####### # ############ #########
                                                                                      1. #########################
                                                  1. ##### ####################################
                                                1. ##### ############# #####################
              1. ############### ##### ######### ### # ###################
          1. ### ###### ## # # # ## ## ### # ### ###############
          2. # # # ### # # ## ## ######
          3. # # ## ## ### # ####### ######
          4. # ### ## ### # ###### ####
          5. ### ## #### # # ## ## ### #####
              1. # # ## # ## ## ## # # ## # #####
        1. ## ## # # ##
            1. # ### ### ## ## ####
            2. # ##### ### #### # ###
            3. ##### ##### #### ### ### # ### ###### ### ###### # ######
            4. ##### ##### #### ### ### ## #### ###### ########## # ######
            5. ########### ############ ############## ########### ## #######
                                    1. ############ ############## ########### ## #######

RANDOMIZE TIMER

DIM a(70, 20)

begin:

CLEAR CLS

FOR l = 1 TO 150

  x = INT(RND * 59) + 6
  y = INT(RND * 9) + 6
  d = INT(RND * 4)
  a(x, y) = 1
  SELECT CASE d
     CASE 0
        FOR i = 1 TO INT(RND * 5)
           a(x + i, y) = 1
           a(x, y - i) = 1
        NEXT i
     CASE 1
        FOR i = 1 TO INT(RND * 5)
           a(x + i, y) = 1
           a(x, y + i) = 1
        NEXT i
     CASE 2
        FOR i = 1 TO INT(RND * 5)
           a(x - i, y) = 1
           a(x, y - i) = 1
        NEXT i
     CASE 3
        FOR i = 1 TO INT(RND * 5)
           a(x - i, y) = 1
           a(x, y + i) = 1
        NEXT i
  END SELECT

NEXT l

FOR row = 1 TO 19

  FOR col = 1 TO 69
     IF a(col, row) = 0 THEN
        PRINT "#";
     ELSE
        PRINT " ";
     END IF
  NEXT col
  PRINT

NEXT row

WHILE INKEY$ = "" WEND

GOTO begin

Populating The Dungeon Of Items & NPC's

By Stu George :: 3may99


I have to say up front, I have not looked in depth(if at all) at how other rogue likes approach this task.

So my methods are probably not as fast or good as ones tried and tested in code like nethack + angband for the past N years they have been using it ;)


Quite often one of the first tasks in a rogue like is creating the mazes... Once you have created a working maze generation routine you have to fill it, both with items, traps, monsters, stairs, etc.

Kitting out your dungeon can be as hard or as easy as you like, but a lot of it has to do with how you generated your maze.

I'll discuss here how I've gone about doing it.


First I'll discuss how NOT to do it, I saw this example only once (in a quite basic "in development" game)...

The dungeon was hewn from a static 128x128 grid and for placement of objects, a random position of x=rnd(128), y=rnd(128) was taken for every object wanting to be placed on the map, this x.y was then tested against the grid to see if it was a floor tile, if so was placed, and if not was repeatedly calling for random numbers for x.y and testing them all over the grid.

Needless to say, with lots of objects and a small dungeon, this could make the computer test locations for days until it got a match...

That is how NOT to do it, basically its a poor mans algorithm. (But as someone pointed out, its easy to do things this way and it does indeed work if you maze fills most of the confines of your 'grid')

When I generate the maze, i store in a list all the rooms created. Hallways are just "skinny" rooms in my view, so they all get put on the list.

This list is quite basic, its a linked list and contains the x1.y1-x2.y2 and a flag of every object and nothing else. the flag is just set when its wider or longer than 1 (ie flag is set when its not a "hall"), if you have to refer to the list often its easier to test a flag than to test x2-x1 + y2-y1 for every object..

When I want to add say, stairs up, i just randomly pick an object from my list, then once you have your "room" randomly pick an x.y within that room y=rnd(y2)+y1, x=rnd(x2)+x1 and place the object. repeat as necessary.

You can check for overlapping if you wish or simply stack items in a list.

Since hallways outnumber rooms by a great number, its nice to not always have everything generated in a hallway, thats why the flag is for, so when objects from the list are selected, you can give a greater chance to gen something in a room than in a hallway...

You could also store two lists, one for "rooms" and one for "halls".


My dungeons are created entirely by the RNG, so when i save/load a level I only need take note of the RNG seed before creation starts, since the same seed produces the same level, the object list gets rebuilt and thus you don't have to store that list.

You _do_ have to save the x.y positions of static things, ala traps (moving bear pits?) and stairs. monsters move (for the most part) so if they are not in the same spot, you could say they wandered about ;), and items, well they got picked up and moved and dropped ;). But these are weak excuses for cutting code really... ^_^


When going from 1 level to another you can dump the object list for the same reasons as the load/save given above.

This is of course, very simple and does not take into account someone with a digging wand adding a new corridor to your dungeon (since its user created, it wont be created with the RNG seed). Of course it would be easy to add the newly created portions to a list, stored with the RNG dungeon seed, etc.


I find this method quite good, its quick and easy to "spawn" monsters with this method..


The one thing I thought I should mention is the fact that my "rooms" and "hallways" are not connected. doors are placed in between as "connections" but they not connected on creation by "touching" each other, and thus doorways don't show up on my object list. (good or bad I don't know, but I'm very happy with my dun-gen routine, it also just means nothing will be placed over the top of a doorway)

A Method For Growing Rivers In A Randomly Generated World - Dana Larose [dana@pixelenvy.ca].txt

In response to a question on rec.games.roguelike.development, I coded up a demo on how one might make randomized rivers that originate in a part of the world that hasn't been generated yet.


The Problem

You are building a world region by region (as the player explores them), so you do not the the layout of the entire planet in advance. How to create long rivers that can span into regions that haven't be created yet? I'll present here an explanation of how this can be done and provide a demo written in Python.


Summary of Algorithm (Although it's simple enough to almost not qualify as an algorithm!)


Suppose you generate a 20X20 area of the world that looks like this:


. . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ = water . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ . = plains . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ # = trees . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ^ = hills/mountains . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ^ . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ^ ^ . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ^ ^ ^ . . . . . . . . . . . . ~ ~ ~ ~ ~ ^ ^ ^ ^ . . . . . . . . . . . . ~ ~ ~ ~ ^ ^ ^ ^ ^ . . . # # # . . . . . . ~ ~ ~ ^ ^ ^ ^ ^ . . # # . . . . . . . . . ~ ~ ^ ^ ^ ^ ^ ^ # # # # . . . . . . . . . ~ ^ ^ ^ ^ ^ ^ ^ ^ # # # . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ # # . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . .


Your world generation algorithm determines this lake/ocean will have a river flowing into it. Start drawing a river backwards from the ocean. For my simple demo, I used the following stopping condition for the river: If river was about to cross from an area of higher elevation to an area of lower elevation, terminate the loop. Additionally, I started with a 5% chance of terminating the river and each time the drawing loop iterates, I increase that by 5%.


One particular run of my demo made the following map:


. . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ^ . . . . . . . . . . ~ . ~ ~ ~ ~ ~ ~ ~ ^ ^ . . . . . . . . ~ . . . ~ ~ ~ ~ ~ ~ ^ ^ ^ . . . . . . ~ . . . . . ~ ~ ~ ~ ~ ^ ^ ^ ^ . . . . ~ . . . . . . . ~ ~ ~ ~ ^ ^ ^ ^ ^ . ~ ~ # # # . . . . . . ~ ~ ~ ^ ^ ^ ^ ~ ~ . # # . . . . . . . . . ~ ~ ^ ~ ~ ~ ^ ^ # # # # . . . . . . . . . ~ ~ ^ ^ ^ ^ ^ ^ ^ # # # . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ # # . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . .

If your river reaches the border of a region, again terminate it. (Note that it should also terminate before crossing into region that has already been generated, my demo doesn't do this). At this point, you need to store the fact that a river has terminated at a border of the region. Python is OOP-enabled, so it was quite easy for me to add this information to the region class. I stored the instance of the terrain, it's coordinates and the last move the drawing algorithm was about to make (so I can continue drawing it in the same general direction when it is time to build the next region).

When the player cross into an previously unexplored region, you will have to pass the details of already generated neighbouring regions, providing access to their lists of border features. If a neighbour is null, it hasn't been made yet and can be ignored. In the demo, when a new region is made, we see that it has a neighbour to the east, and that a river terminated at the border (row 12, column 0). After the new region is created, we need to draw a river starting at (row 12, column 19). Using the same algorithm, we draw until we hit a termination condition. In this case, the river started in the hills, so it will continue until it hits a border, or is about to cross from the hills (high elevation) to the plains (lower elevation).

A sample run of my demo produce: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  1. # # # # # # # . . . . . . . . . . . .
  2. . . . . . . . . . . . . . . . . . . .
  3. # # # # # # ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
  4. # # . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
  5. # # # # # # . . . . . ^ ^ ^ ^ ^ ^ ^ ^
  6. # # # # # . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^
  7. # # # # # # # ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
  8. # . . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^
  9. # # # # # # . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
  10. # # # # # # . . . . . . . ^ ^ ^ ^ ^ ~
  11. # . . . . . . ^ ^ ^ ^ ^ * ^ ^ ^ ^ * ^
  12. # # # . . . . . . ^ ^ ^ ^ * ^ ^ * ^ ^
  13. # # # # # # # . . ^ ^ ^ ^ ^ * * ^ ^ ^
  14. # . . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^
  15. . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

. . . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

(The river created is marked with *'s so they stand out a little better).

Putting them side by side: . . . . . . . . . . . . . . . . . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

  1. # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~ ~
  2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ~ ~ ~ ~ ~ ~ ~ ~
  3. # # # # # # ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . . . ~ . ~ ~ ~ ~ ~ ~ ~
  4. # # . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . ~ . . . ~ ~ ~ ~ ~ ~
  5. # # # # # # . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . ~ . . . . . ~ ~ ~ ~ ~
  6. # # # # # . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . ~ . . . . . . . ~ ~ ~ ~
  7. # # # # # # # ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . ~ ~ # # # . . . . . . ~ ~ ~
  8. # . . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ~ ~ . # # . . . . . . . . . ~ ~
  9. # # # # # # . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ~ ~ ~ ^ ^ # # # # . . . . . . . . . ~
  10. # # # # # # . . . . . . . ^ ^ ^ ^ ^ ~ ~ ^ ^ ^ ^ ^ ^ ^ # # # . . . . . . . . .
  11. # . . . . . . ^ ^ ^ ^ ^ * ^ ^ ^ ^ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ # # . . . . . . . . .
  12. # # # . . . . . . ^ ^ ^ ^ * ^ ^ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . . .
  13. # # # # # # # . . ^ ^ ^ ^ ^ * * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . .
  14. # . . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . .
  15. . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . .

. . . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . . . . . . . . . . . ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ . . . . .

A nice, slightly winding river is created in one region, then continued in the bordering region when it comes time to generate the neighbour.


Notes About The Demo - The demo was slapped together in about an hour, so please don't judge my coding skills on it! It probably has bugs, invalid assumptions, poor coding standards/styles, inefficiencies and/or redundant code!

- There are probably plenty of ways to generate nicer looking rivers, I just used a couple of ideas that popped into my head while coding. Mine often generates straight lines, which look silly (it took me a couple tries to get a nice looking river for this page). But again, that wasn't the point of the demo!

- The termination condititions could be improved. For instance, if you are stopping because you are about to cross into another region, you could back the drawing up one square so it doesn't look like the river originates at the border of two elevations.

- It would be neat to look for good likely termination points. Suppose a lake was generated at the same (or higher) elevation as the river, it would make a good candidate for a termination point. (Hmm - confusing terminology - when I speak of termination point, I mean where the algorithm stops drawing, which is the origin point for the river in the geographic sense)

- The demo doesn't generate terrain, I don't know if my roguelike is going to have random or fixed wildernesses, I just wanted to offer a solution to the question on the newsgroup.

- The demo is cooked to draw a river that starts at the lake and ends at the border of the first region (the cooked functions are labeled as such). See previous point.

- My method only draws rivers from the mouth of the river backwards to the spring, but it woulddn't take a great leap to make a version that draws from a spring to a terminatition point. Indeed, since you would be drawing into a region that has not been determined, you could force the generator to create a nice termination point for your river.

- Written and tested in Python 2.2.1, probably works with Python 2.x.x, might even work with Python 1.5.x


There are three main classes used in the demo:

Terrain - Represents an individual square of terrain. Uses fields ch (the character to display), type (the type of terrain and elevation - integer saying how high the terrain is. I used ocean/lake = 0, plains/trees = 1 and hills = 2. An interesting idea would be to store a floating point number and use that to determine where the river should flow from the geography of the land?

Region - stores information about the section of the world this represents. In the demo, this is essentially a collection of Terrain squares and a little additional info used in the demo (such as the border features of this region). In a full game, this would need to store a fair amount of additional information.

RegionGenerator - builds a region of land. Note that in the demo, the regions are cooked and the river in the first region is partially cooked.

The code is offered without warranty or guarantee as an idea for folks writing map generators. If you want to use a substantial part of the code in your game, please ask permission. Here is grow_river.py.txt (named so because browsers sometimes complain about .py extentions, save it your harddrive and rename it grow_river.py before running).

You can reach me at dana@pixelenvy.ca with questions, suggestions, etc.

=Here is a list of articles from the old roguelikedevelopment.org that I am trying to salvage:

Cannot Find:

  * How to finish your roguelike - Peter Farabaugh [pete@tbe.net].txt Found a russian translation: http://www.rlgclub.ru/pmwiki.php?n=Main.ArticlesDevRlgFinish
  * User Interface in Roguelikes - Jim Babcock [jimmy_b@earthlink.net].txt Found a russian translation: http://www.rlgclub.ru/pmwiki.php?n=Main.ArticlesDevUserInterface
  * Roguelike Step by Step Guide.txt
  * Mostly Turn-based Multiplayer Timing - Isaac Kuo [mechdan@yahoo.com].txt Found a russian translation: http://www.rlgclub.ru/pmwiki.php?n=Main.ArticlesDevTurnBasedMultiplayer
  * Lake and Oasis Generator - Adam Szczepaniak [adamshc@wp.pl].txt
  * Fill-area-with-rooms and Maze - algorithms - Josh VertexNortmal Tippetts [vertexnormal@email.com].txt Found russian translation: http://www.rlgclub.ru/pmwiki.php?n=Main.ArticlesDevMazeGen
  * Recursive randomized world-map generation Phillip C. Culliton [pcullit@hotmail.com].txt
  * 3D Representation for Roguelike Worlds - Jimmy Babcock [jimmy_b@earthlink.net].txt
  * Random Dungeon Algo in QBasic - Andrew Collins [andrewcollins@hotmail.com].txt
  * Nest of Ants - Jakub Debski [jakub@mks.com.pl].txt
  * Passable Cave Building Algorithm - Josh Tippets [vertexnormal@email.com].txt

TODO:

  * Add a link to blah.tar.gz
  * add a link to name.zip for Random Name Generation Using Regular Expressions

Representing Magick Spells - Sean Middleditch [sean.middleditch@iname.com].txt

This article describes the basics of representing and using Magick Spells in roguelikes. The general techniques are very similar to those used in my article on Object representation.

For starts, we need a class to hold the information for a specific spell.

class Spell { public:

OK. Now, let's give the spell a name.

char *Name;

There. Now, every magick spell costs Mana Points (well, if you're using a magick system similar to most others). So we need to define the spell's cost in MP.

int MPCost;

Also, every spell has a level: how difficult a spell it is. Only more powerful casters can use more powerful spells.

int Level;

There. Now all we need to know is what in Gehenna the spell does. We'll make a sub-class called Effect to store this information.

class Effect: { friend Spell;

OK, so what does a specific spell do? We'll make a simple int to describe what a specific Effect describes.

int Type;

So what does Type mean? We'll use some #define's to specify.

#define HEAL 0 #define SCORCH 1 #define TICKLE 2 #define CREATE_OBJ 3

You can of course add as many as you want. Now, we know what an Effect does, but that's not enough. For example, for a HEAL Effect, how much HP does it heal? We could base everything of level (making a rigid and uniform magick system, which may be what you want: predictability), or we could give each Effect a set of arguments to define in more detial what it does. We'll do this through the use of 5 int's.

int Args[5];

What do the fields of Args mean? That's based on what Type is equal to. For an Effect with Type HEAL, we might say that:

Args[0] is Number of Dice Args[1] is Sides per Die Args[3] is Roll Mod

So an Effect of type HEAL with Args[0] = 2, Args[1] = 6, Args[3] = 2 would heal 2d6+2 HP. Pretty simple, eh?

Anyways, we can close of the Effect class. We want each Spell to have 5 Effect's (so every spell can have lots of flexibility).

} Effects[5];

We can now close of the Spell class.

};

So that's all there is to a basic magick class.

Casting the spell is just as simple. Make a function called Cast or whatever (I used an object method inside the Spell class, since I'm a C++ OOP freak). The function would take as arguments the spell to cast, the target, etc.

void Cast ( Spell *SpellToCast, int TX, int TY );

Then we go with a big, evil, switch statement based on effect. This actually works VERY well. The flexibility is astounding...

Of course, how each spell takes effect is based on how you've programmed the rest of your roguelike. Because of the OO nature of WotR, I found it very easy to create simple object Methods for spell effects.

For the HEAL Spell Effect Type, you might to do something as simple as loop through all the Characters (NPC's and Players) in the target loc (defined by TX and TY), and heal them based on the arguments listed above... 2d6+2, or whatever.

Anyways, this is just the basics. The advanced stuff all depends on your magick system and how you programmed the rest of the game.

The complete source for the Spell class is:

  1. define HEAL 0
  2. define SCORCH 1
  3. define TICKLE 2
  4. define CREATE_OBJ 3

class Spell { public: char *Name;

int MPCost; int Level;

class Effect: { friend Spell;

int Type;

int Args[5]; } Effects[5]; };

Any questions, comments, threats, etc., e-mail me at sean.middleditch@iname.com Well, I don't really want any threats.

The End


RL Dev Code 0.6 - Kornel _ Anubis_ Kisielewicz [kisiel@fulbrightweb.org].txt

         RL Developer Code
         Version 0.6.0
         Designed by Kornel \"Anubis\" Kisielewicz
         (kisiel@fulbrightweb.org)

Hey, I noticed that both Angband and NetHack users have their own GeekCode. Why not us? ;). This is the first draft, and it\'s realy RLDev specific. I think that a Roguelike Dev Code will be especialy useful, because it may make us more aware of the others ideas. I\'m open to all new ideas, or corrections. In all project specific questions answer about your current project. A sample of the code is on the bottom of the document.

I encourage to at least post your code once, so someone can collect them and post somewhere :).


1. General info about the developers methods


\"L\": Language used to program your roguelike project.

L:C C L:C++ C++ L:VC++ Visual C++ L:Java Java L:FP FreePascal L:TP Turbo Pascal L:DP Delphi (Pascal) L:Pyt Python ?L I still didn\'t decide !L I\'m a designer [more]


\"E\": Experience in programing.

E+++ I\'m a professional programmer E++ I program as a part time job E+ I program quite well, as a hobby E- I\'ve read a few books and made some programs E-- I\'ve made a few simple programs E--- I\'m learning while I write a roguelike

!E I\'m just a designer ;) ?E What do I need programming for?


\"T\": Time invested in rl-development. Choose the most true one :).

T+++ Every minute of my spare time! T++ Most of my free time T+ Regulary T- From time to time T-- As a recreation T--- Rarely

!T I don\'t write yet!


\"R\": Rewrites. A rewrite is writing your code from scratch, using only old libraries, and fragments of the old code.

R+++ more than 5 R++ 3-4 rewrites R+ 1-2 rewrites R- not yet R-- I\'ve just started R--- I do not program yet

?R What are rewrites? !R My game doesn\'t need rewrites, cause I write error-free!


\"P\": Porting to other systems

P+++ My game will be ported to most known platforms P++ Linux and DOS/Win P+ I try to keep the code portable. P- Why the hell? I write only for Linux/DOS (you may recompile it though) P-- DOS/WIN only P--- Windows only!

!P I use Java (or something similar)


\"D\": Importance of design before programming

D+++ I had a detailed DesignDoc before I started programming D++ I had many notes and information before I started coding D+ I keep my designdoc ahead of the project, but update it regulary D- I had a few notes before I started coding D-- I had a general image of what I\'m trying to do

!D Who the hell needs a DesignDoc? I make everything on the fly! ?D What\'s a DesignDoc?


\"G\": The generic engine, that is, how generic your game will be.

G+++ You will be able to make a hard-sci-fi game out of my engine, by just changing the info-files! G++ My engine is very generic -- you will be able to make a different game by changing the info files G+ I have info files for maps, monsters, items and dungeon generators G- I have a few general info files G-- I keep everything in the code

!G Why the hell generic engine? I wan\'t to make a GAME.


\"F\": Favourite Roguelike

F:ToME F:ADoM F:V Vanilla Angband F:*band *bands in general F:Rogue Yeah :). F:Moria F:NHack NetHack F:Hack F:GH Gearhead F:DC DeadCold [more]


\"RL\": Your roguelike definition

RL+++ A roguelike MUST be ASCII, MUST be a dungeon crawl, and MUST be based on a system similar to AD&D, and MUST be permadeath. RL++ A roguelike has to be ASCII, has to be random, and have experience levels, and permadeath. RL+ A roguelike has to be ASCII or use tiles, must have dungeons, and focus on killing things for experience. It has to be permadeath too. RL- A roguelike may have graphics but has to be rather dungeon themed permadeath game. RL-- A roguelike is a game that focuses on randomness, and features permadeath. RL--- A roguelike is a game inspired by other roguelike games.

!RL This is completely unimportant ?RL What is a roguelike actually?


\"RLA\": Roguelike community activity

RLA+++ I\'ve created a popular game, or host one of the main roguelike sites on the web. RLA++ I\'ve created a roguelike dedicated webpage (focusing not only on my game) RLA+ I\'m a FAQ maintainer, or wrote a roguelike article, or created a roguelike document RLA- I play roguelikes and post on a few roguelike newsgroups RLA-- I post on one roguelike newsgroup

!RLA Who is that guy?



2. Project specific questions


\"W\": World of the game, the genre

W:F Fantasy W:DF DarkFantasy W:AF Alternative Fantasy W:SF Science Fiction W:HSF Hard Science-Fiction W:MH Mecha W:M Modern W:CP CyberPunk W:G Generic engine (give eventual default genre in bracets)


\"Q\": Quests in your project

Q+++ The plot is the master! You will have random interesting quests in my game. Q++ I will add many pre-written quests. Q+ I will add a few quest for flavor, or even ToME-like random quests. Q- Maybe a few quests for flavor Q-- Kill Sauron. Kill Morgoth. Q--- No quests -- just Hack\'n\'slash.

!Q Who the hell needs quests? ?Q What is a quest?


\"AI\": Approach to AI in your project

AI+++ AI is the key! The creatures will behave diablo inteligently and talk to you with Bot-generated messages. They will use military tactics, recognize dangers, and create traps. AI++ The NPCs will behave quite reasonable, will flee, band together, pickup and use items. AI+ The creatures will use items like wands, staves and the like. AI- The creatures will be able to pickup and equip items. AI-- No monster-inventory -- just Hack\'n\'Slash AI--- Kill player. Kill player.


\"GFX\": Approach to graphics

GFX+++ The game will be graphical with nice graphics GFX++ The hame will have tiled graphics GFX+ Some popular freeware tiles GFX- Somewhere in the future I plan to add graphics GFX-- I\'d like graphics, but I\'m a poor artist

!GFX Pure ASCII rulez!


\"SFX\": Approach to sound

SFX+++ Digitalized Speech and Music is my aim SFX++ I will add many wave files and maybe some music SFX+ Just a few Sound-Effects SFX- Maybe in the future SFX-- I\'d like sound, but I\'m a poor at that

!SFX A roguelike with sound? Buhahahaha...


\"RN\": Approach to randomness in your project

RN++++ The whole world will be random, random quests, random dialogs, random plot RN+++ Same as above, but the plot will be fixed RN++ The world will be fixed, but there will be random quests, dungeons and items and monsters RN+ Random dungeons+items+monster placement RN- Just the dungeons and monster placement RN-- I plan to make everything fixed


\"PO\": Popularity of current project

PO+++ I have fan-sites of my playable roguelike (reserved for ToME, NetHack, ADoM, Angband and the like :) PO++ I have a playable version on the web that can be enjoyed PO+ I have a playable version on the web that can be looked at PO- I have a designer version on the web (dungeon+items+npcs and the like) PO-- I have a few design programs (map-view, dungeon generator) PO--- I haven\'t published anything

!PO I didn\'t do anything yet!


\"Hp\": Hitpoint treatment in the roguelike

Hp+++ A 1-st level character has a few hitpoints, a 50th level character has a few hundred... Hp++ I keep the hitpoints rather lower. Hp+ The player rarely recieves hit-points, I don\'t use a level system. Hp- Fully skillbased Hp-- Fully skillbased and advancement doesn\'t make you realy powerfull

!Hp I don\'t use hitpoints!


\"Re\": Realism in the roguelike

Re+++ You can die because of disease, rusty weapon wounds, or the after-effects of an out-dated portion of speed Re++ Each fight is dangerous Re+ I\'d rather not let the player kill hordes of monsters Re- I like to keep things real as in NetHack Re-- I like to keep things real as in Angband Re--- Who needs realism? It\'s the hack\'n\'slash that counts!


\"S\": Seriousness of the world

S+++ THE GAME. You think it\'s funny? You\'re talking to me? S++ The game has to be serious. I want to make an atmosphere... S+ (ADoM) From time to time a funny in-game situation is fun S- I like to keep the world rather not gloomy S-- (ZAngband) Lets keep it easy, sometimes a Barney, or Bull Gates is fun to kill S--- (NetHack) Why the hell? Let\'s have nuclear scientists, tourists, photo-cameras and sinks in a dark dungeon


regards, and I\'m waiting for your codes and opinions :), -- Kornel \"Anubis\" Kisielewicz RLDev Code v.0.6

    L:FP E+ T+ R+++ P+ D++ G++ RL-- RLA++ F:ADoM
    GenRogue 0.16 V8 ( http://genrogue.felis7.civ.pl/ )
    W:DF Q+++ AI++ !GFX !SFX RN+++ PO--- Hp-- Re+++ S+++