From 719d61982953caf61c0df7776347e13105a2e8b2 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sat, 22 Oct 2022 12:53:57 +0200 Subject: Add asset rendering scripts. --- tools/boxes.svg | 688 +++++++++++++++++++++++++++++++++++++++++++++ tools/build_cards1.sh | 86 ++++++ tools/build_cards2.sh | 10 + tools/build_counters1.sh | 117 ++++++++ tools/build_counters2.sh | 119 ++++++++ tools/build_counters3.sh | 5 + tools/build_map.sh | 16 ++ tools/build_mats.sh | 35 +++ tools/build_screen.sh | 10 + tools/build_stickers.sh | 37 +++ tools/colors.mjs | 108 ++++++++ tools/genboxes.py | 65 +++++ tools/gencss.js | 5 + tools/gencyl.js | 51 ++++ tools/gendata.js | 705 +++++++++++++++++++++++++++++++++++++++++++++++ tools/scale.sh | 18 ++ tools/svgo.config.js | 10 + 17 files changed, 2085 insertions(+) create mode 100644 tools/boxes.svg create mode 100644 tools/build_cards1.sh create mode 100644 tools/build_cards2.sh create mode 100644 tools/build_counters1.sh create mode 100644 tools/build_counters2.sh create mode 100644 tools/build_counters3.sh create mode 100644 tools/build_map.sh create mode 100644 tools/build_mats.sh create mode 100644 tools/build_screen.sh create mode 100644 tools/build_stickers.sh create mode 100644 tools/colors.mjs create mode 100644 tools/genboxes.py create mode 100644 tools/gencss.js create mode 100644 tools/gencyl.js create mode 100644 tools/gendata.js create mode 100644 tools/scale.sh create mode 100644 tools/svgo.config.js diff --git a/tools/boxes.svg b/tools/boxes.svg new file mode 100644 index 0000000..16b8e71 --- /dev/null +++ b/tools/boxes.svg @@ -0,0 +1,688 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/build_cards1.sh b/tools/build_cards1.sh new file mode 100644 index 0000000..3459345 --- /dev/null +++ b/tools/build_cards1.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# Extract, crop, and rename card images to create 300 dpi PNG versions. + +function extract_images { + echo "$1" + mutool extract -r "$1" + mkdir -p $2 + mv image* $2 + rm -f font* +} + +extract_images "../HIRES/Nevsky_Arts of War Cards_42 Anverses.pdf" tmp/aow_front +extract_images "../HIRES/Nevsky_Arts of War Cards_42 Backs.pdf" tmp/aow_back +extract_images "../HIRES/Nevsky_Arts of War Cards_R1 and R2 Anverses_Corrected.pdf" tmp/aow_corr +extract_images "../HIRES/Nevsky_Command Cards_42 Anverses.pdf" tmp/cc_front +extract_images "../HIRES/Nevsky_Command Cards_42 Backs.pdf" tmp/cc_back + +# cards are 63.5 x 89.0 mm - 2.5 x 3.5 inches - 750 x 1050 pixels +# rounded to multiple of 12 = 744 x 1044 +for IM in tmp/aow_*/*.png tmp/cc_*/*.png +do + echo $IM + convert $IM -gravity Center -crop 744x1040+0+0 +repage ${IM/png/ppm} +done + +mkdir -p cards300 +pnmtopng tmp/aow_back/image-0083.ppm >cards300/aow_russian_back.png +pnmtopng tmp/aow_back/image-0102.ppm >cards300/aow_teutonic_back.png +pnmtopng tmp/aow_corr/image-0004.ppm >cards300/aow_russian_02.png +pnmtopng tmp/aow_corr/image-0015.ppm >cards300/aow_russian_01.png +pnmtopng tmp/aow_front/image-0004.ppm >cards300/aow_teutonic_02.png +pnmtopng tmp/aow_front/image-0008.ppm >cards300/aow_teutonic_03.png +pnmtopng tmp/aow_front/image-0012.ppm >cards300/aow_teutonic_04.png +pnmtopng tmp/aow_front/image-0016.ppm >cards300/aow_teutonic_05.png +pnmtopng tmp/aow_front/image-0020.ppm >cards300/aow_teutonic_06.png +pnmtopng tmp/aow_front/image-0024.ppm >cards300/aow_teutonic_07.png +pnmtopng tmp/aow_front/image-0028.ppm >cards300/aow_teutonic_08.png +pnmtopng tmp/aow_front/image-0032.ppm >cards300/aow_teutonic_09.png +pnmtopng tmp/aow_front/image-0036.ppm >cards300/aow_teutonic_10.png +pnmtopng tmp/aow_front/image-0040.ppm >cards300/aow_teutonic_11.png +pnmtopng tmp/aow_front/image-0044.ppm >cards300/aow_teutonic_12.png +pnmtopng tmp/aow_front/image-0048.ppm >cards300/aow_teutonic_13.png +pnmtopng tmp/aow_front/image-0052.ppm >cards300/aow_teutonic_14.png +pnmtopng tmp/aow_front/image-0056.ppm >cards300/aow_teutonic_15.png +pnmtopng tmp/aow_front/image-0060.ppm >cards300/aow_teutonic_16.png +pnmtopng tmp/aow_front/image-0064.ppm >cards300/aow_teutonic_17.png +pnmtopng tmp/aow_front/image-0068.ppm >cards300/aow_teutonic_18.png +# pnmtopng tmp/aow_front/image-0078.ppm >cards300/aow_russian_01.ppm # corrected +# pnmtopng tmp/aow_front/image-0082.ppm >cards300/aow_russian_02.ppm # corrected +pnmtopng tmp/aow_front/image-0086.ppm >cards300/aow_russian_03.png +pnmtopng tmp/aow_front/image-0090.ppm >cards300/aow_russian_04.png +pnmtopng tmp/aow_front/image-0094.ppm >cards300/aow_russian_05.png +pnmtopng tmp/aow_front/image-0098.ppm >cards300/aow_russian_06.png +pnmtopng tmp/aow_front/image-0102.ppm >cards300/aow_russian_07.png +pnmtopng tmp/aow_front/image-0106.ppm >cards300/aow_russian_08.png +pnmtopng tmp/aow_front/image-0110.ppm >cards300/aow_russian_09.png +pnmtopng tmp/aow_front/image-0114.ppm >cards300/aow_russian_10.png +pnmtopng tmp/aow_front/image-0118.ppm >cards300/aow_russian_11.png +pnmtopng tmp/aow_front/image-0122.ppm >cards300/aow_russian_12.png +pnmtopng tmp/aow_front/image-0126.ppm >cards300/aow_russian_13.png +pnmtopng tmp/aow_front/image-0130.ppm >cards300/aow_russian_14.png +pnmtopng tmp/aow_front/image-0134.ppm >cards300/aow_russian_15.png +pnmtopng tmp/aow_front/image-0138.ppm >cards300/aow_russian_16.png +pnmtopng tmp/aow_front/image-0142.ppm >cards300/aow_russian_17.png +pnmtopng tmp/aow_front/image-0146.ppm >cards300/aow_russian_18.png +pnmtopng tmp/aow_front/image-0153.ppm >cards300/aow_teutonic_none.png +pnmtopng tmp/aow_front/image-0155.ppm >cards300/aow_russian_none.png +pnmtopng tmp/aow_front/image-0175.ppm >cards300/aow_teutonic_01.png +pnmtopng tmp/cc_back/image-0083.ppm >cards300/cc_russian_back.png +pnmtopng tmp/cc_back/image-0102.ppm >cards300/cc_teutonic_back.png +pnmtopng tmp/cc_front/image-0083.ppm >cards300/cc_teutonic_andreas.png +pnmtopng tmp/cc_front/image-0085.ppm >cards300/cc_teutonic_pass.png +pnmtopng tmp/cc_front/image-0087.ppm >cards300/cc_teutonic_heinrich.png +pnmtopng tmp/cc_front/image-0089.ppm >cards300/cc_teutonic_rudolf.png +pnmtopng tmp/cc_front/image-0091.ppm >cards300/cc_teutonic_knud_and_abel.png +pnmtopng tmp/cc_front/image-0093.ppm >cards300/cc_teutonic_yaroslav.png +pnmtopng tmp/cc_front/image-0095.ppm >cards300/cc_russian_aleksandr.png +pnmtopng tmp/cc_front/image-0097.ppm >cards300/cc_russian_domash.png +pnmtopng tmp/cc_front/image-0099.ppm >cards300/cc_russian_vladislav.png +pnmtopng tmp/cc_front/image-0101.ppm >cards300/cc_russian_pass.png +pnmtopng tmp/cc_front/image-0103.ppm >cards300/cc_russian_karelians.png +pnmtopng tmp/cc_front/image-0105.ppm >cards300/cc_russian_andrey.png +pnmtopng tmp/cc_front/image-0107.ppm >cards300/cc_russian_gavrilo.png +pnmtopng tmp/cc_front/image-0126.ppm >cards300/cc_teutonic_hermann.png + +rm -rf tmp diff --git a/tools/build_cards2.sh b/tools/build_cards2.sh new file mode 100644 index 0000000..bcf4062 --- /dev/null +++ b/tools/build_cards2.sh @@ -0,0 +1,10 @@ +# 300dpi @ 744 x 1044 + +mkdir -p cards75 cards150 + +for IM in cards300/*.png +do + echo $IM + convert $IM -colorspace RGB -resize 25% -colorspace sRGB ${IM/cards300/cards75} + convert $IM -colorspace RGB -resize 50% -colorspace sRGB ${IM/cards300/cards150} +done diff --git a/tools/build_counters1.sh b/tools/build_counters1.sh new file mode 100644 index 0000000..a8573e2 --- /dev/null +++ b/tools/build_counters1.sh @@ -0,0 +1,117 @@ +# 3 counter sheet dies +# 1 and 3 has square counters, only bottom row differs +# 2 has rectangular tiles + +# circular (sheet 1 bottom) 210x210 +# large square 190x190 (188-190-ish) +# rectangle 380x190 (188-190-ish) +# small square 150x150 + +mkdir -p tmp + +# large squares (top sheet 1 and 3) +ROW=1 +for TOP in 340 586 833 1080 1326 +do + COL=1 + RCOL=12 + for LEFT in 304 551 797 1043 1290 1536 1874 2121 2367 2613 2860 3106 + do + echo large square $ROW $COL + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 168 -height 168 ../HIRES/nocut/NEVSKY-1F-nf.ppm > tmp/cs_sq_large_1_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 168 -height 168 ../HIRES/nocut/NEVSKY-1B-nf.ppm > tmp/cs_sq_large_1_${ROW}_${RCOL}_b.ppm + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 168 -height 168 ../HIRES/nocut/NEVSKY-3F-nf.ppm > tmp/cs_sq_large_3_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 168 -height 168 ../HIRES/nocut/NEVSKY-3B-nf.ppm > tmp/cs_sq_large_3_${ROW}_${RCOL}_b.ppm + COL=$(expr $COL + 1) + RCOL=$(expr $RCOL - 1) + done + ROW=$(expr $ROW + 1) +done + +# large squares (bottom sheet 2) +ROW=1 +for TOP in 2075 2322 +do + COL=1 + RCOL=12 + for LEFT in 304 551 797 1043 1290 1536 1874 2121 2367 2613 2860 3106 + do + echo large square $ROW $COL + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 168 -height 168 ../HIRES/nocut/NEVSKY-2F-nf.ppm > tmp/cs_sq_large_2_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 168 -height 168 ../HIRES/nocut/NEVSKY-2B-nf.ppm > tmp/cs_sq_large_2_${ROW}_${RCOL}_b.ppm + COL=$(expr $COL + 1) + RCOL=$(expr $RCOL - 1) + done + ROW=$(expr $ROW + 1) +done + +# small squares (bottom sheet 1 and 3) +ROW=1 +for TOP in 1595 1745 1970 2120 2345 +do + COL=1 + RCOL=4 + for LEFT in 305 1275 2175 2695 + do + echo small square $ROW $COL + pnmcut -top $(expr 3 + $TOP) -left $(expr 3 + $LEFT) -width 144 -height 144 ../HIRES/nocut/NEVSKY-1F-nf.ppm > tmp/cs_sq_small_1_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 3 + $TOP) -left $(expr 3 + $LEFT) -width 144 -height 144 ../HIRES/nocut/NEVSKY-1B-nf.ppm > tmp/cs_sq_small_1_${ROW}_${RCOL}_b.ppm + pnmcut -top $(expr 3 + $TOP) -left $(expr 3 + $LEFT) -width 144 -height 144 ../HIRES/nocut/NEVSKY-3F-nf.ppm > tmp/cs_sq_small_3_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 3 + $TOP) -left $(expr 3 + $LEFT) -width 144 -height 144 ../HIRES/nocut/NEVSKY-3B-nf.ppm > tmp/cs_sq_small_3_${ROW}_${RCOL}_b.ppm + COL=$(expr $COL + 1) + RCOL=$(expr $RCOL - 1) + done + ROW=$(expr $ROW + 1) +done + +# large rects (top sheet 2) +ROW=1 +for TOP in 340 586 833 1080 1326 1572 1818 +do + COL=1 + RCOL=7 + TOP=$(expr $TOP + 1) + for LEFT in 304 739 1175 1611 2047 2483 2919 + do + echo rectangle $ROW $COL + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 360 -height 168 ../HIRES/nocut/NEVSKY-2F-nf.ppm > tmp/cs_rect_2_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 360 -height 168 ../HIRES/nocut/NEVSKY-2B-nf.ppm > tmp/cs_rect_2_${ROW}_${RCOL}_b.ppm + COL=$(expr $COL + 1) + RCOL=$(expr $RCOL - 1) + done + ROW=$(expr $ROW + 1) +done + +# circles (sheet 1) +ROW=1 +for TOP in 2332 +do + COL=1 + RCOL=6 + for LEFT in 987 1253 1518 1874 2139 2404 + do + echo circle $ROW $COL + pnmcut -top $(expr 3 + $TOP) -left $(expr 3 + $LEFT) -width 204 -height 204 ../HIRES/nocut/NEVSKY-1F-nf.ppm > tmp/cs_circle_1_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 3 + $TOP) -left $(expr 3 + $LEFT) -width 204 -height 204 ../HIRES/nocut/NEVSKY-1B-nf.ppm > tmp/cs_circle_1_${ROW}_${RCOL}_b.ppm + COL=$(expr $COL + 1) + RCOL=$(expr $RCOL - 1) + done + ROW=$(expr $ROW + 1) +done + +# rectangles (sheet 1) +ROW=1 +for TOP in 2342 +do + COL=1 + RCOL=2 + for LEFT in 416 2806 + do + echo rectangle $ROW $COL + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 360 -height 168 ../HIRES/nocut/NEVSKY-1F-nf.ppm > tmp/cs_rect_1_${ROW}_${COL}_a.ppm + pnmcut -top $(expr 10 + $TOP) -left $(expr 10 + $LEFT) -width 360 -height 168 ../HIRES/nocut/NEVSKY-1B-nf.ppm > tmp/cs_rect_1_${ROW}_${RCOL}_b.ppm + COL=$(expr $COL + 1) + RCOL=$(expr $RCOL - 1) + done + ROW=$(expr $ROW + 1) +done diff --git a/tools/build_counters2.sh b/tools/build_counters2.sh new file mode 100644 index 0000000..ad7bc5d --- /dev/null +++ b/tools/build_counters2.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +# set -x + +mkdir -p counters300 + +function marker { + pnmtopng tmp/${1}_a.ppm > counters300/$2.a.png + pnmtopng tmp/${1}_b.ppm > counters300/$2.b.png +} + +function marker2 { + pnmtopng tmp/${1}_a.ppm > counters300/$2.png + pnmtopng tmp/${1}_b.ppm > counters300/$3.png +} + +marker2 cs_circle_1_1_1 marker_battle marker_storm +marker2 cs_circle_1_1_2 marker_levy marker_campaign +marker2 cs_circle_1_1_3 marker_victory_teutonic marker_victory_half_teutonic +marker2 cs_circle_1_1_4 marker_victory_russian marker_victory_half_russian +marker2 cs_circle_1_1_5 marker_enemy_lords_removed_teutonic marker_pleskau_blue +marker2 cs_circle_1_1_6 marker_enemy_lords_removed_russian makrer_pleskau_gray + +marker2 cs_sq_small_1_1_2 marker_ravaged_teutonic marker_ravaged_russian + +marker cs_sq_small_1_1_1 unit_men_at_arms +marker cs_sq_small_3_1_1 unit_knights +marker cs_sq_small_3_1_3 unit_asiatic_horse +marker cs_sq_small_3_1_4 unit_militia +marker cs_sq_small_3_3_1 unit_light_horse +marker cs_sq_small_3_3_3 unit_serfs +marker cs_sq_small_3_5_1 unit_sergeants + +marker2 cs_sq_large_1_1_7 marker_conquered_teutonic marker_conquered_russian +marker2 cs_sq_large_1_4_11 marker_moved_fought marker_supply_source +marker2 cs_sq_large_2_1_1 marker_siege_teutonic marker_siege_russian +marker cs_sq_large_2_1_8 marker_walls + +marker2 cs_sq_large_2_1_10 marker_1_teutonic marker_1_russian +marker2 cs_sq_large_2_1_11 marker_2_teutonic marker_2_russian +marker2 cs_sq_large_2_1_12 marker_3_teutonic marker_3_russian +marker2 cs_sq_large_2_2_10 marker_4_teutonic marker_4_russian +marker2 cs_sq_large_2_2_11 marker_5_teutonic marker_5_russian +marker2 cs_sq_large_2_2_12 marker_6_teutonic marker_6_russian + +marker2 cs_sq_large_1_1_2 asset_coin_x1 asset_coin_x2 +marker2 cs_sq_large_1_3_1 asset_coin_x3 asset_coin_x4 + +marker2 cs_sq_large_1_3_3 asset_loot_x1 asset_loot_x2 +marker2 cs_sq_large_1_4_6 asset_loot_x3 asset_loot_x4 + +marker2 cs_sq_large_1_5_1 asset_prov_x1 asset_prov_x2 +marker2 cs_sq_large_3_4_10 asset_prov_x3 asset_prov_x4 + +marker2 cs_sq_large_3_1_1 asset_boat_x1 asset_ship_x1 +marker2 cs_sq_large_3_4_1 asset_boat_x2 asset_ship_x2 +marker2 cs_sq_large_3_4_2 asset_boat_x4 asset_ship_x4 + +marker2 cs_sq_large_3_1_7 asset_sled_x1 asset_cart_x1 +marker2 cs_sq_large_3_4_4 asset_sled_x2 asset_cart_x2 +marker2 cs_sq_large_3_5_6 asset_sled_x4 asset_cart_x4 + +marker cs_rect_1_1_1 marker_sea_trade_blocked + +marker cs_rect_2_1_1 lord_russian_aleksandr +marker cs_rect_2_1_2 lord_russian_andrey +marker cs_rect_2_1_3 vassal_russian_gavrilo_pskov +marker cs_rect_2_1_4 vassal_russian_andrey_vladimir +marker cs_rect_2_1_5 vassal_russian_domash_novgorod +marker cs_rect_2_1_6 vassal_russian_andrey_kipchaqs +marker cs_rect_2_1_7 vassal_teutonic_knud_and_abel_dietrich_von_kivel + +marker cs_rect_2_2_1 lord_russian_vladislav +marker cs_rect_2_2_2 lord_russian_karelians +marker cs_rect_2_2_3 vassal_russian_aleksandr_pereyaslavl +marker cs_rect_2_2_4 vassal_russian_andrey_suzdal +marker cs_rect_2_2_5 lord_teutonic_andreas +marker cs_rect_2_2_6 vassal_teutonic_andreas_summer_crusaders +marker cs_rect_2_2_7 vassal_teutonic_knud_and_abel_otto_von_luneburg + +marker cs_rect_2_3_1 lord_russian_domash +marker cs_rect_2_3_2 vassal_russian_vladislav_vepsian_auxiliaries +marker cs_rect_2_3_3 vassal_russian_aleksandr_rostov +marker cs_rect_2_3_4 vassal_teutonic_hermann_ugaunian_auxiliaries +marker cs_rect_2_3_5 lord_teutonic_hermann +marker cs_rect_2_3_6 lord_teutonic_knud_and_abel +marker cs_rect_2_3_7 vassal_teutonic_knud_and_abel_estonian_auxiliaries + +marker cs_rect_2_4_1 lord_russian_gavrilo +marker cs_rect_2_4_2 vassal_russian_vladislav_ingrian_auxiliaries +marker cs_rect_2_4_3 vassal_russian_aleksandr_yaroslavl +marker cs_rect_2_4_4 vassal_teutonic_hermann_helmond_von_luneburg +marker cs_rect_2_4_5 lord_teutonic_heinrich +marker cs_rect_2_4_6 lord_teutonic_yaroslav +marker2 cs_rect_2_4_7 marker_castle_teutonic marker_castle_russian + +marker cs_rect_2_5_1 vassal_russian_vladislav_vodian_auxiliaries +marker cs_rect_2_5_2 vassal_russian_vladislav_izhoran_auxiliaries +marker cs_rect_2_5_3 vassal_russian_aleksandr_mongols +marker cs_rect_2_5_4 vassal_teutonic_hermann_johannes_von_dolen +marker cs_rect_2_5_5 lord_teutonic_rudolf +marker cs_rect_2_5_6 vassal_teutonic_rudolf_summer_crusaders +#marker2 cs_rect_2_5_7 marker_castle_teutonic marker_castle_russian + +marker cs_rect_2_6_1 vassal_russian_gavrilo_borderland_russians +marker cs_rect_2_6_2 vassal_russian_domash_novgorod +#marker cs_rect_2_6_3 vassal_russian_aleksandr_mongols +marker cs_rect_2_6_4 vassal_teutonic_heinrich_odward_von_lode +marker cs_rect_2_6_5 vassal_teutonic_andreas_teutonic_vassals +marker cs_rect_2_6_6 vassal_teutonic_rudolf_ex_sword_brethren +marker cs_rect_2_6_7 vassal_teutonic_yaroslav_mstislavich_partisans + +marker cs_rect_2_7_1 vassal_russian_gavrilo_pskov_militia +marker cs_rect_2_7_2 vassal_russian_domash_novgorod +#marker cs_rect_2_7_3 vassal_russian_andrey_kipchaqs +marker cs_rect_2_7_4 vassal_teutonic_heinrich_heinrich_von_lode +marker cs_rect_2_7_5 vassal_teutonic_andreas_lettgallian_auxiliaries +marker cs_rect_2_7_6 vassal_teutonic_rudolf_jerwen_teutonic_vassals +marker2 cs_rect_2_7_7 marker_pursuit_teutonic marker_pursuit_russian diff --git a/tools/build_counters3.sh b/tools/build_counters3.sh new file mode 100644 index 0000000..142d802 --- /dev/null +++ b/tools/build_counters3.sh @@ -0,0 +1,5 @@ +mkdir -p service300 +montage -mode concatenate -tile 2x counters300/lord_teutonic_andreas.a.png counters300/lord_teutonic_andreas.b.png counters300/lord_teutonic_heinrich.a.png counters300/lord_teutonic_heinrich.b.png counters300/lord_teutonic_hermann.a.png counters300/lord_teutonic_hermann.b.png counters300/lord_teutonic_knud_and_abel.a.png counters300/lord_teutonic_knud_and_abel.b.png counters300/lord_teutonic_rudolf.a.png counters300/lord_teutonic_rudolf.b.png counters300/lord_teutonic_yaroslav.a.png counters300/lord_teutonic_yaroslav.b.png service300/service_lords_teutonic.png +montage -mode concatenate -tile 2x counters300/vassal_teutonic_andreas_lettgallian_auxiliaries.a.png counters300/vassal_teutonic_andreas_lettgallian_auxiliaries.b.png counters300/vassal_teutonic_andreas_summer_crusaders.a.png counters300/vassal_teutonic_andreas_summer_crusaders.b.png counters300/vassal_teutonic_andreas_teutonic_vassals.a.png counters300/vassal_teutonic_andreas_teutonic_vassals.b.png counters300/vassal_teutonic_heinrich_heinrich_von_lode.a.png counters300/vassal_teutonic_heinrich_heinrich_von_lode.b.png counters300/vassal_teutonic_heinrich_odward_von_lode.a.png counters300/vassal_teutonic_heinrich_odward_von_lode.b.png counters300/vassal_teutonic_hermann_helmond_von_luneburg.a.png counters300/vassal_teutonic_hermann_helmond_von_luneburg.b.png counters300/vassal_teutonic_hermann_johannes_von_dolen.a.png counters300/vassal_teutonic_hermann_johannes_von_dolen.b.png counters300/vassal_teutonic_hermann_ugaunian_auxiliaries.a.png counters300/vassal_teutonic_hermann_ugaunian_auxiliaries.b.png counters300/vassal_teutonic_knud_and_abel_dietrich_von_kivel.a.png counters300/vassal_teutonic_knud_and_abel_dietrich_von_kivel.b.png counters300/vassal_teutonic_knud_and_abel_estonian_auxiliaries.a.png counters300/vassal_teutonic_knud_and_abel_estonian_auxiliaries.b.png counters300/vassal_teutonic_knud_and_abel_otto_von_luneburg.a.png counters300/vassal_teutonic_knud_and_abel_otto_von_luneburg.b.png counters300/vassal_teutonic_rudolf_ex_sword_brethren.a.png counters300/vassal_teutonic_rudolf_ex_sword_brethren.b.png counters300/vassal_teutonic_rudolf_jerwen_teutonic_vassals.a.png counters300/vassal_teutonic_rudolf_jerwen_teutonic_vassals.b.png counters300/vassal_teutonic_rudolf_summer_crusaders.a.png counters300/vassal_teutonic_rudolf_summer_crusaders.b.png counters300/vassal_teutonic_yaroslav_mstislavich_partisans.a.png counters300/vassal_teutonic_yaroslav_mstislavich_partisans.b.png service300/service_vassals_teutonic.png +montage -mode concatenate -tile 2x counters300/lord_russian_aleksandr.a.png counters300/lord_russian_aleksandr.b.png counters300/lord_russian_andrey.a.png counters300/lord_russian_andrey.b.png counters300/lord_russian_domash.a.png counters300/lord_russian_domash.b.png counters300/lord_russian_gavrilo.a.png counters300/lord_russian_gavrilo.b.png counters300/lord_russian_karelians.a.png counters300/lord_russian_karelians.b.png counters300/lord_russian_vladislav.a.png counters300/lord_russian_vladislav.b.png service300/service_lords_russian.png +montage -mode concatenate -tile 2x counters300/vassal_russian_aleksandr_mongols.a.png counters300/vassal_russian_aleksandr_mongols.b.png counters300/vassal_russian_aleksandr_pereyaslavl.a.png counters300/vassal_russian_aleksandr_pereyaslavl.b.png counters300/vassal_russian_aleksandr_rostov.a.png counters300/vassal_russian_aleksandr_rostov.b.png counters300/vassal_russian_aleksandr_yaroslavl.a.png counters300/vassal_russian_aleksandr_yaroslavl.b.png counters300/vassal_russian_andrey_kipchaqs.a.png counters300/vassal_russian_andrey_kipchaqs.b.png counters300/vassal_russian_andrey_suzdal.a.png counters300/vassal_russian_andrey_suzdal.b.png counters300/vassal_russian_andrey_vladimir.a.png counters300/vassal_russian_andrey_vladimir.b.png counters300/vassal_russian_domash_novgorod.a.png counters300/vassal_russian_domash_novgorod.b.png counters300/vassal_russian_gavrilo_borderland_russians.a.png counters300/vassal_russian_gavrilo_borderland_russians.b.png counters300/vassal_russian_gavrilo_pskov_militia.a.png counters300/vassal_russian_gavrilo_pskov_militia.b.png counters300/vassal_russian_gavrilo_pskov.a.png counters300/vassal_russian_gavrilo_pskov.b.png counters300/vassal_russian_vladislav_izhoran_auxiliaries.a.png counters300/vassal_russian_vladislav_izhoran_auxiliaries.b.png counters300/vassal_russian_vladislav_ingrian_auxiliaries.a.png counters300/vassal_russian_vladislav_ingrian_auxiliaries.b.png counters300/vassal_russian_vladislav_vepsian_auxiliaries.a.png counters300/vassal_russian_vladislav_vepsian_auxiliaries.b.png counters300/vassal_russian_vladislav_vodian_auxiliaries.a.png counters300/vassal_russian_vladislav_vodian_auxiliaries.b.png service300/service_vassals_russian.png diff --git a/tools/build_map.sh b/tools/build_map.sh new file mode 100644 index 0000000..1af18c4 --- /dev/null +++ b/tools/build_map.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -x + +mutool extract -r "../HIRES/Nevsky - Game Board_CORRECTED 080919.pdf" +mv image-0017.png map300_uncropped.png + +# ArtBox 63.5197 63.5197 1287.52 1647.52 +# 5100x6600 +convert map300_uncropped.png -gravity Center -crop 5100x6600+0+0 +repage map300.png +rm map300_uncropped.png + +# convert map300.png -colorspace RGB -resize 33.3333333% -colorspace sRGB map100.png +# convert map300.png -colorspace RGB -resize 66.6666667% -colorspace sRGB map200.png +convert map300.png -colorspace RGB -resize 25% -colorspace sRGB map75.png +convert map300.png -colorspace RGB -resize 50% -colorspace sRGB map150.png diff --git a/tools/build_mats.sh b/tools/build_mats.sh new file mode 100644 index 0000000..a9e348b --- /dev/null +++ b/tools/build_mats.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +set -x + +mkdir -p tmp/mat +mkdir -p output300 + +if [ ! -f ../HIRES/raw_mat_01.1200.png ] +then + gs -sDEVICE=png16m -r1200 -o ../HIRES/raw_mat_%02d.1200.png "../HIRES/Lord Mats-FINAL-nf.pdf" +fi + +for F in ../HIRES/raw_mat_*.1200.png +do + convert -colorspace RGB -scale 25% -colorspace sRGB $F ${F/.1200.png/.png} +done + +# crop: 150,150 to 1650,1650 = 1500x1500 + +# ARGS="-gravity Center -crop 1500x1500+0+0 +repage -background #d0bf7d -flatten" +ARGS="-gravity Center -crop 1440x1440+0+0 +repage -background #d0bf7d -flatten" + +convert ../HIRES/raw_mat_01.png $ARGS output300/mat_russian_aleksandr.png +convert ../HIRES/raw_mat_02.png $ARGS output300/mat_russian_andrey.png +convert ../HIRES/raw_mat_03.png $ARGS output300/mat_russian_domash.png +convert ../HIRES/raw_mat_04.png $ARGS output300/mat_russian_gavrilo.png +convert ../HIRES/raw_mat_05.png $ARGS output300/mat_russian_vladislav.png +convert ../HIRES/raw_mat_06.png $ARGS output300/mat_russian_karelians.png +convert ../HIRES/raw_mat_07.png $ARGS output300/mat_teutonic_yaroslav.png +convert ../HIRES/raw_mat_08.png $ARGS output300/mat_teutonic_knud_and_abel.png +convert ../HIRES/raw_mat_09.png $ARGS output300/mat_teutonic_rudolf.png +convert ../HIRES/raw_mat_10.png $ARGS output300/mat_teutonic_heinrich.png +convert ../HIRES/raw_mat_11.png $ARGS output300/mat_teutonic_hermann.png +convert ../HIRES/raw_mat_12.png $ARGS output300/mat_teutonic_andreas.png +convert ../HIRES/raw_mat_13.png $ARGS output300/mat_battle.png diff --git a/tools/build_screen.sh b/tools/build_screen.sh new file mode 100644 index 0000000..607ca7b --- /dev/null +++ b/tools/build_screen.sh @@ -0,0 +1,10 @@ +mkdir -p tmp +convert -size 2160x750 gradient:white-none tmp/gradient.png +convert -resize 2250x750 -gravity Center -crop 2160x750+0+0 +repage ../HIRES/screen1.png tmp/screen1.png +convert -resize 2250x750 -gravity Center -crop 2160x750+0+0 +repage ../HIRES/screen2.png tmp/screen2.png +convert -resize 2250x750 -gravity Center -crop 2160x750+0+0 +repage ../HIRES/screen3.png tmp/screen3.png +convert -resize 2250x750 -gravity Center -crop 2160x750+0+0 +repage ../HIRES/screen4.png tmp/screen4.png +convert tmp/screen1.png gradient.png -compose Over -flatten screen1.png +convert tmp/screen2.png gradient.png -compose Over -flatten screen2.png +convert tmp/screen3.png gradient.png -compose Over -flatten screen3.png +convert tmp/screen4.png gradient.png -compose Over -flatten screen4.png diff --git a/tools/build_stickers.sh b/tools/build_stickers.sh new file mode 100644 index 0000000..3e49e69 --- /dev/null +++ b/tools/build_stickers.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -x + +#gs -sDEVICE=png16m -r1200 -o tmp/stickers1200.png ../HIRES/stickers3.pdf + +mkdir -p tmp + +# 672x672 stickers @1200 +#pngtopnm tmp/stickers1200.png > tmp/stickers1200.ppm +pnmcut -top 1912 -height 672 tmp/stickers1200.ppm > tmp/row1x.ppm +pnmcut -top 2856 -height 672 tmp/stickers1200.ppm > tmp/row2x.ppm + +I=1 +for LEFT in 405 641 877 1113 1349 1586 1822 +do + pnmcut -left $(expr 4 '*' $LEFT) -width 672 tmp/row1x.ppm | pnmtopng > tmp/lord_teutonic_$I.png + pnmcut -left $(expr 4 '*' $LEFT) -width 672 tmp/row2x.ppm | pnmtopng > tmp/lord_russian_$I.png + I=$(expr $I + 1) +done + +# 150dpi -> 84x84 +# 75dpi -> 42x42 +# 3d -> 42x28 +for I in 1 2 3 4 5 6 7 +do + convert tmp/lord_teutonic_$I.png -colorspace RGB -geometry 84x56! -colorspace sRGB output150/lord_teutonic_${I}_3d.png + convert tmp/lord_russian_$I.png -colorspace RGB -geometry 84x56! -colorspace sRGB output150/lord_russian_${I}_3d.png + convert tmp/lord_teutonic_$I.png -colorspace RGB -geometry 84x84! -colorspace sRGB output150/lord_teutonic_${I}.png + convert tmp/lord_russian_$I.png -colorspace RGB -geometry 84x84! -colorspace sRGB output150/lord_russian_${I}.png + + convert tmp/lord_teutonic_$I.png -colorspace RGB -geometry 42x28! -colorspace sRGB output75/lord_teutonic_${I}_3d.png + convert tmp/lord_russian_$I.png -colorspace RGB -geometry 42x28! -colorspace sRGB output75/lord_russian_${I}_3d.png + convert tmp/lord_teutonic_$I.png -colorspace RGB -geometry 42x42! -colorspace sRGB output75/lord_teutonic_${I}.png + convert tmp/lord_russian_$I.png -colorspace RGB -geometry 42x42! -colorspace sRGB output75/lord_russian_${I}.png +done + diff --git a/tools/colors.mjs b/tools/colors.mjs new file mode 100644 index 0000000..4af8545 --- /dev/null +++ b/tools/colors.mjs @@ -0,0 +1,108 @@ +import { formatHex, filterBrightness, parseHex, convertRgbToOklab, convertRgbToLrgb, interpolate } from 'culori' + +const yuv = true; +const gamma = 2.2; + +const data = [ +[".mat .background", "d1c07e"], +[".card.teutonic", "e1e6e8"], +[".card.russian", "e1d6c1"], +[".service_marker.teutonic.vassal", "777474"], +[".service_marker.russian.vassal", "f0ead8"], +[".asset.sled", "e5dcc1"], +[".asset.boat", "adceed"], +[".asset.cart.x1", "daba8b"], +[".asset.cart.x2", "d1a973"], +[".asset.cart.x4", "c4975b"], +[".asset.coin.x1", "d2d5d4"], +[".asset.coin.x2", "d2d5d4"], +[".asset.coin.x3", "b3b5b4"], +[".asset.coin.x4", "b3b5b4"], +[".asset.prov.x1", "ffe293"], +[".asset.prov.x2", "ffe293"], +[".asset.prov.x3", "ffcd66"], +[".asset.prov.x4", "ffcd66"], +[".asset.ship.x1", "79b7e4"], +[".asset.ship.x2", "79b7e4"], +[".asset.ship.x4", "5da9dd"], +[".asset.loot.x1", "f0b64f"], +[".asset.loot.x2", "eda44c"], +[".asset.loot.x3", "eb924a"], +[".asset.loot.x4", "e1884a"], +[".marker.battle", "d0bf7d"], +[".marker.storm", "d0bf7d"], +[".marker.pursuit", "c6ab7f"], +[".marker.turn.campaign", "6a8aa8"], +[".marker.turn.levy", "967348"], +[".marker.teutonic.victory", "ffd400"], +[".marker.teutonic.siege", "a39382"], +[".marker.russian.conquered", "649655"], +[".marker.russian.enemy_lords_removed", "ffd400"], +[".marker.russian.victory", "2d8b47"], +[".marker.walls", "e3dedc"], +[".marker.russian.number", "c6992f"], +[".marker.teutonic.number", "a02532"], + +/* +[".unit", "ffd768"], +[".marker.supply_source", "e6dcb9"], +[".marker.moved_fought", "0072bc"], +[".marker.pleskau_black", "324b5b"], +[".marker.pleskau_white", "e3dedc"], +*/ +].map(([sel,color])=>[ sel, parseHex(color) ]) + +const colors = `knights_fill ffffff +knights_stroke d1d3d4 +asiatic_horse_fill f7df93 +asiatic_horse_stroke 908357 +serfs_fill e39c43 +serfs_stroke b17b33 +militia_fill cc6a2c +militia_stroke 773b0c +men_at_arms_fill c0b6b3 +men_at_arms_stroke 716c6b +die_1 662c91 +die_2 ee161c +die_3 f7941d +die_4 ffd400 +die_5 26903a` + +let css = [] + +function brighten(color, n) { + return { mode: 'lrgb', + r: 1 - (1-color.r) * n, + g: 1 - (1-color.g) * n, + b: 1 - (1-color.b) * n, + } +} + +function darken(color, n) { + return { mode: 'lrgb', + r: (color.r) * n, + g: (color.g) * n, + b: (color.b) * n, + } +} + +let white = parseHex('#fff') +let black = parseHex('#000') + +for (let [ sel, rgb ] of data) { + let base = formatHex(rgb) + //let hi = formatHex(brighten(convertRgbToLrgb(rgb), 0.8)) + //let lo = formatHex(darken(convertRgbToLrgb(rgb), 0.8)) + //let sh = formatHex(darken(convertRgbToLrgb(rgb), 0.125)) + //let hi = formatHex(interpolate([rgb,white],'lrgb')(0.2)) + //let lo = formatHex(interpolate([rgb,black],'lrgb')(0.2)) + //let sh = formatHex(interpolate([rgb,black],'lrgb')(0.6)) + let hic = convertRgbToOklab(rgb); hic.l = Math.min(1,hic.l+0.1) + let loc = convertRgbToOklab(rgb); loc.l = Math.max(0,loc.l-0.1) + let shc = convertRgbToOklab(rgb); shc.l = Math.max(0,shc.l-0.4) + let sh = formatHex(shc) + let hi = formatHex(hic) + let lo = formatHex(loc) + css.push(`${sel} { background-color: ${base}; border-color: ${hi} ${lo} ${lo} ${hi}; box-shadow: 0 0 0 1px ${sh}, 1px 2px 4px #0008; }`) +} +console.log(css.join("\n")) diff --git a/tools/genboxes.py b/tools/genboxes.py new file mode 100644 index 0000000..92488ed --- /dev/null +++ b/tools/genboxes.py @@ -0,0 +1,65 @@ +mode = None + +list = [] + +x = y = w = h = 0 +name = None + +def flush(): + global x, y, w, h, name + if mode == 'rect': + list.append((x,y,w,h,'box',name)) + if mode == 'circle': + x = cx - rx + y = cy - ry + w = rx * 2 + h = ry * 2 + list.append((x,y,w,h,'circle',name)) + x = y = w = h = 0 + name = None + +for line in open("boxes.svg").readlines(): + line = line.strip() + if line == "') + print('
') + print('') + for (x,y,w,h,c,name) in list: + x = round(x/4) - 1 + y = round(y/4) - 1 + w = round(w/4) + 2 + h = round(h/4) + 2 + print(f'
{name}
') + print('
') + +#print_html() +print_list() diff --git a/tools/gencss.js b/tools/gencss.js new file mode 100644 index 0000000..4edc4be --- /dev/null +++ b/tools/gencss.js @@ -0,0 +1,5 @@ +const h = 42 +for (let i = 0; i < 15; ++i) + console.log(`.service_marker.image${i}{background-position:0 -${i*h}px}`) +for (let i = 0; i < 15; ++i) + console.log(`.service_marker.image${i}:hover{background-position:100% -${i*h}px}`) diff --git a/tools/gencyl.js b/tools/gencyl.js new file mode 100644 index 0000000..bae34b9 --- /dev/null +++ b/tools/gencyl.js @@ -0,0 +1,51 @@ +// physical cylinders are diameter 15mm x 10mm +// at 75dpi => 44px x 29px +// stickers: 42x28 +// image: 44x? - outline at 1 to 2 - start at 1.5 + +const fs = require('fs') + +function print_lord(output, side, label) { + let image = fs.readFileSync(label).toString('base64') + let svg = [] + let bd = '#222' + let f = 'url(#g)' + svg.push('') + svg.push('') + + if (1) { + svg.push('') + if (side === 'russian') { + svg.push('') + svg.push('') + svg.push('') + bd = '#555' + } else { + svg.push('') + svg.push('') + svg.push('') + bd = '#111' + } + svg.push('') + } else { + if (side === 'russian') { + f = '#ddd' + bd = '#222' + } else { + f = '#555' + bd = '#222' + } + } + + svg.push(``) + svg.push(``) + svg.push(``) + + svg.push('') + fs.writeFileSync(output, svg.join("\n") + "\n") +} + +for (let i = 1; i <= 7; ++i) { + print_lord(`images/lord_teutonic_${i}.svg`, "teutonic", `tools/output150/lord_teutonic_${i}_3d.png`) + print_lord(`images/lord_russian_${i}.svg`, "russian", `tools/output150/lord_russian_${i}_3d.png`) +} diff --git a/tools/gendata.js b/tools/gendata.js new file mode 100644 index 0000000..2968023 --- /dev/null +++ b/tools/gendata.js @@ -0,0 +1,705 @@ +// Run this script inside the "tools" directory to generate data.js and build_counters3.sh + +"use strict" + +const fs = require('fs') + +// :r !python3 genboxes.py +const boxes = { +"Wesenberg": [1448,3625,304,60], +"Fellin": [1013,4583,184,61], +"Odenpäh": [1378,5103,250,61], +"Adsel": [1504,5612,185,60], +"Wenden": [909,5759,232,60], +"Luga": [2667,3295,148,62], +"Kaibolovo": [2904,3522,285,62], +"Koporye": [3133,3160,241,62], +"Neva": [3924,2934,148,62], +"Volkhov": [4591,3783,231,63], +"Lovat": [4243,5581,187,63], +"Porkhov": [3515,5467,241,63], +"Izborsk": [2240,5431,241,62], +"Velikiye Luki": [3706,6347,351,61], +"Tesovo": [3936,4102,121,32], +"Zheltsy": [3501,4176,128,30], +"Sablia": [3788,4541,104,31], +"Gdov": [2427,4149,88,30], +"Dubrovno": [3153,5214,161,31], +"Ostrov": [2746,5717,115,30], +"Rositten": [2046,6307,146,30], +"Kirrumpäh": [1877,5389,175,30], +"Pernau": [517,4580,118,30], +"Narwia": [2371,3549,123,31], +"Wierland": [1999,3680,200,100], +"Warbola": [292,3797,142,31], +"Waiga": [1535,4113,200,100], +"Jerwen": [1064,3946,200,100], +"Harrien": [567,3983,200,100], +"Sackala": [617,4769,200,100], +"Metsepole": [509,5226,200,100], +"Lettgallia": [2048,5777,200,100], +"Tolowa": [1541,5933,200,100], +"Ugaunia": [1957,4940,200,100], +"Revala": [1030,3410,200,100], +"Velikaya River": [3029,6090,200,100], +"Sorot River": [3299,5781,200,100], +"Shelon River": [3654,4864,200,100], +"Zhelcha River": [2782,4586,200,100], +"Plyussa River": [2829,4234,200,100], +"Ingria": [3820,3639,200,100], +"Vod": [3488,3345,200,100], +"Izhora": [4074,3323,200,100], +"Karelia": [3833,2408,200,100], +"Ladoga": [4619,2817,238,90], +"Novgorod": [4318,4315,333,112], +"Rusa": [4329,5166,205,92], +"Riga": [273,6231,205,91], +"Pskov": [2680,5263,205,91], +"Dorpat": [1625,4589,253,91], +"Leal": [108,4266,205,91], +"Reval": [601,3564,206,91], +"box1": [40,168,592,917], +"box2": [650,168,591,913], +"box3": [1313,167,591,916], +"box4": [1922,167,590,916], +"box5": [2587,167,592,918], +"box6": [3196,167,588,916], +"box7": [3859,167,594,916], +"box8": [4469,166,591,918], +"box9": [39,1119,594,915], +"Victory": [172,183,217,215], +"Turn": [399,184,216,214], +"Novgorod Veche": [4193,5847,844,628], +"Uzmen": [2112,4692,200,100], +"way-crossroads": [1500,4717,462,149], +"way-wirz": [1295,4526,175,350], +"way-peipus-east": [2232,4197,220,465], +"way-peipus-north": [2065,3836,361,228], +"way-peipus-west": [1988,4141,218,520], +} + +let data = [] +function print(str) { + data.push(str) +} + +var locmap = {} + +// 0=offmap, 1-N=map locales, 100-M=calendar boxes +var locales = [null] +var ways = [] +var waterways = [] +var trackways = [] + +const scale = 1 + +function defloc(region, stronghold, type, name) { + let [x, y, w, h] = boxes[name] + x = Math.round(x * scale) + y = Math.round(y * scale) + w = Math.round(w * scale) + h = Math.round(h * scale) + locmap[name] = locales.length + locales.push({ name, type, stronghold, region, ways: [], box: { x, y, w, h } }) +} + +function defway(type, list) { + let ix = ways.length + list = list.map(name=>locmap[name]).sort((a,b)=>a-b) + ways.push({type, locales: list}) + for (let from of list) { + for (let to of list) { + if (from !== to) { + let old = locales[from].ways.find(w => w[0] === to) + if (old) + old.push(ix) + else + locales[from].ways.push([to, ix]) + } + } + } + return ways[ix] +} + +function waterway(locs) { return defway('waterway', locs.split(", ")) } +function trackway(locs) { return defway('trackway', locs.split(", ")) } + +defloc("Danish Estonia", 3, "bishopric", "Reval") +defloc("Danish Estonia", 2, "castle", "Wesenberg") +defloc("Danish Estonia", 0, "town", "Narwia") +defloc("Danish Estonia", 0, "town", "Warbola") +defloc("Danish Estonia", 0, "region", "Harrien") +defloc("Danish Estonia", 0, "region", "Revala") +defloc("Danish Estonia", 0, "region", "Wierland") + +defloc("Crusader Livonia", 3, "bishopric", "Dorpat") +defloc("Crusader Livonia", 3, "bishopric", "Leal") +defloc("Crusader Livonia", 3, "bishopric", "Riga") +defloc("Crusader Livonia", 2, "castle", "Adsel") +defloc("Crusader Livonia", 2, "castle", "Fellin") +defloc("Crusader Livonia", 2, "castle", "Odenpäh") +defloc("Crusader Livonia", 2, "castle", "Wenden") +defloc("Crusader Livonia", 0, "town", "Kirrumpäh") +defloc("Crusader Livonia", 0, "town", "Pernau") +defloc("Crusader Livonia", 0, "town", "Rositten") +defloc("Crusader Livonia", 0, "region", "Jerwen") +defloc("Crusader Livonia", 0, "region", "Lettgallia") +defloc("Crusader Livonia", 0, "region", "Metsepole") +defloc("Crusader Livonia", 0, "region", "Sackala") +defloc("Crusader Livonia", 0, "region", "Tolowa") +defloc("Crusader Livonia", 0, "region", "Ugaunia") +defloc("Crusader Livonia", 0, "region", "Waiga") + +defloc("Novgorodan Rus", 3, "archbishopric", "Novgorod") +defloc("Novgorodan Rus", 3, "city", "Ladoga") +defloc("Novgorodan Rus", 3, "city", "Pskov") +defloc("Novgorodan Rus", 3, "city", "Rusa") +defloc("Novgorodan Rus", 0, "traderoute", "Lovat") +defloc("Novgorodan Rus", 0, "traderoute", "Luga") +defloc("Novgorodan Rus", 0, "traderoute", "Neva") +defloc("Novgorodan Rus", 0, "traderoute", "Volkhov") +defloc("Novgorodan Rus", 1, "fort", "Izborsk") +defloc("Novgorodan Rus", 1, "fort", "Kaibolovo") +defloc("Novgorodan Rus", 1, "fort", "Koporye") +defloc("Novgorodan Rus", 1, "fort", "Porkhov") +defloc("Novgorodan Rus", 1, "fort", "Velikiye Luki") +defloc("Novgorodan Rus", 0, "town", "Dubrovno") +defloc("Novgorodan Rus", 0, "town", "Gdov") +defloc("Novgorodan Rus", 0, "town", "Ostrov") +defloc("Novgorodan Rus", 0, "town", "Sablia") +defloc("Novgorodan Rus", 0, "town", "Tesovo") +defloc("Novgorodan Rus", 0, "town", "Zheltsy") +defloc("Novgorodan Rus", 0, "region", "Ingria") +defloc("Novgorodan Rus", 0, "region", "Izhora") +defloc("Novgorodan Rus", 0, "region", "Karelia") +defloc("Novgorodan Rus", 0, "region", "Plyussa River") +defloc("Novgorodan Rus", 0, "region", "Shelon River") +defloc("Novgorodan Rus", 0, "region", "Sorot River") +defloc("Novgorodan Rus", 0, "region", "Uzmen") +defloc("Novgorodan Rus", 0, "region", "Velikaya River") +defloc("Novgorodan Rus", 0, "region", "Vod") +defloc("Novgorodan Rus", 0, "region", "Zhelcha River") + +waterway("Dorpat, Narwia, Gdov, Uzmen").name = "Pleipat W" +waterway("Gdov, Uzmen").name = "Pleipat E" +waterway("Fellin, Dorpat, Odenpäh").name = "Wirz" +trackway("Dorpat, Odenpäh, Ugaunia").name = "Crossroads" + +waterway("Uzmen, Pskov") +waterway("Uzmen, Zhelcha River") +waterway("Novgorod, Shelon River, Rusa") +waterway("Pernau, Fellin, Jerwen") +waterway("Riga, Wenden") +waterway("Wenden, Adsel") +waterway("Pskov, Ostrov") +waterway("Ostrov, Velikaya River") +waterway("Sorot River, Velikaya River") +waterway("Rusa, Lovat") +waterway("Lovat, Velikiye Luki") +waterway("Shelon River, Dubrovno") +waterway("Shelon River, Porkhov") +waterway("Narwia, Plyussa River") +waterway("Luga, Kaibolovo") +waterway("Kaibolovo, Zheltsy") +waterway("Zheltsy, Sablia") +waterway("Zheltsy, Tesovo") +waterway("Ladoga, Volkhov") +waterway("Volkhov, Novgorod") +waterway("Neva, Ladoga") + +trackway("Reval, Revala") +trackway("Revala, Wesenberg") +trackway("Wierland, Narwia") +trackway("Narwia, Kaibolovo") +trackway("Wierland, Waiga") +trackway("Wesenberg, Jerwen") +trackway("Reval, Warbola") +trackway("Warbola, Harrien") +trackway("Harrien, Jerwen") +trackway("Warbola, Leal") + +trackway("Waiga, Dorpat") +trackway("Leal, Pernau") +trackway("Fellin, Sackala") +trackway("Sackala, Metsepole") +trackway("Metsepole, Wenden") +trackway("Wenden, Tolowa") +trackway("Tolowa, Rositten") +trackway("Lettgallia, Rositten") +trackway("Adsel, Tolowa, Lettgallia") +trackway("Adsel, Kirrumpäh") +trackway("Odenpäh, Kirrumpäh") +trackway("Kirrumpäh, Izborsk") +trackway("Ugaunia, Uzmen") +trackway("Ugaunia, Izborsk") +trackway("Lettgallia, Ostrov") +trackway("Lettgallia, Izborsk") + +trackway("Izborsk, Pskov") +trackway("Kaibolovo, Koporye") +trackway("Koporye, Vod") +trackway("Vod, Neva") +trackway("Vod, Ingria") +trackway("Karelia, Neva") +trackway("Neva, Izhora") +trackway("Izhora, Ladoga") +trackway("Izhora, Ingria") +trackway("Ingria, Tesovo") +trackway("Tesovo, Novgorod") +trackway("Novgorod, Sablia") +trackway("Sablia, Shelon River") + +trackway("Gdov, Plyussa River") +trackway("Plyussa River, Zheltsy") +trackway("Plyussa River, Zhelcha River") +trackway("Zhelcha River, Pskov") +trackway("Pskov, Dubrovno") +trackway("Dubrovno, Porkhov") +trackway("Porkhov, Sorot River") +trackway("Velikaya River, Velikiye Luki") + +let seaports = [ + "Riga", "Pernau", "Leal", "Reval", "Narwia", "Luga", "Koporye", "Neva" +].map(name => locmap[name]).sort((a,b)=>a-b) + +function dumplist(name, list) { + print(name + ":[") + for (let item of list) + print(JSON.stringify(item) + ",") + print("],") +} + +function seats(list) { + return list.split(", ").map(name => locmap[name]).sort((a,b)=>a-b) +} + +let lords = [ + + { + side: "Teutonic", + name: "Andreas", + full_name: "Andreas von Felben", + title: "Landmeister in Livonia", + seats: seats("Riga, Wenden"), + marshal: 2, + fealty: 2, + service: 4, + lordship: 3, + command: 3, + forces: { + knights: 1, + sergeants: 2, + light_horse: 0, + men_at_arms: 1, + militia: 0, + }, + assets: { + transport: 2, + prov: 2, + }, + ships: 1, + }, + + { + side: "Teutonic", + name: "Heinrich", + full_name: "Heinrich", + title: "Bishop of Ösel-Wiek", + seats: seats("Leal"), + marshal: 0, + fealty: 3, + service: 4, + lordship: 2, + command: 1, + forces: { + knights: 1, + sergeants: 1, + light_horse: 0, + men_at_arms: 1, + militia: 0, + }, + assets: { + ship: 1, + coin: 2, + prov: 1, + }, + ships: 1, + }, + + { + side: "Teutonic", + name: "Hermann", + full_name: "Hermann", + title: "Bishop of Dorpat", + seats: seats("Dorpat, Odenpäh"), + marshal: 1, + fealty: 4, + service: 4, + lordship: 3, + command: 3, + forces: { + knights: 1, + sergeants: 1, + light_horse: 0, + men_at_arms: 2, + militia: 0, + }, + assets: { + transport: 1, + coin: 1, + prov: 1, + }, + ships: 0, + }, + + { + side: "Teutonic", + name: "Knud & Abel", + full_name: "Knud & Abel", + title: "Princes of Denmark", + seats: seats("Reval, Wesenburg"), + marshal: 0, + fealty: 2, + service: 3, + lordship: 3, + command: 2, + forces: { + knights: 1, + sergeants: 1, + light_horse: 3, + men_at_arms: 0, + militia: 0, + }, + assets: { + ship: 2, + prov: 2, + }, + ships: 1, + }, + + { + side: "Teutonic", + name: "Rudolf", + full_name: "Rudolf von Kassel", + title: "Castellan of Wenden", + seats: seats("Wenden"), + marshal: 0, + fealty: 5, + service: 2, + lordship: 1, + command: 3, + forces: { + knights: 1, + sergeants: 1, + light_horse: 0, + men_at_arms: 1, + militia: 0, + }, + assets: { + transport: 1, + prov: 1, + }, + ships: 0, + }, + + { + side: "Teutonic", + name: "Yaroslav", + full_name: "Yaroslav", + title: "Exile of Pskov", + seats: seats("Odenpäh, Pskov"), + marshal: 0, + fealty: 4, + service: 2, + lordship: 1, + command: 2, + forces: { + knights: 1, + sergeants: 0, + light_horse: 1, + men_at_arms: 1, + militia: 0, + }, + assets: { + transport: 1, + prov: 1, + }, + ships: 0, + }, + + { + side: "Russian", + name: "Aleksandr", + full_name: "Aleksandr", + title: "Prince of Novgorod", + seats: seats("Novgorod, Rusa"), + marshal: 2, + fealty: 0, + service: 6, + lordship: 4, + command: 3, + forces: { + knights: 3, + sergeants: 0, + light_horse: 0, + men_at_arms: 2, + militia: 0, + }, + assets: { + transport: 2, + }, + ships: 1, + }, + + { + side: "Russian", + name: "Andrey", + full_name: "Andrey", + title: "Prince of Suzdal", + seats: seats("Novgorod, Rusa"), + marshal: 1, + fealty: 4, + service: 5, + lordship: 3, + command: 2, + forces: { + knights: 3, + sergeants: 0, + light_horse: 0, + men_at_arms: 2, + militia: 0, + }, + assets: { + transport: 2, + }, + ships: 1, + }, + + { + side: "Russian", + name: "Domash", + full_name: "Domash", + title: "Tysyatskiy of Novgorod", + seats: seats("Novgorod"), + marshal: 0, + fealty: 4, + service: 4, + lordship: 2, + command: 2, + forces: { + knights: 0, + sergeants: 1, + light_horse: 1, + men_at_arms: 2, + militia: 1, + }, + assets: { + transport: 4, + prov: 4, + }, + ships: 1, + }, + + { + side: "Russian", + name: "Gavrilo", + full_name: "Gavrilo", + title: "Voyevoda of Pskov", + seats: seats("Pskov"), + marshal: 0, + fealty: 3, + service: 4, + lordship: 3, + command: 2, + forces: { + knights: 1, + sergeants: 0, + light_horse: 1, + men_at_arms: 1, + militia: 1, + }, + assets: { + transport: 2, + coin: 1, + prov: 2, + }, + ships: 1, + }, + + { + side: "Russian", + name: "Karelians", + full_name: "Karelians", + title: "Tributaries of Novgorod", + seats: seats("Ladoga"), + marshal: 0, + fealty: 4, + service: 2, + lordship: 1, + command: 2, + forces: { + knights: 0, + sergeants: 0, + light_horse: 1, + men_at_arms: 0, + militia: 4, + }, + assets: { + transport: 1, + }, + ships: 1, + }, + + { + side: "Russian", + name: "Vladislav", + full_name: "Vladislav", + title: "Bailiff of Ladoga", + seats: seats("Ladoga"), + marshal: 0, + fealty: 5, + service: 3, + lordship: 2, + command: 3, + forces: { + knights: 0, + sergeants: 1, + light_horse: 1, + men_at_arms: 2, + militia: 0, + }, + assets: { + transport: 1, + prov: 1, + }, + ships: 1, + }, + +] + +let vassals = [] +for (let lord of lords) + lord.vassals = [] + +function vassal(lord, service, name, forces, capability) { + let lord_id = lords.findIndex(x => x.name === lord) + if (lord_id < 0) throw Error("no such lord", lord) + lords[lord_id].vassals.push(vassals.length) + vassals.push({ lord: lord_id, name, service, forces, capability }) +} + +vassal("Andreas", 1, "Lettgallian Auxiliaries", { light_horse: 1, militia: 1 }) +vassal("Andreas", 2, "Summer Crusaders", { knights: 3 }, "Crusade") +vassal("Andreas", 3, "Teutonic Vassals", { knights: 1, men_at_arms: 2 }) + +vassal("Heinrich", 2, "Heinrich von Lode", { knights: 1, men_at_arms: 1 }) +vassal("Heinrich", 2, "Odward von Lode", { knights: 1, men_at_arms: 1 }) + +vassal("Hermann", 2, "Helmond von Lüneburg", { knights: 1, men_at_arms: 1 }) +vassal("Hermann", 2, "Johannes von Dolen", { knights: 1, men_at_arms: 1 }) +vassal("Hermann", 1, "Ugaunian Auxiliaries", { light_horse: 1, militia: 1 }) + +vassal("Knud & Abel", 2, "Dietrich von Kivel", { knights: 1, men_at_arms: 1 }) +vassal("Knud & Abel", 1, "Estonian Auxiliaries", { light_horse: 1, militia: 1 }) +vassal("Knud & Abel", 2, "Otto von Lüneburg", { knights: 1, men_at_arms: 1 }) + +vassal("Rudolf", 2, "Ex-Sword Brethren", { knights: 1, sergeants: 1 }) +vassal("Rudolf", 2, "Jerwen Teutonic Vassals", { knights: 1, men_at_arms: 1 }) +vassal("Rudolf", 2, "Summer Crusaders", { knights: 2 }, "Crusade") + +vassal("Yaroslav", 1, "Mstislavich Partisans", { militia: 2 }) + +vassal("Aleksandr", 3, "Mongols", { asiatic_horse: 2 }, "Steppe Warriors") +vassal("Aleksandr", 3, "Mongols", { asiatic_horse: 2 }, "Steppe Warriors") +vassal("Aleksandr", 4, "Pereyaslavl", { men_at_arms: 1 }) +vassal("Aleksandr", 3, "Rostov", { men_at_arms: 1 }) +vassal("Aleksandr", 3, "Yaroslavl", { men_at_arms: 1 }) + +vassal("Andrey", 3, "Kipchaqs", { asiatic_horse: 3 }, "Steppe Warriors") +vassal("Andrey", 3, "Kipchaqs", { asiatic_horse: 3 }, "Steppe Warriors") +vassal("Andrey", 4, "Suzdal", { men_at_arms: 1 }) +vassal("Andrey", 4, "Vladimir", { men_at_arms: 1 }) + +vassal("Domash", 2, "Novgorod", { militia: 2 }) +vassal("Domash", 2, "Novgorod", { militia: 2 }) +vassal("Domash", 2, "Novgorod", { militia: 2 }) + +vassal("Gavrilo", 1, "Borderland Russians", { light_horse: 1, militia: 1 }) +vassal("Gavrilo", 2, "Pskov Militia", { militia: 2 }) +vassal("Gavrilo", 4, "Pskov", { men_at_arms: 1 }) + +vassal("Vladislav", 1, "Izhoran Auxiliaries", { militia: 1 }) +vassal("Vladislav", 1, "Ingrian Auxiliaries", { militia: 1 }) +vassal("Vladislav", 1, "Vepsian Auxiliaries", { militia: 1 }) +vassal("Vladislav", 1, "Vodian Auxiliaries", { militia: 1 }) + +function to_path(name) { + return name + .toLowerCase() + .replace(/&/g, 'and') + .replace(/[ -]/g, '_') + .replace(/ü/g, 'u') + .replace(/ö/g, 'o') + .replace(/ä/g, 'a') +} + +let lord_service = {Russian:[],Teutonic:[]} +let vassal_service = {Russian:[],Teutonic:[]} + +let last_path, last_side, last_ix + +last_path = null +last_side = null +lords.forEach((lord,id) => { + let side = lord.side + let path = "counters300/lord_" + side.toLowerCase() + "_" + to_path(lord.name) + if (side !== last_side) { + last_ix = 0 + last_side = side + } + lord.image = last_ix + if (path !== last_path) { + last_ix++ + last_path = path + lord_service[side].push(path + ".a.png") + lord_service[side].push(path + ".b.png") + } +}) + +last_path = null +last_side = null +vassals.forEach((vassal,id) => { + let lord = lords[vassal.lord] + let side = lord.side + let path = "counters300/vassal_" + side.toLowerCase() + "_" + to_path(lord.name) + "_" + to_path(vassal.name) + if (side !== last_side) { + last_ix = 0 + last_side = side + } + vassal.image = last_ix + if (path !== last_path) { + last_ix++ + last_path = path + vassal_service[side].push(path + ".a.png") + vassal_service[side].push(path + ".b.png") + } +}) + +let script = [] +script.push("mkdir -p service300") +script.push("montage -mode concatenate -tile 2x " + lord_service.Teutonic.join(" ") + " service300/service_lords_teutonic.png") +script.push("montage -mode concatenate -tile 2x " + vassal_service.Teutonic.join(" ") + " service300/service_vassals_teutonic.png") +script.push("montage -mode concatenate -tile 2x " + lord_service.Russian.join(" ") + " service300/service_lords_russian.png") +script.push("montage -mode concatenate -tile 2x " + vassal_service.Russian.join(" ") + " service300/service_vassals_russian.png") + +print("const data = {") +print("seaports:" + JSON.stringify(seaports) + ",") +dumplist("locales", locales) +dumplist("ways", ways) +dumplist("lords", lords) +dumplist("vassals", vassals) +print("}") +print("if (typeof module !== 'undefined') module.exports = data") + +fs.writeFileSync("build_counters3.sh", script.join("\n") + "\n") +fs.writeFileSync("../data.js", data.join("\n") + "\n") diff --git a/tools/scale.sh b/tools/scale.sh new file mode 100644 index 0000000..a54d41e --- /dev/null +++ b/tools/scale.sh @@ -0,0 +1,18 @@ +mkdir -p output75 +mkdir -p output150 +for F in output300/*.png +do + echo $F + + O=${F/300/75} + gm convert $F -colorspace RGB -resize 25% -colorspace sRGB $O.tmp + rm -f $O + zopflipng -m $O.tmp $O + rm -f $O.tmp + + O=${F/300/150} + gm convert $F -colorspace RGB -resize 50% -colorspace sRGB $O.tmp + rm -f $O + zopflipng -m $O.tmp $O + rm -f $O.tmp +done diff --git a/tools/svgo.config.js b/tools/svgo.config.js new file mode 100644 index 0000000..ef3339c --- /dev/null +++ b/tools/svgo.config.js @@ -0,0 +1,10 @@ +module.exports = { + js2svg: { + 'finalNewline': true, + }, + plugins: [ + 'preset-default', + 'convertStyleToAttrs', + 'sortAttrs', + ], +} -- cgit v1.2.3