Into The Mists - Roguelike

 Link to Repository

 Skip to Section

Team Size: 1 individual project

Engine: Personal Engine in C++ with Opengl

Genre: 2D Roguelike

Role: Programmer

Into the Mists is a 2D ascii roguelike.  Notable features include: 

 

Self registering map generators

NPC Factories

AI behaviors with A* pathing and faction loyalty

Saving

 

Overview
 
 
 
 
 
High Concept

Development Time: 8 weeks

 Game Mechanics Overview

 

 Game Loop

 Each turn, the player can move in one of the four cardinal direction or in the diagonals.  If the player would collide with a wall, he loses a turn.  If the player runs into an NPC, the player attacks the NPC.  The player can also choose to open doors or pick up items on his turn.  After each turn, every NPC takes an action.

 Icons

@          Player

Letter   NPC Character 

;            Torch

)            Weapon

[            Armor

+           Door Closed

-            Door Opened

 Controls

    H:           Move W
    J:            Move S
    K:           Move N
    L:            Move E
    Y:            Move NW
    U:            Move NE
    B:            Move SW
    N:            Move SE

    

    Space:     Progress message bar
    ,:              Pick up item
    O:             Operate nearby feature or door

 Map Generation

 

 Map Generation Overview

 Each map generator contains a static self registrion object that allows each map generator to add itself to the std::map of map generators without the class containing the std::map having to have a .h include to each generator.  The base map generator class then creates each generator when called on startup.  Each child generator inherits the generateMap function.  GenerateMap is called when the map type tied to the map generator is called to be created via the in game menu. 

 The code below show the header file of the BaseMapGenerator which other generators inherit from.  It also contains the MapGeneratorRegistration class.  Each time a MapGeneratorRegistration is constructed, they add a reference of themselves to the s_mapRegistration which is the handle each map gets to be referenced outside of the class without having to include a .h to the game.  

 Upon initializing the game, create generators is called.  For each map generator registered, a map generator is constructed with createMapGenerator and placed in s_generatedMaps.

 Example Generated Map - Buildings with River

The map above is called Buildings with River.  Initially, the plan was to make the water a river, but I kept the water in a lake setup due to lack of development time.  The map has fog of war, making everything outside of the player's view darker.  Light falls off the farther from the player it is.  Building floor tiles are represented by light brown, light grey is walkable outside tiles, dark grey is building wall tiles, and dark green is outside wall tiles.  

 

The base of the map consists of the outside floor and outside walls which are generated with cellular autamata.  Afterwards, buildings are placed randomly.  Each building on each of its walls have atleast one doorway if the wall is connected walkable space.   Multiple doorwayss will appear on the same wall if the wall is connected to two or more sections of walkable space. 

 

After each building is placed, the water is generated.  Finally, items, doors, and NPCs are added to the map.

In generateMap below, initializeRandomData creates the cellular autamata, processOneStep creates one building, and addRiver adds water to the map.

BuildingsWithRiverGenerator.cpp

 NPCs

 

 NPCs are added to a map during on load or during the map generation process.  NPCs are created using factories.  When a map generates its NPCs, the map checks the tile type then creates an NPC appropriate for that tile.

Upon initializing the game, each file of extension type blueprint.xml is found in the Data/NPCs/ folder.  For each file found, a new factory is created.

NPCFactory.cpp

 

The above XML is an example of what is fed into the NPCFactory in order to create new NPCs. The XML defines the name, where it can spawn, what faction it belongs to, what the creature looks like (color and glyph), the NPC's attack values, and what behaviors are available to the NPC.

Behaviors

Behaviors self register in the same manner as the map generators.  Each behavior calculates it's importance with the calculateImportance function and that is given back to the calling function to help choose what behavior to act out when Think is called. 

 

Below is some examples in the Steal behavior.

Factions

Each NPC and the player has thier own faction.  As the player attacks a certain faction and is caught doing so, the player become more loyal or less loyal to the other factions.  A friend of an enemy is an enemy and an enemy of an enemy is a friend kind of mentality.  

 

Faction loyalty is stored in: 

std::map< PersonalFaction, std::map< OtherFaction, HowMuchPersonalFactionLikesOtherFaction>> FactionManager::s_factionLoyaltyMap;

A* Pathing

 

In the video below, the orc 'O' and goblin 'g' follows the player until the player '@' walks over lava, then they lose interest in the player.  Once the demon 'd' notices the player, he follows him, even through lava.

NPC

 

 Saving and Loading

 

The code below shows how every object is saved and loaded.  The XML reader used for the process is TinyXML.

Below is the code sample of how the agent class is saved an loaded.