Generate maps for Dungeon Keeper 1 PC game.
- Generated map types
- Running the generator
- Building under Linux (including WLS)
- Building under other platforms
- Building Python bindings
- Config parameters
- Releasing
- Examples of various used techniques
- Sources of randomness
- References
Following map types can be generated:
- cave -- open area with chambers in center with hidden enemy creatures (sample)
- maze -- big maze in center of map with hidden trasures and traps (sample)
- herofortress -- siege of hero fortress (sample)
- random -- randomly picks one of modes described above
Linked samples and following previews were generated with Sample seed.
Before first run edit config.ini
placed along main executable. Inside the file fill required variables (paths to game directories). Example of configuration file is described here.
For simple generation just execute dkmagecli
to generate random map. Generated map will be stored in level_path
defined in config. If the path is game's directory then map will be ready to play from within Free Play levels
game's menu. For advanced use of generator execute dkmagecli --help
or open dkmagecli help description.
Generator parameters can be passed by command line argument or by configuration file. Processing sequence of parameters:
- load
config.ini
from file passed by command line argument--config
, if no cmd argument given then use default location - load all parameters from
general
section of configuration file - load all parameters from type section pointed by
--type
command line argument ortype
fromgeneral
section - overwrite loaded parameters by arguments passed through command line (if any)
Processing sequence defines following priority of parameters (from most to least important):
- command line parameters
- type section from configuration file
general
section from configuration file- default values if no parameters set
There are few exceptions from priority rule described above:
config
parameter is only read from command lineseed
parameter is only read from command line orgeneral
section from configuration filetype
parameter is only read from command line orgeneral
section from configuration file
Generator produces the same files as ADiKtEd does. Moreover there is one additional file *.mage.ini
along stored map containing parameters used for generate map. The Ini file can be passed to generator to repeat the generation (it produces the same map). It is useful to share maps or for debug purpose.
In addition in work directory can be found two log files:
adikted.log.txt
containing logs from execution of ADiKtEd librarydkmage.log.txt
containing logs from execution of generator modules
To generate build system execute one of scripts placed in configure
directory. It will create proper folder in build
directory.
For example calling configure/lin_release_gcc.sh
will create build/lin_release_gcc
directory. To build the application then go to build/lin_release_gcc
and run make
.
It is also possible to configure prepare customized build by using cmake
directly.
To build Linux executables run configure/lin_release_gcc.sh
or configure/lin_debug_gcc.sh
scripts then run make
in proper subdirectory in build
.
Following packages are required to proceed with build:
- cmake
- gcc
- g++
They can be installed by following command sudo apt install cmake g++ gcc
.
To build Windows executables run configure/win_release_gcc.sh
or configure/win_debug_gcc.sh
scripts then run make
in proper subdirectory in build
.
Following packages are required to build application under Linux for Windows platform:
- g++-mingw-w64-i686
- gcc-mingw-w64-i686
- binutils-mingw-w64-i686
They can be installed by following command sudo apt install g++-mingw-w64-i686 gcc-mingw-w64-i686 binutils-mingw-w64-i686
.
Unit tests can be executed from within proper build
subdirectory by executing ctest
command.
To build one have to execute cmake
directly in order to configure project and then execute cmake --build .
from within configured build directory.
Generation of Python bindings requires two elements:
- Python
- swig generator (swig3.0 package on Ubuntu)
To generate bindings one has to check BUILD_PYTHON_BINDINGS
in cmake configuration (e.g. by executing cmake-gui
). Next step is to build the source code and preferably execute tests (make
and ctest
respectively). Final step is to execute ./deploy_zip.sh
. Script will package all bindings and required libraries into deploy/pydkmage_{version}_{platform}.zip
archive.
Archive contains numerous unit tests and simple examples (generate_map.py
, generator.py
) how to use the bindings under Python. Unit tests can be executed from bindings root directory by following command: python3 -m unittest
.
Adding new config parameters consists of several steps:
- add or edit entry in src/gen/parameter_name.csv
- run parameters generator
src/gen/params_generator.py
- use new
ParameterName::PN_*
enum value (defined in ParameterName.h) - use one of generated default value constants
PN_DEFAULT_*
(defined in ParameterDefaults.h) - extend config.ini.in with proper description of new parameter. Default values can be referenced using cmake constants
PN_DEFAULT_*
(defined in ParameterDefaults.cmake)
To release binaries proceed with following steps:
- update version number of project (
project()
command in src/CMakeLists.txt) - build source code
- ensure all tests pass (execute
ctest
from build directory) - generate documentation (usage info, samples, previews etc.) by running
generate_doc.sh
script from build directory (script will use prepared executable to generate required artifacts) - commit and push changes
- run
deploy_zip.sh
from build directory - upload binaries (build/bin/dkmage*.zip file)
- upload bindings (build/bin/pydkmage*.zip file)
Note that deploy_zip.sh
prepares deploymnet package for platform configured in build directory. It might be desirable to execute the script on multiple build directories to collect proper artifacts.
- CMake's
FetchContent
and proper configuration foradd_directory
(target_include_directories
) - generating sourcecode (*.h, *.cpp and *.cmake) based on content of *.csv files using Python
- generation of Python bindings using swig generator on non-trivial codebase
- random number generator (
stdlib.h
) - uninitialized variables
- order of objects stored as pointers containers having order, especially pointers in
std::set
-- e.g.
std::set< int* > data;
data.insert( new int(1) );
data.insert( new int(2) );
data.insert( new int(3) );
/// each time order of numbers can be different
- Mapmaker's Documentation (https://lubiki.keeperklan.com/dk1_docs/)
- description of Dungeon Keeper data formats (https://jonskeet.uk/dk/index.html)
- ADiKtEd editor (https://github.com/dkfans/ADiKtEd)
- maps and tools (https://lubiki.keeperklan.com/index.php)
- KeeperFX (https://github.com/dkfans/keeperfx)
- generation of caves (http://roguebasin.roguelikedevelopment.org/index.php?title=Cellular_Automata_Method_for_Generating_Random_Cave-Like_Levels)
- Dungeon Keeper 2 mapper (https://www.killerbeesoftware.com/dk2/)
- Diablo map generator explained (https://www.boristhebrave.com/2019/07/14/dungeon-generation-in-diablo-1/)
- Swig: bindings generator (http://www.swig.org/)
- ADiKtEd: handling DK's file formats (https://github.com/dkfans/ADiKtEd)
- filesystem: pre C++17
std::filesystem
compatible implementation (https://github.com/gulrak/filesystem) - LEMON: graphs implementation (https://lemon.cs.elte.hu)
- TCLAP: command line args processing (http://tclap.sourceforge.net/)
- inih: INI files parser (https://github.com/jtilly/inih)
- Catch2: testing framework for unit-tests (https://github.com/catchorg/Catch2)