···44, substituteAll
55, runCommand
66, coreutils
77+, gawk
78, dwarf-fortress
89, dwarf-therapist
910, enableDFHack ? false
···1617, twbt
1718, themes ? { }
1819, theme ? null
2020+, extraPackages ? [ ]
1921 # General config options:
2022, enableIntro ? true
2121-, enableTruetype ? true
2323+, enableTruetype ? null # defaults to 24, see init.txt
2224, enableFPS ? false
2325, enableTextMode ? false
2426, enableSound ? true
2727+# An attribute set of settings to override in data/init/*.txt.
2828+# For example, `init.FOO = true;` is translated to `[FOO:YES]` in init.txt
2929+, settings ? { }
3030+# TODO world-gen.txt, interface.txt require special logic
2531}:
26322733let
2834 dfhack_ = dfhack.override {
2935 inherit enableStoneSense;
3030- inherit enableTWBT;
3136 };
32373338 ptheme =
···3540 then builtins.getAttr theme themes
3641 else theme;
37423838- unBool = b: if b then "YES" else "NO";
4343+ baseEnv = buildEnv {
4444+ name = "dwarf-fortress-base-env-${dwarf-fortress.dfVersion}";
39454040- # These are in inverse order for first packages to override the next ones.
4141- themePkg = lib.optional (theme != null) ptheme;
4242- pkgs = lib.optional enableDFHack dfhack_
4343- ++ lib.optional enableSoundSense soundSense
4444- ++ lib.optional enableTWBT twbt.art
4545- ++ [ dwarf-fortress ];
4646+ # These are in inverse order for first packages to override the next ones.
4747+ paths = extraPackages
4848+ ++ lib.optional (theme != null) ptheme
4949+ ++ lib.optional enableDFHack dfhack_
5050+ ++ lib.optional enableSoundSense soundSense
5151+ ++ lib.optionals enableTWBT [ twbt.lib twbt.art ]
5252+ ++ [ dwarf-fortress ];
46534747- fixup = lib.singleton (runCommand "fixup" { } (''
5454+ ignoreCollisions = true;
5555+ };
5656+5757+ settings_ = lib.recursiveUpdate {
5858+ init = {
5959+ PRINT_MODE = if enableTextMode then "TEXT" else if enableTWBT then "TWBT" else null;
6060+ INTRO = enableIntro;
6161+ TRUETYPE = enableTruetype;
6262+ FPS = enableFPS;
6363+ SOUND = enableSound;
6464+ };
6565+ } settings;
6666+6767+ forEach = attrs: f: lib.concatStrings (lib.mapAttrsToList f attrs);
6868+6969+ toTxt = v:
7070+ if lib.isBool v then if v then "YES" else "NO"
7171+ else if lib.isInt v then toString v
7272+ else if lib.isString v then v
7373+ else throw "dwarf-fortress: unsupported configuration value ${toString v}";
7474+7575+ config = runCommand "dwarf-fortress-config" {
7676+ nativeBuildInputs = [ gawk ];
7777+ } (''
4878 mkdir -p $out/data/init
4949- '' + (if (theme != null) then ''
5050- cp ${lib.head themePkg}/data/init/init.txt $out/data/init/init.txt
5151- '' else ''
5252- cp ${dwarf-fortress}/data/init/init.txt $out/data/init/init.txt
5353- '') + lib.optionalString enableDFHack ''
7979+8080+ edit_setting() {
8181+ v=''${v//'&'/'\&'}
8282+ if ! gawk -i inplace -v RS='\r?\n' '
8383+ { n += sub("\\[" ENVIRON["k"] ":[^]]*\\]", "[" ENVIRON["k"] ":" ENVIRON["v"] "]"); print }
8484+ END { exit(!n) }
8585+ ' "$out/$file"; then
8686+ echo "error: no setting named '$k' in $file" >&2
8787+ exit 1
8888+ fi
8989+ }
9090+ '' + forEach settings_ (file: kv: ''
9191+ file=data/init/${lib.escapeShellArg file}.txt
9292+ cp ${baseEnv}/"$file" "$out/$file"
9393+ '' + forEach kv (k: v: lib.optionalString (v != null) ''
9494+ export k=${lib.escapeShellArg k} v=${lib.escapeShellArg (toTxt v)}
9595+ edit_setting
9696+ '')) + lib.optionalString enableDFHack ''
5497 mkdir -p $out/hack
55985699 # Patch the MD5
5757- orig_md5=$(cat "${dwarf-fortress}/hash.md5.orig")
5858- patched_md5=$(cat "${dwarf-fortress}/hash.md5")
100100+ orig_md5=$(< "${dwarf-fortress}/hash.md5.orig")
101101+ patched_md5=$(< "${dwarf-fortress}/hash.md5")
59102 input_file="${dfhack_}/hack/symbols.xml"
60103 output_file="$out/hack/symbols.xml"
61104···66109 echo " Replace: $patched_md5"
6711068111 substitute "$input_file" "$output_file" --replace "$orig_md5" "$patched_md5"
6969- '' + lib.optionalString enableTWBT ''
7070- substituteInPlace $out/data/init/init.txt \
7171- --replace '[PRINT_MODE:2D]' '[PRINT_MODE:TWBT]'
7272- '' +
7373- lib.optionalString enableTextMode ''
7474- substituteInPlace $out/data/init/init.txt \
7575- --replace '[PRINT_MODE:2D]' '[PRINT_MODE:TEXT]'
7676- '' + ''
7777- substituteInPlace $out/data/init/init.txt \
7878- --replace '[INTRO:YES]' '[INTRO:${unBool enableIntro}]' \
7979- --replace '[TRUETYPE:YES]' '[TRUETYPE:${unBool enableTruetype}]' \
8080- --replace '[FPS:NO]' '[FPS:${unBool enableFPS}]' \
8181- --replace '[SOUND:YES]' '[SOUND:${unBool enableSound}]'
8282- ''));
112112+ '');
83113114114+ # This is a separate environment because the config files to modify may come
115115+ # from any of the paths in baseEnv.
84116 env = buildEnv {
85117 name = "dwarf-fortress-env-${dwarf-fortress.dfVersion}";
8686-8787- paths = fixup ++ themePkg ++ pkgs;
8888- pathsToLink = [ "/" "/hack" "/hack/scripts" ];
8989-118118+ paths = [ config baseEnv ];
90119 ignoreCollisions = true;
91120 };
92121in
122122+123123+lib.throwIf (enableTWBT && !enableDFHack) "dwarf-fortress: TWBT requires DFHack to be enabled"
124124+lib.throwIf (enableStoneSense && !enableDFHack) "dwarf-fortress: StoneSense requires DFHack to be enabled"
125125+lib.throwIf (enableTextMode && enableTWBT) "dwarf-fortress: text mode and TWBT are mutually exclusive"
9312694127stdenv.mkDerivation {
95128 pname = "dwarf-fortress";
···114147 runDFHack = ./dfhack.in;
115148 runSoundSense = ./soundSense.in;
116149117117- passthru = { inherit dwarf-fortress dwarf-therapist; };
150150+ passthru = {
151151+ inherit dwarf-fortress dwarf-therapist twbt env;
152152+ dfhack = dfhack_;
153153+ };
118154119155 buildCommand = ''
120156 mkdir -p $out/bin
+2-2
pkgs/games/dwarf-fortress/wrapper/dfhack.in
···2233source @dfInit@
4455-for i in dfhack.init-example dfhack-config/default hack/* stonesense/*; do
66- update_path "$i"
55+for i in *.init *.init-example dfhack-config/default dfhack-config/init hack/* stonesense/*; do
66+ if [ -e "$i" ]; then update_path "$i"; fi
77done
8899cd "$DF_DIR"