Merge branch 'develop' into spectate

develop
Josh Cooper 2022-10-14 17:41:34 -07:00
commit 9b1541add5
46 changed files with 557 additions and 186 deletions

@ -0,0 +1,6 @@
#query label(query)
,,"{givename name=""foo dumper""}"
,,"{givename name=""foo""}"
Can't render this file because it has a wrong number of fields in line 5.

@ -0,0 +1,28 @@
#build label(construct) start(14;14)
,trackNS,trackE,,trackW,trackS,trackN,,,,,,,,,,,,,,trackN,trackS,trackE,,trackW,trackNS
trackEW,,trackSE,,trackSW,trackNE,trackNW,,,,,,,,,,,,,,trackNE,trackNW,trackSE,,trackSW,,trackEW
trackS,trackSE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackSW,trackS
trackN,trackNE,trackSEW,,,trackSEW,trackNEW,,,,,,,,,,,,,,trackNEW,trackSEW,,,trackSEW,trackNW,trackN
trackE,trackSW,trackNEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackNEW,trackSE,trackW
trackW,trackNW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackNE,trackE
,,,,,,,,,,trackrampNW,trackrampNS,trackrampN,,trackrampN,trackrampNS,trackrampNE
,,,,,,,,,trackrampNW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampNE
,,,,,,,,,trackrampEW,trackrampSEW,,trackrampNSEW,,trackrampNSEW,,trackrampSEW,trackrampEW
,,,,,,,,,trackrampW,trackrampNEW,trackrampNSEW,,,,trackrampNSEW,trackrampNEW,trackrampE
,,,,,,,,,trackrampW,trackrampSEW,trackrampNSEW,,,,trackrampNSEW,trackrampSEW,trackrampE
,,,,,,,,,trackrampEW,trackrampNEW,,trackrampNSEW,,trackrampNSEW,,trackrampNEW,trackrampEW
,,,,,,,,,trackrampSW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampSE
,,,,,,,,,,trackrampSW,trackrampNS,trackrampS,,trackrampS,trackrampNS,trackrampSE
trackW,trackSW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackSE,trackE
trackE,trackNW,trackSEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackSEW,trackNE,trackW
trackS,trackSE,trackNEW,,,trackNEW,trackSEW,,,,,,,,,,,,,,trackSEW,trackNEW,,,trackNEW,trackSW,trackS
trackN,trackNE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackNW,trackN
trackEW,,trackNE,,trackNW,trackSE,trackSW,,,,,,,,,,,,,,trackSE,trackSW,trackNE,,trackNW,,trackEW
,trackNS,trackE,,trackW,trackN,trackS,,,,,,,,,,,,,,trackS,trackN,trackE,,trackW,trackNS
1 #build label(construct) start(14;14)
2 ,trackNS,trackE,,trackW,trackS,trackN,,,,,,,,,,,,,,trackN,trackS,trackE,,trackW,trackNS
3 trackEW,,trackSE,,trackSW,trackNE,trackNW,,,,,,,,,,,,,,trackNE,trackNW,trackSE,,trackSW,,trackEW
4 trackS,trackSE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackSW,trackS
5 trackN,trackNE,trackSEW,,,trackSEW,trackNEW,,,,,,,,,,,,,,trackNEW,trackSEW,,,trackSEW,trackNW,trackN
6 trackE,trackSW,trackNEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackNEW,trackSE,trackW
7 trackW,trackNW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackNE,trackE
8 ,,,,,,,,,,trackrampNW,trackrampNS,trackrampN,,trackrampN,trackrampNS,trackrampNE
9 ,,,,,,,,,trackrampNW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampNE
10 ,,,,,,,,,trackrampEW,trackrampSEW,,trackrampNSEW,,trackrampNSEW,,trackrampSEW,trackrampEW
11 ,,,,,,,,,trackrampW,trackrampNEW,trackrampNSEW,,,,trackrampNSEW,trackrampNEW,trackrampE
12 ,,,,,,,,,trackrampW,trackrampSEW,trackrampNSEW,,,,trackrampNSEW,trackrampSEW,trackrampE
13 ,,,,,,,,,trackrampEW,trackrampNEW,,trackrampNSEW,,trackrampNSEW,,trackrampNEW,trackrampEW
14 ,,,,,,,,,trackrampSW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampSE
15 ,,,,,,,,,,trackrampSW,trackrampNS,trackrampS,,trackrampS,trackrampNS,trackrampSE
16 trackW,trackSW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackSE,trackE
17 trackE,trackNW,trackSEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackSEW,trackNE,trackW
18 trackS,trackSE,trackNEW,,,trackNEW,trackSEW,,,,,,,,,,,,,,trackSEW,trackNEW,,,trackNEW,trackSW,trackS
19 trackN,trackNE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackNW,trackN
20 trackEW,,trackNE,,trackNW,trackSE,trackSW,,,,,,,,,,,,,,trackSE,trackSW,trackNE,,trackNW,,trackEW
21 ,trackNS,trackE,,trackW,trackN,trackS,,,,,,,,,,,,,,trackS,trackN,trackE,,trackW,trackNS

@ -0,0 +1,28 @@
#build label(build) start(14;14)
,~,~,,~,~,~,,gs(1x2),ga(2x1),,gx(1x2),gw(1x2),,gw(1x2),gx(1x2),gd(2x1),,gs(1x2),,~,~,~,,~,~
~,,~,,~,~,~,,,gd(2x1),,,,,,,ga(2x1),,,,~,~,~,,~,,~
~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~
,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
~,~,~,,,~,~,,CSa,,Mrss(1x2),Mw,,,,Mw,Mrss(1x2),,CSa,,~,~,,,~,~,~
~,~,~,,~,,~,,,Msm,,,Mhs(1x2),,Mhs(1x2),,,Msm,,,~,,~,,~,~,~
~,~,~,,~,~,,,Msu,,Mws,,,,,,Mws,,Msu,,,~,~,,~,~,~
,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
gs(2x1),,Mrqq(1x2),CSddaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSddaaaa,Mrqq(1x2),gs(2x1)
gw(1x2),gx(1x2),,,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,,,gx(1x2),gw(1x2)
,,,Msm,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,Msm
gd(2x1),,Msu,,Mws,,,Mhs(1x2),,~,~,,~,,~,,~,~,,Mhs(1x2),,,Mws,,Msu,ga(2x1)
ga(2x1),,,Mws,,Mh(2x1),,,,~,~,~,,,,~,~,~,,,Mh(2x1),,,Mws,,gd(2x1)
ga(2x1),,,Mws,,Mh(2x1),,Mhs(1x2),,~,~,~,,,,~,~,~,,Mhs(1x2),Mh(2x1),,,Mws,,gd(2x1)
gd(2x1),,,,Mws,,,,,~,~,,~,,~,,~,~,,,,,Mws,,,ga(2x1)
gx(1x2),gw(1x2),Msm,,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,,Msm,gw(1x2),gx(1x2)
,,Mrssqq(1x2),Msu,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,Msu,Mrssqq(1x2)
gs(2x1),,,CSdaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSdaaaa,,gs(2x1)
,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
~,~,~,,~,~,,,,,Mws,,Mhs(1x2),,Mhs(1x2),,Mws,,,,,~,~,,~,~,~
~,~,~,,~,,~,,Msm,,Mr(1x2),,,,,,Mr(1x2),,Msm,,~,,~,,~,~,~
~,~,~,,,~,~,,CSa,Msu,,Mw,,,,Mw,,Msu,CSa,,~,~,,,~,~,~
,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~
~,,~,,~,~,~,,gs(1x2),gd(2x1),,gw(1x2),gx(1x2),,gx(1x2),gw(1x2),ga(2x1),,gs(1x2),,~,~,~,,~,,~
,~,~,,~,~,~,,,ga(2x1),,,,,,,gd(2x1),,,,~,~,~,,~,~
1 #build label(build) start(14;14)
2 ,~,~,,~,~,~,,gs(1x2),ga(2x1),,gx(1x2),gw(1x2),,gw(1x2),gx(1x2),gd(2x1),,gs(1x2),,~,~,~,,~,~
3 ~,,~,,~,~,~,,,gd(2x1),,,,,,,ga(2x1),,,,~,~,~,,~,,~
4 ~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~
5 ,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
6 ~,~,~,,,~,~,,CSa,,Mrss(1x2),Mw,,,,Mw,Mrss(1x2),,CSa,,~,~,,,~,~,~
7 ~,~,~,,~,,~,,,Msm,,,Mhs(1x2),,Mhs(1x2),,,Msm,,,~,,~,,~,~,~
8 ~,~,~,,~,~,,,Msu,,Mws,,,,,,Mws,,Msu,,,~,~,,~,~,~
9 ,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
10 gs(2x1),,Mrqq(1x2),CSddaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSddaaaa,Mrqq(1x2),gs(2x1)
11 gw(1x2),gx(1x2),,,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,,,gx(1x2),gw(1x2)
12 ,,,Msm,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,Msm
13 gd(2x1),,Msu,,Mws,,,Mhs(1x2),,~,~,,~,,~,,~,~,,Mhs(1x2),,,Mws,,Msu,ga(2x1)
14 ga(2x1),,,Mws,,Mh(2x1),,,,~,~,~,,,,~,~,~,,,Mh(2x1),,,Mws,,gd(2x1)
15 ga(2x1),,,Mws,,Mh(2x1),,Mhs(1x2),,~,~,~,,,,~,~,~,,Mhs(1x2),Mh(2x1),,,Mws,,gd(2x1)
16 gd(2x1),,,,Mws,,,,,~,~,,~,,~,,~,~,,,,,Mws,,,ga(2x1)
17 gx(1x2),gw(1x2),Msm,,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,,Msm,gw(1x2),gx(1x2)
18 ,,Mrssqq(1x2),Msu,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,Msu,Mrssqq(1x2)
19 gs(2x1),,,CSdaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSdaaaa,,gs(2x1)
20 ,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
21 ~,~,~,,~,~,,,,,Mws,,Mhs(1x2),,Mhs(1x2),,Mws,,,,,~,~,,~,~,~
22 ~,~,~,,~,,~,,Msm,,Mr(1x2),,,,,,Mr(1x2),,Msm,,~,,~,,~,~,~
23 ~,~,~,,,~,~,,CSa,Msu,,Mw,,,,Mw,,Msu,CSa,,~,~,,,~,~,~
24 ,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
25 ~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~
26 ~,,~,,~,~,~,,gs(1x2),gd(2x1),,gw(1x2),gx(1x2),,gx(1x2),gw(1x2),ga(2x1),,gs(1x2),,~,~,~,,~,,~
27 ,~,~,,~,~,~,,,ga(2x1),,,,,,,gd(2x1),,,,~,~,~,,~,~

@ -1,28 +0,0 @@
#build label(build) start(14;14)
,trackNS,trackE,,trackW,trackS,trackN,,gs(1x2),ga(2x1),,gx(1x2),gw(1x2),,gw(1x2),gx(1x2),gd(2x1),,gs(1x2),,trackN,trackS,trackE,,trackW,trackNS
trackEW,,trackSE,,trackSW,trackNE,trackNW,,,gd(2x1),,,,,,,ga(2x1),,,,trackNE,trackNW,trackSE,,trackSW,,trackEW
trackS,trackSE,,,trackNSE,trackNSW,trackEW,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,trackEW,trackNSE,trackNSW,,,trackSW,trackS
,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
trackN,trackNE,trackSEW,,,trackSEW,trackNEW,,CSa,,Mrss(1x2),Mw,,,,Mw,Mrss(1x2),,CSa,,trackNEW,trackSEW,,,trackSEW,trackNW,trackN
trackE,trackSW,trackNEW,,trackNSE,,trackNSEW,,,Msm,,,Mhs(1x2),,Mhs(1x2),,,Msm,,,trackNSEW,,trackNSW,,trackNEW,trackSE,trackW
trackW,trackNW,trackNS,,trackNSW,trackNSEW,,,Msu,,Mws,,,,,,Mws,,Msu,,,trackNSEW,trackNSE,,trackNS,trackNE,trackE
,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
gs(2x1),,Mrqq(1x2),CSddaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSddaaaa,Mrqq(1x2),gs(2x1)
gw(1x2),gx(1x2),,,,Msk,,Mw,,,trackrampNW,trackrampNS,trackrampN,,trackrampN,trackrampNS,trackrampNE,,,Mw,,,Msh,,,gx(1x2),gw(1x2)
,,,Msm,Mrs(2x1),,Mw,,,trackrampNW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampNE,,,Mw,Mrsss(2x1),,Msm
gd(2x1),,Msu,,Mws,,,Mhs(1x2),,trackrampEW,trackrampSEW,,trackrampNSEW,,trackrampNSEW,,trackrampSEW,trackrampEW,,Mhs(1x2),,,Mws,,Msu,ga(2x1)
ga(2x1),,,Mws,,Mh(2x1),,,,trackrampW,trackrampNEW,trackrampNSEW,,,,trackrampNSEW,trackrampNEW,trackrampE,,,Mh(2x1),,,Mws,,gd(2x1)
ga(2x1),,,Mws,,Mh(2x1),,Mhs(1x2),,trackrampW,trackrampSEW,trackrampNSEW,,,,trackrampNSEW,trackrampSEW,trackrampE,,Mhs(1x2),Mh(2x1),,,Mws,,gd(2x1)
gd(2x1),,,,Mws,,,,,trackrampEW,trackrampNEW,,trackrampNSEW,,trackrampNSEW,,trackrampNEW,trackrampEW,,,,,Mws,,,ga(2x1)
gx(1x2),gw(1x2),Msm,,Mrs(2x1),,Mw,,,trackrampSW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampSE,,,Mw,Mrsss(2x1),,,Msm,gw(1x2),gx(1x2)
,,Mrssqq(1x2),Msu,,Msk,,Mw,,,trackrampSW,trackrampNS,trackrampS,,trackrampS,trackrampNS,trackrampSE,,,Mw,,,Msh,Msu,Mrssqq(1x2)
gs(2x1),,,CSdaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSdaaaa,,gs(2x1)
,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
trackW,trackSW,trackNS,,trackNSW,trackNSEW,,,,,Mws,,Mhs(1x2),,Mhs(1x2),,Mws,,,,,trackNSEW,trackNSE,,trackNS,trackSE,trackE
trackE,trackNW,trackSEW,,trackNSE,,trackNSEW,,Msm,,Mr(1x2),,,,,,Mr(1x2),,Msm,,trackNSEW,,trackNSW,,trackSEW,trackNE,trackW
trackS,trackSE,trackNEW,,,trackNEW,trackSEW,,CSa,Msu,,Mw,,,,Mw,,Msu,CSa,,trackSEW,trackNEW,,,trackNEW,trackSW,trackS
,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
trackN,trackNE,,,trackNSE,trackNSW,trackEW,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,trackEW,trackNSE,trackNSW,,,trackNW,trackN
trackEW,,trackNE,,trackNW,trackSE,trackSW,,gs(1x2),gd(2x1),,gw(1x2),gx(1x2),,gx(1x2),gw(1x2),ga(2x1),,gs(1x2),,trackSE,trackSW,trackNE,,trackNW,,trackEW
,trackNS,trackE,,trackW,trackN,trackS,,,ga(2x1),,,,,,,gd(2x1),,,,trackS,trackN,trackE,,trackW,trackNS
1 #build label(build) start(14;14)
2 ,trackNS,trackE,,trackW,trackS,trackN,,gs(1x2),ga(2x1),,gx(1x2),gw(1x2),,gw(1x2),gx(1x2),gd(2x1),,gs(1x2),,trackN,trackS,trackE,,trackW,trackNS
3 trackEW,,trackSE,,trackSW,trackNE,trackNW,,,gd(2x1),,,,,,,ga(2x1),,,,trackNE,trackNW,trackSE,,trackSW,,trackEW
4 trackS,trackSE,,,trackNSE,trackNSW,trackEW,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,trackEW,trackNSE,trackNSW,,,trackSW,trackS
5 ,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
6 trackN,trackNE,trackSEW,,,trackSEW,trackNEW,,CSa,,Mrss(1x2),Mw,,,,Mw,Mrss(1x2),,CSa,,trackNEW,trackSEW,,,trackSEW,trackNW,trackN
7 trackE,trackSW,trackNEW,,trackNSE,,trackNSEW,,,Msm,,,Mhs(1x2),,Mhs(1x2),,,Msm,,,trackNSEW,,trackNSW,,trackNEW,trackSE,trackW
8 trackW,trackNW,trackNS,,trackNSW,trackNSEW,,,Msu,,Mws,,,,,,Mws,,Msu,,,trackNSEW,trackNSE,,trackNS,trackNE,trackE
9 ,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
10 gs(2x1),,Mrqq(1x2),CSddaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSddaaaa,Mrqq(1x2),gs(2x1)
11 gw(1x2),gx(1x2),,,,Msk,,Mw,,,trackrampNW,trackrampNS,trackrampN,,trackrampN,trackrampNS,trackrampNE,,,Mw,,,Msh,,,gx(1x2),gw(1x2)
12 ,,,Msm,Mrs(2x1),,Mw,,,trackrampNW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampNE,,,Mw,Mrsss(2x1),,Msm
13 gd(2x1),,Msu,,Mws,,,Mhs(1x2),,trackrampEW,trackrampSEW,,trackrampNSEW,,trackrampNSEW,,trackrampSEW,trackrampEW,,Mhs(1x2),,,Mws,,Msu,ga(2x1)
14 ga(2x1),,,Mws,,Mh(2x1),,,,trackrampW,trackrampNEW,trackrampNSEW,,,,trackrampNSEW,trackrampNEW,trackrampE,,,Mh(2x1),,,Mws,,gd(2x1)
15 ga(2x1),,,Mws,,Mh(2x1),,Mhs(1x2),,trackrampW,trackrampSEW,trackrampNSEW,,,,trackrampNSEW,trackrampSEW,trackrampE,,Mhs(1x2),Mh(2x1),,,Mws,,gd(2x1)
16 gd(2x1),,,,Mws,,,,,trackrampEW,trackrampNEW,,trackrampNSEW,,trackrampNSEW,,trackrampNEW,trackrampEW,,,,,Mws,,,ga(2x1)
17 gx(1x2),gw(1x2),Msm,,Mrs(2x1),,Mw,,,trackrampSW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampSE,,,Mw,Mrsss(2x1),,,Msm,gw(1x2),gx(1x2)
18 ,,Mrssqq(1x2),Msu,,Msk,,Mw,,,trackrampSW,trackrampNS,trackrampS,,trackrampS,trackrampNS,trackrampSE,,,Mw,,,Msh,Msu,Mrssqq(1x2)
19 gs(2x1),,,CSdaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSdaaaa,,gs(2x1)
20 ,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws
21 trackW,trackSW,trackNS,,trackNSW,trackNSEW,,,,,Mws,,Mhs(1x2),,Mhs(1x2),,Mws,,,,,trackNSEW,trackNSE,,trackNS,trackSE,trackE
22 trackE,trackNW,trackSEW,,trackNSE,,trackNSEW,,Msm,,Mr(1x2),,,,,,Mr(1x2),,Msm,,trackNSEW,,trackNSW,,trackSEW,trackNE,trackW
23 trackS,trackSE,trackNEW,,,trackNEW,trackSEW,,CSa,Msu,,Mw,,,,Mw,,Msu,CSa,,trackSEW,trackNEW,,,trackNEW,trackSW,trackS
24 ,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa
25 trackN,trackNE,,,trackNSE,trackNSW,trackEW,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,trackEW,trackNSE,trackNSW,,,trackNW,trackN
26 trackEW,,trackNE,,trackNW,trackSE,trackSW,,gs(1x2),gd(2x1),,gw(1x2),gx(1x2),,gx(1x2),gw(1x2),ga(2x1),,gs(1x2),,trackSE,trackSW,trackNE,,trackNW,,trackEW
27 ,trackNS,trackE,,trackW,trackN,trackS,,,ga(2x1),,,,,,,gd(2x1),,,,trackS,trackN,trackE,,trackW,trackNS

@ -0,0 +1,21 @@
#build label(construct)
Cw
Cf
Cr
Cu
Cd
Cx
CF
1 #build label(construct)
2 Cw
3 Cf
4 Cr
5 Cu
6 Cd
7 Cx
8 CF

@ -0,0 +1,33 @@
#build label(build)
a,Mg,,CS
b,Mh(1x1),S,CSa,,,,,,Mw,,,wm,,,wp
c,Mhs(1x1),m,CSaa,,,,,,,,,,,,,,,,,D
n,Mv,v,CSaaa,,Msu
,Mr(1x1),j,CSaaaa,,,,,,Mws,,,wu,,,ew
d,Mrq(1x1),A,CSd,,,Msk
,Mrqq(1x1),R,CSda
l,Mrqqq(1x1),N,CSdaa,,Msm,,,,we,,,wn,,,es,,,,,k
x,Mrqqqq(1x1),~h,CSdaaa
H,Mrs(1x1),~a,CSdaaaa,,,Msh
W,Mrsq(1x1),~c,CSdd,,,,,,wq,,,wr,,,el
G,Mrsqq(1x1),F,CSdda
B,Mrsqqq(1x1),o(1x1),CSddaa,,,,,,,,,,,,,,,,,ws
~,~b,Mrsqqqq(1x1),CSddaaa,,,,,,wM,,,wt,,,eg
~,f,Mrss(1x1),CSddaaaa
~,h,Mrssq(1x1),CSddd
~,r,Mrssqq(1x1),CSddda,,,,,,wo,,,wl,,,ea,,,,gx(1x2),gx(1x2)
~,s,Mrssqqq(1x1),CSdddaa
~,~s,Mrssqqqq(1x1),CSdddaaa,,,,,,,,,,,,,,gd(2x1),,gs(2x1),,ga(2x1)
~,t,Mrsss(1x1),CSdddaaaa,,,,,,wk,,,ww,,,ek,,gd(2x1),,gs(2x1),,ga(2x1)
gs(1x1),Mrsssq(1x1),,CSdddd,,,,,,,,,,,,,,,,gw(1x2),gw(1x2)
ga(1x1),Mrsssqq(1x1),,CSdddda
gd(1x1),Mrsssqqq(1x1),,CSddddaa,,,,,,wb,,,wz,,,en
gw(1x1),Mrsssqqqq(1x1),,CSddddaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1),,Mhs(1x2),Mhs(1x2)
gx(1x1),,,CSddddaaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1)
,,,Ts,,,,,,wc,,,wh,,,ib,,Mr(1x2),Mr(1x2),Mrs(2x1),,Mhs(1x2),Mhs(1x2)
y,,,Tw,,,,,,,,,,,,,,,,Mrs(2x1)
Y,,,Tl,,,,,,,,,,,,,,Mr(1x2),Mr(1x2),Mrsq(2x1),,Mrsq(2x1)
,,,Tp,,,,,,wf,,,wy,,,ic,,,,Mrsssqqqq(2x1),,Mrsssqqqq(2x1)
,,,Tc
,,,TS
,,,,,,,,,,wv,,,wd,,,wj,,,wS
1 #build label(build)
2 a,Mg,,CS
3 b,Mh(1x1),S,CSa,,,,,,Mw,,,wm,,,wp
4 c,Mhs(1x1),m,CSaa,,,,,,,,,,,,,,,,,D
5 n,Mv,v,CSaaa,,Msu
6 ,Mr(1x1),j,CSaaaa,,,,,,Mws,,,wu,,,ew
7 d,Mrq(1x1),A,CSd,,,Msk
8 ,Mrqq(1x1),R,CSda
9 l,Mrqqq(1x1),N,CSdaa,,Msm,,,,we,,,wn,,,es,,,,,k
10 x,Mrqqqq(1x1),~h,CSdaaa
11 H,Mrs(1x1),~a,CSdaaaa,,,Msh
12 W,Mrsq(1x1),~c,CSdd,,,,,,wq,,,wr,,,el
13 G,Mrsqq(1x1),F,CSdda
14 B,Mrsqqq(1x1),o(1x1),CSddaa,,,,,,,,,,,,,,,,,ws
15 ~,~b,Mrsqqqq(1x1),CSddaaa,,,,,,wM,,,wt,,,eg
16 ~,f,Mrss(1x1),CSddaaaa
17 ~,h,Mrssq(1x1),CSddd
18 ~,r,Mrssqq(1x1),CSddda,,,,,,wo,,,wl,,,ea,,,,gx(1x2),gx(1x2)
19 ~,s,Mrssqqq(1x1),CSdddaa
20 ~,~s,Mrssqqqq(1x1),CSdddaaa,,,,,,,,,,,,,,gd(2x1),,gs(2x1),,ga(2x1)
21 ~,t,Mrsss(1x1),CSdddaaaa,,,,,,wk,,,ww,,,ek,,gd(2x1),,gs(2x1),,ga(2x1)
22 gs(1x1),Mrsssq(1x1),,CSdddd,,,,,,,,,,,,,,,,gw(1x2),gw(1x2)
23 ga(1x1),Mrsssqq(1x1),,CSdddda
24 gd(1x1),Mrsssqqq(1x1),,CSddddaa,,,,,,wb,,,wz,,,en
25 gw(1x1),Mrsssqqqq(1x1),,CSddddaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1),,Mhs(1x2),Mhs(1x2)
26 gx(1x1),,,CSddddaaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1)
27 ,,,Ts,,,,,,wc,,,wh,,,ib,,Mr(1x2),Mr(1x2),Mrs(2x1),,Mhs(1x2),Mhs(1x2)
28 y,,,Tw,,,,,,,,,,,,,,,,Mrs(2x1)
29 Y,,,Tl,,,,,,,,,,,,,,Mr(1x2),Mr(1x2),Mrsq(2x1),,Mrsq(2x1)
30 ,,,Tp,,,,,,wf,,,wy,,,ic,,,,Mrsssqqqq(2x1),,Mrsssqqqq(2x1)
31 ,,,Tc
32 ,,,TS
33 ,,,,,,,,,,wv,,,wd,,,wj,,,wS

@ -1,33 +0,0 @@
#build label(build)
a,Mg,,CS,trackN
b,Mh(1x1),S,CSa,trackS,,,,,,Mw,,,wm,,,wp
c,Mhs(1x1),m,CSaa,trackE,,,,,,,,,,,,,,,,,D
n,Mv,v,CSaaa,trackW,,Msu
,Mr(1x1),j,CSaaaa,trackNS,,,,,,Mws,,,wu,,,ew
d,Mrq(1x1),A,CSd,trackNE,,,Msk
,Mrqq(1x1),R,CSda,trackNW
l,Mrqqq(1x1),N,CSdaa,trackSE,,Msm,,,,we,,,wn,,,es,,,,,k
x,Mrqqqq(1x1),~h,CSdaaa,trackSW
H,Mrs(1x1),~a,CSdaaaa,trackEW,,,Msh
W,Mrsq(1x1),~c,CSdd,trackNSE,,,,,,wq,,,wr,,,el
G,Mrsqq(1x1),F,CSdda,trackNSW
B,Mrsqqq(1x1),o(1x1),CSddaa,trackNEW,,,,,,,,,,,,,,,,,ws
~b,Mrsqqqq(1x1),Cw,CSddaaa,trackSEW,,,,,,wM,,,wt,,,eg
f,Mrss(1x1),Cf,CSddaaaa,trackNSEW
h,Mrssq(1x1),Cr,CSddd,trackrampN
r,Mrssqq(1x1),Cu,CSddda,trackrampS,,,,,,wo,,,wl,,,ea,,,,gx(1x2),gx(1x2)
s,Mrssqqq(1x1),Cd,CSdddaa,trackrampE
~s,Mrssqqqq(1x1),Cx,CSdddaaa,trackrampW,,,,,,,,,,,,,,gd(2x1),,gs(2x1),,ga(2x1)
t,Mrsss(1x1),CF,CSdddaaaa,trackrampNS,,,,,,wk,,,ww,,,ek,,gd(2x1),,gs(2x1),,ga(2x1)
gs(1x1),Mrsssq(1x1),,CSdddd,trackrampNE,,,,,,,,,,,,,,,,gw(1x2),gw(1x2)
ga(1x1),Mrsssqq(1x1),,CSdddda,trackrampNW
gd(1x1),Mrsssqqq(1x1),,CSddddaa,trackrampSE,,,,,,wb,,,wz,,,en
gw(1x1),Mrsssqqqq(1x1),,CSddddaaa,trackrampSW,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1),,Mhs(1x2),Mhs(1x2)
gx(1x1),,,CSddddaaaa,trackrampEW,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1)
,,,Ts,trackrampNSE,,,,,,wc,,,wh,,,ib,,Mr(1x2),Mr(1x2),Mrs(2x1),,Mhs(1x2),Mhs(1x2)
y,,,Tw,trackrampNSW,,,,,,,,,,,,,,,,Mrs(2x1)
Y,,,Tl,trackrampNEW,,,,,,,,,,,,,,Mr(1x2),Mr(1x2),Mrsq(2x1),,Mrsq(2x1)
,,,Tp,trackrampSEW,,,,,,wf,,,wy,,,ic,,,,Mrsssqqqq(2x1),,Mrsssqqqq(2x1)
,,,Tc,trackrampNSEW
,,,TS
,,,,,,,,,,wv,,,wd,,,wj,,,wS
1 #build label(build)
2 a,Mg,,CS,trackN
3 b,Mh(1x1),S,CSa,trackS,,,,,,Mw,,,wm,,,wp
4 c,Mhs(1x1),m,CSaa,trackE,,,,,,,,,,,,,,,,,D
5 n,Mv,v,CSaaa,trackW,,Msu
6 ,Mr(1x1),j,CSaaaa,trackNS,,,,,,Mws,,,wu,,,ew
7 d,Mrq(1x1),A,CSd,trackNE,,,Msk
8 ,Mrqq(1x1),R,CSda,trackNW
9 l,Mrqqq(1x1),N,CSdaa,trackSE,,Msm,,,,we,,,wn,,,es,,,,,k
10 x,Mrqqqq(1x1),~h,CSdaaa,trackSW
11 H,Mrs(1x1),~a,CSdaaaa,trackEW,,,Msh
12 W,Mrsq(1x1),~c,CSdd,trackNSE,,,,,,wq,,,wr,,,el
13 G,Mrsqq(1x1),F,CSdda,trackNSW
14 B,Mrsqqq(1x1),o(1x1),CSddaa,trackNEW,,,,,,,,,,,,,,,,,ws
15 ~b,Mrsqqqq(1x1),Cw,CSddaaa,trackSEW,,,,,,wM,,,wt,,,eg
16 f,Mrss(1x1),Cf,CSddaaaa,trackNSEW
17 h,Mrssq(1x1),Cr,CSddd,trackrampN
18 r,Mrssqq(1x1),Cu,CSddda,trackrampS,,,,,,wo,,,wl,,,ea,,,,gx(1x2),gx(1x2)
19 s,Mrssqqq(1x1),Cd,CSdddaa,trackrampE
20 ~s,Mrssqqqq(1x1),Cx,CSdddaaa,trackrampW,,,,,,,,,,,,,,gd(2x1),,gs(2x1),,ga(2x1)
21 t,Mrsss(1x1),CF,CSdddaaaa,trackrampNS,,,,,,wk,,,ww,,,ek,,gd(2x1),,gs(2x1),,ga(2x1)
22 gs(1x1),Mrsssq(1x1),,CSdddd,trackrampNE,,,,,,,,,,,,,,,,gw(1x2),gw(1x2)
23 ga(1x1),Mrsssqq(1x1),,CSdddda,trackrampNW
24 gd(1x1),Mrsssqqq(1x1),,CSddddaa,trackrampSE,,,,,,wb,,,wz,,,en
25 gw(1x1),Mrsssqqqq(1x1),,CSddddaaa,trackrampSW,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1),,Mhs(1x2),Mhs(1x2)
26 gx(1x1),,,CSddddaaaa,trackrampEW,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1)
27 ,,,Ts,trackrampNSE,,,,,,wc,,,wh,,,ib,,Mr(1x2),Mr(1x2),Mrs(2x1),,Mhs(1x2),Mhs(1x2)
28 y,,,Tw,trackrampNSW,,,,,,,,,,,,,,,,Mrs(2x1)
29 Y,,,Tl,trackrampNEW,,,,,,,,,,,,,,Mr(1x2),Mr(1x2),Mrsq(2x1),,Mrsq(2x1)
30 ,,,Tp,trackrampSEW,,,,,,wf,,,wy,,,ic,,,,Mrsssqqqq(2x1),,Mrsssqqqq(2x1)
31 ,,,Tc,trackrampNSEW
32 ,,,TS
33 ,,,,,,,,,,wv,,,wd,,,wj,,,wS

@ -1,12 +1,3 @@
#build label(big) hidden()
gw(1x2),gx(1x2),gd(2x1),,gs(1x2)
,,ga(2x1)
,,Msk,Mrsqq(2x1)
Mw,,,Msh,CSddddaaaa
,Mw,Mrss(1x2),,CSa
Mhs(1x2),,,Msm
,,Mws,,Msu
Mh(2x1),,,Mws
#build label(outer) hidden()
trackN,trackS,trackE,,trackW,trackNS
trackNE,trackNW,trackSE,,trackSW
@ -19,10 +10,9 @@ trackrampN,trackrampNS,trackrampNE
trackrampNSE,trackrampNSW
trackrampNSEW
#meta label(chunk) hidden()
/big shift(1 -13)
/outer shift(7 -13)
/inner shift(1 -4)
#meta label(build)
#meta label(construct)
/chunk
/chunk transform(cw)
/chunk transform(cw cw)
1 #build label(big) hidden() #build label(outer) hidden()
#build label(big) hidden()
gw(1x2),gx(1x2),gd(2x1),,gs(1x2)
,,ga(2x1)
,,Msk,Mrsqq(2x1)
Mw,,,Msh,CSddddaaaa
,Mw,Mrss(1x2),,CSa
Mhs(1x2),,,Msm
,,Mws,,Msu
Mh(2x1),,,Mws
1 #build label(outer) hidden() #build label(outer) hidden()
2 trackN,trackS,trackE,,trackW,trackNS trackN,trackS,trackE,,trackW,trackNS
3 trackNE,trackNW,trackSE,,trackSW trackNE,trackNW,trackSE,,trackSW
10 trackrampNSEW trackrampNSEW
11 #meta label(chunk) hidden() #meta label(chunk) hidden()
12 /big shift(1 -13) /outer shift(7 -13)
/outer shift(7 -13)
13 /inner shift(1 -4) /inner shift(1 -4)
14 #meta label(build) #meta label(construct)
15 /chunk /chunk
16 /chunk transform(cw) /chunk transform(cw)
17 /chunk transform(cw cw) /chunk transform(cw cw)
18 /chunk transform(ccw) /chunk transform(ccw)

@ -0,0 +1,20 @@
#build label(big) hidden()
gw(1x2),gx(1x2),gd(2x1),,gs(1x2)
,,ga(2x1)
,,Msk,Mrsqq(2x1)
Mw,,,Msh,CSddddaaaa
,Mw,Mrss(1x2),,CSa
Mhs(1x2),,,Msm
,,Mws,,Msu
Mh(2x1),,,Mws
#meta label(chunk) hidden()
/big shift(1 -13)
#meta label(build)
/chunk
/chunk transform(cw)
/chunk transform(cw cw)
/chunk transform(ccw)
/chunk transform(fliph)
/chunk transform(flipv)
/chunk transform(cw flipv)
/chunk transform(ccw flipv)
1 #build label(big) hidden()
2 gw(1x2),gx(1x2),gd(2x1),,gs(1x2)
3 ,,ga(2x1)
4 ,,Msk,Mrsqq(2x1)
5 Mw,,,Msh,CSddddaaaa
6 ,Mw,Mrss(1x2),,CSa
7 Mhs(1x2),,,Msm
8 ,,Mws,,Msu
9 Mh(2x1),,,Mws
10 #meta label(chunk) hidden()
11 /big shift(1 -13)
12 #meta label(build)
13 /chunk
14 /chunk transform(cw)
15 /chunk transform(cw cw)
16 /chunk transform(ccw)
17 /chunk transform(fliph)
18 /chunk transform(flipv)
19 /chunk transform(cw flipv)
20 /chunk transform(ccw flipv)

@ -1906,6 +1906,14 @@ Constructions module
coordinates, designates it for removal, or instantly cancels the planned one.
Returns *true, was_only_planned* if removed; or *false* if none found.
* ``dfhack.constructions.findAtTile(pos)``, or ``findAtTile(x,y,z)``
Returns the construction at the given position, or ``nil`` if there isn't one.
* ``dfhack.constructions.insert(construction)``
Properly inserts the given construction into the game. Returns false and fails to
insert if there was already a construction at the position.
Kitchen module
--------------

@ -38,12 +38,21 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## Fixes
## Misc Improvements
- `blueprint`: new ``--smooth`` option for recording all smoothed floors and walls instead of just the ones that require smoothing for later carving
- `blueprint`: record built constructions in blueprints
- `blueprint`: record stockpile/building/zone names in blueprints
- `blueprint`: record room sizes in blueprints
- `blueprint`: generate meta blueprints to reduce the number of blueprints you have to apply
- `blueprint`: support splitting the output file into phases grouped by when they can be applied
- `blueprint`: when splitting output files, number them so they sort into the order you should apply them in
- `ls`: indent tag listings and wrap them in the right column for better readability
- `ls`: new ``--exclude`` option for hiding matched scripts from the output. this can be especially useful for modders who don't want their mod scripts to be included in ``ls`` output.
- `digtype`: new ``-z`` option for digtype to restrict designations to the current z-level and down
- UX: List widgets now have mouse-interactive scrollbars
- UX: You can now hold down the mouse button on a scrollbar to make it scroll multiple times.
- UX: You can now drag the scrollbar to scroll to a specific spot
- `overlay`: reduce the size of the "DFHack Launcher" button
- Constructions module: ``findAtTile`` now uses a binary search intead of a linear search.
- `spectate`: new ``auto-unpause`` option for auto-dismissal of announcement pause events (e.g. sieges).
- `spectate`: new ``auto-disengage`` option for auto-disengagement of plugin through player interaction whilst unpaused.
- `spectate`: new ``focus-jobs`` option for following a dwarf after their job has finished (when disabled).
@ -54,9 +63,12 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- `spectate`: improved documentation of features and functionality
## API
- Constructions module: added ``insert()`` to insert constructions into the game's sorted list.
## Lua
- ``widgets.Scrollbar``: new scrollbar widget that can be paired with an associated scrollable widget. Integrated with ``widgets.Label`` and ``widgets.List``.
- ``dfhack.constructions.findAtTile()``: exposed preexisting function to Lua.
- ``dfhack.constructions.insert()``: exposed new function to Lua.
# 0.47.05-r7

@ -7,11 +7,11 @@ blueprint
With ``blueprint``, you can export the structure of a portion of your fortress
in a blueprint file that you (or anyone else) can later play back with
`quickfort`.
`gui/quickfort`.
Blueprints are ``.csv`` or ``.xlsx`` files created in the ``blueprints``
subdirectory of your DF folder. The map area to turn into a blueprint is either
selected interactively with the ``blueprint gui`` command or, if the GUI is not
selected interactively with the ``gui/blueprint`` command or, if the GUI is not
used, starts at the active cursor location and extends right and down for the
requested width and height.
@ -27,16 +27,16 @@ Examples
--------
``blueprint gui``
Runs `gui/blueprint`, the interactive frontend, where all configuration for
a ``blueprint`` command can be set visually and interactively.
Runs `gui/blueprint`, the GUI frontend, where all configuration for a
``blueprint`` command can be set visually and interactively.
``blueprint 30 40 bedrooms``
Generates blueprints for an area 30 tiles wide by 40 tiles tall, starting
from the active cursor on the current z-level. Blueprints are written to
``bedrooms.csv`` in the ``blueprints`` directory.
``blueprint 30 40 bedrooms dig --cursor 108,100,150``
Generates only the ``#dig`` blueprint in the ``bedrooms.csv`` file, and
the start of the blueprint area is set to a specific value instead of using
the in-game cursor position.
the start of the blueprint area is set to a specific coordinate instead of
using the in-game cursor position.
Positional parameters
---------------------
@ -66,14 +66,21 @@ phases; just separate them with a space.
Generate quickfort ``#dig`` blueprints for digging natural stone.
``carve``
Generate quickfort ``#dig`` blueprints for smoothing and carving.
``construct``
Generate quickfort ``#build`` blueprints for constructions (e.g. flooring
and walls).
``build``
Generate quickfort ``#build`` blueprints for constructions and buildings.
Generate quickfort ``#build`` blueprints for buildings (including
furniture).
``place``
Generate quickfort ``#place`` blueprints for placing stockpiles.
``zone``
Generate quickfort ``#zone`` blueprints for designating zones.
``query``
Generate quickfort ``#query`` blueprints for configuring rooms.
Generate quickfort ``#query`` blueprints for configuring stockpiles and
naming buildings.
``rooms``
Generate quickfort ``#query`` blueprints for defining rooms.
If no phases are specified, phases are autodetected. For example, a ``#place``
blueprint will be created only if there are stockpiles in the blueprint area.
@ -92,8 +99,14 @@ Options
Select the output format of the generated files. See the `Output formats`_
section below for options. If not specified, the output format defaults to
"minimal", which will produce a small, fast ``.csv`` file.
``-h``, ``--help``
Show command help text.
``--nometa``
`Meta blueprints <quickfort-meta>` let you apply all blueprints that can be
replayed at the same time (without unpausing the game) with a single
command. This usually reduces the number of `quickfort` commands you need to
run to rebuild your fort from about 6 to 2 or 3. If you would rather just
have the low-level blueprints, this flag will prevent meta blueprints from
being generated and any low-level blueprints from being
`hidden <quickfort-hidden>` from the ``quickfort list`` command.
``-s``, ``--playback-start <x>,<y>,<comment>``
Specify the column and row offsets (relative to the upper-left corner of the
blueprint, which is ``1,1``) where the player should put the cursor when the
@ -133,5 +146,10 @@ The ``--splitby`` flag can take any of the following values:
``none``
Writes all blueprints into a single file. This is the standard format for
quickfort fortress blueprint bundles and is the default.
``group``
Creates one file per group of blueprints that can be played back at the same
time (without have to unpause the game and let dwarves fulfill jobs between
blueprint runs).
``phase``
Creates a separate file for each phase.
Creates a separate file for each phase. Implies ``--nometa`` since meta
blueprints can't combine blueprints that are in separate files.

@ -2264,6 +2264,7 @@ static const luaL_Reg dfhack_buildings_funcs[] = {
static const LuaWrapper::FunctionReg dfhack_constructions_module[] = {
WRAPM(Constructions, designateNew),
WRAPM(Constructions, insert),
{ NULL, NULL }
};
@ -2276,8 +2277,16 @@ static int constructions_designateRemove(lua_State *L)
return 2;
}
static int constructions_findAtTile(lua_State *L)
{
auto pos = CheckCoordXYZ(L, 1, true);
Lua::PushDFObject(L, Constructions::findAtTile(pos));
return 1;
}
static const luaL_Reg dfhack_constructions_funcs[] = {
{ "designateRemove", constructions_designateRemove },
{ "findAtTile", constructions_findAtTile },
{ NULL, NULL }
};

@ -116,7 +116,7 @@ namespace DFHack
//This is a static string, overwritten with every call!
//Support values > 2 even though they should never happen.
//Copy string if it will be used.
inline char * getStr() const
inline const char * getStr() const
{
static char str[16];

@ -45,6 +45,8 @@ namespace Constructions
DFHACK_EXPORT df::construction * findAtTile(df::coord pos);
DFHACK_EXPORT bool insert(df::construction * constr);
DFHACK_EXPORT bool designateNew(df::coord pos, df::construction_type type,
df::item_type item = df::item_type::NONE, int mat_index = -1);

@ -54,11 +54,18 @@ using df::global::world;
df::construction * Constructions::findAtTile(df::coord pos)
{
for (auto it = world->constructions.begin(); it != world->constructions.end(); ++it) {
if ((*it)->pos == pos)
return *it;
int index = binsearch_index(world->constructions, pos);
if (index == -1) {
return NULL;
}
return NULL;
return world->constructions[index];
}
bool Constructions::insert(df::construction * constr)
{
bool toInsert;
insert_into_vector(world->constructions, &df::construction::pos, constr, &toInsert);
return toInsert;
}
bool Constructions::designateNew(df::coord pos, df::construction_type type,

@ -5,7 +5,6 @@
* Written by cdombroski.
*/
#include <algorithm>
#include <sstream>
#include <unordered_map>
@ -13,6 +12,7 @@
#include "DataDefs.h"
#include "DataFuncs.h"
#include "DataIdentity.h"
#include "Debug.h"
#include "LuaTools.h"
#include "PluginManager.h"
#include "TileTypes.h"
@ -46,6 +46,10 @@ using namespace DFHack;
DFHACK_PLUGIN("blueprint");
REQUIRE_GLOBAL(world);
namespace DFHack {
DBG_DECLARE(blueprint,log);
}
struct blueprint_options {
// whether to display help
bool help = false;
@ -58,6 +62,9 @@ struct blueprint_options {
// for it.
string format;
// whether to skip generating meta blueprints
bool nometa = false;
// offset and comment to write in the quickfort start() modeline marker
// if not set, coordinates are set to 0 and the comment will be empty
df::coord2d playback_start = df::coord2d(0, 0);
@ -85,12 +92,14 @@ struct blueprint_options {
bool auto_phase = false;
// if not autodetecting, which phases to output
bool dig = false;
bool dig = false;
bool carve = false;
bool construct = false;
bool build = false;
bool place = false;
bool zone = false;
bool zone = false;
bool query = false;
bool rooms = false;
static struct_identity _identity;
};
@ -98,6 +107,7 @@ static const struct_field_info blueprint_options_fields[] = {
{ struct_field_info::PRIMITIVE, "help", offsetof(blueprint_options, help), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::SUBSTRUCT, "start", offsetof(blueprint_options, start), &df::coord::_identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "format", offsetof(blueprint_options, format), df::identity_traits<string>::get(), 0, 0 },
{ struct_field_info::PRIMITIVE, "nometa", offsetof(blueprint_options, nometa), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::SUBSTRUCT, "playback_start", offsetof(blueprint_options, playback_start), &df::coord2d::_identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "playback_start_comment", offsetof(blueprint_options, playback_start_comment), df::identity_traits<string>::get(), 0, 0 },
{ struct_field_info::PRIMITIVE, "split_strategy", offsetof(blueprint_options, split_strategy), df::identity_traits<string>::get(), 0, 0 },
@ -110,10 +120,12 @@ static const struct_field_info blueprint_options_fields[] = {
{ struct_field_info::PRIMITIVE, "auto_phase", offsetof(blueprint_options, auto_phase), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "dig", offsetof(blueprint_options, dig), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "carve", offsetof(blueprint_options, carve), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "construct", offsetof(blueprint_options, construct), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "build", offsetof(blueprint_options, build), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "place", offsetof(blueprint_options, place), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "zone", offsetof(blueprint_options, zone), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "query", offsetof(blueprint_options, query), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::PRIMITIVE, "rooms", offsetof(blueprint_options, rooms), &df::identity_traits<bool>::identity, 0, 0 },
{ struct_field_info::END }
};
struct_identity blueprint_options::_identity(sizeof(blueprint_options), &df::allocator_fn<blueprint_options>, NULL, "blueprint_options", NULL, blueprint_options_fields);
@ -132,11 +144,36 @@ DFhackCExport command_result plugin_shutdown(color_ostream &) {
return CR_OK;
}
struct blueprint_processor;
struct tile_context {
blueprint_processor *processor;
bool pretty = false;
df::building* b = NULL;
};
typedef vector<const char *> bp_row; // index is x coordinate
typedef map<int16_t, bp_row> bp_area; // key is y coordinate
typedef map<int16_t, bp_area> bp_volume; // key is z coordinate
typedef const char * (get_tile_fn)(const df::coord &pos,
const tile_context &ctx);
typedef void (init_ctx_fn)(const df::coord &pos, tile_context &ctx);
struct blueprint_processor {
bp_volume mapdata;
const string mode;
const string phase;
const bool force_create;
get_tile_fn * const get_tile;
init_ctx_fn * const init_ctx;
std::set<df::building *> seen;
blueprint_processor(const string &mode, const string &phase,
bool force_create, get_tile_fn *get_tile,
init_ctx_fn *init_ctx)
: mode(mode), phase(phase), force_create(force_create),
get_tile(get_tile), init_ctx(init_ctx) { }
};
// global engravings cache, cleared when the string cache is cleared
struct PosHash {
size_t operator()(const df::coord &c) const {
@ -332,6 +369,108 @@ static const char * get_tile_carve(const df::coord &pos, const tile_context &tc)
return NULL;
}
static const char * get_construction_str(df::building *b) {
df::building_constructionst *cons =
virtual_cast<df::building_constructionst>(b);
if (!cons)
return "~";
switch (cons->type) {
case construction_type::Fortification: return "CF";
case construction_type::Wall: return "Cw";
case construction_type::Floor: return "Cf";
case construction_type::UpStair: return "Cu";
case construction_type::DownStair: return "Cd";
case construction_type::UpDownStair: return "Cx";
case construction_type::Ramp: return "Cr";
case construction_type::TrackN: return "trackN";
case construction_type::TrackS: return "trackS";
case construction_type::TrackE: return "trackE";
case construction_type::TrackW: return "trackW";
case construction_type::TrackNS: return "trackNS";
case construction_type::TrackNE: return "trackNE";
case construction_type::TrackNW: return "trackNW";
case construction_type::TrackSE: return "trackSE";
case construction_type::TrackSW: return "trackSW";
case construction_type::TrackEW: return "trackEW";
case construction_type::TrackNSE: return "trackNSE";
case construction_type::TrackNSW: return "trackNSW";
case construction_type::TrackNEW: return "trackNEW";
case construction_type::TrackSEW: return "trackSEW";
case construction_type::TrackNSEW: return "trackNSEW";
case construction_type::TrackRampN: return "trackrampN";
case construction_type::TrackRampS: return "trackrampS";
case construction_type::TrackRampE: return "trackrampE";
case construction_type::TrackRampW: return "trackrampW";
case construction_type::TrackRampNS: return "trackrampNS";
case construction_type::TrackRampNE: return "trackrampNE";
case construction_type::TrackRampNW: return "trackrampNW";
case construction_type::TrackRampSE: return "trackrampSE";
case construction_type::TrackRampSW: return "trackrampSW";
case construction_type::TrackRampEW: return "trackrampEW";
case construction_type::TrackRampNSE: return "trackrampNSE";
case construction_type::TrackRampNSW: return "trackrampNSW";
case construction_type::TrackRampNEW: return "trackrampNEW";
case construction_type::TrackRampSEW: return "trackrampSEW";
case construction_type::TrackRampNSEW: return "trackrampNSEW";
case construction_type::NONE:
default:
return "~";
}
}
static const char * get_constructed_track_str(df::tiletype *tt,
const char * base) {
TileDirection dir = tileDirection(*tt);
if (!dir.whole)
return "~";
std::ostringstream str;
str << base;
if (dir.north) str << "N";
if (dir.south) str << "S";
if (dir.east) str << "E";
if (dir.west) str << "W";
return cache(str);
}
static const char * get_constructed_floor_str(df::tiletype *tt) {
if (tileSpecial(*tt) != df::tiletype_special::TRACK)
return "Cf";
return get_constructed_track_str(tt, "track");
}
static const char * get_constructed_ramp_str(df::tiletype *tt) {
if (tileSpecial(*tt) != df::tiletype_special::TRACK)
return "Cr";
return get_constructed_track_str(tt, "trackramp");
}
static const char * get_tile_construct(const df::coord &pos,
const tile_context &ctx) {
if (ctx.b && ctx.b->getType() == building_type::Construction)
return get_construction_str(ctx.b);
df::tiletype *tt = Maps::getTileType(pos);
if (!tt || tileMaterial(*tt) != df::tiletype_material::CONSTRUCTION)
return NULL;
switch (tileShape(*tt)) {
case tiletype_shape::WALL: return "Cw";
case tiletype_shape::FLOOR: return get_constructed_floor_str(tt);
case tiletype_shape::RAMP: return get_constructed_ramp_str(tt);
case tiletype_shape::FORTIFICATION: return "CF";
case tiletype_shape::STAIR_UP: return "Cu";
case tiletype_shape::STAIR_DOWN: return "Cd";
case tiletype_shape::STAIR_UPDOWN: return "Cx";
default:
return "~";
}
return NULL;
}
static pair<uint32_t, uint32_t> get_building_size(const df::building *b) {
return pair<uint32_t, uint32_t>(b->x2 - b->x1 + 1, b->y2 - b->y1 + 1);
}
@ -461,56 +600,6 @@ static const char * get_furnace_str(df::building *b) {
}
}
static const char * get_construction_str(df::building *b) {
df::building_constructionst *cons =
virtual_cast<df::building_constructionst>(b);
if (!cons)
return "~";
switch (cons->type) {
case construction_type::Fortification: return "CF";
case construction_type::Wall: return "Cw";
case construction_type::Floor: return "Cf";
case construction_type::UpStair: return "Cu";
case construction_type::DownStair: return "Cd";
case construction_type::UpDownStair: return "Cx";
case construction_type::Ramp: return "Cr";
case construction_type::TrackN: return "trackN";
case construction_type::TrackS: return "trackS";
case construction_type::TrackE: return "trackE";
case construction_type::TrackW: return "trackW";
case construction_type::TrackNS: return "trackNS";
case construction_type::TrackNE: return "trackNE";
case construction_type::TrackNW: return "trackNW";
case construction_type::TrackSE: return "trackSE";
case construction_type::TrackSW: return "trackSW";
case construction_type::TrackEW: return "trackEW";
case construction_type::TrackNSE: return "trackNSE";
case construction_type::TrackNSW: return "trackNSW";
case construction_type::TrackNEW: return "trackNEW";
case construction_type::TrackSEW: return "trackSEW";
case construction_type::TrackNSEW: return "trackNSEW";
case construction_type::TrackRampN: return "trackrampN";
case construction_type::TrackRampS: return "trackrampS";
case construction_type::TrackRampE: return "trackrampE";
case construction_type::TrackRampW: return "trackrampW";
case construction_type::TrackRampNS: return "trackrampNS";
case construction_type::TrackRampNE: return "trackrampNE";
case construction_type::TrackRampNW: return "trackrampNW";
case construction_type::TrackRampSE: return "trackrampSE";
case construction_type::TrackRampSW: return "trackrampSW";
case construction_type::TrackRampEW: return "trackrampEW";
case construction_type::TrackRampNSE: return "trackrampNSE";
case construction_type::TrackRampNSW: return "trackrampNSW";
case construction_type::TrackRampNEW: return "trackrampNEW";
case construction_type::TrackRampSEW: return "trackrampSEW";
case construction_type::TrackRampNSEW: return "trackrampNSEW";
case construction_type::NONE:
default:
return "~";
}
}
static const char * get_trap_str(df::building *b) {
df::building_trapst *trap = virtual_cast<df::building_trapst>(b);
if (!trap)
@ -622,6 +711,7 @@ static const char * get_build_keys(const df::coord &pos,
bool at_center = static_cast<int32_t>(pos.x) == ctx.b->centerx
&& static_cast<int32_t>(pos.y) == ctx.b->centery;
// building_type::Construction is handled by the construction phase
switch(ctx.b->getType()) {
case building_type::Armorstand:
return "a";
@ -666,8 +756,6 @@ static const char * get_build_keys(const df::coord &pos,
return "y";
case building_type::WindowGem:
return "Y";
case building_type::Construction:
return get_construction_str(ctx.b);
case building_type::Shop:
return do_block_building(ctx, "z", at_center);
case building_type::AnimalTrap:
@ -921,10 +1009,82 @@ static const char * get_tile_zone(const df::coord &pos,
return add_expansion_syntax(zone, get_zone_keys(zone));
}
static const char * get_tile_query(const df::coord &, const tile_context &ctx) {
// surrounds the given string in quotes and replaces internal double quotes (")
// with double double quotes ("") (as per the csv spec)
static string csv_quote(const string &str) {
std::ostringstream outstr;
outstr << "\"";
size_t start = 0;
auto end = str.find('"');
while (end != std::string::npos) {
outstr << str.substr(start, end - start);
outstr << "\"\"";
start = end + 1;
end = str.find('"', start);
}
outstr << str.substr(start, end) << "\"";
return outstr.str();
}
static const char * get_tile_query(const df::coord &pos,
const tile_context &ctx) {
string bld_name, zone_name;
auto & seen = ctx.processor->seen;
if (ctx.b && !seen.count(ctx.b)) {
bld_name = ctx.b->name;
seen.emplace(ctx.b);
}
vector<df::building_civzonest*> civzones;
if (Buildings::findCivzonesAt(&civzones, pos)) {
auto civzone = civzones.back();
if (!seen.count(civzone)) {
zone_name = civzone->name;
seen.emplace(civzone);
}
}
if (!bld_name.size() && !zone_name.size())
return NULL;
std::ostringstream str;
if (bld_name.size())
str << "{givename name=" + csv_quote(bld_name) + "}";
if (zone_name.size())
str << "{namezone name=" + csv_quote(zone_name) + "}";
return cache(csv_quote(str.str()));
}
static const char * get_tile_rooms(const df::coord &, const tile_context &ctx) {
if (!ctx.b || !ctx.b->is_room)
return NULL;
return "r+";
// get the maximum distance from the center of the building
df::building_extents &room = ctx.b->room;
int32_t x1 = room.x;
int32_t x2 = room.x + room.width - 1;
int32_t y1 = room.y;
int32_t y2 = room.y + room.height - 1;
int32_t dimx = std::max(ctx.b->centerx - x1, x2 - ctx.b->centerx);
int32_t dimy = std::max(ctx.b->centery - y1, y2 - ctx.b->centery);
int32_t max_dim = std::max(dimx, dimy);
switch (max_dim) {
case 0: return "r---&";
case 1: return "r--&";
case 2: return "r-&";
case 3: return "r&";
case 4: return "r+&";
}
std::ostringstream str;
str << "r{+ " << (max_dim - 3) << "}&";
return cache(str);
}
static bool create_output_dir(color_ostream &out,
@ -945,11 +1105,12 @@ static bool create_output_dir(color_ostream &out,
static bool get_filename(string &fname,
color_ostream &out,
blueprint_options opts, // copy because we can't const
const string &phase) {
const string &phase,
int32_t ordinal) {
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
if (!lua_checkstack(L, 3) ||
if (!lua_checkstack(L, 4) ||
!Lua::PushModulePublic(
out, L, "plugins.blueprint", "get_filename")) {
out.printerr("Failed to load blueprint Lua code\n");
@ -958,8 +1119,9 @@ static bool get_filename(string &fname,
Lua::Push(L, &opts);
Lua::Push(L, phase);
Lua::Push(L, ordinal);
if (!Lua::SafeCall(out, L, 2, 1)) {
if (!Lua::SafeCall(out, L, 3, 1)) {
out.printerr("Failed Lua call to get_filename\n");
return false;
}
@ -974,27 +1136,31 @@ static bool get_filename(string &fname,
return true;
}
typedef vector<const char *> bp_row; // index is x coordinate
typedef map<int16_t, bp_row> bp_area; // key is y coordinate
typedef map<int16_t, bp_area> bp_volume; // key is z coordinate
// returns true if we could interface with lua and could verify that the given
// phase is a meta phase
static bool is_meta_phase(color_ostream &out,
blueprint_options opts, // copy because we can't const
const string &phase) {
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
typedef const char * (get_tile_fn)(const df::coord &pos,
const tile_context &ctx);
typedef void (init_ctx_fn)(const df::coord &pos, tile_context &ctx);
if (!lua_checkstack(L, 3) ||
!Lua::PushModulePublic(
out, L, "plugins.blueprint", "is_meta_phase")) {
out.printerr("Failed to load blueprint Lua code\n");
return false;
}
struct blueprint_processor {
bp_volume mapdata;
const string mode;
const string phase;
const bool force_create;
get_tile_fn * const get_tile;
init_ctx_fn * const init_ctx;
blueprint_processor(const string &mode, const string &phase,
bool force_create, get_tile_fn *get_tile,
init_ctx_fn *init_ctx)
: mode(mode), phase(phase), force_create(force_create),
get_tile(get_tile), init_ctx(init_ctx) { }
};
Lua::Push(L, &opts);
Lua::Push(L, phase);
if (!Lua::SafeCall(out, L, 2, 1)) {
out.printerr("Failed Lua call to is_meta_phase\n");
return false;
}
return lua_toboolean(L, -1);
}
static void write_minimal(ofstream &ofile, const blueprint_options &opts,
const bp_volume &mapdata) {
@ -1052,8 +1218,8 @@ static void write_pretty(ofstream &ofile, const blueprint_options &opts,
}
}
static string get_modeline(const blueprint_options &opts, const string &mode,
const string &phase) {
static string get_modeline(color_ostream &out, const blueprint_options &opts,
const string &mode, const string &phase) {
std::ostringstream modeline;
modeline << "#" << mode << " label(" << phase << ")";
if (opts.playback_start.x > 0) {
@ -1064,6 +1230,8 @@ static string get_modeline(const blueprint_options &opts, const string &mode,
}
modeline << ")";
}
if (is_meta_phase(out, opts, phase))
modeline << " hidden()";
return modeline.str();
}
@ -1072,15 +1240,15 @@ static bool write_blueprint(color_ostream &out,
std::map<string, ofstream*> &output_files,
const blueprint_options &opts,
const blueprint_processor &processor,
bool pretty) {
bool pretty, int32_t ordinal) {
string fname;
if (!get_filename(fname, out, opts, processor.phase))
if (!get_filename(fname, out, opts, processor.phase, ordinal))
return false;
if (!output_files.count(fname))
output_files[fname] = new ofstream(fname, ofstream::trunc);
ofstream &ofile = *output_files[fname];
ofile << get_modeline(opts, processor.mode, processor.phase) << endl;
ofile << get_modeline(out, opts, processor.mode, processor.phase) << endl;
if (pretty)
write_pretty(ofile, opts, processor.mapdata);
@ -1090,6 +1258,28 @@ static bool write_blueprint(color_ostream &out,
return true;
}
static void write_meta_blueprint(color_ostream &out,
std::map<string, ofstream*> &output_files,
const blueprint_options &opts,
const std::vector<string> & meta_phases,
int32_t ordinal) {
string fname;
get_filename(fname, out, opts, meta_phases.front(), ordinal);
ofstream &ofile = *output_files[fname];
ofile << "#meta label(";
for (string phase : meta_phases) {
ofile << phase;
if (phase != meta_phases.back())
ofile << "_";
}
ofile << ")" << endl;
for (string phase : meta_phases) {
ofile << "/" << phase << endl;
}
}
static void ensure_building(const df::coord &pos, tile_context &ctx) {
if (ctx.b)
return;
@ -1108,7 +1298,7 @@ static void add_processor(vector<blueprint_processor> &processors,
static bool do_transform(color_ostream &out,
const df::coord &start, const df::coord &end,
const blueprint_options &opts,
blueprint_options opts, // copy so we can munge it
vector<string> &filenames) {
// empty map instances to pass to emplace() below
static const bp_area EMPTY_AREA;
@ -1132,6 +1322,8 @@ static bool do_transform(color_ostream &out,
smooth_get_tile_fn);
add_processor(processors, opts, "dig", "carve", opts.carve,
opts.engrave ? get_tile_carve : get_tile_carve_minimal);
add_processor(processors, opts, "build", "construct", opts.construct,
get_tile_construct, ensure_building);
add_processor(processors, opts, "build", "build", opts.build,
get_tile_build, ensure_building);
add_processor(processors, opts, "place", "place", opts.place,
@ -1139,6 +1331,8 @@ static bool do_transform(color_ostream &out,
add_processor(processors, opts, "zone", "zone", opts.zone, get_tile_zone);
add_processor(processors, opts, "query", "query", opts.query,
get_tile_query, ensure_building);
add_processor(processors, opts, "query", "rooms", opts.rooms,
get_tile_rooms, ensure_building);
if (processors.empty()) {
out.printerr("no phases requested! nothing to do!\n");
@ -1157,6 +1351,7 @@ static bool do_transform(color_ostream &out,
tile_context ctx;
ctx.pretty = pretty;
for (blueprint_processor &processor : processors) {
ctx.processor = &processor;
if (processor.init_ctx)
processor.init_ctx(pos, ctx);
const char *tile_str = processor.get_tile(pos, ctx);
@ -1176,13 +1371,36 @@ static bool do_transform(color_ostream &out,
}
}
std::vector<string> meta_phases;
for (blueprint_processor &processor : processors) {
if (processor.mapdata.empty() && !processor.force_create)
continue;
if (is_meta_phase(out, opts, processor.phase))
meta_phases.push_back(processor.phase);
}
if (meta_phases.size() <= 1)
opts.nometa = true;
bool in_meta = false;
int32_t ordinal = 0;
std::map<string, ofstream*> output_files;
for (blueprint_processor &processor : processors) {
if (processor.mapdata.empty() && !processor.force_create)
continue;
if (!write_blueprint(out, output_files, opts, processor, pretty))
bool meta_phase = is_meta_phase(out, opts, processor.phase);
if (!in_meta)
++ordinal;
if (in_meta && !meta_phase) {
write_meta_blueprint(out, output_files, opts, meta_phases, ordinal);
++ordinal;
}
in_meta = meta_phase;
if (!write_blueprint(out, output_files, opts, processor, pretty,
ordinal))
break;
}
if (in_meta)
write_meta_blueprint(out, output_files, opts, meta_phases, ordinal);
for (auto &it : output_files) {
filenames.push_back(it.first);

@ -6,13 +6,23 @@ local utils = require('utils')
local valid_phase_list = {
'dig',
'carve',
'construct',
'build',
'place',
'zone',
'query',
'rooms',
}
valid_phases = utils.invert(valid_phase_list)
local meta_phase_list = {
'build',
'place',
'zone',
'query',
}
meta_phases = utils.invert(meta_phase_list)
local valid_formats_list = {
'minimal',
'pretty',
@ -21,6 +31,7 @@ valid_formats = utils.invert(valid_formats_list)
local valid_split_strategies_list = {
'none',
'group',
'phase',
}
valid_split_strategies = utils.invert(valid_split_strategies_list)
@ -121,6 +132,7 @@ local function process_args(opts, args)
{'f', 'format', hasArg=true,
handler=function(optarg) parse_format(opts, optarg) end},
{'h', 'help', handler=function() opts.help = true end},
{nil, 'nometa', handler=function() opts.nometa = true end},
{'s', 'playback-start', hasArg=true,
handler=function(optarg) parse_start(opts, optarg) end},
{nil, 'smooth', handler=function() opts.smooth = true end},
@ -132,6 +144,10 @@ local function process_args(opts, args)
return
end
if opts.split_strategy == 'phase' then
opts.nometa = true
end
return positionals
end
@ -183,8 +199,13 @@ function parse_commandline(opts, ...)
parse_positionals(opts, positionals, depth and 4 or 3)
end
function is_meta_phase(opts, phase)
-- this is called directly by cpp so ensure we return a boolean, not nil
return not opts.nometa and meta_phases[phase] or false
end
-- returns the name of the output file for the given context
function get_filename(opts, phase)
function get_filename(opts, phase, ordinal)
local fullname = 'blueprints/' .. opts.name
local _,_,basename = fullname:find('/([^/]+)/?$')
if not basename then
@ -194,11 +215,13 @@ function get_filename(opts, phase)
if fullname:endswith('/') then
fullname = fullname .. basename
end
if opts.split_strategy == 'phase' then
return ('%s-%s.csv'):format(fullname, phase)
if opts.split_strategy == 'none' then
return ('%s.csv'):format(fullname)
end
if is_meta_phase(opts, phase) then
phase = 'meta'
end
-- no splitting
return ('%s.csv'):format(fullname)
return ('%s-%d-%s.csv'):format(fullname, ordinal, phase)
end
-- compatibility with old exported API.

@ -99,7 +99,7 @@ namespace DFHack {
DBG_DECLARE(overlay, log, DebugCategory::LINFO);
}
static const std::string button_text = "[ DFHack Launcher ]";
static const std::string button_text = "[ DFHack ]";
static bool clicked = false;
static bool handle_click() {

@ -1 +1 @@
Subproject commit 937cf27f9b41301be6df0fe1d75d77b6f089f688
Subproject commit 0be5cc0eaf625029ef26392224db5c3d2822a63d

@ -20,6 +20,12 @@ function test.parse_gui_commandline()
b.parse_gui_commandline(opts, {'-h'})
expect.table_eq({help=true, format='minimal', split_strategy='none'}, opts)
opts = {}
b.parse_gui_commandline(opts, {'--nometa'})
expect.table_eq({auto_phase=true, format='minimal', split_strategy='none',
name='blueprint', nometa=true},
opts)
opts = {}
mock.patch(dfhack.maps, 'isValidTilePos', mock.func(true),
function()
@ -95,7 +101,7 @@ function test.parse_gui_commandline()
opts = {}
b.parse_gui_commandline(opts, {'--splitby', 'phase'})
expect.table_eq({auto_phase=true, format='minimal', split_strategy='phase',
name='blueprint'},
name='blueprint', nometa=true},
opts)
expect.error_match('unknown split_strategy',
@ -235,16 +241,16 @@ end
function test.get_filename()
local opts = {name='a', split_strategy='none'}
expect.eq('blueprints/a.csv', b.get_filename(opts, 'dig'))
expect.eq('blueprints/a.csv', b.get_filename(opts, 'dig', 1))
opts = {name='a/', split_strategy='none'}
expect.eq('blueprints/a/a.csv', b.get_filename(opts, 'dig'))
expect.eq('blueprints/a/a.csv', b.get_filename(opts, 'dig', 1))
opts = {name='a', split_strategy='phase'}
expect.eq('blueprints/a-dig.csv', b.get_filename(opts, 'dig'))
expect.eq('blueprints/a-1-dig.csv', b.get_filename(opts, 'dig', 1))
opts = {name='a/', split_strategy='phase'}
expect.eq('blueprints/a/a-dig.csv', b.get_filename(opts, 'dig'))
expect.eq('blueprints/a/a-5-dig.csv', b.get_filename(opts, 'dig', 5))
expect.error_match('could not parse basename', function()
b.get_filename({name='', split_strategy='none'})

@ -327,10 +327,12 @@ function test.end_to_end()
do_dig_phase(phases.dig, area, spec)
if phases.smooth then do_dig_phase(phases.smooth, area, spec) end
if phases.carve then do_dig_phase(phases.carve, area, spec) end
if phases.construct then do_phase(phases.construct, area, spec) end
if phases.build then do_phase(phases.build, area, spec) end
if phases.place then do_phase(phases.place, area, spec) end
if phases.zone then do_phase(phases.zone, area, spec) end
if phases.query then do_phase(phases.query, area, spec) end
if phases.rooms then do_phase(phases.rooms, area, spec) end
-- run any extra commands, if defined by the blueprint spec
if spec.extra_fn then