Difference between revisions of "Dungeon Building"

From IvanWiki
Jump to navigation Jump to search
 
(62 intermediate revisions by one other user not shown)
Line 1: Line 1:
 +
''This section is all about dungeon building. If you would like to learn about adding dungeons to the world map, see [[Adding Cities and Dungeons to the IVAN World Map]].''
 +
 +
__TOC__
  
 
== Introduction ==
 
== Introduction ==
Line 13: Line 16:
 
=== A suitable text editor and font ===
 
=== A suitable text editor and font ===
  
When editing the dungeon file, it pays to have a good text editor. A nice program in Windows might be, for example, Programmer’s Notepad 2, but any program with suitable syntax highlighting will do. The script file text is based on C/C++ syntax, so you can set the syntax highlighting to this language. It is also highly prudent to select a mono-space typeface. A mono-space typeface means each character has the same horizontal length in the editor. Because we are also going to “draw” with ASCII characters in the script files, it would be good if the characters can properly align in a grid-like fashion, making it easy to identify the geometrical patterns. This is indispensable when it comes to laying out large rooms and even particular dungeons, helping to avoid confusion along the way. Suitable typefaces to consider for this purpose might include Courier New or Lucida Console fonts.
+
When editing the dungeon file, it pays to have a good text editor. A nice program in Windows might be, for example, Programmer’s Notepad 2, but any program with suitable syntax highlighting will do. The script file text is based on C/C++ syntax, so you can set the syntax highlighting to this language. It is also highly prudent to select a mono-space typeface. A mono-space typeface means each character has the same horizontal length in the editor. Because we are also going to “draw” with ASCII characters in the script files, it would be good if the characters can properly align in a grid-like fashion, making it easy to identify the geometrical patterns. This is indispensable when it comes to laying out large rooms and even particular dungeons, helping to avoid confusion along the way. Suitable typefaces to consider for this purpose might include [https://en.wikipedia.org/wiki/Consolas Consolas], [https://en.wikipedia.org/wiki/Courier_%28typeface%29#Courier_New Courier New] or [https://en.wikipedia.org/wiki/Lucida#Lucida_Console Lucida Console] fonts, or any [https://fonts.google.com/?category=Monospace other suitable monospace font].
  
 
=== Backing up your work ===
 
=== Backing up your work ===
 
This is really the most important step, and should be the first thing you organize. Make a copy of your dungeon file and store the copy somewhere else, that way, you can always revert to the original if you make changes all over the place. No matter if you lose original files, you can usually pick up an old file from a repository somewhere and revert back to it.
 
This is really the most important step, and should be the first thing you organize. Make a copy of your dungeon file and store the copy somewhere else, that way, you can always revert to the original if you make changes all over the place. No matter if you lose original files, you can usually pick up an old file from a repository somewhere and revert back to it.
  
A more guru way to do this, would be to set up your own IVAN development branch, by cloning the <code>attnam/ivan</code> git repository and making changes in your own branch. You can make pull requests to merge you work into the main line of IVAN development! By using a version control system like GIT, you enable for yourself a great tool for maintaining your dungeon script file.
+
A more guru way to do this, would be to set up your own IVAN development branch, by cloning the [https://github.com/Attnam/ivan <code>attnam/ivan</code>] git repository and making changes in your own branch. You can make pull requests to merge you work into the main line of IVAN development! By using a version control system like GIT, you enable for yourself a great tool for maintaining your dungeon script file.
  
 
== Philosophy ==
 
== Philosophy ==
Line 28: Line 31:
  
 
== A first dungeon ==
 
== A first dungeon ==
 +
 +
== Dungeon script hierarchy ==
 +
 +
[[File:DungeonHierarchies.png|thumb|Example of hierarchy in a dungeon script]]
 +
The dungeon script file follows a definite structure. However, this may be hard to see since certain keywords can be used over and over again. For example to re-define default values in a certain portion of the script, the keyword <code>RoomDefault</code> might be encountered at the <code>LevelDefault</code> stage or simply the <code>Level</code> stage.
 +
 +
Each dungeon has default parameters specified within <code>LevelDefault</code> and <code>RoomDefault</code>. This is where the general look and feel of the dungeon can be uniformly specified with only a few commands. These defaults can be overridden at any point in the script, within that dungeon.
 +
 +
Each level is explicitly catalogued by level number. <code>LevelDefault</code> can be overridden to change the look and feel of just one particular level if desired.
 +
 +
Rooms are described in the <code>Level</code> portion of the script, since rooms are contained on levels in the same way levels are contained in dungeons. Default specs for rooms (<code>RoomDefault</code>) can be overridden. This can either be done within each level, affecting only the specifications for rooms generated on that level, or it may be done on a per-room basis. Rooms can be rigidly specified, with special "script maps" <code>GTerrainMap</code>, <code>OTerrainMap</code>, <code>ItemMap</code> and <code>CharacterMap</code> listed, showing which types to be generated.
 +
 +
Squares can be defined within rooms, or within a level somewhere. On a square may be placed any amount of items, or a particular ground-terrain or over-terrain, such as stairs or a fountain.
 +
 +
Each room and square can be made to appear randomly within a level, in a random position, and/or within a random sub-area of a level (handled by <code>BoundedRandom</code>), and/or on a random member of a subset of levels (handled by <code>RandomLevel</code>).
 +
 +
== Examples from the original game ==
 +
 +
=== Gloomy Caves Shop ===
 +
 +
The shop in the gloomy caves is a good example of how to manually lay out a specific room in the script. The shop is declared as a simple room. The size is set to 5 tiles wide by 9 tiles high. Because it is a shop, and Mellis is the god of trade and politics, the divine master is set to Mellis. No altars, fountains, locked doors or booby trapped doors will generate here. This will generate a bare room (see adjacent image). It generates doors and lanterns by itself, because this is specified in the default parameters for rooms in the dungeon.
 +
 +
{| class="wikitable"
 +
! Script
 +
! Result
 +
|-
 +
|
 +
<tt>Room
 +
{
 +
  Size = 5,9;
 +
  AltarPossible = false;
 +
  DivineMaster = MELLIS;
 +
  Type = ROOM_SHOP;
 +
  GenerateFountains = false;
 +
  AllowLockedDoors = false;
 +
  AllowBoobyTrappedDoors = false;</tt>
 +
| [[File:ShopBare.png|160px]]
 +
|}
 +
 +
 +
Next we can fill the room with characters. We can place each character in a precise way, by writing a little ASCII map showing where everyone will go. The map - a character map - has a size, a position relative to the room's origin (the top-left corner is <code>x = 0; y = 0;</code>), and a key showing all the character types to be found on the character map. The character map can be thought of as a little sub-map belonging to the room. We need to show where the character map is positioned relative to the room it is in. We see the top-left corner of the room <code>Pos = 0, 0;</code> is occupied by a wall. We want to have a map that covers the floor area. The total floor area available in the shop is 3 tiles wide by 7 tiles tall, so this will be the size of or character map. The top-left tile in the character map will be the top-left tile in the room's available floor space. Therefore we will position the character map at <code>Pos = 1, 1;</code>, relative to the co-ordinates of the room's total space.
 +
 +
We need a shop keeper, and some strong guards to protect the fine wares. Therefore we will add the types <code>g</code> for a <code>guard</code> character with the config <code>SHOP</code>, and <code>s</code> for a <code>shopkeeper</code> with the config <code>ELPURI_CAVE</code>. We'll put them both on the same team, and we'll make the shopkeeper the room's master, which is relevant to the room type being a shop. So when the player character wishes to make a trade in the shop, the person he will deal with is the shopkeeper.
 +
 +
We then lay the types out in a 3x7 ASCII map. White spaces are ignored, full-stops represent no character, and g and s represent the guard and the shop keeper. We can place the guard in the shop many times over, and we will place one of them in each corner. We probably only want one shop keeper, and so he is placed in the middle of the map.
 +
 +
{| class="wikitable"
 +
! Script
 +
! Result
 +
|-
 +
|
 +
<tt>CharacterMap
 +
{
 +
  Pos = 1, 1;
 +
  Size = 3, 7;
 +
  Types
 +
  {
 +
    g = guard(SHOP) { Team = 5; }
 +
    s = shopkeeper(ELPURI_CAVE) { Team = 5; Flags = IS_MASTER; }
 +
  }
 +
}
 +
{
 +
  g.g
 +
  ...
 +
  ...
 +
  .s.
 +
  ...
 +
  ...
 +
  g.g
 +
}</tt>
 +
| [[File:ShopPeople.png|160px]]
 +
|}
 +
 +
 +
We need to put items in the room so the shopkeeper has something to sell. We can do this in the same way as with the character map, only this time with an item map. The item map will have the same footprint as the character map, so this will be the same as before.
 +
We want to fill the remaining available spaces in the room with random item types of varying categories and worth. In the script, random items are created, but within the parameters of minimum and maximum prices, and item category flags. This enables a good balance between high and low value items, preventing the game from creating a room full of broken leather boots, or for that matter, a room full of magic lamps! If we want we can generate specific items, and so by looking at this script you will see a wand of striking will generate in every shop, for every game of IVAN. This is an example of a so-called "guaranteed item", and is a design element I hope you will choose to use sparingly.
 +
 +
We can then populate our 3x7 item map with the types we specified, and using a full-stop to leave some spaces for the character types we placed in the character map for the shop.
 +
 +
{| class="wikitable"
 +
! Script
 +
! Result
 +
|-
 +
|
 +
<tt>ItemMap
 +
{
 +
  Pos = 1,1;
 +
  Size = 3,7;
 +
  Types
 +
  {
 +
    g == Random { MinPrice = 100; MaxPrice = 10000; Category = GAUNTLET|BOOT; }
 +
    b == Random { MinPrice = 100; MaxPrice = 10000; Category = GAUNTLET|BOOT; }
 +
    a == Random { MinPrice = 500; MaxPrice = 10000; Category = HELMET|CLOAK|BODY_ARMOR|BELT; }
 +
    d == Random { MinPrice = 200; MaxPrice = 10000; Category = RING|AMULET; }
 +
    w == Random { MinPrice = 500; MaxPrice = 10000; Category = WEAPON|SHIELD; }
 +
    e == Random { MinPrice = 50; MaxPrice = 10000; Category = FOOD|POTION; }
 +
    u == Random { MinPrice = 200; MaxPrice = 10000; Category = WAND|TOOL; }
 +
    r == Random { MinPrice = 200; MaxPrice = 10000; Category = SCROLL|BOOK; }
 +
    s == wand(WAND_OF_STRIKING);
 +
  }
 +
}
 +
{
 +
  .g.
 +
  ddb
 +
  err
 +
  e.w
 +
  auw
 +
  auw
 +
  .s.
 +
}</tt>
 +
| [[File:ShopItems.png|160px]]
 +
|}
 +
 +
== Dungeon default control variables ==
 +
 +
=== Dungeon ===
 +
 +
{| class="wikitable"
 +
! Keyword
 +
! Values
 +
! Description
 +
|-
 +
| <div id="DungeonControlVariable"><code>Dungeon</code></div>
 +
| 0, 1, 2, ... , 64
 +
| This is the dungeon enumerator variable. Enumerations 0 to 4 are occupied by the original dungeons with predefined variables like ATTNAM or ELPURI_CAVE.
 +
|-
 +
| <code>Levels</code>
 +
| 0, 1, 2, ...
 +
| This determines the total number of levels in the dungeon.
 +
|-
 +
| <code>Description</code>
 +
| "string"
 +
| This is a short name for the dungeon that shows up in the high score list explaining which dungeon the player died in.
 +
|-
 +
| <code>ShortDescription</code>
 +
| "string"
 +
| This is an even shorter name for the dungeon usually limited to two or three characters, for example "GC" for gloomy caves. It shows up on the side bar.
 +
|}
 +
 +
=== LevelDefault ===
 +
 +
{| class="wikitable"
 +
! Keyword
 +
! Values
 +
! Description
 +
|-
 +
| <code>Size</code>
 +
| <code>x, y;</code>
 +
| This is the size of the level in squares. x and y are the horizontal and vertical size respectively with x, y ∈ {1, 2, 3, ... }.
 +
|-
 +
| <code>Rooms</code>
 +
| <code>n;</code> or <code>p:q;</code>
 +
| Total number of rooms possible on the level. Can be a fixed number, n, or a number of generic rooms between p and q with p < q. n, p and q ∈ {0, 1, 2, 3, ... }.
 +
|-
 +
| <code>Items</code>
 +
| <code>n;</code> or <code>p:q;</code>
 +
| Total number of items that will generate on the level. Can be a fixed number, n, or a random number of items between p and q with p < q. n, p and q ∈ {0, 1, 2, 3, ... }.
 +
|-
 +
| <code>TunnelSquare</code>
 +
| <code>solidterrain(FLOOR_TYPE), 0;</code>
 +
| TunnelSquare determines the appearance of the tunnel floor. First parameter determines the floor appearance, second parameter should be zero.
 +
|-
 +
|
 +
| <code>FLOOR_TYPE</code>
 +
| Choose from PARQUET, FLOOR, GROUND, GRASS_TERRAIN etcetera
 +
|-
 +
|
 +
| <code>0;</code>
 +
| To make a tunnel, this ought to remain zero. Non-zero will cause the tunnel to fill with material!
 +
|-
 +
| <code>FillSquare</code>
 +
| <code>solidterrain(FLOOR_TYPE), MATERIAL earth</code>
 +
| FillSquare determines what to fill the level's walls and filling material with, and what type of ground appears under those walls. First parameter determines the floor, second parameter determines the walls.
 +
|-
 +
|
 +
| <code>FLOOR_TYPE</code>
 +
| Choose from PARQUET, FLOOR, GROUND, GRASS_TERRAIN etcetera. Good to choose from the same type as TunnelSquare.
 +
|-
 +
|
 +
| <code>MATERIAL</code>
 +
| Choose from GRAVEL, MORAINE, GOLD etcetera
 +
|-
 +
| <code>BackGroundType</code>
 +
| <code>m;</code>
 +
| Defines the default background type. Not sure what it precisely affects. m can be <code>GRAY_FRACTAL</code>, <code>RED_FRACTAL</code>, <code>GREEN_FRACTAL</code> etcetera.
 +
|-
 +
| <code>EarthquakesAffectTunnels</code>
 +
| <code>true</code> or <code>false</code>
 +
| Tells the game whether an earthquake on the level can rearrange the layout of tunnels. Open levels will crash if this is not set to false (because there are no tunnels to shift). Set to true if the level has tunnels, set to false if it is open. See also <code>IsOnGround</code>.
 +
|-
 +
| <code>IsOnGround</code>
 +
| <code>true</code> or <code>false</code>
 +
| Tells the game whether the level is above ground. This prevents earthquakes from happening on the level. Silva will summon wolves instead.
 +
|-
 +
| <code>IgnoreDefaultSpecialSquares</code>
 +
| <code>true</code> or <code>false</code>
 +
| If specific squares containing items/traps etc are specified in LevelDefault, then setting this to true for a particular level will cause these random squares not to appear. Accordingly, in LevelDefault this should be set to false. See [[#Square_.28DefaultSpecialSquares.29|Square (DefaultSpecialSquares)]].
 +
|-
 +
| <code>CanGenerateBone</code>
 +
| <code>true</code> or <code>false</code>
 +
| Tells the game whether a bone file can be generated on this level, or not. Best to set the default value to true. Typically set this to false if the level will generate a shop, or a victory boss like Oree (not Enner).
 +
|-
 +
| <code>LOSModifier</code>
 +
| <code>16, 24, 32, 48, ...</code>
 +
| Line of sight modifier. Typical value for underwater tunnel or gloomy caves is 16. Zombie level is 24. Sumo area is 32. Towns are typically 48. Higher value means player character can see further.
 +
|-
 +
| <code>DifficultyBase</code>
 +
| <code> 0, 5, 10, ...</code>
 +
| Sets the base difficulty for the level. In LevelDefault, this is the base difficulty for all the levels.
 +
|-
 +
| <code>DifficultyDelta</code>
 +
| <code> 0, 5, 10, ...</code>
 +
| This sets the value added to the DifficultyBase for each consecutive level. In LevelDefault, this is the change in difficulty per level (dD), without needing to continually specify DifficultyBase (DB) for each level. The difficulty, D, is therefore set to <code>D = DB + dD * L</code>, where L is the current level number.
 +
|-
 +
| <code>GenerateMonsters</code>
 +
| <code>true</code> or <code>false</code>
 +
| Whether monsters can be generated on the level or not. Set to false in peaceful towns; typically set to true in caves.
 +
|-
 +
| <code>TeamDefault</code>
 +
| <code>TEAM_NAME</code>
 +
| Sets the team to which spawned monsters are aligned. Typically set to <code>MONSTER_TEAM</code> to generate hostile enemies.
 +
|-
 +
| <code>MonsterAmountBase</code>
 +
| <code>0, 10, 20, ...</code>
 +
| Sets the maximum number of monsters for the level for the generator. While the number of monsters is less than this value, the monster generator adds a new monster. Above this value, monsters are not generated.
 +
|-
 +
| <code>MonsterAmountDelta</code>
 +
| <code>0, 5, 10, ...</code>
 +
| This sets the value added to the MonsterAmountBase for each consecutive level. In LevelDefault, this is the change in monster setpoint per level (dM), without needing to continually specify MonsterAmountBase (MB) for each level. The number of monsters (M) setpoint for any given level, is set to <code>M = MB + dM * L</code>, where L is the current level number.
 +
|-
 +
| <code>MonsterGenerationIntervalBase</code>
 +
| <code>100, 120, ...</code>
 +
| The time taken between monster generations, in tens of ticks
 +
|-
 +
| <code>MonsterGenerationIntervalDelta</code>
 +
| <code>..., -10, 0, 10, ...</code>
 +
| The increment per level in the time taken between monster generations, in tens of ticks. A negative number means that that the generation interval becomes shorter by that amount, for each consecutive level. The implication being, negative numbers increase the frequency of monster generation with increasing level depth.
 +
|-
 +
| <code>ItemMinPriceBase</code>
 +
| <code>0, 20, 40, ...</code>
 +
| The minimum price for items generated on the level, in gold coins. Lower minimum price causes items to generate from low-value materials.
 +
|-
 +
| <code>ItemMinPriceDelta</code>
 +
| <code>0, 10, 20, ...</code>
 +
| Incremental increase or decrease in generated item value per level, in gold coins.
 +
|-
 +
| <code>EnchantmentMinusChanceBase</code>
 +
| <code>0, 5, 10, ...</code>
 +
| Make a finite chance that weapons generate with negative enchantment. High values increase the odds the player will come acrossterrible equipment.
 +
|-
 +
| <code>EnchantmentMinusChanceDelta</code>
 +
| <code>..., -5, 0, 5, ...</code>
 +
| Increments the <code>EnchantmentMinusChance</code> with increasing level depth.
 +
|-
 +
| <code>EnchantmentPlusChanceBase</code>
 +
| <code>0, 5, 10, ...</code>
 +
| Make a finite chance that weapons generate with positive enchantment. High values increase the odds the player will come across good equipment.
 +
|-
 +
| <code>EnchantmentPlusChanceDelta</code>
 +
| <code>..., -5, 0, 5, ...</code>
 +
| Increments the <code>EnchantmentPlusChance</code> with increasing level depth.
 +
|-
 +
| <code>IsCatacomb</code>
 +
| <code>true</code> or <code>false</code>
 +
| Normally set to false. This variable causes a level to spawn only ghosts, skeletons and zombies. Used in the Attnamese Catacombs.
 +
|}
 +
 +
=== RoomDefault ===
 +
 +
{| class="wikitable"
 +
! Keyword
 +
! Values
 +
! Description
 +
|-
 +
| <code>Size</code>
 +
| <code>x, y;</code> or <code>m:n, p:q;</code>
 +
|
 +
|-
 +
| <code>Pos</code>
 +
| <code>x, y;</code> or <code>a:XSize-b, c:YSize-d;</code>
 +
|
 +
|-
 +
|
 +
| <code>XSize, YSize</code>
 +
| These are special keywords that return the horizontal length (XSize) and vertical length (YSize) of the level, in squares.
 +
|-
 +
| <code>Type</code>
 +
| <code>ROOM_TYPE</code>
 +
| Tells IVAN what type of room. Choose from ROOM_NORMAL, ROOM_SHOP, ROOM_CATHEDRAL, ROOM_LIBRARY, ROOM_BANANA_DROP_AREA or ROOM_SUMO_ARENA. Most common are ROOM_NORMAL and ROOM_SHOP.
 +
|-
 +
| <code>Shape</code>
 +
| <code>1, 2</code>
 +
| Determines whether room has rounded corners, or rectangular corners. Choose from either <code>RECTANGLE</code> or <code>ROUND_CORNERS</code>.
 +
|-
 +
| <code>GenerateTunnel</code>
 +
| <code>true</code> or <code>false</code>
 +
| Determines whether the room is to be connected to the rest of the level via a tunnel. Normally set to true. Set to false to create a secret vault...
 +
|-
 +
| <code>UseFillSquareWalls</code>
 +
| <code>true</code> or <code>false</code>
 +
|
 +
|-
 +
| <code>WallSquare</code>
 +
|
 +
|
 +
|-
 +
| <code>FloorSquare</code>
 +
|
 +
|
 +
|-
 +
| <code>DoorSquare</code>
 +
|
 +
|
 +
|-
 +
| <code>GenerateDoor</code>
 +
| <code>true</code> or <code>false</code>
 +
| Tell IVAN whether to generate doors for this room.
 +
|-
 +
| <code>GenerateWindows</code>
 +
| <code>true</code> or <code>false</code>
 +
| Tell IVAN whether to generate windows for this room. Normally set to true in cities above ground. Normally false underground.
 +
|-
 +
| <code>GenerateLanterns</code>
 +
| <code>true</code> or <code>false</code>
 +
| Whether lanterns are to be generated in the room.
 +
|-
 +
| <code>GenerateFountains</code>
 +
| <code>true</code> or <code>false</code>
 +
| Whether to generate fountains in the room.
 +
|-
 +
| <code>AllowLockedDoors</code>
 +
| <code>true</code> or <code>false</code>
 +
| Allows the possibility for doors to be spawned in a locked state. Only makes sense if doors can be generated for the room.
 +
|-
 +
| <code>AllowBoobyTrappedDoors</code>
 +
| <code>true</code> or <code>false</code>
 +
| Allows the possibility for doors to spawn with booby traps. A door does not need to be locked in order to be booby trapped.
 +
|-
 +
| <code>DivineMaster</code>
 +
| <code>0, 1, ... , 15, 16(?)</code>
 +
| Restricts range of gods player can pray to, to only this god. Select from <code>VALPURUS</code>, <code>LEGIFER</code> etc. 0 (zero) is all gods, so set this as the default value for your rooms in general.
 +
|-
 +
| <code>AltarPossible</code>
 +
| <code>true</code> or <code>false</code>
 +
| Allows the possibility of spawning an altar. If <code>DivineMaster</code> is set to zero, then it will be an arbitrary god. If <code>DivineMaster</code> is non-zero up to the number of gods, then it will spawn an altar of that deity. If <code>DivineMaster</code> is <code>ATHEIST</code> then it spawns a blank altar (???)
 +
|-
 +
| <code>IsInside</code>
 +
| <code>true</code> or <code>false</code>
 +
|
 +
|-
 +
| <code>Flags</code>
 +
|
 +
|
 +
|}
 +
 +
=== Square (DefaultSpecialSquares) ===
 +
 +
== Dungeon concrete elements ==
 +
 +
=== Level ===
 +
 +
=== Room ===
 +
 +
=== Square (on level) ===
 +
 +
 +
== Rooms ==
 +
 +
=== GTerrainMap ===
 +
 +
=== OTerrainMap ===
 +
 +
=== ItemMap ===
 +
 +
=== CharacterMap ===
 +
 +
=== Square (in room) ===
 +
 +
 +
== Dungeon random elements ==
 +
 +
=== RandomLevel ===
 +
 +
=== Random rooms ===
 +
 +
=== Square, BoundedRandom; ===
 +
 +
== Dungeon balancing ==
 +
 +
=== Monster net population ===
 +
 +
=== Monster generation net interval ===
 +
 +
=== Net difficulty ===
 +
 +
=== Item price ===
 +
 +
=== Item enchantment ===
 +
 +
 +
[[Category:Modding]]

Latest revision as of 14:29, 23 October 2019

This section is all about dungeon building. If you would like to learn about adding dungeons to the world map, see Adding Cities and Dungeons to the IVAN World Map.

Introduction

Welcome

Welcome to the world of IVAN dungeon building. It is a part of game development that is as interesting and intricate as the game itself. Designing and building a dungeon for IVAN presents many challenges and it can feel like a steep learning curve, however, the satisfaction of creating a world in which many enthusiastic IVANers can play in and feel part of is very rewarding. This guide is aimed at those with little or no coding skills, but who are comfortably computer literate. Those who are already familiar with C++ (or any other language) will be advantaged by their programming experience, and will hopefully find the collection of examples on dungeon building suitably novel and interesting.

What we will look at

Tools

A suitable text editor and font

When editing the dungeon file, it pays to have a good text editor. A nice program in Windows might be, for example, Programmer’s Notepad 2, but any program with suitable syntax highlighting will do. The script file text is based on C/C++ syntax, so you can set the syntax highlighting to this language. It is also highly prudent to select a mono-space typeface. A mono-space typeface means each character has the same horizontal length in the editor. Because we are also going to “draw” with ASCII characters in the script files, it would be good if the characters can properly align in a grid-like fashion, making it easy to identify the geometrical patterns. This is indispensable when it comes to laying out large rooms and even particular dungeons, helping to avoid confusion along the way. Suitable typefaces to consider for this purpose might include Consolas, Courier New or Lucida Console fonts, or any other suitable monospace font.

Backing up your work

This is really the most important step, and should be the first thing you organize. Make a copy of your dungeon file and store the copy somewhere else, that way, you can always revert to the original if you make changes all over the place. No matter if you lose original files, you can usually pick up an old file from a repository somewhere and revert back to it.

A more guru way to do this, would be to set up your own IVAN development branch, by cloning the attnam/ivan git repository and making changes in your own branch. You can make pull requests to merge you work into the main line of IVAN development! By using a version control system like GIT, you enable for yourself a great tool for maintaining your dungeon script file.

Philosophy

Order and Chaos

IVAN has the possibility for building both persistently generated content (order) and procedurally generated content (chaos). It is possible to create very rigidly designed places, with every terrain and item having its proper place. The city of Attnam might be considered a highly persistently generated place. Some places are also generated in a way that produces unique dungeon areas - never before visited - with random layout and loot. The Gloomy Caves might be considered such a place. This is only partly true, however, since we can also find things in the Gloomy Caves that can be encountered in each game, like the Gloomy Caves shop or the Enner Beast. We will examine both philosphies in detail, using the Gloomy Caves as an example of a balance between the tools for producing persistent elements and procedural elements in a dungeon.

A first dungeon

Dungeon script hierarchy

Example of hierarchy in a dungeon script

The dungeon script file follows a definite structure. However, this may be hard to see since certain keywords can be used over and over again. For example to re-define default values in a certain portion of the script, the keyword RoomDefault might be encountered at the LevelDefault stage or simply the Level stage.

Each dungeon has default parameters specified within LevelDefault and RoomDefault. This is where the general look and feel of the dungeon can be uniformly specified with only a few commands. These defaults can be overridden at any point in the script, within that dungeon.

Each level is explicitly catalogued by level number. LevelDefault can be overridden to change the look and feel of just one particular level if desired.

Rooms are described in the Level portion of the script, since rooms are contained on levels in the same way levels are contained in dungeons. Default specs for rooms (RoomDefault) can be overridden. This can either be done within each level, affecting only the specifications for rooms generated on that level, or it may be done on a per-room basis. Rooms can be rigidly specified, with special "script maps" GTerrainMap, OTerrainMap, ItemMap and CharacterMap listed, showing which types to be generated.

Squares can be defined within rooms, or within a level somewhere. On a square may be placed any amount of items, or a particular ground-terrain or over-terrain, such as stairs or a fountain.

Each room and square can be made to appear randomly within a level, in a random position, and/or within a random sub-area of a level (handled by BoundedRandom), and/or on a random member of a subset of levels (handled by RandomLevel).

Examples from the original game

Gloomy Caves Shop

The shop in the gloomy caves is a good example of how to manually lay out a specific room in the script. The shop is declared as a simple room. The size is set to 5 tiles wide by 9 tiles high. Because it is a shop, and Mellis is the god of trade and politics, the divine master is set to Mellis. No altars, fountains, locked doors or booby trapped doors will generate here. This will generate a bare room (see adjacent image). It generates doors and lanterns by itself, because this is specified in the default parameters for rooms in the dungeon.

Script Result
Room
{
  Size = 5,9;
  AltarPossible = false;
  DivineMaster = MELLIS;
  Type = ROOM_SHOP;
  GenerateFountains = false;
  AllowLockedDoors = false;
  AllowBoobyTrappedDoors = false;
ShopBare.png


Next we can fill the room with characters. We can place each character in a precise way, by writing a little ASCII map showing where everyone will go. The map - a character map - has a size, a position relative to the room's origin (the top-left corner is x = 0; y = 0;), and a key showing all the character types to be found on the character map. The character map can be thought of as a little sub-map belonging to the room. We need to show where the character map is positioned relative to the room it is in. We see the top-left corner of the room Pos = 0, 0; is occupied by a wall. We want to have a map that covers the floor area. The total floor area available in the shop is 3 tiles wide by 7 tiles tall, so this will be the size of or character map. The top-left tile in the character map will be the top-left tile in the room's available floor space. Therefore we will position the character map at Pos = 1, 1;, relative to the co-ordinates of the room's total space.

We need a shop keeper, and some strong guards to protect the fine wares. Therefore we will add the types g for a guard character with the config SHOP, and s for a shopkeeper with the config ELPURI_CAVE. We'll put them both on the same team, and we'll make the shopkeeper the room's master, which is relevant to the room type being a shop. So when the player character wishes to make a trade in the shop, the person he will deal with is the shopkeeper.

We then lay the types out in a 3x7 ASCII map. White spaces are ignored, full-stops represent no character, and g and s represent the guard and the shop keeper. We can place the guard in the shop many times over, and we will place one of them in each corner. We probably only want one shop keeper, and so he is placed in the middle of the map.

Script Result
CharacterMap
{
  Pos = 1, 1;
  Size = 3, 7;
  Types
  {
    g = guard(SHOP) { Team = 5; }
    s = shopkeeper(ELPURI_CAVE) { Team = 5; Flags = IS_MASTER; }
  }
}
{
  g.g
  ...
  ...
  .s.
  ...
  ...
  g.g
}
ShopPeople.png


We need to put items in the room so the shopkeeper has something to sell. We can do this in the same way as with the character map, only this time with an item map. The item map will have the same footprint as the character map, so this will be the same as before. We want to fill the remaining available spaces in the room with random item types of varying categories and worth. In the script, random items are created, but within the parameters of minimum and maximum prices, and item category flags. This enables a good balance between high and low value items, preventing the game from creating a room full of broken leather boots, or for that matter, a room full of magic lamps! If we want we can generate specific items, and so by looking at this script you will see a wand of striking will generate in every shop, for every game of IVAN. This is an example of a so-called "guaranteed item", and is a design element I hope you will choose to use sparingly.

We can then populate our 3x7 item map with the types we specified, and using a full-stop to leave some spaces for the character types we placed in the character map for the shop.

Script Result
ItemMap
{
  Pos = 1,1;
  Size = 3,7;
  Types
  {
    g == Random { MinPrice = 100; MaxPrice = 10000; Category = GAUNTLET|BOOT; }
    b == Random { MinPrice = 100; MaxPrice = 10000; Category = GAUNTLET|BOOT; }
    a == Random { MinPrice = 500; MaxPrice = 10000; Category = HELMET|CLOAK|BODY_ARMOR|BELT; }
    d == Random { MinPrice = 200; MaxPrice = 10000; Category = RING|AMULET; }
    w == Random { MinPrice = 500; MaxPrice = 10000; Category = WEAPON|SHIELD; }
    e == Random { MinPrice = 50; MaxPrice = 10000; Category = FOOD|POTION; }
    u == Random { MinPrice = 200; MaxPrice = 10000; Category = WAND|TOOL; }
    r == Random { MinPrice = 200; MaxPrice = 10000; Category = SCROLL|BOOK; }
    s == wand(WAND_OF_STRIKING);
  }
}
{
  .g.
  ddb
  err
  e.w
  auw
  auw
  .s.
}
ShopItems.png

Dungeon default control variables

Dungeon

Keyword Values Description
Dungeon
0, 1, 2, ... , 64 This is the dungeon enumerator variable. Enumerations 0 to 4 are occupied by the original dungeons with predefined variables like ATTNAM or ELPURI_CAVE.
Levels 0, 1, 2, ... This determines the total number of levels in the dungeon.
Description "string" This is a short name for the dungeon that shows up in the high score list explaining which dungeon the player died in.
ShortDescription "string" This is an even shorter name for the dungeon usually limited to two or three characters, for example "GC" for gloomy caves. It shows up on the side bar.

LevelDefault

Keyword Values Description
Size x, y; This is the size of the level in squares. x and y are the horizontal and vertical size respectively with x, y ∈ {1, 2, 3, ... }.
Rooms n; or p:q; Total number of rooms possible on the level. Can be a fixed number, n, or a number of generic rooms between p and q with p < q. n, p and q ∈ {0, 1, 2, 3, ... }.
Items n; or p:q; Total number of items that will generate on the level. Can be a fixed number, n, or a random number of items between p and q with p < q. n, p and q ∈ {0, 1, 2, 3, ... }.
TunnelSquare solidterrain(FLOOR_TYPE), 0; TunnelSquare determines the appearance of the tunnel floor. First parameter determines the floor appearance, second parameter should be zero.
FLOOR_TYPE Choose from PARQUET, FLOOR, GROUND, GRASS_TERRAIN etcetera
0; To make a tunnel, this ought to remain zero. Non-zero will cause the tunnel to fill with material!
FillSquare solidterrain(FLOOR_TYPE), MATERIAL earth FillSquare determines what to fill the level's walls and filling material with, and what type of ground appears under those walls. First parameter determines the floor, second parameter determines the walls.
FLOOR_TYPE Choose from PARQUET, FLOOR, GROUND, GRASS_TERRAIN etcetera. Good to choose from the same type as TunnelSquare.
MATERIAL Choose from GRAVEL, MORAINE, GOLD etcetera
BackGroundType m; Defines the default background type. Not sure what it precisely affects. m can be GRAY_FRACTAL, RED_FRACTAL, GREEN_FRACTAL etcetera.
EarthquakesAffectTunnels true or false Tells the game whether an earthquake on the level can rearrange the layout of tunnels. Open levels will crash if this is not set to false (because there are no tunnels to shift). Set to true if the level has tunnels, set to false if it is open. See also IsOnGround.
IsOnGround true or false Tells the game whether the level is above ground. This prevents earthquakes from happening on the level. Silva will summon wolves instead.
IgnoreDefaultSpecialSquares true or false If specific squares containing items/traps etc are specified in LevelDefault, then setting this to true for a particular level will cause these random squares not to appear. Accordingly, in LevelDefault this should be set to false. See Square (DefaultSpecialSquares).
CanGenerateBone true or false Tells the game whether a bone file can be generated on this level, or not. Best to set the default value to true. Typically set this to false if the level will generate a shop, or a victory boss like Oree (not Enner).
LOSModifier 16, 24, 32, 48, ... Line of sight modifier. Typical value for underwater tunnel or gloomy caves is 16. Zombie level is 24. Sumo area is 32. Towns are typically 48. Higher value means player character can see further.
DifficultyBase 0, 5, 10, ... Sets the base difficulty for the level. In LevelDefault, this is the base difficulty for all the levels.
DifficultyDelta 0, 5, 10, ... This sets the value added to the DifficultyBase for each consecutive level. In LevelDefault, this is the change in difficulty per level (dD), without needing to continually specify DifficultyBase (DB) for each level. The difficulty, D, is therefore set to D = DB + dD * L, where L is the current level number.
GenerateMonsters true or false Whether monsters can be generated on the level or not. Set to false in peaceful towns; typically set to true in caves.
TeamDefault TEAM_NAME Sets the team to which spawned monsters are aligned. Typically set to MONSTER_TEAM to generate hostile enemies.
MonsterAmountBase 0, 10, 20, ... Sets the maximum number of monsters for the level for the generator. While the number of monsters is less than this value, the monster generator adds a new monster. Above this value, monsters are not generated.
MonsterAmountDelta 0, 5, 10, ... This sets the value added to the MonsterAmountBase for each consecutive level. In LevelDefault, this is the change in monster setpoint per level (dM), without needing to continually specify MonsterAmountBase (MB) for each level. The number of monsters (M) setpoint for any given level, is set to M = MB + dM * L, where L is the current level number.
MonsterGenerationIntervalBase 100, 120, ... The time taken between monster generations, in tens of ticks
MonsterGenerationIntervalDelta ..., -10, 0, 10, ... The increment per level in the time taken between monster generations, in tens of ticks. A negative number means that that the generation interval becomes shorter by that amount, for each consecutive level. The implication being, negative numbers increase the frequency of monster generation with increasing level depth.
ItemMinPriceBase 0, 20, 40, ... The minimum price for items generated on the level, in gold coins. Lower minimum price causes items to generate from low-value materials.
ItemMinPriceDelta 0, 10, 20, ... Incremental increase or decrease in generated item value per level, in gold coins.
EnchantmentMinusChanceBase 0, 5, 10, ... Make a finite chance that weapons generate with negative enchantment. High values increase the odds the player will come acrossterrible equipment.
EnchantmentMinusChanceDelta ..., -5, 0, 5, ... Increments the EnchantmentMinusChance with increasing level depth.
EnchantmentPlusChanceBase 0, 5, 10, ... Make a finite chance that weapons generate with positive enchantment. High values increase the odds the player will come across good equipment.
EnchantmentPlusChanceDelta ..., -5, 0, 5, ... Increments the EnchantmentPlusChance with increasing level depth.
IsCatacomb true or false Normally set to false. This variable causes a level to spawn only ghosts, skeletons and zombies. Used in the Attnamese Catacombs.

RoomDefault

Keyword Values Description
Size x, y; or m:n, p:q;
Pos x, y; or a:XSize-b, c:YSize-d;
XSize, YSize These are special keywords that return the horizontal length (XSize) and vertical length (YSize) of the level, in squares.
Type ROOM_TYPE Tells IVAN what type of room. Choose from ROOM_NORMAL, ROOM_SHOP, ROOM_CATHEDRAL, ROOM_LIBRARY, ROOM_BANANA_DROP_AREA or ROOM_SUMO_ARENA. Most common are ROOM_NORMAL and ROOM_SHOP.
Shape 1, 2 Determines whether room has rounded corners, or rectangular corners. Choose from either RECTANGLE or ROUND_CORNERS.
GenerateTunnel true or false Determines whether the room is to be connected to the rest of the level via a tunnel. Normally set to true. Set to false to create a secret vault...
UseFillSquareWalls true or false
WallSquare
FloorSquare
DoorSquare
GenerateDoor true or false Tell IVAN whether to generate doors for this room.
GenerateWindows true or false Tell IVAN whether to generate windows for this room. Normally set to true in cities above ground. Normally false underground.
GenerateLanterns true or false Whether lanterns are to be generated in the room.
GenerateFountains true or false Whether to generate fountains in the room.
AllowLockedDoors true or false Allows the possibility for doors to be spawned in a locked state. Only makes sense if doors can be generated for the room.
AllowBoobyTrappedDoors true or false Allows the possibility for doors to spawn with booby traps. A door does not need to be locked in order to be booby trapped.
DivineMaster 0, 1, ... , 15, 16(?) Restricts range of gods player can pray to, to only this god. Select from VALPURUS, LEGIFER etc. 0 (zero) is all gods, so set this as the default value for your rooms in general.
AltarPossible true or false Allows the possibility of spawning an altar. If DivineMaster is set to zero, then it will be an arbitrary god. If DivineMaster is non-zero up to the number of gods, then it will spawn an altar of that deity. If DivineMaster is ATHEIST then it spawns a blank altar (???)
IsInside true or false
Flags

Square (DefaultSpecialSquares)

Dungeon concrete elements

Level

Room

Square (on level)

Rooms

GTerrainMap

OTerrainMap

ItemMap

CharacterMap

Square (in room)

Dungeon random elements

RandomLevel

Random rooms

Square, BoundedRandom;

Dungeon balancing

Monster net population

Monster generation net interval

Net difficulty

Item price

Item enchantment