summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.css18
-rw-r--r--play.html1
-rw-r--r--play.js249
-rw-r--r--rules.js109
-rw-r--r--tools/genroads.js53
-rw-r--r--tools/makeroads.js30
-rw-r--r--tools/roads.svg693
7 files changed, 1135 insertions, 18 deletions
diff --git a/play.css b/play.css
index 5810496..dd0e513 100644
--- a/play.css
+++ b/play.css
@@ -195,6 +195,23 @@ body.Saracens header.your_turn { background-color: hsl(120, 50%, 70%); } /* 50%
#sea { visibility: hidden; }
#sea.highlight { visibility: visible; cursor: pointer; }
+.road {
+ position: absolute;
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ text-align: center;
+ line-height: 24px;
+ font-size: 16px;
+ font-weight: bold;
+ background-color: hsl(35, 15%, 50%);
+ color: hsl(35, 15%, 30%);
+ box-shadow: 0px 0px 4px 1px #0004;
+}
+
+.road.Franks { background-color: khaki; color: hsl(54, 27%, 35%); }
+.road.Saracens { background-color: seagreen; color: honeydew; }
+
/* BLOCKS */
body.shift .block.known:hover {
@@ -382,6 +399,7 @@ body.shift .block.known:hover {
body.shift #padmap #map > .block.known:hover {
transform: rotate(90deg) scale(2) !important;
}
+ .road { transform: rotate(90deg); }
#blocks > .block { transform: rotate(90deg); }
#blocks > .block.r1 { transform: rotate(0deg); }
#blocks > .block.r2 { transform: rotate(-90deg); }
diff --git a/play.html b/play.html
index 2dd0591..fbebc8d 100644
--- a/play.html
+++ b/play.html
@@ -78,6 +78,7 @@
<svg id="svgmap" width="1275px" height="2475px" viewBox="0 0 1275 2475">
<path id="sea" d="M30 1201v1170l2-1c1 0 4-1 5-3 2-1 4-2 5-2 2 0 5-1 7-2 3-2 7-4 11-6 3-2 7-4 8-6 1-1 3-2 3-2 2 0 47-23 54-27 4-2 10-6 14-8 7-3 13-7 27-19 4-3 5-4 5-8l1-4h5c4 0 7-1 12-5 6-4 27-24 41-41 7-8 20-21 23-24 1-1 4-3 5-6l6-6c1-1 3-3 4-5 2-3 3-4 10-12 3-3 6-7 6-9 1-1 2-3 3-4 2-1 5-5 7-9 2-3 4-6 5-6 2 0 5-6 5-9 0-2 2-6 5-10s5-7 5-8 0-1 1-1 1-1 2-3c1-4 3-9 8-14 4-5 7-12 7-14 0-1 2-6 4-10 3-4 5-9 6-10 0-1 1-4 3-5 1-2 2-4 2-5 0 0 1-3 3-5 2-3 3-5 3-10 0-6 1-9 4-14 2-3 3-7 3-8 0-3 4-20 6-22 2-3 4-11 4-17 0-1 0-3 1-3 0 0 2-2 2-5 1-2 3-7 4-9 1-3 2-9 3-15 1-11 1-10 0-18 0-5 0-7 1-9s2-5 2-7c1-3 1-5 2-7 0-1 1-4 1-6v-8c4-22 4-23 3-26-1-2-1-4 0-6s1-8 1-13 1-9 1-10v-5c-1-3-1-8-1-12v-10-36c0-8-1-21-2-23 0-1-1-5-1-10 0-14-1-27-2-35-1-3-1-8-1-11s-2-10-5-17c-1-1-1-2 0-3 1-2 1-2 0-3 0-1-1-2 0-2 0-1 0-2-1-3 0-1 0-4-1-7 0-3-1-6-2-9-1-2-2-4-1-4 0-1-1-2-2-2-1-2-1-2 1-3s2-1 3-8c0-5 0-8-2-11-1-2-1-7-1-11-1-5-1-8-3-12-4-6-3-10 0-13 5-4 18-4 26 0l5 3 3-2c1-2 4-3 6-4 3-1 10-9 15-16 2-3 2-3 1-12-2-13-4-18-9-16-2 0-3 0-2-3 0-2-1-4-3-7-2-4-2-5-3-16 0-22-1-28-2-29s-1-2 0-3c2-1-1-9-3-12-2-1-2-2-1-5 0-4 2-7 8-9 9-5 10-5 10-6s1-3 3-5c1-2 2-5 2-6-1-1-1-2 0-3 1 0 1-2 1-2-1-2 0-2 3-2 2 0 4-1 6-3 3-3 4-9 3-10s0-2 1-3c4-3 3-5 0-16-2-5-3-6-6-8-2-1-6-2-8-2-5 0-5-2-1-2 6-2 7-2 8-4 0-2 1-5 2-8 0-3 1-6 2-7s1-3 1-3c-1-1 0-2 0-3 1 0 1-3 1-6v-13c0-4-1-8-1-9-1-2-1-3 1-4 2-2 2-2 1-5 0-2-1-4 0-4 0-1 1-3 2-5 1-3 1-4-1-5-1-1-1-1 2-3 2-2 3-3 3-4s1-2 3-2c4-2 12-10 16-16 2-2 3-4 4-4 0 0 1-1 2-3 1-1 2-4 4-6s2-3 2-6c-1-2-1-5-1-6s0-3-1-4-1-1 1-3c4-3 6-11 4-14-1-2-1-2 1-4 1-2 1-2 0-6-1-2-2-5-1-6 0 0 0-2-1-2-1-2 0-2 3-4l4-3-2-6c-1-3-2-7-3-7-2-1 1-4 4-4s7-4 7-8c0-1-1-4-2-5-2-3-3-6-2-7 1 0 1-1 1-2s2-6 5-11c4-7 4-9 4-13-1-11-12-33-16-33-2 0-7-3-7-4s5-4 8-5c1 0 7 0 12-1s10-1 11-2c3-2 6-1 7 1 1 3 3 4 3 2 0-3 3-5 7-6 7-2 11-4 13-9 1-2 2-4 2-5v-7c-1-4 0-6 1-7 1 0 2-2 1-4 0-2 0-3 3-4 1 0 3-2 3-3 1-1 2-2 5-2 5-1 8-5 6-8-1-2-6-4-11-4-1 0-3-1-4-1-2-2-1-13 0-16 1-1 2-5 2-9 1-8 1-9-2-12-2-2-4-4-5-4 0 0-2-1-2-3-2-2-3-3-6-4-6-1-7-1-7-3 0-1-1-3-2-5-1-3-2-5-2-7 0-1-1-3-2-4-1-3-1-5 3-7 3-3 6-9 4-11 0-1-1-3 0-4 0-1-1-2-3-4-3-3-3-3-2-4 1-2 1-2-2-3-4-3-4-4 1-8 3-2 3-3 3-6-1-4-1-4 4-6 4-3 5-3 8-2 7 1 14-2 15-6v-5c1-1 0-4 0-7-2-3-2-5-1-5 0-1 1-3 1-4 0-3 0-3 3-5 2 0 5-1 7-1 1 0 3-1 5-2 0-1 2-2 3-2l4-2c1-2 3-3 4-3 0 0 2-1 3-3 1-1 5-3 7-4 4-2 4-3 4-6 0-1-1-3-2-4-2-1-4-3-5-4-1-2-4-3-5-4-5-1-3-2 4-2 6 0 13-1 14-3 1-1 11-5 16-6 2-1 4-2 4-3 0-2 5-4 10-3 3 0 4 0 9-5 3-3 6-6 6-7 0-2 13-13 15-14 2 0 5-1 8-2l5-2v-6c0-5-1-7-4-14-2-4-6-10-8-12-5-6-28-25-36-28-2-1-6-5-9-8-4-3-7-6-8-7-4-1-8-6-11-12-2-5-3-7-7-9-2-2-5-3-5-3-1 0-9-5-10-6-5-5-19-15-22-16-1-1-2-2-2-3l-5-5c-7-5-9-9-9-15-1-4-2-7-5-9 0-1-1-2-1-4s0-3-1-3-1-2-2-4c0-3 0-4 4-8 2-2 4-5 4-5 0-2-12-14-15-16-4-2-5-6-3-9s1-5-3-7c-3-1-4-4-2-5 1-1 1-2 1-3s1-3 3-4c2-2 3-3 3-5 0-1 0-4 2-6 2-3 3-5 1-8s0-5 5-8c5-2 9-6 9-8 0-4-20-18-30-22-8-3-10-6-10-12-1-6-1-7-6-13-2-3-4-6-4-8 0-1-2-5-6-9-7-9-8-11-7-15 0-3 0-3-3-4-1-1-6-2-11-2-11-2-10-2-27-9-4-2-8-3-11-3s-10-1-15-2c-5 0-10-1-11-1-7 0-15 2-19 4s-8 2-9-1c0-1 0-3 1-4 2-3 1-6-1-8-1-1-6-2-13-3-14-2-15-2-13-5 1-2 1-3 0-4s-2-1-6 1c-2 1-4 2-5 2 0-1 4-4 11-8 5-2 7-3 7-5 0-1 1-2 3-3 1 0 2-1 2-3s0-3 1-4c1 0 1-1 1-3s-1-3-4-5c-2-2-5-3-6-4-4-1-5-3-2-7 1-2 3-3 7-4 5-1 5-1 8-7 1-3 3-6 5-7 1-1 3-4 3-7 1-3 3-7 3-8 1-1 1-3 1-4-1-3-11-13-17-16-3-2-7-5-10-8-2-2-5-4-7-4-1 0-2-1-3-2s-2-2-4-3l-3-1 7-2c3 0 9-1 12-2 7-1 12-3 18-7 5-4 7-8 7-15 0-5 1-7 10-14 1-1 2-3 2-4 0-3 5-14 9-18s5-6 4-9c0-2 0-3 4-5 6-2 6-4-1-9-6-4-9-7-14-13-2-1-5-4-7-6-3-2-7-5-8-7-2-1-6-3-9-4-2-1-5-2-6-3-2-1-13-6-15-6s-11-4-11-5c-1-1-9-5-18-10-18-8-30-15-35-18-2-2-12-5-31-10-7-3-12-7-12-11 0-2 1-4 5-7 4-4 6-7 7-10l2-5 9-5c10-4 12-6 12-12s1-7 8-10c10-5 11-7 11-12-1-4-1-5 4-9 4-5 9-8 21-12 4-1 11-4 15-7 9-4 10-5 11-9 2-8 8-13 18-16 8-2 11-6 12-13v-5H30v1171z"/>
</svg>
+<div id="roads"></div>
<div id="blocks"></div>
<div id="offmap" style="visibility:hidden"></div>
<div id="towns"></div>
diff --git a/play.js b/play.js
index cf4f4d7..eefe5f0 100644
--- a/play.js
+++ b/play.js
@@ -16,6 +16,22 @@ function set_has(set, item) {
return false
}
+function map_get(map, key, missing) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else
+ return map[(m<<1)+1]
+ }
+ return missing
+}
+
const FRANKS = "Franks"
const SARACENS = "Saracens"
@@ -83,6 +99,193 @@ const VICTORY_TOWNS = [
town_index["Jerusalem"]
]
+// :r !node tools/genroads.js
+const ROADS_XY = {
+ "Germania / Aleppo": [975,64],
+ "Germania / St. Simeon": [297,100],
+ "Germania / Antioch": [512,54],
+ "Aleppo / Artah": [939,147],
+ "Aleppo / Zerdana": [1045,218],
+ "Artah / Zerdana": [941,227],
+ "Artah / Harim": [761,127],
+ "Zerdana / Hama": [1028,388],
+ "Zerdana / Albara": [942,342],
+ "Hama / Homs": [1133,571],
+ "Hama / Albara": [950,450],
+ "Hama / Monterrand": [964,554],
+ "Homs / Lacum": [980,780],
+ "Homs / Qaddas": [1156,780],
+ "Homs / Monterrand": [986,643],
+ "Homs / Krak": [927,726],
+ "Lacum / Qaddas": [1063,906],
+ "Lacum / Baalbek": [889,953],
+ "Lacum / Krak": [867,794],
+ "Qaddas / Damascus": [1170,1038],
+ "Baalbek / Anjar": [812,1082],
+ "Baalbek / Tripoli": [776,953],
+ "Anjar / Damascus": [869,1177],
+ "Anjar / Beirut": [635,1137],
+ "Anjar / Beaufort": [718,1198],
+ "Damascus / Banyas": [936,1267],
+ "Damascus / Ashtera": [1051,1339],
+ "Banyas / Ashtera": [907,1411],
+ "Banyas / Beaufort": [666,1389],
+ "Banyas / Tiberias": [730,1455],
+ "Ashtera / Ajlun": [1046,1491],
+ "Ajlun / Tiberias": [911,1554],
+ "Ajlun / Amman": [1035,1711],
+ "St. Simeon / Antioch": [412,208],
+ "Antioch / Harim": [600,127],
+ "Antioch / Kassab": [477,260],
+ "Harim / Shughur": [684,214],
+ "Kassab / Latakia": [406,388],
+ "Shughur / Saône": [635,374],
+ "Shughur / Albara": [704,345],
+ "Latakia / Saône": [524,432],
+ "Latakia / Margat": [492,488],
+ "Saône / Albara": [735,421],
+ "Margat / Tartus": [547,654],
+ "Monterrand / Krak": [851,664],
+ "Tartus / Krak": [689,722],
+ "Tartus / Tripoli": [669,786],
+ "Krak / Tripoli": [757,807],
+ "Tripoli / Botron": [571,933],
+ "Botron / Beirut": [567,1052],
+ "Beirut / Sidon": [503,1219],
+ "Sidon / Tyre": [460,1330],
+ "Sidon / Beaufort": [542,1324],
+ "Tyre / Beaufort": [546,1388],
+ "Tyre / Acre": [427,1492],
+ "Acre / Tiberias": [601,1572],
+ "Acre / Legio": [518,1653],
+ "Acre / Caesarea": [390,1658],
+ "Tiberias / Baisan": [759,1632],
+ "Legio / Baisan": [653,1685],
+ "Legio / Nablus": [619,1724],
+ "Baisan / Nablus": [675,1736],
+ "Baisan / Damiya": [811,1723],
+ "Caesarea / Nablus": [520,1777],
+ "Caesarea / Jaffa": [409,1837],
+ "Nablus / Damiya": [745,1797],
+ "Nablus / Jerusalem": [653,1883],
+ "Damiya / Amman": [934,1781],
+ "Damiya / Jericho": [845,1883],
+ "Amman / Jericho": [958,1892],
+ "Amman / Kerak": [1130,1973],
+ "Jaffa / Ramallah": [463,1932],
+ "Jaffa / Ascalon": [391,2004],
+ "Ramallah / Jerusalem": [586,1972],
+ "Ramallah / Ascalon": [448,2014],
+ "Jerusalem / Jericho": [789,1954],
+ "Jerusalem / Hebron": [677,2050],
+ "Jericho / Kerak": [952,1976],
+ "Ascalon / Lachish": [439,2128],
+ "Ascalon / Gaza": [330,2133],
+ "Lachish / Hebron": [556,2151],
+ "Lachish / Gaza": [430,2172],
+ "Hebron / Dimona": [658,2242],
+ "Hebron / Zoar": [779,2195],
+ "Kerak / Zoar": [998,2140],
+ "Gaza / Beersheba": [369,2265],
+ "Gaza / Egypt": [225,2266],
+ "Beersheba / Dimona": [539,2293],
+ "Beersheba / Egypt": [415,2312],
+ "Dimona / Zoar": [788,2291],
+}
+
+const ROADS_BG = {
+ "Germania / Aleppo": "hsl(36, 72%, 76%)",
+ "Germania / St. Simeon": "hsl(37, 79%, 77%)",
+ "Germania / Antioch": "hsl(61, 30%, 58%)",
+ "Aleppo / Artah": "hsl(37, 80%, 78%)",
+ "Aleppo / Zerdana": "hsl(36, 81%, 81%)",
+ "Artah / Zerdana": "hsl(37, 82%, 78%)",
+ "Artah / Harim": "hsl(35, 68%, 70%)",
+ "Zerdana / Hama": "hsl(36, 78%, 77%)",
+ "Zerdana / Albara": "hsl(36, 76%, 77%)",
+ "Hama / Homs": "hsl(36, 78%, 77%)",
+ "Hama / Albara": "hsl(39, 69%, 74%)",
+ "Hama / Monterrand": "hsl(34, 76%, 67%)",
+ "Homs / Lacum": "hsl(42, 57%, 70%)",
+ "Homs / Qaddas": "hsl(36, 82%, 78%)",
+ "Homs / Monterrand": "hsl(34, 78%, 70%)",
+ "Homs / Krak": "hsl(36, 74%, 72%)",
+ "Lacum / Qaddas": "hsl(36, 60%, 75%)",
+ "Lacum / Baalbek": "hsl(45, 45%, 68%)",
+ "Lacum / Krak": "hsl(38, 59%, 65%)",
+ "Qaddas / Damascus": "hsl(36, 80%, 78%)",
+ "Baalbek / Anjar": "hsl(48, 43%, 68%)",
+ "Baalbek / Tripoli": "hsl(56, 30%, 55%)",
+ "Anjar / Damascus": "hsl(42, 59%, 73%)",
+ "Anjar / Beirut": "hsl(51, 39%, 61%)",
+ "Anjar / Beaufort": "hsl(47, 43%, 67%)",
+ "Damascus / Banyas": "hsl(38, 58%, 78%)",
+ "Damascus / Ashtera": "hsl(38, 65%, 74%)",
+ "Banyas / Ashtera": "hsl(38, 56%, 75%)",
+ "Banyas / Beaufort": "hsl(53, 36%, 59%)",
+ "Banyas / Tiberias": "hsl(54, 35%, 62%)",
+ "Ashtera / Ajlun": "hsl(37, 70%, 75%)",
+ "Ajlun / Tiberias": "hsl(46, 48%, 68%)",
+ "Ajlun / Amman": "hsl(37, 85%, 80%)",
+ "St. Simeon / Antioch": "hsl(66, 32%, 58%)",
+ "Antioch / Harim": "hsl(46, 48%, 69%)",
+ "Antioch / Kassab": "hsl(66, 32%, 58%)",
+ "Harim / Shughur": "hsl(41, 61%, 74%)",
+ "Kassab / Latakia": "hsl(66, 32%, 58%)",
+ "Shughur / Saône": "hsl(47, 48%, 69%)",
+ "Shughur / Albara": "hsl(41, 53%, 72%)",
+ "Latakia / Saône": "hsl(60, 31%, 61%)",
+ "Latakia / Margat": "hsl(63, 32%, 59%)",
+ "Saône / Albara": "hsl(41, 60%, 74%)",
+ "Margat / Tartus": "hsl(50, 39%, 61%)",
+ "Monterrand / Krak": "hsl(40, 57%, 68%)",
+ "Tartus / Krak": "hsl(62, 31%, 59%)",
+ "Tartus / Tripoli": "hsl(55, 35%, 65%)",
+ "Krak / Tripoli": "hsl(52, 39%, 64%)",
+ "Tripoli / Botron": "hsl(72, 33%, 57%)",
+ "Botron / Beirut": "hsl(44, 43%, 57%)",
+ "Beirut / Sidon": "hsl(42, 57%, 79%)",
+ "Sidon / Tyre": "hsl(45, 42%, 71%)",
+ "Sidon / Beaufort": "hsl(70, 33%, 57%)",
+ "Tyre / Beaufort": "hsl(69, 32%, 56%)",
+ "Tyre / Acre": "hsl(58, 33%, 63%)",
+ "Acre / Tiberias": "hsl(56, 27%, 60%)",
+ "Acre / Legio": "hsl(61, 31%, 57%)",
+ "Acre / Caesarea": "hsl(52, 40%, 70%)",
+ "Tiberias / Baisan": "hsl(49, 44%, 67%)",
+ "Legio / Baisan": "hsl(56, 38%, 64%)",
+ "Legio / Nablus": "hsl(58, 32%, 60%)",
+ "Baisan / Nablus": "hsl(48, 50%, 71%)",
+ "Baisan / Damiya": "hsl(51, 40%, 65%)",
+ "Caesarea / Nablus": "hsl(59, 32%, 60%)",
+ "Caesarea / Jaffa": "hsl(51, 40%, 70%)",
+ "Nablus / Damiya": "hsl(39, 64%, 77%)",
+ "Nablus / Jerusalem": "hsl(45, 51%, 71%)",
+ "Damiya / Amman": "hsl(46, 47%, 69%)",
+ "Damiya / Jericho": "hsl(48, 48%, 69%)",
+ "Amman / Jericho": "hsl(40, 66%, 75%)",
+ "Amman / Kerak": "hsl(36, 72%, 79%)",
+ "Jaffa / Ramallah": "hsl(58, 34%, 61%)",
+ "Jaffa / Ascalon": "hsl(46, 44%, 69%)",
+ "Ramallah / Jerusalem": "hsl(47, 46%, 68%)",
+ "Ramallah / Ascalon": "hsl(49, 43%, 66%)",
+ "Jerusalem / Jericho": "hsl(41, 52%, 70%)",
+ "Jerusalem / Hebron": "hsl(41, 62%, 75%)",
+ "Jericho / Kerak": "hsl(40, 58%, 72%)",
+ "Ascalon / Lachish": "hsl(44, 57%, 72%)",
+ "Ascalon / Gaza": "hsl(45, 51%, 74%)",
+ "Lachish / Hebron": "hsl(42, 56%, 71%)",
+ "Lachish / Gaza": "hsl(41, 65%, 74%)",
+ "Hebron / Dimona": "hsl(40, 60%, 73%)",
+ "Hebron / Zoar": "hsl(38, 59%, 72%)",
+ "Kerak / Zoar": "hsl(38, 78%, 77%)",
+ "Gaza / Beersheba": "hsl(36, 82%, 76%)",
+ "Gaza / Egypt": "hsl(50, 44%, 63%)",
+ "Beersheba / Dimona": "hsl(36, 71%, 78%)",
+ "Beersheba / Egypt": "hsl(34, 80%, 71%)",
+ "Dimona / Zoar": "hsl(36, 78%, 77%)",
+}
+
let label_layout = window.localStorage['crusader-rex/label-layout'] || 'spread'
function set_spread_layout() {
@@ -105,6 +308,7 @@ let ui = {
cards: [],
card_backs: [],
towns: [],
+ roads: [],
blocks: [],
battle_menu: [],
battle_block: [],
@@ -478,6 +682,21 @@ function build_map() {
ui.blocks[b] = build_map_block(b, block)
build_battle_block(b, block)
}
+
+ for (let name in ROADS_XY) {
+ let [x, y] = ROADS_XY[name]
+ let [a, b] = name.split(" / ")
+ let id = town_index[a] * 100 + town_index[b]
+ let e = document.createElement("div")
+ e.my_id = id
+ e.my_bgnd = ROADS_BG[name]
+ e.my_show = "road " + ROADS[id]
+ e.className = "hide"
+ e.style.left = (x - 12) + "px"
+ e.style.top = (y - 12) + "px"
+ ui.roads.push(e)
+ document.getElementById("roads").appendChild(e)
+ }
}
function update_steps(b, steps, element) {
@@ -736,6 +955,36 @@ function update_map() {
ui.blocks[view.who].classList.add('selected')
for (let b of view.castle)
ui.blocks[b].classList.add('castle')
+
+ for (let e of ui.roads) {
+ let u = map_get(view.last_used, e.my_id, 0)
+ let n = map_get(view.road_limit, e.my_id, "")
+ if (view.main_road && set_has(view.main_road, e.my_id))
+ n += "*"
+ switch (u) {
+ case 1:
+ e.style.backgroundColor = null
+ e.className = "road Franks"
+ e.textContent = n
+ break
+ case 2:
+ e.style.backgroundColor = null
+ e.className = "road Saracens"
+ e.textContent = n
+ break
+ case 0:
+ if (n) {
+ e.style.backgroundColor = e.my_bgnd
+ e.className = e.my_show
+ e.textContent = n
+ } else {
+ e.style.backgroundColor = null
+ e.className = "hide"
+ e.textContent = ""
+ }
+ break
+ }
+ }
}
function update_card_display(element, card, prior_card) {
diff --git a/rules.js b/rules.js
index 509e67c..1ebd165 100644
--- a/rules.js
+++ b/rules.js
@@ -199,6 +199,14 @@ function print_summary(text, skip_if_empty = false) {
logi("nothing.")
}
+const id_player = [ null, FRANKS, SARACENS ]
+
+function player_id(p) {
+ if (p === FRANKS) return 1
+ if (p === SARACENS) return 2
+ return 0
+}
+
function enemy(p) {
if (p === FRANKS) return SARACENS
if (p === SARACENS) return FRANKS
@@ -365,11 +373,11 @@ function road_id(a, b) {
}
function road_was_last_used_by_enemy(from, to) {
- return game.last_used[road_id(from, to)] === enemy(game.active)
+ return map_get(game.last_used, road_id(from, to)) === player_id(enemy(game.active))
}
function road_was_last_used_by_friendly(from, to) {
- return game.last_used[road_id(from, to)] === game.active
+ return map_get(game.last_used, road_id(from, to)) === player_id(game.active)
}
function road_type(a, b) {
@@ -377,11 +385,15 @@ function road_type(a, b) {
}
function road_limit(a, b) {
- return game.road_limit[road_id(a,b)] || 0
+ return map_get(game.road_limit, road_id(a,b), 0)
+}
+
+function set_road_limit(a, b, n) {
+ map_set(game.road_limit, road_id(a,b), n)
}
function reset_road_limits() {
- game.road_limit = {}
+ game.road_limit.length = 0
}
function count_player(p, where) {
@@ -749,7 +761,7 @@ function can_use_richards_sea_legs(who, to) {
if (!game.attacker[to])
return true
if (game.attacker[to] === FRANKS)
- return (game.main_road[to] === "England")
+ return (get_main_road(to) === ENGLAND)
}
}
return false
@@ -1165,7 +1177,7 @@ function start_game_turn() {
// Reset movement and attack tracking state
reset_road_limits()
- game.last_used = {}
+ game.last_used = []
game.attacker = {}
set_clear(game.reserves1)
set_clear(game.reserves2)
@@ -1313,7 +1325,7 @@ function start_player_turn() {
log("")
log(".h2 " + game.active)
reset_road_limits()
- game.main_road = {}
+ game.main_road = []
let card = CARDS[game.active === FRANKS ? game.f_card : game.s_card]
if (card.event)
goto_event_card(card.event)
@@ -1533,12 +1545,20 @@ function queue_attack(who, round) {
}
}
+function get_main_road(to) {
+ return map_get(game.main_road, to, NOWHERE)
+}
+
+function set_main_road(to, x) {
+ map_set(game.main_road, to, x)
+}
+
function move_block(who, from, to) {
game.location[who] = to
- game.road_limit[road_id(from, to)] = road_limit(from, to) + 1
+ set_road_limit(from, to, road_limit(from, to) + 1)
game.distance ++
if (is_contested_field(to)) {
- game.last_used[road_id(from, to)] = game.active
+ map_set(game.last_used, road_id(from, to), player_id(game.active))
// 6.56 Main Attack relief force by Player 2 arrives one round later than normal
let relief_delay = 0
@@ -1548,21 +1568,21 @@ function move_block(who, from, to) {
if (!game.attacker[to]) {
game.attacker[to] = game.active
- game.main_road[to] = from
+ set_main_road(to, from)
return queue_attack(who, 1 + relief_delay)
} else {
// Attacker main attack or reinforcements
if (game.attacker[to] === game.active) {
- if (game.main_road[to] !== from)
+ if (get_main_road(to) !== from)
return queue_attack(who, 2 + relief_delay)
return queue_attack(who, 1 + relief_delay)
}
// Defender reinforcements
- if (!game.main_road[to])
- game.main_road[to] = from
+ if (!get_main_road(to))
+ set_main_road(to, from)
- if (game.main_road[to] === from) {
+ if (get_main_road(to) === from) {
return queue_attack(who, 2)
} else {
return queue_attack(who, 3)
@@ -1936,7 +1956,7 @@ states.sea_move_to = {
} else if (!is_friendly_port(to)) {
// English Crusaders attack!
game.attacker[to] = FRANKS
- game.main_road[to] = "England"
+ set_main_road(to, ENGLAND)
log(game.active + " sea moved:")
logi("#" + from + " \u2192 #" + to + ATTACK_MARK + ".")
@@ -2324,6 +2344,7 @@ states.regroup = {
},
end_regroup: function () {
clear_undo()
+ reset_road_limits()
print_summary(game.active + " regrouped:", true)
if (game.assassins) {
delete game.assassins
@@ -3833,11 +3854,11 @@ exports.setup = function (seed, scenario, options) {
steps: [],
attacker: {},
- road_limit: {},
- last_used: {},
+ road_limit: [],
+ last_used: [],
castle: [],
- main_road: {},
+ main_road: [],
moved: [],
reserves1: [],
reserves2: [],
@@ -3923,6 +3944,8 @@ exports.view = function(state, current) {
steps: game.steps,
moved: game.moved,
sieges: make_siege_view(),
+ last_used: game.last_used,
+ road_limit: game.road_limit,
battle: null,
prompt: null,
}
@@ -3932,6 +3955,13 @@ exports.view = function(state, current) {
if (game.winter_campaign && game.winter_campaign !== game.p1 && game.winter_campaign !== game.p2)
view.winter_campaign = game.winter_campaign
+ if (game.main_road && game.main_road.length > 0) {
+ view.main_road = []
+ for (let i = 0; i < game.main_road.length; i += 2)
+ if (game.main_road[i+1] !== ENGLAND)
+ set_add(view.main_road, road_id(game.main_road[i+0], game.main_road[i+1]))
+ }
+
states[game.state].prompt(view, current)
if (states[game.state].show_battle)
@@ -3960,6 +3990,15 @@ function array_insert(array, index, item) {
return array
}
+function array_insert_pair(array, index, key, value) {
+ for (let i = array.length; i > index; i -= 2) {
+ array[i] = array[i-2]
+ array[i+1] = array[i-1]
+ }
+ array[index] = key
+ array[index+1] = value
+}
+
function set_clear(set) {
set.length = 0
}
@@ -4028,6 +4067,40 @@ function set_toggle(set, item) {
return array_insert(set, a, item)
}
+function map_get(map, key, missing) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else
+ return map[(m<<1)+1]
+ }
+ return missing
+}
+
+function map_set(map, key, value) {
+ let a = 0
+ let b = (map.length >> 1) - 1
+ while (a <= b) {
+ let m = (a + b) >> 1
+ let x = map[m<<1]
+ if (key < x)
+ b = m - 1
+ else if (key > x)
+ a = m + 1
+ else {
+ map[(m<<1)+1] = value
+ return
+ }
+ }
+ array_insert_pair(map, a<<1, key, value)
+}
+
// Fast deep copy for objects without cycles
function object_copy(original) {
if (Array.isArray(original)) {
diff --git a/tools/genroads.js b/tools/genroads.js
new file mode 100644
index 0000000..71b1c45
--- /dev/null
+++ b/tools/genroads.js
@@ -0,0 +1,53 @@
+const fs = require("fs")
+
+const { round, floor, ceil } = Math
+
+let output = {}
+let mode, name, x, y, w, h, cx, cy, rx, ry
+
+function flush() {
+ if (mode === 'circle') {
+ output[name] = [ cx, cy ]
+ }
+ x = y = w = h = cx = cy = rx = ry = 0
+ name = null
+}
+
+for (let line of fs.readFileSync("tools/roads.svg", "utf-8").split("\n")) {
+ line = line.trim()
+ if (line.startsWith("<rect")) {
+ flush()
+ mode = "rect"
+ x = y = w = h = 0
+ } else if (line.startsWith("<ellipse") || line.startsWith("<circle")) {
+ flush()
+ mode = "circle"
+ cx = cy = rx = ry = 0
+ } else if (line.startsWith('x="'))
+ x = round(Number(line.split('"')[1]))
+ else if (line.startsWith('y="'))
+ y = round(Number(line.split('"')[1]))
+ else if (line.startsWith('width="'))
+ w = round(Number(line.split('"')[1]))
+ else if (line.startsWith('height="'))
+ h = round(Number(line.split('"')[1]))
+ else if (line.startsWith('cx="'))
+ cx = round(Number(line.split('"')[1]))
+ else if (line.startsWith('cy="'))
+ cy = round(Number(line.split('"')[1]))
+ else if (line.startsWith('r="'))
+ rx = ry = round(Number(line.split('"')[1]))
+ else if (line.startsWith('rx="'))
+ rx = round(Number(line.split('"')[1]))
+ else if (line.startsWith('ry="'))
+ ry = round(Number(line.split('"')[1]))
+ else if (line.startsWith('inkscape:label="'))
+ name = line.split('"')[1]
+}
+
+flush()
+
+console.log("const ROADS_XY = {")
+for (let key in output)
+ console.log("\t\"" + key + "\": " + JSON.stringify(output[key]) + ",")
+console.log("}")
diff --git a/tools/makeroads.js b/tools/makeroads.js
new file mode 100644
index 0000000..edff0b9
--- /dev/null
+++ b/tools/makeroads.js
@@ -0,0 +1,30 @@
+const print = console.log
+
+const data = require("../data.js")
+
+var w = 1275
+var h = 2475
+var m = "../map75.png"
+
+print(`<?xml version="1.0" encoding="UTF-8"?>
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="${w}"
+ height="${h}"
+>
+<image xlink:href="${m}" x="0" y="0" width="${w}" height="${h}" image-rendering="pixelated" sodipodi:insensitive="true" />`)
+
+for (let id in data.ROADS) {
+ id = id | 0
+ let a = (id / 100) | 0
+ let b = id % 100
+ let x = (data.TOWNS[a].layout.x + data.TOWNS[b].layout.x) >> 1
+ let y = (data.TOWNS[a].layout.y + data.TOWNS[b].layout.y) >> 1
+ let label = data.TOWNS[a].name + " / " + data.TOWNS[b].name
+ print(`<circle inkscape:label="${label}" cx="${x}" cy="${y}" r="12"/>`)
+}
+
+print(`</svg>`)
diff --git a/tools/roads.svg b/tools/roads.svg
new file mode 100644
index 0000000..0797f57
--- /dev/null
+++ b/tools/roads.svg
@@ -0,0 +1,693 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1275"
+ height="2475"
+ version="1.1"
+ id="svg184"
+ sodipodi:docname="roads.svg"
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
+ <metadata
+ id="metadata190">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs188" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="640"
+ inkscape:window-height="480"
+ id="namedview186"
+ showgrid="false"
+ inkscape:snap-object-midpoints="true"
+ inkscape:zoom="1.2821617"
+ inkscape:cx="130.6621"
+ inkscape:cy="2153.467"
+ inkscape:current-layer="svg184"
+ inkscape:document-rotation="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid192" />
+ </sodipodi:namedview>
+ <image
+ sodipodi:absref="/home/tor/src/rally/public/crusader-rex/map75.png"
+ xlink:href="../map75.png"
+ id="image2"
+ sodipodi:insensitive="true"
+ image-rendering="pixelated"
+ height="2475"
+ width="1275"
+ y="0"
+ x="0" />
+ <circle
+ inkscape:label="Germania / Aleppo"
+ cx="974.99615"
+ cy="63.622677"
+ r="12"
+ id="circle4"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Germania / St. Simeon"
+ cx="296.58557"
+ cy="99.73616"
+ r="12"
+ id="circle6"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Germania / Antioch"
+ cx="511.75214"
+ cy="54.400223"
+ r="12"
+ id="circle8"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Aleppo / Artah"
+ cx="938.5"
+ cy="147"
+ r="12"
+ id="circle10"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Aleppo / Zerdana"
+ cx="1044.5436"
+ cy="217.55034"
+ r="12"
+ id="circle12"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Artah / Zerdana"
+ cx="940.5"
+ cy="226.5"
+ r="12"
+ id="circle14"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Artah / Harim"
+ cx="760.87262"
+ cy="126.64205"
+ r="12"
+ id="circle16"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Zerdana / Hama"
+ cx="1028"
+ cy="388"
+ r="12"
+ id="circle18"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Zerdana / Albara"
+ cx="941.80188"
+ cy="342.2558"
+ r="12"
+ id="circle20"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Hama / Homs"
+ cx="1132.5"
+ cy="571"
+ r="12"
+ id="circle22"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Hama / Albara"
+ cx="950.42859"
+ cy="450.0629"
+ r="12"
+ id="circle24"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Hama / Monterrand"
+ cx="963.85614"
+ cy="554.27655"
+ r="12"
+ id="circle26"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Homs / Lacum"
+ cx="979.66449"
+ cy="779.88367"
+ r="12"
+ id="circle28"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Homs / Qaddas"
+ cx="1155.5"
+ cy="780"
+ r="12"
+ id="circle30"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Homs / Monterrand"
+ cx="986"
+ cy="643"
+ r="12"
+ id="circle32"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Homs / Krak"
+ cx="926.5"
+ cy="726"
+ r="12"
+ id="circle34"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Lacum / Qaddas"
+ cx="1062.8297"
+ cy="905.73419"
+ r="12"
+ id="circle36"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Lacum / Baalbek"
+ cx="888.5"
+ cy="953"
+ r="12"
+ id="circle38"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Lacum / Krak"
+ cx="867.27191"
+ cy="793.57495"
+ r="12"
+ id="circle40"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Qaddas / Damascus"
+ cx="1170"
+ cy="1038"
+ r="12"
+ id="circle42"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Baalbek / Anjar"
+ cx="811.5"
+ cy="1081.5"
+ r="12"
+ id="circle44"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Baalbek / Tripoli"
+ cx="775.97717"
+ cy="953.27899"
+ r="12"
+ id="circle46"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Anjar / Damascus"
+ cx="868.5"
+ cy="1177"
+ r="12"
+ id="circle48"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Anjar / Beirut"
+ cx="635.32697"
+ cy="1136.762"
+ r="12"
+ id="circle50"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Anjar / Beaufort"
+ cx="717.70734"
+ cy="1197.6344"
+ r="12"
+ id="circle52"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Damascus / Banyas"
+ cx="936.24713"
+ cy="1267.1222"
+ r="12"
+ id="circle54"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Damascus / Ashtera"
+ cx="1050.5"
+ cy="1339"
+ r="12"
+ id="circle56"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Banyas / Ashtera"
+ cx="907.11737"
+ cy="1411.2574"
+ r="12"
+ id="circle58"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Banyas / Beaufort"
+ cx="666.4845"
+ cy="1389.4496"
+ r="12"
+ id="circle60"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Banyas / Tiberias"
+ cx="729.61981"
+ cy="1455.0599"
+ r="12"
+ id="circle62"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Ashtera / Ajlun"
+ cx="1046.3632"
+ cy="1490.8855"
+ r="12"
+ id="circle64"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Ajlun / Tiberias"
+ cx="910.80432"
+ cy="1553.918"
+ r="12"
+ id="circle66"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Ajlun / Amman"
+ cx="1034.8445"
+ cy="1711.1224"
+ r="12"
+ id="circle68"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="St. Simeon / Antioch"
+ cx="412"
+ cy="208"
+ r="12"
+ id="circle70"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Antioch / Harim"
+ cx="600"
+ cy="127.38018"
+ r="12"
+ id="circle72"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Antioch / Kassab"
+ cx="477.3251"
+ cy="259.52649"
+ r="12"
+ id="circle74"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Harim / Shughur"
+ cx="684.38556"
+ cy="214.05885"
+ r="12"
+ id="circle76"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Kassab / Latakia"
+ cx="405.5"
+ cy="387.5"
+ r="12"
+ id="circle78"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Shughur / Saône"
+ cx="635.02734"
+ cy="373.70758"
+ r="12"
+ id="circle80"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Shughur / Albara"
+ cx="704.05487"
+ cy="344.73975"
+ r="12"
+ id="circle82"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Latakia / Saône"
+ cx="523.5"
+ cy="432"
+ r="12"
+ id="circle84"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Latakia / Margat"
+ cx="491.5"
+ cy="487.5"
+ r="12"
+ id="circle86"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Saône / Albara"
+ cx="735"
+ cy="420.5"
+ r="12"
+ id="circle88"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Margat / Tartus"
+ cx="546.5"
+ cy="653.5"
+ r="12"
+ id="circle90"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Monterrand / Krak"
+ cx="850.96875"
+ cy="664.35345"
+ r="12"
+ id="circle92"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Tartus / Krak"
+ cx="689"
+ cy="722"
+ r="12"
+ id="circle94"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Tartus / Tripoli"
+ cx="669"
+ cy="785.5"
+ r="12"
+ id="circle96"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Krak / Tripoli"
+ cx="756.5"
+ cy="806.5"
+ r="12"
+ id="circle98"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Tripoli / Botron"
+ cx="571.41937"
+ cy="932.94006"
+ r="12"
+ id="circle100"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Botron / Beirut"
+ cx="566.5"
+ cy="1052"
+ r="12"
+ id="circle102"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Beirut / Sidon"
+ cx="503"
+ cy="1219"
+ r="12"
+ id="circle104"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Sidon / Tyre"
+ cx="460"
+ cy="1329.5"
+ r="12"
+ id="circle106"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Sidon / Beaufort"
+ cx="542"
+ cy="1323.5"
+ r="12"
+ id="circle108"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Tyre / Beaufort"
+ cx="546"
+ cy="1388"
+ r="12"
+ id="circle110"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Tyre / Acre"
+ cx="427"
+ cy="1492"
+ r="12"
+ id="circle112"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Acre / Tiberias"
+ cx="600.5"
+ cy="1571.5"
+ r="12"
+ id="circle114"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Acre / Legio"
+ cx="518"
+ cy="1652.5"
+ r="12"
+ id="circle116"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Acre / Caesarea"
+ cx="389.65146"
+ cy="1657.533"
+ r="12"
+ id="circle118"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Tiberias / Baisan"
+ cx="758.84827"
+ cy="1631.7234"
+ r="12"
+ id="circle120"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Legio / Baisan"
+ cx="653.27991"
+ cy="1684.589"
+ r="12"
+ id="circle122"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Legio / Nablus"
+ cx="619"
+ cy="1723.5"
+ r="12"
+ id="circle124"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Baisan / Nablus"
+ cx="675"
+ cy="1736"
+ r="12"
+ id="circle126"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Baisan / Damiya"
+ cx="810.5"
+ cy="1723"
+ r="12"
+ id="circle128"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Caesarea / Nablus"
+ cx="519.5"
+ cy="1776.5"
+ r="12"
+ id="circle130"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Caesarea / Jaffa"
+ cx="409"
+ cy="1836.5"
+ r="12"
+ id="circle132"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Nablus / Damiya"
+ cx="745"
+ cy="1797"
+ r="12"
+ id="circle134"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Nablus / Jerusalem"
+ cx="653"
+ cy="1883"
+ r="12"
+ id="circle136"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Damiya / Amman"
+ cx="934.28229"
+ cy="1781.4043"
+ r="12"
+ id="circle138"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Damiya / Jericho"
+ cx="845.08759"
+ cy="1883.2872"
+ r="12"
+ id="circle140"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Amman / Jericho"
+ cx="958.41956"
+ cy="1891.8888"
+ r="12"
+ id="circle142"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Amman / Kerak"
+ cx="1129.8142"
+ cy="1972.9695"
+ r="12"
+ id="circle144"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Jaffa / Ramallah"
+ cx="463"
+ cy="1932"
+ r="12"
+ id="circle146"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Jaffa / Ascalon"
+ cx="390.88397"
+ cy="2003.7799"
+ r="12"
+ id="circle148"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Ramallah / Jerusalem"
+ cx="586"
+ cy="1971.5"
+ r="12"
+ id="circle150"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Ramallah / Ascalon"
+ cx="448"
+ cy="2014"
+ r="12"
+ id="circle152"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Jerusalem / Jericho"
+ cx="789.3551"
+ cy="1954.4401"
+ r="12"
+ id="circle154"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Jerusalem / Hebron"
+ cx="677.30878"
+ cy="2050.4141"
+ r="12"
+ id="circle156"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Jericho / Kerak"
+ cx="951.5"
+ cy="1975.5"
+ r="12"
+ id="circle158"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Ascalon / Lachish"
+ cx="439.29956"
+ cy="2128.4792"
+ r="12"
+ id="circle160"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Ascalon / Gaza"
+ cx="330.43219"
+ cy="2133.1641"
+ r="12"
+ id="circle162"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Lachish / Hebron"
+ cx="556.32245"
+ cy="2150.7788"
+ r="12"
+ id="circle164"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Lachish / Gaza"
+ cx="429.73749"
+ cy="2172.2603"
+ r="12"
+ id="circle166"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Hebron / Dimona"
+ cx="658.28107"
+ cy="2241.6177"
+ r="12"
+ id="circle168"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Hebron / Zoar"
+ cx="779.01019"
+ cy="2195.3918"
+ r="12"
+ id="circle170"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Kerak / Zoar"
+ cx="998.22845"
+ cy="2139.8015"
+ r="12"
+ id="circle172"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Gaza / Beersheba"
+ cx="369"
+ cy="2265"
+ r="12"
+ id="circle174"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Gaza / Egypt"
+ cx="225.37711"
+ cy="2266.1133"
+ r="12"
+ id="circle176"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Beersheba / Dimona"
+ cx="538.5"
+ cy="2293"
+ r="12"
+ id="circle178"
+ style="opacity:0.49443174" />
+ <circle
+ inkscape:label="Beersheba / Egypt"
+ cx="414.74786"
+ cy="2311.9475"
+ r="12"
+ id="circle180"
+ style="opacity:0.494432" />
+ <circle
+ inkscape:label="Dimona / Zoar"
+ cx="788"
+ cy="2290.5"
+ r="12"
+ id="circle182"
+ style="opacity:0.49443174" />
+</svg>