From 3d51314af3e348300736d36660e04c336b86fe99 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Mon, 20 Feb 2023 14:59:22 +0100 Subject: CODE --- create.html | 3 + data.js | 1467 +++++++++++++++++++++++++++++++++++++++++++++++ images/icon_auc.png | Bin 0 -> 9979 bytes images/icon_cartels.png | Bin 0 -> 14139 bytes images/icon_farc.png | Bin 0 -> 9402 bytes images/icon_govt.png | Bin 0 -> 8605 bytes play.css | 428 ++++++++++++++ play.html | 171 ++++++ play.js | 822 ++++++++++++++++++++++++++ rules.js | 1183 ++++++++++++++++++++++++++++++++++++++ tokens.1x/shipment.png | Bin 0 -> 5248 bytes tokens.2x/shipment.png | Bin 0 -> 14844 bytes tools/gendata.js | 86 +-- tools/genpieces.mjs | 1 + tools/scale_tokens.sh | 82 +-- tools/slice_tokens.sh | 13 +- 16 files changed, 4169 insertions(+), 87 deletions(-) create mode 100644 data.js create mode 100644 images/icon_auc.png create mode 100644 images/icon_cartels.png create mode 100644 images/icon_farc.png create mode 100644 images/icon_govt.png create mode 100644 play.css create mode 100644 play.html create mode 100644 play.js create mode 100644 rules.js create mode 100644 tokens.1x/shipment.png create mode 100644 tokens.2x/shipment.png diff --git a/create.html b/create.html index e69de29..b6ec3f7 100644 --- a/create.html +++ b/create.html @@ -0,0 +1,3 @@ +

+ +

diff --git a/data.js b/data.js new file mode 100644 index 0000000..76bce08 --- /dev/null +++ b/data.js @@ -0,0 +1,1467 @@ +const data = { + "first_pop": 1, + "first_city": 0, + "last_city": 10, + "first_dept": 11, + "last_pop": 22, + "last_dept": 26, + "first_foreign": 27, + "last_foreign": 31, + "first_loc": 32, + "last_loc": 49, + "coastal_spaces": [ + 11, + 12, + 13, + 17 + ], + "cards": [ + null, + { + "number": 1, + "name": "1st Division", + "order": [ + "Government", + "FARC", + "AUC", + "Cartels" + ] + }, + { + "number": 2, + "name": "Ospina & Mora", + "order": [ + "Government", + "FARC", + "AUC", + "Cartels" + ] + }, + { + "number": 3, + "name": "Tapias", + "order": [ + "Government", + "FARC", + "AUC", + "Cartels" + ] + }, + { + "number": 4, + "name": "Caño Limón - Coveñas", + "order": [ + "Government", + "FARC", + "Cartels", + "AUC" + ] + }, + { + "number": 5, + "name": "Occidental & Ecopetrol", + "order": [ + "Government", + "FARC", + "Cartels", + "AUC" + ] + }, + { + "number": 6, + "name": "Oil Spill", + "order": [ + "Government", + "FARC", + "Cartels", + "AUC" + ] + }, + { + "number": 7, + "name": "7th Special Forces", + "order": [ + "Government", + "AUC", + "FARC", + "Cartels" + ] + }, + { + "number": 8, + "name": "Fuerza Aérea Colombiana", + "order": [ + "Government", + "AUC", + "FARC", + "Cartels" + ] + }, + { + "number": 9, + "name": "High Mountain Battalions", + "order": [ + "Government", + "AUC", + "FARC", + "Cartels" + ] + }, + { + "number": 10, + "name": "Blackhawks", + "order": [ + "Government", + "AUC", + "Cartels", + "FARC" + ] + }, + { + "number": 11, + "name": "National Defense & Security Council", + "order": [ + "Government", + "AUC", + "Cartels", + "FARC" + ] + }, + { + "number": 12, + "name": "Plan Colombia", + "order": [ + "Government", + "AUC", + "Cartels", + "FARC" + ] + }, + { + "number": 13, + "name": "Plan Meteoro", + "order": [ + "Government", + "Cartels", + "FARC", + "AUC" + ] + }, + { + "number": 14, + "name": "Tres Esquinas", + "order": [ + "Government", + "Cartels", + "FARC", + "AUC" + ] + }, + { + "number": 15, + "name": "War Tax", + "order": [ + "Government", + "Cartels", + "FARC", + "AUC" + ] + }, + { + "number": 16, + "name": "Coffee Prices", + "order": [ + "Government", + "Cartels", + "AUC", + "FARC" + ] + }, + { + "number": 17, + "name": "Madrid Donors", + "order": [ + "Government", + "Cartels", + "AUC", + "FARC" + ] + }, + { + "number": 18, + "name": "NSPD-18", + "order": [ + "Government", + "Cartels", + "AUC", + "FARC" + ] + }, + { + "number": 19, + "name": "General Offensive", + "order": [ + "FARC", + "Government", + "AUC", + "Cartels" + ] + }, + { + "number": 20, + "name": "Mono Jojoy", + "order": [ + "FARC", + "Government", + "AUC", + "Cartels" + ] + }, + { + "number": 21, + "name": "Raúl Reyes", + "order": [ + "FARC", + "Government", + "AUC", + "Cartels" + ] + }, + { + "number": 22, + "name": "Alfonso Cano", + "order": [ + "FARC", + "Government", + "Cartels", + "AUC" + ] + }, + { + "number": 23, + "name": "DoD Contractors", + "order": [ + "FARC", + "Government", + "Cartels", + "AUC" + ] + }, + { + "number": 24, + "name": "Operación Jaque", + "order": [ + "FARC", + "Government", + "Cartels", + "AUC" + ] + }, + { + "number": 25, + "name": "Ejército de Liberación Nacional", + "order": [ + "FARC", + "AUC", + "Government", + "Cartels" + ] + }, + { + "number": 26, + "name": "Gramaje", + "order": [ + "FARC", + "AUC", + "Government", + "Cartels" + ] + }, + { + "number": 27, + "name": "Misil Antiaéreo", + "order": [ + "FARC", + "AUC", + "Government", + "Cartels" + ] + }, + { + "number": 28, + "name": "Hugo Chávez", + "order": [ + "FARC", + "AUC", + "Cartels", + "Government" + ] + }, + { + "number": 29, + "name": "Kill Zone", + "order": [ + "FARC", + "AUC", + "Cartels", + "Government" + ] + }, + { + "number": 30, + "name": "Peace Commission", + "order": [ + "FARC", + "AUC", + "Cartels", + "Government" + ] + }, + { + "number": 31, + "name": "Betancourt", + "order": [ + "FARC", + "Cartels", + "Government", + "AUC" + ] + }, + { + "number": 32, + "name": "Secuestrados", + "order": [ + "FARC", + "Cartels", + "Government", + "AUC" + ] + }, + { + "number": 33, + "name": "Sucumbíos", + "order": [ + "FARC", + "Cartels", + "Government", + "AUC" + ] + }, + { + "number": 34, + "name": "Airdropped AKs", + "order": [ + "FARC", + "Cartels", + "AUC", + "Government" + ] + }, + { + "number": 35, + "name": "Crop Substitution", + "order": [ + "FARC", + "Cartels", + "AUC", + "Government" + ] + }, + { + "number": 36, + "name": "Zona de Convivencia", + "order": [ + "FARC", + "Cartels", + "AUC", + "Government" + ] + }, + { + "number": 37, + "name": "Former Military", + "order": [ + "AUC", + "Government", + "FARC", + "Cartels" + ] + }, + { + "number": 38, + "name": "National Coordination Center", + "order": [ + "AUC", + "Government", + "FARC", + "Cartels" + ] + }, + { + "number": 39, + "name": "Soldados Campesinos", + "order": [ + "AUC", + "Government", + "FARC", + "Cartels" + ] + }, + { + "number": 40, + "name": "Demobilization", + "order": [ + "AUC", + "Government", + "Cartels", + "FARC" + ] + }, + { + "number": 41, + "name": "Mancuso", + "order": [ + "AUC", + "Government", + "Cartels", + "FARC" + ] + }, + { + "number": 42, + "name": "Senado & Cámara", + "order": [ + "AUC", + "Government", + "Cartels", + "FARC" + ] + }, + { + "number": 43, + "name": "Calima Front", + "order": [ + "AUC", + "FARC", + "Government", + "Cartels" + ] + }, + { + "number": 44, + "name": "Colombia Nueva", + "order": [ + "AUC", + "FARC", + "Government", + "Cartels" + ] + }, + { + "number": 45, + "name": "Los Derechos Humanos", + "order": [ + "AUC", + "FARC", + "Government", + "Cartels" + ] + }, + { + "number": 46, + "name": "Limpieza", + "order": [ + "AUC", + "FARC", + "Cartels", + "Government" + ] + }, + { + "number": 47, + "name": "Pinto & del Rosario", + "order": [ + "AUC", + "FARC", + "Cartels", + "Government" + ] + }, + { + "number": 48, + "name": "Unión Sindical Obrera", + "order": [ + "AUC", + "FARC", + "Cartels", + "Government" + ] + }, + { + "number": 49, + "name": "Bloques", + "order": [ + "AUC", + "Cartels", + "Government", + "FARC" + ] + }, + { + "number": 50, + "name": "Carabineros", + "order": [ + "AUC", + "Cartels", + "Government", + "FARC" + ] + }, + { + "number": 51, + "name": "Pipeline Repairs", + "order": [ + "AUC", + "Cartels", + "Government", + "FARC" + ] + }, + { + "number": 52, + "name": "Castaño", + "order": [ + "AUC", + "Cartels", + "FARC", + "Government" + ] + }, + { + "number": 53, + "name": "Criminal Air Force", + "order": [ + "AUC", + "Cartels", + "FARC", + "Government" + ] + }, + { + "number": 54, + "name": "Deserters & Defectors", + "order": [ + "AUC", + "Cartels", + "FARC", + "Government" + ] + }, + { + "number": 55, + "name": "DEA Agents", + "order": [ + "Cartels", + "Government", + "FARC", + "AUC" + ] + }, + { + "number": 56, + "name": "Drogas La Rebaja", + "order": [ + "Cartels", + "Government", + "FARC", + "AUC" + ] + }, + { + "number": 57, + "name": "Op Millennium", + "order": [ + "Cartels", + "Government", + "FARC", + "AUC" + ] + }, + { + "number": 58, + "name": "General Serrano", + "order": [ + "Cartels", + "Government", + "AUC", + "FARC" + ] + }, + { + "number": 59, + "name": "Salcedo", + "order": [ + "Cartels", + "Government", + "AUC", + "FARC" + ] + }, + { + "number": 60, + "name": "The Chess Player", + "order": [ + "Cartels", + "Government", + "AUC", + "FARC" + ] + }, + { + "number": 61, + "name": "Air Bridge", + "order": [ + "Cartels", + "FARC", + "Government", + "AUC" + ] + }, + { + "number": 62, + "name": "Amazonía", + "order": [ + "Cartels", + "FARC", + "Government", + "AUC" + ] + }, + { + "number": 63, + "name": "Narco-War", + "order": [ + "Cartels", + "FARC", + "Government", + "AUC" + ] + }, + { + "number": 64, + "name": "Cocaine Labs", + "order": [ + "Cartels", + "FARC", + "AUC", + "Government" + ] + }, + { + "number": 65, + "name": "Poppies", + "order": [ + "Cartels", + "FARC", + "AUC", + "Government" + ] + }, + { + "number": 66, + "name": "Tingo María", + "order": [ + "Cartels", + "FARC", + "AUC", + "Government" + ] + }, + { + "number": 67, + "name": "Mexican Traffickers", + "order": [ + "Cartels", + "AUC", + "Government", + "FARC" + ] + }, + { + "number": 68, + "name": "Narco-Subs", + "order": [ + "Cartels", + "AUC", + "Government", + "FARC" + ] + }, + { + "number": 69, + "name": "Riverines & Fast Boats", + "order": [ + "Cartels", + "AUC", + "Government", + "FARC" + ] + }, + { + "number": 70, + "name": "Ayahuasca Tourism", + "order": [ + "Cartels", + "AUC", + "FARC", + "Government" + ] + }, + { + "number": 71, + "name": "Darién", + "order": [ + "Cartels", + "AUC", + "FARC", + "Government" + ] + }, + { + "number": 72, + "name": "Sicarios", + "order": [ + "Cartels", + "AUC", + "FARC", + "Government" + ] + }, + { + "number": 73, + "name": "Propaganda!", + "order": null + }, + { + "number": 74, + "name": "Propaganda!", + "order": null + }, + { + "number": 75, + "name": "Propaganda!", + "order": null + }, + { + "number": 76, + "name": "Propaganda!", + "order": null + } + ], + "spaces": [ + { + "type": "city", + "id": "Bogota", + "name": "Bogotá", + "pop": 8, + "adjacent": [ + 35, + 42, + 43, + 45, + 19, + 22, + 14, + 20 + ] + }, + { + "type": "city", + "id": "Cali", + "name": "Cali", + "pop": 3, + "adjacent": [ + 12, + 13, + 20, + 33, + 37, + 41 + ] + }, + { + "type": "city", + "id": "Medellin", + "name": "Medellín", + "pop": 3, + "adjacent": [ + 12, + 18, + 39, + 40 + ] + }, + { + "type": "city", + "id": "Bucaramanga", + "name": "Bucaramanga", + "pop": 2, + "adjacent": [ + 18, + 19, + 42, + 47 + ] + }, + { + "type": "city", + "id": "Ibague", + "name": "Ibagué", + "pop": 2, + "adjacent": [ + 12, + 18, + 20, + 40, + 41, + 42 + ] + }, + { + "type": "city", + "id": "Santa Marta", + "name": "Santa Marta", + "pop": 2, + "adjacent": [ + 11, + 17, + 32, + 46 + ] + }, + { + "type": "city", + "id": "Cartagena", + "name": "Cartagena", + "pop": 1, + "adjacent": [ + 11, + 32, + 38 + ] + }, + { + "type": "city", + "id": "Cucuta", + "name": "Cúcuta", + "pop": 1, + "adjacent": [ + 19, + 31, + 44, + 49 + ] + }, + { + "type": "city", + "id": "Neiva", + "name": "Neiva", + "pop": 1, + "adjacent": [ + 14, + 16, + 20, + 34, + 43 + ] + }, + { + "type": "city", + "id": "Pasto", + "name": "Pasto", + "pop": 1, + "adjacent": [ + 13, + 16, + 20, + 28, + 33, + 34, + 36 + ] + }, + { + "type": "city", + "id": "Sincelejo", + "name": "Sincelejo", + "pop": 1, + "adjacent": [ + 11, + 12, + 18, + 38, + 39, + 48 + ] + }, + { + "type": "forest", + "id": "Atlantico", + "name": "Atlántico", + "pop": 1, + "adjacent": [ + 5, + 6, + 10, + 17, + 18, + 19, + 32, + 38, + 46, + 47, + 48, + 49 + ] + }, + { + "type": "forest", + "id": "Choco", + "name": "Chocó", + "pop": 1, + "adjacent": [ + 1, + 2, + 4, + 10, + 13, + 18, + 20, + 29, + 37, + 39, + 40, + 41 + ] + }, + { + "type": "forest", + "id": "Narino", + "name": "Nariño", + "pop": 1, + "adjacent": [ + 1, + 9, + 12, + 20, + 28, + 33, + 36, + 37 + ] + }, + { + "type": "forest", + "id": "Meta West", + "name": "Meta West", + "pop": 1, + "adjacent": [ + 0, + 8, + 15, + 16, + 20, + 22, + 35, + 43 + ] + }, + { + "type": "forest", + "id": "Guaviare", + "name": "Guaviare", + "pop": 1, + "adjacent": [ + 14, + 16, + 22, + 23, + 24, + 25, + 35 + ] + }, + { + "type": "forest", + "id": "Putumayo", + "name": "Putumayo", + "pop": 1, + "adjacent": [ + 8, + 9, + 14, + 15, + 20, + 25, + 26, + 28, + 30, + 34 + ] + }, + { + "type": "mountain", + "id": "Cesar", + "name": "Cesar", + "pop": 1, + "adjacent": [ + 5, + 11, + 18, + 19, + 31, + 46, + 47, + 48, + 49 + ] + }, + { + "type": "mountain", + "id": "Antioquia", + "name": "Antioquia", + "pop": 2, + "adjacent": [ + 2, + 3, + 4, + 10, + 11, + 12, + 17, + 19, + 20, + 39, + 40, + 42, + 46, + 47, + 48, + 49 + ] + }, + { + "type": "mountain", + "id": "Santander", + "name": "Santander", + "pop": 2, + "adjacent": [ + 0, + 3, + 7, + 11, + 17, + 18, + 20, + 21, + 22, + 31, + 45, + 46, + 47, + 48, + 49 + ] + }, + { + "type": "mountain", + "id": "Huila", + "name": "Huila", + "pop": 2, + "adjacent": [ + 0, + 1, + 4, + 8, + 9, + 12, + 13, + 14, + 16, + 18, + 19, + 33, + 34, + 41, + 42, + 43 + ] + }, + { + "type": "grassland", + "id": "Arauca", + "name": "Arauca", + "pop": 1, + "adjacent": [ + 19, + 22, + 23, + 31, + 44, + 45 + ] + }, + { + "type": "grassland", + "id": "Meta East", + "name": "Meta East", + "pop": 1, + "adjacent": [ + 0, + 14, + 15, + 19, + 21, + 23, + 35, + 45 + ] + }, + { + "type": "grassland", + "id": "Vichada", + "name": "Vichada", + "pop": 0, + "adjacent": [ + 15, + 21, + 22, + 24, + 31 + ] + }, + { + "type": "forest", + "id": "Guainia", + "name": "Guainía", + "pop": 0, + "adjacent": [ + 15, + 23, + 25, + 27, + 31 + ] + }, + { + "type": "forest", + "id": "Vaupes", + "name": "Vaupés", + "pop": 0, + "adjacent": [ + 15, + 16, + 24, + 26, + 27 + ] + }, + { + "type": "forest", + "id": "Amazonas", + "name": "Amazonas", + "pop": 0, + "adjacent": [ + 16, + 25, + 27, + 30 + ] + }, + { + "type": "foreign", + "id": "Brasil", + "name": "Brasil", + "pop": 0, + "adjacent": [ + 24, + 25, + 26 + ] + }, + { + "type": "foreign", + "id": "Ecuador", + "name": "Ecuador", + "pop": 0, + "adjacent": [ + 9, + 13, + 16, + 36 + ] + }, + { + "type": "foreign", + "id": "Panama", + "name": "Panamá", + "pop": 0, + "adjacent": [ + 12 + ] + }, + { + "type": "foreign", + "id": "Peru", + "name": "Perú", + "pop": 0, + "adjacent": [ + 16, + 26 + ] + }, + { + "type": "foreign", + "id": "Venezuela", + "name": "Venezuela", + "pop": 0, + "adjacent": [ + 7, + 17, + 19, + 21, + 23, + 24, + 44, + 49 + ] + }, + { + "type": "road", + "name": "Santa Marta / Cartagena", + "id": "Santa Marta / Cartagena", + "econ": 1, + "adjacent": [ + 5, + 6, + 11 + ] + }, + { + "type": "road", + "name": "Cali / Pasto", + "id": "Cali / Pasto", + "econ": 1, + "adjacent": [ + 1, + 9, + 13, + 20 + ] + }, + { + "type": "road", + "name": "Neiva / Pasto", + "id": "Neiva / Pasto", + "econ": 1, + "adjacent": [ + 8, + 9, + 16, + 20 + ] + }, + { + "type": "road", + "name": "Bogotá / San José", + "id": "Bogota / San Jose", + "econ": 1, + "adjacent": [ + 14, + 15, + 22 + ] + }, + { + "type": "road", + "name": "Pasto / Tumaco", + "id": "Pasto / Tumaco", + "econ": 1, + "adjacent": [ + 9, + 13, + 28 + ] + }, + { + "type": "pipeline", + "name": "Cali / Buenaventura", + "id": "Cali / Buenaventura", + "econ": 1, + "adjacent": [ + 1, + 12, + 13 + ] + }, + { + "type": "pipeline", + "name": "Cartagena / Sincelejo", + "id": "Cartagena / Sincelejo", + "econ": 1, + "adjacent": [ + 6, + 10, + 11 + ] + }, + { + "type": "pipeline", + "name": "Sincelejo / Medellín", + "id": "Sincelejo / Medellin", + "econ": 2, + "adjacent": [ + 2, + 10, + 12, + 18 + ] + }, + { + "type": "pipeline", + "name": "Medellín / Ibagué", + "id": "Medellin / Ibague", + "econ": 1, + "adjacent": [ + 2, + 4, + 12, + 18 + ] + }, + { + "type": "pipeline", + "name": "Ibagué / Cali", + "id": "Ibague / Cali", + "econ": 1, + "adjacent": [ + 1, + 4, + 12, + 20 + ] + }, + { + "type": "pipeline", + "name": "Bucaramanga / Ibagué / Bogotá", + "id": "Bucaramanga / Ibague / Bogota", + "econ": 2, + "adjacent": [ + 3, + 4, + 18, + 20 + ] + }, + { + "type": "pipeline", + "name": "Bogotá / Neiva", + "id": "Bogota / Neiva", + "econ": 2, + "adjacent": [ + 8, + 14, + 20 + ] + }, + { + "type": "pipeline", + "name": "Cúcuta / Arauca", + "id": "Cucuta / Arauca", + "econ": 3, + "adjacent": [ + 7, + 21, + 21, + 31 + ] + }, + { + "type": "pipeline", + "name": "Bogotá / Yopal", + "id": "Bogota / Yopal", + "econ": 2, + "adjacent": [ + 19, + 21, + 22 + ] + }, + { + "type": "pipeline", + "name": "Santa Marta / Ayacucho", + "id": "Santa Marta / Ayacucho", + "econ": 2, + "adjacent": [ + 5, + 11, + 17, + 18, + 19, + 47, + 48, + 49 + ] + }, + { + "type": "pipeline", + "name": "Bucaramanga / Ayacucho", + "id": "Bucaramanga / Ayacucho", + "econ": 2, + "adjacent": [ + 3, + 11, + 17, + 18, + 19, + 46, + 48, + 49 + ] + }, + { + "type": "pipeline", + "name": "Sincelejo / Ayacucho", + "id": "Sincelejo / Ayacucho", + "econ": 3, + "adjacent": [ + 10, + 11, + 17, + 18, + 19, + 46, + 47, + 49 + ] + }, + { + "type": "pipeline", + "name": "Cúcuta / Ayacucho", + "id": "Cucuta / Ayacucho", + "econ": 3, + "adjacent": [ + 7, + 11, + 17, + 18, + 19, + 31, + 46, + 47, + 48 + ] + } + ] +} +if (typeof module !== 'undefined') module.exports = data diff --git a/images/icon_auc.png b/images/icon_auc.png new file mode 100644 index 0000000..c910d32 Binary files /dev/null and b/images/icon_auc.png differ diff --git a/images/icon_cartels.png b/images/icon_cartels.png new file mode 100644 index 0000000..8723fab Binary files /dev/null and b/images/icon_cartels.png differ diff --git a/images/icon_farc.png b/images/icon_farc.png new file mode 100644 index 0000000..fa2d5aa Binary files /dev/null and b/images/icon_farc.png differ diff --git a/images/icon_govt.png b/images/icon_govt.png new file mode 100644 index 0000000..4d6c582 Binary files /dev/null and b/images/icon_govt.png differ diff --git a/play.css b/play.css new file mode 100644 index 0000000..3b0e9d6 --- /dev/null +++ b/play.css @@ -0,0 +1,428 @@ +main { background-color: #777; } + +#role_Government, header.govt.your_turn { background-color: skyblue; } +#role_AUC, header.auc.your_turn { background-color: khaki; } +#role_Cartels, header.cartels.your_turn { background-color: darkseagreen; } +#role_FARC, header.farc.your_turn { background-color: lightcoral; } + +#log { background-color: whitesmoke; } +#log > div { padding-left: 20px; text-indent: -12px; } +#log .h1 { background-color: silver; font-weight: bold; padding-top:4px; padding-bottom:4px; } +#log .h2 { background-color: gainsboro; padding-top:2px; padding-bottom:2px; } +#log .h2.govt { background-color: #c6d1eb } +#log .h2.farc { background-color: #ebc9be } +#log .h2.auc { background-color: #eaddc4 } +#log .h2.cartels { background-color: #c2d7c7 } +#log .h3 { text-decoration: underline; } +#log .tip { cursor: pointer; } +#log .tip:hover { text-decoration: underline; } + +.action { cursor: pointer } + +.role.active span { text-decoration: underline; } + +#card_tip { + position: fixed; + z-index: 100; + right: 240px; + top: 60px; +} + +#mapwrap { + box-shadow: 0px 1px 10px #0008; + width: 1650px; + height: 2550px; + margin-bottom: 36px; +} + +#map { + width: 1650px; + height: 2550px; + background-repeat: no-repeat; + background-size: cover; +} + +#map { background-image: url("map75.jpg") } +@media (min-resolution: 97dpi) { +#map { background-image: url("map150.jpg") } +} + +#svgmap { position: absolute; } +#tokens { position: absolute; } +#pieces { position: absolute; } +#cities { position: absolute; } +#boxes { position: absolute; } + +path { fill: transparent; } +path.action { fill: white; fill-opacity: 0.3; stroke: white; stroke-width: 4; } +path.action.foreign { fill: gold; stroke: lemonchiffon; } +path.action.forest { fill: limegreen; stroke: limegreen; } +path.action.grassland { fill: greenyellow; stroke: greenyellow; } +path.action.mountain { fill: chocolate; stroke: chocolate; } + +.box{position:absolute;box-sizing:border-box;} +.box.action{z-index:100; border:4px solid lemonchiffon;} +.box.city{border-radius:50%} +.box.city.action{background-color:#6495ed55;border:4px solid cornflowerblue;} +.box.loc{border-radius:50%} +.box.loc.action{background-color:#fff5;border:4px solid white;} + +.piece { position: absolute; } +.piece { background-position: center; background-repeat: no-repeat; background-size: contain; } +.piece { + transition-property: top, left; + transition-duration: 700ms; + transition-timing-function: ease; +} +.piece { + filter: drop-shadow(0 1px 2px #000a); +} +.piece.action { + filter: + drop-shadow(0 -2px 0 white) + drop-shadow(0 2px 0 white) + drop-shadow(-2px 0 0 white) + drop-shadow(2px 0 0 white) + ; +} + +.token { + position: absolute; + transition-property: top, left; + transition-duration: 700ms; + transition-timing-function: ease; + background-repeat: no-repeat; + border-radius: 8px; + border: 2px solid #333; + background-size: 45px 45px; + width: 45px; + height: 45px; +} + +.token.terror, +.token.sabotage, +.token.active_opposition, +.token.passive_opposition, +.token.passive_support, +.token.active_support, +.token.reminder +{ + border-radius: 0px; + background-size: 36px 36px; + width: 36px; + height: 36px; +} + +.token.shipment +{ + border-radius: 50%; + background-size: 50px 50px; + background-position: center; + width: 50px; + height: 50px; +} +.token.shipment { background-color: #01904b; border-color: #01904b; box-shadow: 0 0 0 1px #002c00, 0px 1px 4px #0008; } + +#token_total_support { background-color: #006cb7; border-color: #348cda #004d95 #004d95 #348cda; box-shadow: 0 0 0 1px #000d55, 0px 1px 4px #0008; } +#token_prop_card { background-color: #80643e; border-color: #a0835c #614721 #614721 #a0835c; box-shadow: 0 0 0 1px #291200, 0px 1px 4px #0008; } +#token_oppose_plus_bases { background-color: #d74729; border-color: #ff6f50 #ad1800 #ad1800 #ff6f50; box-shadow: 0 0 0 1px #5a0000, 0px 1px 4px #0008; } +#token_el_presidente { background-color: #004e81; border-color: #23669b #003768 #003768 #23669b; box-shadow: 0 0 0 1px #000939, 0px 1px 4px #0008; } +#token_aid { background-color: #6a8796; border-color: #8eacbc #486472 #486472 #8eacbc; box-shadow: 0 0 0 1px #08232f, 0px 1px 4px #0008; } +.token.passive_support { background-color: #4b87c0; border-color: #70ade8 #266399 #266399 #70ade8; box-shadow: 0 0 0 1px #001e50, 0px 1px 4px #0008; } +.token.passive_opposition { background-color: #b75f61; border-color: #df8384 #903c40 #903c40 #df8384; box-shadow: 0 0 0 1px #460005, 0px 1px 4px #0008; } +.token.active_support { background-color: #0054a6; border-color: #286fc4 #003989 #003989 #286fc4; box-shadow: 0 0 0 1px #000051, 0px 1px 4px #0008; } +.token.active_opposition { background-color: #991a1e; border-color: #b73a37 #7b0001 #7b0001 #b73a37; box-shadow: 0 0 0 1px #400000, 0px 1px 4px #0008; } +.token.govt_control { background-color: #0054a6; border-color: #286fc4 #003989 #003989 #286fc4; box-shadow: 0 0 0 1px #000051, 0px 1px 4px #0008; } +.token.farc_control { background-color: #991a1e; border-color: #b73a37 #7b0001 #7b0001 #b73a37; box-shadow: 0 0 0 1px #400000, 0px 1px 4px #0008; } +.token.farc_zone { background-color: #ffc509; border-color: #fff75f #c68e00 #c68e00 #fff75f; box-shadow: 0 0 0 1px #5d2800, 0px 1px 4px #0008; } +.token.terror { background-color: #535052; border-color: #6b686a #3c393b #3c393b #6b686a; box-shadow: 0 0 0 1px #120f11, 0px 1px 4px #0008; } +.token.sabotage { background-color: #535052; border-color: #6b686a #3c393b #3c393b #6b686a; box-shadow: 0 0 0 1px #120f11, 0px 1px 4px #0008; } +.token.unshaded { background-color: #9dadb3; border-color: #ccdce2 #718086 #718086 #ccdce2; box-shadow: 0 0 0 1px #222f34, 0px 1px 4px #0008; } +.token.shaded { background-color: #465c80; border-color: #60779d #2d4264 #2d4264 #60779d; box-shadow: 0 0 0 1px #021230, 0px 1px 4px #0008; } +.token.reminder.sucumbios { background-color: #6d5735; border-color: #89724f #523d1b #523d1b #89724f; box-shadow: 0 0 0 1px #210f00, 0px 1px 4px #0008; } +.token.reminder.senado_farc { background-color: #cf1f30; border-color: #f74d51 #a7000b #a7000b #f74d51; box-shadow: 0 0 0 1px #590000, 0px 1px 4px #0008; } +.token.reminder.senado_cartels { background-color: #6d9f3b; border-color: #94c865 #487703 #487703 #94c865; box-shadow: 0 0 0 1px #012e00, 0px 1px 4px #0008; } +.token.reminder.senado_auc { background-color: #ffcf00; border-color: #fffa57 #c69700 #c69700 #fffa57; box-shadow: 0 0 0 1px #5b2e00, 0px 1px 4px #0008; } +.token.reminder.darien { background-color: #8dc73f; border-color: #bdfa75 #609600 #609600 #bdfa75; box-shadow: 0 0 0 1px #0a3c00, 0px 1px 4px #0008; } + +#token_aid { background-image: url(tokens.1x/aid.png) } +#token_el_presidente { background-image: url(tokens.1x/el_presidente.png) } +#token_oppose_plus_bases { background-image: url(tokens.1x/oppose_plus_bases.png) } +#token_prop_card { background-image: url(tokens.1x/prop_card.png) } +#token_total_support { background-image: url(tokens.1x/total_support.png) } +.token.shipment { background-image: url(tokens.1x/shipment.png) } +.token.terror { background-image: url(tokens.1x/terror.png) } +.token.sabotage { background-image: url(tokens.1x/sabotage.png) } +.token.active_opposition { background-image: url(tokens.1x/active_opposition.png) } +.token.passive_opposition { background-image: url(tokens.1x/passive_opposition.png) } +.token.passive_support { background-image: url(tokens.1x/passive_support.png) } +.token.active_support { background-image: url(tokens.1x/active_support.png) } +.token.farc_control { background-image: url(tokens.1x/farc_control.png) } +.token.govt_control { background-image: url(tokens.1x/govt_control.png) } +.token.farc_zone { background-image: url(tokens.1x/farc_zone.png) } +.token.unshaded.first_div { background-image: url(tokens.1x/unshaded_1st_div.png) } +.token.unshaded.seventh_sf { background-image: url(tokens.1x/unshaded_7th_sf.png) } +.token.unshaded.black_hawks { background-image: url(tokens.1x/unshaded_black_hawks.png) } +.token.unshaded.meteoro { background-image: url(tokens.1x/unshaded_meteoro.png) } +.token.unshaded.mtn_bns { background-image: url(tokens.1x/unshaded_mtn_bns.png) } +.token.unshaded.ndsc { background-image: url(tokens.1x/unshaded_ndsc.png) } +.token.unshaded.ospina { background-image: url(tokens.1x/unshaded_ospina.png) } +.token.unshaded.tapias { background-image: url(tokens.1x/unshaded_tapias.png) } +.token.shaded.first_div { background-image: url(tokens.1x/shaded_1st_div.png) } +.token.shaded.seventh_sf { background-image: url(tokens.1x/shaded_7th_sf.png) } +.token.shaded.black_hawks { background-image: url(tokens.1x/shaded_black_hawks.png) } +.token.shaded.meteoro { background-image: url(tokens.1x/shaded_meteoro.png) } +.token.shaded.mtn_bns { background-image: url(tokens.1x/shaded_mtn_bns.png) } +.token.shaded.ndsc { background-image: url(tokens.1x/shaded_ndsc.png) } +.token.shaded.ospina { background-image: url(tokens.1x/shaded_ospina.png) } +.token.shaded.tapias { background-image: url(tokens.1x/shaded_tapias.png) } +.token.reminder.darien { background-image: url(tokens.1x/reminder_darien.png) } +.token.reminder.senado_auc { background-image: url(tokens.1x/reminder_senado_auc.png) } +.token.reminder.senado_cartels { background-image: url(tokens.1x/reminder_senado_cartels.png) } +.token.reminder.senado_farc { background-image: url(tokens.1x/reminder_senado_farc.png) } +.token.reminder.sucumbios { background-image: url(tokens.1x/reminder_sucumbios.png) } + +@media (min-resolution: 97dpi) { +#token_aid { background-image: url(tokens.2x/aid.png) } +#token_el_presidente { background-image: url(tokens.2x/el_presidente.png) } +#token_oppose_plus_bases { background-image: url(tokens.2x/oppose_plus_bases.png) } +#token_prop_card { background-image: url(tokens.2x/prop_card.png) } +#token_total_support { background-image: url(tokens.2x/total_support.png) } +.token.shipment { background-image: url(tokens.2x/shipment.png) } +.token.terror { background-image: url(tokens.2x/terror.png) } +.token.sabotage { background-image: url(tokens.2x/sabotage.png) } +.token.active_opposition { background-image: url(tokens.2x/active_opposition.png) } +.token.passive_opposition { background-image: url(tokens.2x/passive_opposition.png) } +.token.passive_support { background-image: url(tokens.2x/passive_support.png) } +.token.active_support { background-image: url(tokens.2x/active_support.png) } +.token.farc_control { background-image: url(tokens.2x/farc_control.png) } +.token.govt_control { background-image: url(tokens.2x/govt_control.png) } +.token.farc_zone { background-image: url(tokens.2x/farc_zone.png) } +.token.unshaded.first_div { background-image: url(tokens.2x/unshaded_1st_div.png) } +.token.unshaded.seventh_sf { background-image: url(tokens.2x/unshaded_7th_sf.png) } +.token.unshaded.black_hawks { background-image: url(tokens.2x/unshaded_black_hawks.png) } +.token.unshaded.meteoro { background-image: url(tokens.2x/unshaded_meteoro.png) } +.token.unshaded.mtn_bns { background-image: url(tokens.2x/unshaded_mtn_bns.png) } +.token.unshaded.ndsc { background-image: url(tokens.2x/unshaded_ndsc.png) } +.token.unshaded.ospina { background-image: url(tokens.2x/unshaded_ospina.png) } +.token.unshaded.tapias { background-image: url(tokens.2x/unshaded_tapias.png) } +.token.shaded.first_div { background-image: url(tokens.2x/shaded_1st_div.png) } +.token.shaded.seventh_sf { background-image: url(tokens.2x/shaded_7th_sf.png) } +.token.shaded.black_hawks { background-image: url(tokens.2x/shaded_black_hawks.png) } +.token.shaded.meteoro { background-image: url(tokens.2x/shaded_meteoro.png) } +.token.shaded.mtn_bns { background-image: url(tokens.2x/shaded_mtn_bns.png) } +.token.shaded.ndsc { background-image: url(tokens.2x/shaded_ndsc.png) } +.token.shaded.ospina { background-image: url(tokens.2x/shaded_ospina.png) } +.token.shaded.tapias { background-image: url(tokens.2x/shaded_tapias.png) } +.token.reminder.darien { background-image: url(tokens.2x/reminder_darien.png) } +.token.reminder.senado_auc { background-image: url(tokens.2x/reminder_senado_auc.png) } +.token.reminder.senado_cartels { background-image: url(tokens.2x/reminder_senado_cartels.png) } +.token.reminder.senado_farc { background-image: url(tokens.2x/reminder_senado_farc.png) } +.token.reminder.sucumbios { background-image: url(tokens.2x/reminder_sucumbios.png) } +} + +.cylinder { width: 44px; height: 48px; } +.base { width: 44px; height: 38px; } +.guerrilla { width: 29px; height: 36px; } +.police, .troops { width: 29px; height: 36px; } + +.govt.cylinder { background-image: url(images/govt_cylinder.svg) } +.govt.police { background-image: url(images/govt_police.svg) } +.govt.troops { background-image: url(images/govt_troops.svg) } +.govt.base { background-image: url(images/govt_base.svg) } +.auc.cylinder { background-image: url(images/auc_cylinder.svg) } +.auc.guerrilla { background-image: url(images/auc_guerrilla.svg) } +.auc.guerrilla.active { background-image: url(images/auc_guerrilla_active.svg) } +.auc.base { background-image: url(images/auc_base.svg) } +.cartels.cylinder { background-image: url(images/cartels_cylinder.svg) } +.cartels.guerrilla { background-image: url(images/cartels_guerrilla.svg) } +.cartels.guerrilla.active { background-image: url(images/cartels_guerrilla_active.svg) } +.cartels.base { background-image: url(images/cartels_base.svg) } +.farc.cylinder { background-image: url(images/farc_cylinder.svg) } +.farc.guerrilla { background-image: url(images/farc_guerrilla.svg) } +.farc.guerrilla.active { background-image: url(images/farc_guerrilla_active.svg) } +.farc.base { background-image: url(images/farc_base.svg) } + +#card_panel { + display: flex; + flex-wrap: wrap; + gap: 18px; + padding: 0 18px; + max-width: 1614px; + margin: 36px auto; +} + +#deck_outer { + position: relative; +} +#deck_size { + position: absolute; + right: 24px; + bottom: 16px; + font-size: 24px; + font-weight: bold; + color: white; +} + +.card { + width: 248px; + height: 348px; + border-radius: 16px; + box-shadow: 1px 1px 4px #0008; + background-color: darkgreen; + background-size: cover; + background-repeat: no-repeat; + border: 1px solid #454; +} + +.card.card_back{background-image:url(cards.1x/card_back.jpg)} +.card.card_1{background-image:url(cards.1x/card_01.jpg)} +.card.card_2{background-image:url(cards.1x/card_02.jpg)} +.card.card_3{background-image:url(cards.1x/card_03.jpg)} +.card.card_4{background-image:url(cards.1x/card_04.jpg)} +.card.card_5{background-image:url(cards.1x/card_05.jpg)} +.card.card_6{background-image:url(cards.1x/card_06.jpg)} +.card.card_7{background-image:url(cards.1x/card_07.jpg)} +.card.card_8{background-image:url(cards.1x/card_08.jpg)} +.card.card_9{background-image:url(cards.1x/card_09.jpg)} +.card.card_10{background-image:url(cards.1x/card_10.jpg)} +.card.card_11{background-image:url(cards.1x/card_11.jpg)} +.card.card_12{background-image:url(cards.1x/card_12.jpg)} +.card.card_13{background-image:url(cards.1x/card_13.jpg)} +.card.card_14{background-image:url(cards.1x/card_14.jpg)} +.card.card_15{background-image:url(cards.1x/card_15.jpg)} +.card.card_16{background-image:url(cards.1x/card_16.jpg)} +.card.card_17{background-image:url(cards.1x/card_17.jpg)} +.card.card_18{background-image:url(cards.1x/card_18.jpg)} +.card.card_19{background-image:url(cards.1x/card_19.jpg)} +.card.card_20{background-image:url(cards.1x/card_20.jpg)} +.card.card_21{background-image:url(cards.1x/card_21.jpg)} +.card.card_22{background-image:url(cards.1x/card_22.jpg)} +.card.card_23{background-image:url(cards.1x/card_23.jpg)} +.card.card_24{background-image:url(cards.1x/card_24.jpg)} +.card.card_25{background-image:url(cards.1x/card_25.jpg)} +.card.card_26{background-image:url(cards.1x/card_26.jpg)} +.card.card_27{background-image:url(cards.1x/card_27.jpg)} +.card.card_28{background-image:url(cards.1x/card_28.jpg)} +.card.card_29{background-image:url(cards.1x/card_29.jpg)} +.card.card_30{background-image:url(cards.1x/card_30.jpg)} +.card.card_31{background-image:url(cards.1x/card_31.jpg)} +.card.card_32{background-image:url(cards.1x/card_32.jpg)} +.card.card_33{background-image:url(cards.1x/card_33.jpg)} +.card.card_34{background-image:url(cards.1x/card_34.jpg)} +.card.card_35{background-image:url(cards.1x/card_35.jpg)} +.card.card_36{background-image:url(cards.1x/card_36.jpg)} +.card.card_37{background-image:url(cards.1x/card_37.jpg)} +.card.card_38{background-image:url(cards.1x/card_38.jpg)} +.card.card_39{background-image:url(cards.1x/card_39.jpg)} +.card.card_40{background-image:url(cards.1x/card_40.jpg)} +.card.card_41{background-image:url(cards.1x/card_41.jpg)} +.card.card_42{background-image:url(cards.1x/card_42.jpg)} +.card.card_43{background-image:url(cards.1x/card_43.jpg)} +.card.card_44{background-image:url(cards.1x/card_44.jpg)} +.card.card_45{background-image:url(cards.1x/card_45.jpg)} +.card.card_46{background-image:url(cards.1x/card_46.jpg)} +.card.card_47{background-image:url(cards.1x/card_47.jpg)} +.card.card_48{background-image:url(cards.1x/card_48.jpg)} +.card.card_49{background-image:url(cards.1x/card_49.jpg)} +.card.card_50{background-image:url(cards.1x/card_50.jpg)} +.card.card_51{background-image:url(cards.1x/card_11.jpg)} +.card.card_52{background-image:url(cards.1x/card_52.jpg)} +.card.card_53{background-image:url(cards.1x/card_53.jpg)} +.card.card_54{background-image:url(cards.1x/card_54.jpg)} +.card.card_55{background-image:url(cards.1x/card_55.jpg)} +.card.card_56{background-image:url(cards.1x/card_56.jpg)} +.card.card_57{background-image:url(cards.1x/card_57.jpg)} +.card.card_58{background-image:url(cards.1x/card_58.jpg)} +.card.card_59{background-image:url(cards.1x/card_59.jpg)} +.card.card_60{background-image:url(cards.1x/card_60.jpg)} +.card.card_61{background-image:url(cards.1x/card_61.jpg)} +.card.card_62{background-image:url(cards.1x/card_62.jpg)} +.card.card_63{background-image:url(cards.1x/card_63.jpg)} +.card.card_64{background-image:url(cards.1x/card_64.jpg)} +.card.card_65{background-image:url(cards.1x/card_65.jpg)} +.card.card_66{background-image:url(cards.1x/card_66.jpg)} +.card.card_67{background-image:url(cards.1x/card_67.jpg)} +.card.card_68{background-image:url(cards.1x/card_68.jpg)} +.card.card_69{background-image:url(cards.1x/card_69.jpg)} +.card.card_70{background-image:url(cards.1x/card_70.jpg)} +.card.card_71{background-image:url(cards.1x/card_71.jpg)} +.card.card_72{background-image:url(cards.1x/card_72.jpg)} +.card.card_73, .card.card_74, .card.card_75, .card.card_76 {background-image:url(cards.1x/card_7x.jpg)} + +@media (min-resolution: 97dpi) { +.card.card_back{background-image:url(cards.2x/card_back.jpg)} +.card.card_1{background-image:url(cards.2x/card_01.jpg)} +.card.card_2{background-image:url(cards.2x/card_02.jpg)} +.card.card_3{background-image:url(cards.2x/card_03.jpg)} +.card.card_4{background-image:url(cards.2x/card_04.jpg)} +.card.card_5{background-image:url(cards.2x/card_05.jpg)} +.card.card_6{background-image:url(cards.2x/card_06.jpg)} +.card.card_7{background-image:url(cards.2x/card_07.jpg)} +.card.card_8{background-image:url(cards.2x/card_08.jpg)} +.card.card_9{background-image:url(cards.2x/card_09.jpg)} +.card.card_10{background-image:url(cards.2x/card_10.jpg)} +.card.card_11{background-image:url(cards.2x/card_11.jpg)} +.card.card_12{background-image:url(cards.2x/card_12.jpg)} +.card.card_13{background-image:url(cards.2x/card_13.jpg)} +.card.card_14{background-image:url(cards.2x/card_14.jpg)} +.card.card_15{background-image:url(cards.2x/card_15.jpg)} +.card.card_16{background-image:url(cards.2x/card_16.jpg)} +.card.card_17{background-image:url(cards.2x/card_17.jpg)} +.card.card_18{background-image:url(cards.2x/card_18.jpg)} +.card.card_19{background-image:url(cards.2x/card_19.jpg)} +.card.card_20{background-image:url(cards.2x/card_20.jpg)} +.card.card_21{background-image:url(cards.2x/card_21.jpg)} +.card.card_22{background-image:url(cards.2x/card_22.jpg)} +.card.card_23{background-image:url(cards.2x/card_23.jpg)} +.card.card_24{background-image:url(cards.2x/card_24.jpg)} +.card.card_25{background-image:url(cards.2x/card_25.jpg)} +.card.card_26{background-image:url(cards.2x/card_26.jpg)} +.card.card_27{background-image:url(cards.2x/card_27.jpg)} +.card.card_28{background-image:url(cards.2x/card_28.jpg)} +.card.card_29{background-image:url(cards.2x/card_29.jpg)} +.card.card_30{background-image:url(cards.2x/card_30.jpg)} +.card.card_31{background-image:url(cards.2x/card_31.jpg)} +.card.card_32{background-image:url(cards.2x/card_32.jpg)} +.card.card_33{background-image:url(cards.2x/card_33.jpg)} +.card.card_34{background-image:url(cards.2x/card_34.jpg)} +.card.card_35{background-image:url(cards.2x/card_35.jpg)} +.card.card_36{background-image:url(cards.2x/card_36.jpg)} +.card.card_37{background-image:url(cards.2x/card_37.jpg)} +.card.card_38{background-image:url(cards.2x/card_38.jpg)} +.card.card_39{background-image:url(cards.2x/card_39.jpg)} +.card.card_40{background-image:url(cards.2x/card_40.jpg)} +.card.card_41{background-image:url(cards.2x/card_41.jpg)} +.card.card_42{background-image:url(cards.2x/card_42.jpg)} +.card.card_43{background-image:url(cards.2x/card_43.jpg)} +.card.card_44{background-image:url(cards.2x/card_44.jpg)} +.card.card_45{background-image:url(cards.2x/card_45.jpg)} +.card.card_46{background-image:url(cards.2x/card_46.jpg)} +.card.card_47{background-image:url(cards.2x/card_47.jpg)} +.card.card_48{background-image:url(cards.2x/card_48.jpg)} +.card.card_49{background-image:url(cards.2x/card_49.jpg)} +.card.card_50{background-image:url(cards.2x/card_50.jpg)} +.card.card_51{background-image:url(cards.2x/card_11.jpg)} +.card.card_52{background-image:url(cards.2x/card_52.jpg)} +.card.card_53{background-image:url(cards.2x/card_53.jpg)} +.card.card_54{background-image:url(cards.2x/card_54.jpg)} +.card.card_55{background-image:url(cards.2x/card_55.jpg)} +.card.card_56{background-image:url(cards.2x/card_56.jpg)} +.card.card_57{background-image:url(cards.2x/card_57.jpg)} +.card.card_58{background-image:url(cards.2x/card_58.jpg)} +.card.card_59{background-image:url(cards.2x/card_59.jpg)} +.card.card_60{background-image:url(cards.2x/card_60.jpg)} +.card.card_61{background-image:url(cards.2x/card_61.jpg)} +.card.card_62{background-image:url(cards.2x/card_62.jpg)} +.card.card_63{background-image:url(cards.2x/card_63.jpg)} +.card.card_64{background-image:url(cards.2x/card_64.jpg)} +.card.card_65{background-image:url(cards.2x/card_65.jpg)} +.card.card_66{background-image:url(cards.2x/card_66.jpg)} +.card.card_67{background-image:url(cards.2x/card_67.jpg)} +.card.card_68{background-image:url(cards.2x/card_68.jpg)} +.card.card_69{background-image:url(cards.2x/card_69.jpg)} +.card.card_70{background-image:url(cards.2x/card_70.jpg)} +.card.card_71{background-image:url(cards.2x/card_71.jpg)} +.card.card_72{background-image:url(cards.2x/card_72.jpg)} +.card.card_73, .card.card_74, .card.card_75, .card.card_76 {background-image:url(cards.2x/card_7x.jpg)} +} diff --git a/play.html b/play.html new file mode 100644 index 0000000..9b68a9d --- /dev/null +++ b/play.html @@ -0,0 +1,171 @@ + + + + + + +ANDEAN ABYSS + + + + + + + + + + +
+ +
+
+ +
+
+
+
+
+
+
+ + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+ + + + diff --git a/play.js b/play.js new file mode 100644 index 0000000..89df679 --- /dev/null +++ b/play.js @@ -0,0 +1,822 @@ +// TODO: FARC zone +// TODO: terror markers + +// Spaces +const AVAILABLE = -1 + +// Sequence of Play options +const ELIGIBLE = 0 +const SOP_A1 = 1 +const SOP_A2 = 2 +const SOP_B1 = 3 +const SOP_B2 = 4 +const SOP_C1 = 5 +const SOP_C2 = 6 +const SOP_PASS = 7 +const INELIGIBLE = 8 + +let ui = { + favicon: document.getElementById("favicon"), + header: document.querySelector("header"), + player: { + govt: document.getElementById("role_Government"), + auc: document.getElementById("role_AUC"), + cartels: document.getElementById("role_Cartels"), + farc: document.getElementById("role_FARC"), + }, + spaces: [], + control: [], + support: [], + sabotage: [], + next_card: document.getElementById("next_card"), + this_card: document.getElementById("this_card"), + deck_size: document.getElementById("deck_size"), + sop: [ + null, + document.getElementById("SOP_A1"), + document.getElementById("SOP_A2"), + document.getElementById("SOP_B1"), + document.getElementById("SOP_B2"), + document.getElementById("SOP_C1"), + document.getElementById("SOP_C2"), + document.getElementById("SOP_PASS"), + ], + misc: { + aid: document.getElementById("token_aid"), + total_support: document.getElementById("token_total_support"), + oppose_plus_bases: document.getElementById("token_oppose_plus_bases"), + president: document.getElementById("token_el_presidente"), + propaganda: document.getElementById("token_prop_card"), + shipments: [], + }, + govt: { + resources: document.getElementById("govt_resources"), + cylinder: document.getElementById("govt_cylinder"), + police: [], + troops: [], + bases: [], + }, + auc: { + resources: document.getElementById("auc_resources"), + cylinder: document.getElementById("auc_cylinder"), + guerrillas: [], + bases: [], + }, + cartels: { + resources: document.getElementById("cartels_resources"), + cylinder: document.getElementById("cartels_cylinder"), + guerrillas: [], + bases: [], + }, + farc: { + resources: document.getElementById("farc_resources"), + cylinder: document.getElementById("farc_cylinder"), + guerrillas: [], + bases: [], + }, +} + +function create(t, p, ...c) { + let e = document.createElement(t) + Object.assign(e, p) + e.append(c) + return e +} + +function register_action(e, action, id) { + e.my_action = action + e.my_id = id + e.onclick = on_click_action +} + +function is_action(action, arg) { + if (arg === undefined) + return !!(view.actions && view.actions[action] === 1) + return !!(view.actions && view.actions[action] && set_has(view.actions[action], arg)) +} + +function toggle_pieces() { + document.getElementById("pieces").classList.toggle("hide") +} + +function on_click_action(evt) { + if (evt.button === 0) + send_action(evt.target.my_action, evt.target.my_id) +} + +const first_pop = 1 +const first_city = 0 +const last_city = 10 +const first_dept = 11 +const last_pop = 22 +const last_dept = 26 +const first_foreign = 27 +const last_foreign = 31 +const first_loc = 32 +const last_loc = 49 + +const center_xy = { + "Santa Marta": [682,436], + "Cartagena": [500,512], + "Sincelejo": [514,708], + "Medellin": [513,1066], + "Ibague": [507,1278], + "Cali": [391,1497], + "Pasto": [274,1783], + "Neiva": [589,1542], + "Bogota": [754,1336], + "Bucaramanga": [839,980], + "Cucuta": [951,864], + "Guainia": [1409,1542], + "Vaupes": [1167,1785], + "Amazonas": [1085,2064], + "Vichada": [1340,1274], + "Ecuador": [94,1792], + "Panama": [188,686], + "Cesar": [802,533], + "Atlantico": [646,642], + "Antioquia": [666,910], + "Choco": [373,1040], + "Narino": [212,1642], + "Huila": [457,1628], + "Santander": [818,1177], + "Arauca": [1092,1128], + "Meta East": [973,1410], + "Meta West": [720,1539], + "Guaviare": [976,1669], + "Putumayo": [680,1826], + "Sincelejo / Ayacucho": [642,696], + "Cucuta / Arauca": [994,977], + "Bucaramanga / Ibague / Bogota": [626,1224], + "Bogota / Yopal": [887,1276], + "Bogota / Neiva": [612,1414], + "Bogota / San Jose": [826,1474], + "Neiva / Pasto": [530,1698], + "Pasto / Tumaco": [146,1766], + "Cali / Pasto": [348,1625], + "Cali / Buenaventura": [368,1412], + "Ibague / Cali": [436,1362], + "Medellin / Ibague": [511,1169], + "Cartagena / Sincelejo": [514,613], + "Sincelejo / Medellin": [563,876], + "Bucaramanga / Ayacucho": [778,830], + "Cucuta / Ayacucho": [872,708], + "Santa Marta / Ayacucho": [746,601], + "Santa Marta / Cartagena": [588,466], + // TODO: + "Brasil": [10, 10], + "Peru": [30, 10], + "Venezuela": [40, 10], +} + +const layout_xy = { + "Atlantico": [620,540], + "Choco": [370,1190], + "Narino": [260,1530], + + "Cesar": [860,420], + "Antioquia": [640,1010], + "Santander": [710,1175], + "Huila": [525,1425], + + "Arauca": [1210,1090], + "Vichada": [1210,1305], + "Meta East": [971,1320], + + "Meta West": [720,1630], + "Guaviare": [860,1670], + "Putumayo": [840,1880], + + "Guainia": [1310,1540], + "Vaupes": [1080,1810], + "Amazonas": [950,2080], + + "Ecuador": [190,1870], + "Panama": [235,810], + "Brasil": [1300, 1900], + "Peru": [720, 2170], + "Venezuela": [1130, 880], +} + +function get_center_xy(s) { + let id = data.spaces[s].id + return center_xy[id] +} + +function get_layout_xy(s) { + let id = data.spaces[s].id + if (layout_xy[id]) + return layout_xy[id] + return center_xy[id] +} + +function get_layout_radius(s) { + switch (data.spaces[s].pop) { + case 0: return 0 + case 1: return 53 + case 2: return 57 + case 3: return 61 + case 8: return 68 + } +} + +function init_ui() { + for (let i = 0; i < data.spaces.length; ++i) { + let id = data.spaces[i].id + let type = data.spaces[i].type + let e = null + if (type === "road" || type === "pipeline") { + e = document.createElement("div") + let [ x, y ] = center_xy[id] + e.className = "box loc" + e.style.left = x - 28 + "px" + e.style.top = y - 28 + "px" + e.style.width = 56 + "px" + e.style.height = 56 + "px" + document.getElementById("boxes").appendChild(e) + } else if (type === "city") { + e = document.getElementById(id) + } else { + e = document.getElementById("svgmap").getElementById(id) + } + if (!e) + console.log("MISSING SPACE", id) + else { + ui.spaces[i] = e + register_action(e, "space", i) + } + + if (i <= last_pop) { + let [x, y] = center_xy[id] + if (i <= last_city) + ui.support[i] = e = create("div", { className: "hide" }) + else + ui.support[i] = e = create("div", { className: "hide" }) + if (i <= last_city) { + let r = get_layout_radius(i) + e.style.left = (x - 20) + "px" + e.style.top = (y - 20 - r) + "px" + } else { + e.style.left = (x + 14) + "px" + e.style.top = (y - 45) + "px" + } + document.getElementById("tokens").appendChild(e) + } + + if (i <= last_dept || id === "Panama" || id === "Ecuador") { + let [x, y] = center_xy[id] + if (i <= last_city) + ui.control[i] = e = create("div", { className: "token govt_control" }) + else + ui.control[i] = e = create("div", { className: "hide" }) + if (i <= last_city) { + let r = get_layout_radius(i) + e.style.left = (x - 25 + r) + "px" + e.style.top = (y - 25) + "px" + } else if (i > last_pop) { + e.style.left = (x - 25) + "px" + e.style.top = (y - 25) + "px" + } else { + e.style.left = (x - 57) + "px" + e.style.top = (y - 49) + "px" + } + document.getElementById("tokens").appendChild(e) + } + + if (i >= first_loc && i <= last_loc) { + let [x, y] = center_xy[id] + ui.sabotage[i] = e = create("div", { className: "hide" }) + e.style.left = (x - 20) + "px" + e.style.top = (y - 20) + "px" + document.getElementById("tokens").appendChild(e) + } + } + + function create_piece(c, action, id, x, y) { + let e = create("div", { + className: c, + my_action: action, + my_id: id, + my_x_offset: x, + my_y_offset: y, + onclick: on_click_action + }) + document.getElementById("pieces").appendChild(e) + return e + } + + function create_piece_list(list, c, action, n, x, y) { + for (let i = 0; i < n; ++i) + list[i] = create_piece(c, action, i, x, y) + } + + create_piece_list(ui.misc.shipments, "token shipment", "shipment", 4, 0, 0) + + create_piece_list(ui.govt.police, "piece govt police", "govt_police", 30, 0, 4) + create_piece_list(ui.govt.troops, "piece govt troops", "govt_troops", 30, 0, 4) + create_piece_list(ui.govt.bases, "piece govt base", "govt_base", 3, -4, 10) + + create_piece_list(ui.auc.guerrillas, "piece auc guerrilla", "auc_guerrilla", 18, 2, 0) + create_piece_list(ui.auc.bases, "piece auc base", "auc_base", 6, -4, 10) + + create_piece_list(ui.cartels.guerrillas, "piece cartels guerrilla", "cartels_guerrilla", 12, 2, 0) + create_piece_list(ui.cartels.bases, "piece cartels base", "cartels_base", 15, -4, 10) + + create_piece_list(ui.farc.guerrillas, "piece farc guerrilla", "farc_guerrilla", 30, 2, 0) + create_piece_list(ui.farc.bases, "piece farc base", "farc_base", 9, -4, 10) + + register_action(ui.sop[1], "sop", 1) + register_action(ui.sop[2], "sop", 2) + register_action(ui.sop[3], "sop", 3) + register_action(ui.sop[4], "sop", 4) + register_action(ui.sop[5], "sop", 5) + register_action(ui.sop[6], "sop", 6) + register_action(ui.sop[7], "sop", 7) +} + +function filter_piece_list(list, slist, elist, space) { + for (let i = 0; i < slist.length; ++i) + if (slist[i] === space) + list.push(elist[i]) +} + +function layout_cubes_available(slist, elist, space, xorig, yorig) { + let list = [] + filter_piece_list(list, slist, elist, space) + layout_pieces(list, xorig, yorig) +} + +function layout_guerrillas_available(slist, elist, space, xorig, yorig) { + let list = [] + filter_piece_list(list, slist, elist, space) + layout_pieces(list, xorig, yorig) +} + +function layout_pieces(list, xorig, yorig) { + const dx = 17 + const dy = 11 + if (list.length > 0) { + let ncol = Math.round(Math.sqrt(list.length)) + let nrow = Math.ceil(list.length / ncol) + function layout_piece(row, col, e, z) { + // basic piece size = 29x36 + let x = xorig - (row * dx - col * dx) - 15 + (nrow-ncol) * 6 + let y = yorig - (row * dy + col * dy) - 24 + (nrow-1) * 8 + let xo = e.my_x_offset + let yo = e.my_y_offset + e.style.left = (xo + x) + "px" + e.style.top = (yo + y) + "px" + e.style.zIndex = z + } + let z = 50 + let i = 0 + for (let row = 0; row < nrow; ++row) + for (let col = 0; col < ncol && i < list.length; ++col) + layout_piece(row, col, list[list.length-(++i)], z--) + } +} + +function place_piece(p, x, y, z) { + p.style.top = y + "px" + p.style.left = x + "px" + if (z) + p.style.zIndex = z +} + +function layout_space_bases(list, xc, yc, r) { + // base is 44x38 + if (r > 0) { + let a = 45 * Math.PI / 180 + let dx = Math.round((r) * Math.cos(a)) + let dy = Math.round((r) * Math.sin(a)) + if (list.length > 0) + place_piece(list[0], xc - 22 + dx, yc - 19 + dy) + if (list.length > 1) + place_piece(list[1], xc - 22 - dx, yc - 19 + dy) + } else { + if (list.length > 0) + place_piece(list[0], xc - 20 - 34, yc + 13) + if (list.length > 1) + place_piece(list[1], xc - 20 + 31, yc + 13) + } +} + +function layout_available_bases(list, x0, y0, cols, rows, dx, dy) { + let x = x0 + let y = y0 + // for (let i = list.length-1; i >= 0; --i) { + for (let i = 0; i < list.length; ++i) { + place_piece(list[list.length-i-1], x - 44 - 6, y + 8) + y += dy + if (i % rows === rows - 1) { + x -= dx + y = y0 + } + } +} + +const sop_xy = [ + [SOP_A1, 1298-22, 475-24], + [SOP_A2, 1374-22, 475-24], + [SOP_B1, 1298-22, 554-24], + [SOP_B2, 1374-22, 554-24], + [SOP_C1, 1298-22, 632-24], + [SOP_C2, 1374-22, 632-24], +] + +const SHORT_LIST = [ "govt", "auc", "cartels", "farc" ] +const SHORT = { + "Government": "govt", + "AUC": "auc", + "Cartels": "cartels", + "FARC": "farc", +} + +function layout_sop() { + let x, y, z + + // Eligible + x = 1164 - 22 + y = 480 + z = 1 + let order = data.cards[view.deck[0]].order + if (!order) + order = [ "Government", "AUC", "Cartels", "FARC" ] + for (let faction of order) { + faction = SHORT[faction] + if (view[faction].cylinder === ELIGIBLE) { + place_piece(ui[faction].cylinder, x, y, z) + y += 40 + z += 1 + } + } + + // Ineligible + x = 1510 - 22 + y = 480 + z = 1 + for (let faction of SHORT_LIST) { + if (view[faction].cylinder === INELIGIBLE) { + place_piece(ui[faction].cylinder, x, y, z) + y += 40 + z += 1 + } + } + + // Pass + x = 1164 - 22 - 24 + y = 688 - 28 + z = 1 + i = 0 + for (let faction of SHORT_LIST) { + if (view[faction].cylinder === SOP_PASS) { + place_piece(ui[faction].cylinder, x, y, z) + x += 48 + z += 1 + if (++i === 2) { x -= 72; y += 28 } + } + } + + for (let [i, x, y] of sop_xy) { + if (view.govt.cylinder === i) place_piece(ui.govt.cylinder, x, y) + if (view.auc.cylinder === i) place_piece(ui.auc.cylinder, x, y) + if (view.cartels.cylinder === i) place_piece(ui.cartels.cylinder, x, y) + if (view.farc.cylinder === i) place_piece(ui.farc.cylinder, x, y) + } + + for (let i = 1; i <= 7; ++i) { + if (view.actions && view.actions.sop && set_has(view.actions.sop, i)) + ui.sop[i].classList.add("action") + else + ui.sop[i].classList.remove("action") + } +} + +function calc_oppose_bases() { + let total = 0 + for (let s = 0; s <= last_pop; ++s) { + if (view.misc.support[s] < 0) + total -= data.spaces[s].pop * view.misc.support[s] + } + for (let b of view.farc.bases) + if (b !== AVAILABLE) + total += 1 + return total +} + +function calc_support() { + let total = 0 + for (let s = 0; s <= last_pop; ++s) { + if (view.misc.support[s] > 0) + total += data.spaces[s].pop * view.misc.support[s] + } + return total +} + +function layout_score_cell(list, x, y, dx, dy) { + let z = 1 + if (list.length > 1) { + if (dy > 0) y -= 12 + if (dy < 0) y += 12 + if (dx > 0) x -= 12 + if (dx < 0) x += 12 + } + for (let p of list) { + if (p.classList.contains("token")) + place_piece(p, x - 24, y - 24, z) + else + place_piece(p, x - 22, y - 24, z) + x += dx + y += dy + z += 1 + } +} + +function layout_score() { + let list = [] + let x, y + for (let i = 0; i <= 99; ++i) { + + let total_support = calc_support() + let oppose_plus_bases = calc_oppose_bases() + + if (total_support === i) list.push(ui.misc.total_support) + if (oppose_plus_bases === i) list.push(ui.misc.oppose_plus_bases) + if (view.misc.aid === i) list.push(ui.misc.aid) + + if (view.govt.resources === i) list.push(ui.govt.resources) + if (view.auc.resources === i) list.push(ui.auc.resources) + if (view.cartels.resources === i) list.push(ui.cartels.resources) + if (view.farc.resources === i) list.push(ui.farc.resources) + + if (i <= 30) y = 16 + else if (i >= 77) y = 2486 + else y = 16 + (i - 30) * 52.55 + + if (i < 1) x = 19 + 4 + else if (i <= 30) x = 80 + (i - 1) * 52.07 + else if (i <= 77) x = 1590 + else x = 1590 - (i - 77) * 52.09 + + x = Math.round(x) + 24 + y = Math.round(y) + 24 + + if (i < 1) layout_score_cell(list, x, y, 15, 25) + else if (i < 30) layout_score_cell(list, x, y, 0, 28) + else if (i === 30) layout_score_cell(list, x, y, -18, 25) + else if (i < 77) layout_score_cell(list, x, y, -41, 0) + else if (i === 77) layout_score_cell(list, x, y, -15, -19) + else layout_score_cell(list, x, y, 0, -19) + if (list.length > 0) + list.length = 0 + } +} + +function update_guerrillas_active(elts, guerrillas, active) { + for (let i = 0; i < guerrillas.length; ++i) { + if (active & (1 << i)) + elts[i].classList.add("active") + else + elts[i].classList.remove("active") + } +} + +function on_update() { + ui.header.classList.toggle("govt", view.active === "Government") + ui.header.classList.toggle("auc", view.active === "AUC") + ui.header.classList.toggle("cartels", view.active === "Cartels") + ui.header.classList.toggle("farc", view.active === "FARC") + + switch (player) { + case "Government": favicon.href = "images/icon_govt.png"; break + case "AUC": favicon.href = "images/icon_auc.png"; break + case "Cartels": favicon.href = "images/icon_cartels.png"; break + case "FARC": favicon.href = "images/icon_farc.png"; break + } + + ui.misc.president.style.left = [ 0, "254px", "337px", "420px" ][view.misc.president] + + ui.player.govt.classList.toggle("active", view.active === "Government") + ui.player.auc.classList.toggle("active", view.active === "AUC") + ui.player.cartels.classList.toggle("active", view.active === "Cartels") + ui.player.farc.classList.toggle("active", view.active === "FARC") + + if (view.propaganda > 0) { + ui.misc.propaganda.style.top = "744px" + ui.misc.propaganda.style.left = (1124 + 75 * (view.propaganda - 1)) + "px" + } else { + ui.misc.propaganda.style.top = "666px" + ui.misc.propaganda.style.left = "1029px" + } + + ui.this_card.className = "card card_" + view.deck[0] + ui.next_card.className = "card card_" + view.deck[1] + ui.deck_size.textContent = view.deck[2] + + layout_sop() + layout_score() + + layout_cubes_available(view.govt.troops, ui.govt.troops, AVAILABLE, 114, 248) + layout_cubes_available(view.govt.police, ui.govt.police, AVAILABLE, 114, 448) + layout_guerrillas_available(view.auc.guerrillas, ui.auc.guerrillas, AVAILABLE, 196, 2370) + layout_guerrillas_available(view.cartels.guerrillas, ui.cartels.guerrillas, AVAILABLE, 1465, 1970) + layout_guerrillas_available(view.farc.guerrillas, ui.farc.guerrillas, AVAILABLE, 1396, 234) + + let list = [] + for (let s = 0; s < data.spaces.length; ++s) { + if (s <= last_pop) { + switch (view.misc.support[s]) { + case -2: ui.support[s].className = "token active_opposition"; break + case -1: ui.support[s].className = "token passive_opposition"; break + case 0: ui.support[s].className = "hide"; break + case 1: ui.support[s].className = "token passive_support"; break + case 2: ui.support[s].className = "token active_support"; break + } + } + + if (s >= first_loc && s <= last_loc) { + if (set_has(view.misc.sabotage, s)) + ui.sabotage[s].className = "token sabotage" + else + ui.sabotage[s].className = "hide" + } + + if (s <= last_dept) { + if (set_has(view.misc.farc_zones, s)) + ui.control[s].className = "token farc_zone" + else switch (view.misc.control[s]) { + case 0: ui.control[s].className = "hide"; break + case 1: ui.control[s].className = "token govt_control"; break + case 2: ui.control[s].className = "token farc_control"; break + } + } + + update_guerrillas_active(ui.auc.guerrillas, view.auc.guerrillas, view.auc.active) + update_guerrillas_active(ui.cartels.guerrillas, view.cartels.guerrillas, view.cartels.active) + update_guerrillas_active(ui.farc.guerrillas, view.farc.guerrillas, view.farc.active) + + list.length = 0 + filter_piece_list(list, view.auc.guerrillas, ui.auc.guerrillas, s) + filter_piece_list(list, view.cartels.guerrillas, ui.cartels.guerrillas, s) + filter_piece_list(list, view.farc.guerrillas, ui.farc.guerrillas, s) + filter_piece_list(list, view.govt.troops, ui.govt.troops, s) + filter_piece_list(list, view.govt.police, ui.govt.police, s) + + // TODO: associate shipments with other piece, not space + filter_piece_list(list, view.misc.shipments, ui.misc.shipments, s) + + let xy = get_layout_xy(s) + if (xy) + layout_pieces(list, xy[0], xy[1]) + + list.length = 0 + filter_piece_list(list, view.govt.bases, ui.govt.bases, s) + filter_piece_list(list, view.auc.bases, ui.auc.bases, s) + filter_piece_list(list, view.farc.bases, ui.farc.bases, s) + filter_piece_list(list, view.cartels.bases, ui.cartels.bases, s) + + xy = get_center_xy(s) + if (xy) + layout_space_bases(list, xy[0], xy[1], s <= last_city ? get_layout_radius(s) : 0) + else + console.log("NO SPACE", s, data.spaces[s].name) + + ui.spaces[s].classList.toggle("action", is_action("space", s)) + } + + list.length = 0 + filter_piece_list(list, view.misc.shipments, ui.misc.shipments, AVAILABLE) + layout_available_bases(list, 1532, 1722, 2, 2, 89, 69) + + list.length = 0 + filter_piece_list(list, view.govt.bases, ui.govt.bases, AVAILABLE) + layout_available_bases(list, 287 + 177, 371, 3, 1, 61, 0) + + list.length = 0 + filter_piece_list(list, view.auc.bases, ui.auc.bases, AVAILABLE) + layout_available_bases(list, 446 + 360, 2386, 6, 1, 61, 0) + + list.length = 0 + filter_piece_list(list, view.farc.bases, ui.farc.bases, AVAILABLE) + layout_available_bases(list, 446 + 543, 2295, 9, 1, 61, 0) + + list.length = 0 + filter_piece_list(list, view.cartels.bases, ui.cartels.bases, AVAILABLE) + layout_available_bases(list, 1373 + 183, 2117, 3, 5, 63, 63) + + action_button("train", "Train") + action_button("patrol", "Patrol") + action_button("sweep", "Sweep") + action_button("assault", "Assault") + + action_button("rally", "Rally") + action_button("march", "March") + action_button("attack", "Attack") + action_button("terror", "Terror") + + action_button("air_lift", "Air Lift") + action_button("air_strike", "Air Strike") + action_button("eradicate", "Eradicate") + + action_button("extort", "Extort") + action_button("ambush", "Ambush") + action_button("kidnap", "Assassinate") + action_button("kidnap", "Kidnap") + action_button("kidnap", "Cultivate") + action_button("kidnap", "Process") + action_button("kidnap", "Bribe") + + action_button("unshaded", "Unshaded") + action_button("shaded", "Shaded") + + action_button("event", "Event") + action_button("limop", "LimOp") + action_button("undo", "Undo") +} + +function on_focus_card_tip(c) { + document.getElementById("card_tip").className = "card card_" + c +} + +function on_blur_card_tip(c) { + document.getElementById("card_tip").className = "hide" +} + +function sub_card(match, p1) { + let x = p1 | 0 + let n = data.cards[x].name + return `${n}` +} + +function sub_space(match, p1) { + let x = p1 | 0 + let n = data.spaces[x].name + return `${n}` +} + +function on_log(text) { + let p = document.createElement("div") + + if (text.match(/^>/)) { + text = text.substring(1) + p.className = "i" + } + + text = text.replace(/&/g, "&") + text = text.replace(//g, ">") + + text = text.replace(/C(\d+)/g, sub_card) + text = text.replace(/S(\d+)/g, sub_space) + + if (text.match(/^\.h1/)) { + text = text.substring(4) + p.className = "h1" + } + else if (text.match(/^\.h2 Government/)) { + text = text.substring(3) + p.className = "h2 govt" + } + else if (text.match(/^\.h2 AUC/)) { + text = text.substring(3) + p.className = "h2 auc" + } + else if (text.match(/^\.h2 Cartels/)) { + text = text.substring(3) + p.className = "h2 cartels" + } + else if (text.match(/^\.h2 FARC/)) { + text = text.substring(3) + p.className = "h2 farc" + } + else if (text.match(/^\.h3/)) { + text = text.substring(4) + p.className = "h3" + } + else if (text.match(/^\.h4/)) { + text = text.substring(4) + p.className = "h4" + } + + p.innerHTML = text + return p +} + +function set_has(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return true + } + return false +} + +init_ui() +scroll_with_middle_mouse("main") diff --git a/rules.js b/rules.js new file mode 100644 index 0000000..717b521 --- /dev/null +++ b/rules.js @@ -0,0 +1,1183 @@ +"use strict" + +let states = {} +let game = null +let view = null + +const data = require("./data.js") + +const GOVT = "Government" +const AUC = "AUC" +const CARTELS = "Cartels" +const FARC = "FARC" + +// For 3 and 2 player games +const AUC_CARTELS = "AUC + Cartels" +const GOVT_AUC = "Government + AUC" +const FARC_CARTELS = "FARC + Cartels" + +// Sequence of Play options +const ELIGIBLE = 0 +const SOP_1ST_OP_ONLY = 1 +const SOP_2ND_LIMOP = 2 +const SOP_1ST_OP_AND_SA = 3 +const SOP_2ND_LIMOP_OR_EVENT = 4 +const SOP_1ST_EVENT = 5 +const SOP_2ND_OP_AND_SA = 6 +const SOP_PASS = 7 +const INELIGIBLE = 8 + +// Support +const ACTIVE_SUPPORT = 2 +const PASSIVE_SUPPORT = 1 +const NEUTRAL = 0 +const PASSIVE_OPPOSITION = -1 +const ACTIVE_OPPOSITION = -2 + +// Control ? +const UNCONTROLLED = 0 +const CTL_GOVERNMENT = 1 +const CTL_AUC = 2 +const CTL_CARTELS = 3 +const CTL_FARC = 4 + +const SAMPER = 1 +const PASTRANA = 2 +const URIBE = 3 + +const first_pop = 1 +const first_city = 0 +const last_city = 10 +const first_dept = 11 +const last_pop = 22 +const last_dept = 26 +const first_foreign = 27 +const last_foreign = 31 +const first_loc = 32 +const last_loc = 49 + +const AVAILABLE = -1 + +// Cities +const BOGOTA = 0 +const CALI = 1 +const MEDELLIN = 2 +const BUCARAMANGA = 3 +const IBAGUE = 4 +const SANTA_MARTA = 5 +const CARTAGENA = 6 +const CUCUTA = 7 +const NEIVA = 8 +const PASTO = 9 +const SINCELEJO = 10 + +// 1+ Pop Depts +const ATLANTICO = 11 +const CHOCO = 12 +const NARINO = 13 +const META_WEST = 14 +const GUAVIARE = 15 +const PUTUMAYO = 16 +const CESAR = 17 +const ANTIOQUIA = 18 +const SANTANDER = 19 +const HUILA = 20 +const ARAUCA = 21 +const META_EAST = 22 + +// 0 Pop Depts +const VICHADA = 23 +const GUAINIA = 24 +const VAUPES = 25 +const AMAZONAS = 26 + +// Foreign Countries +const BRASIL = 27 +const ECUADOR = 28 +const PANAMA = 29 +const PERU = 30 +const VENEZUELA = 31 + +const COASTAL_SPACES = [ ATLANTICO, CHOCO, NARINO, CESAR ] + +exports.roles = function (scenario) { + if (scenario.startsWith("2P")) + return [ GOVT_AUC, FARC_CARTELS ] + if (scenario.startsWith("3P")) + return [ GOVT, FARC, AUC_CARTELS ] + return [ GOVT, AUC, CARTELS, FARC ] +} + +exports.scenarios = [ + "Standard", + "Short", + "Quick", + "3P Standard", + "3P Short", + "3P Quick", + "2P Standard", + "2P Short", + "2P Quick", +] + +function load_game(state) { + game = state + if (game.scenario !== 4) + game.active = game.save_active +} + +function save_game() { + if (game.scenario === 3) { + game.save_active = game.active + if (game.active === AUC || game.active === CARTELS) + game.active = AUC_CARTELS + } + if (game.scenario === 2) { + game.save_active = game.active + if (game.active === GOVT || game.active === AUC) + game.active = GOVT_AUC + if (game.active === FARC || game.active === CARTELS) + game.active = FARC_CARTELS + } + return game +} + +exports.setup = function (seed, scenario, options) { + game = { + seed, + log: [], + undo: [], + + scenario: 4, + active: null, + state: null, + + op_spaces: null, + sa_spaces: null, + + deck: [], + misc: { + aid: 0, + president: 0, + shipments: [ AVAILABLE, AVAILABLE, AVAILABLE, AVAILABLE ], + control: Array(27).fill(0), + support: Array(23).fill(NEUTRAL), + farc_zones: [], + terror: [], + sabotage: [], + }, + govt: { + cylinder: ELIGIBLE, + resources: 0, + troops: Array(30).fill(AVAILABLE), + police: Array(30).fill(AVAILABLE), + bases: Array(3).fill(AVAILABLE), + }, + auc: { + cylinder: ELIGIBLE, + resources: 0, + guerrillas: Array(18).fill(AVAILABLE), + bases: Array(6).fill(AVAILABLE), + active: 0, + }, + cartels: { + cylinder: ELIGIBLE, + resources: 0, + guerrillas: Array(12).fill(AVAILABLE), + bases: Array(15).fill(AVAILABLE), + active: 0, + }, + farc: { + cylinder: ELIGIBLE, + resources: 0, + guerrillas: Array(30).fill(AVAILABLE), + bases: Array(9).fill(AVAILABLE), + active: 0, + }, + } + + if (scenario.startsWith("3P")) + game.scenario = 3 + if (scenario.startsWith("2P")) + game.scenario = 2 + + setup_standard() + + if (scenario === "Quick") { + log_h1("Scenario: Quick") + setup_quick() + setup_quick_deck() + } else if (scenario === "Short") { + setup_short_deck() + } else { + setup_standard_deck() + } + + update_control() + + goto_card() + + return save_game() +} + +function setup_standard() { + game.misc.aid = 9 + game.misc.president = SAMPER + game.govt.resources = 40 + game.auc.resources = 10 + game.cartels.resources = 10 + game.farc.resources = 10 + + set_support(ATLANTICO, ACTIVE_SUPPORT) + set_support(SANTANDER, ACTIVE_SUPPORT) + for (let s = first_city; s <= last_city; ++s) + if (s !== CALI) + set_support(s, ACTIVE_SUPPORT) + + set_support(CHOCO, ACTIVE_OPPOSITION) + set_support(ARAUCA, ACTIVE_OPPOSITION) + set_support(META_EAST, ACTIVE_OPPOSITION) + set_support(META_WEST, ACTIVE_OPPOSITION) + set_support(GUAVIARE, ACTIVE_OPPOSITION) + set_support(PUTUMAYO, ACTIVE_OPPOSITION) + set_support(NARINO, ACTIVE_OPPOSITION) + + place_piece(game.govt.troops, 3, BOGOTA) + place_piece(game.govt.troops, 3, MEDELLIN) + place_piece(game.govt.troops, 3, CALI) + place_piece(game.govt.troops, 3, SANTANDER) + place_piece(game.govt.police, 2, BOGOTA) + for (let s = first_city; s <= last_city; ++s) + if (s !== BOGOTA) + place_piece(game.govt.police, 1, s) + place_piece(game.govt.bases, 1, SANTANDER) + + place_piece(game.farc.guerrillas, 1, NARINO) + place_piece(game.farc.guerrillas, 1, CHOCO) + place_piece(game.farc.guerrillas, 1, SANTANDER) + place_piece(game.farc.guerrillas, 1, HUILA) + place_piece(game.farc.guerrillas, 1, ARAUCA) + place_piece(game.farc.guerrillas, 1, META_EAST) + place_piece(game.farc.guerrillas, 2, META_WEST) + place_piece(game.farc.guerrillas, 2, GUAVIARE) + place_piece(game.farc.guerrillas, 2, PUTUMAYO) + place_piece(game.farc.bases, 1, CHOCO) + place_piece(game.farc.bases, 1, HUILA) + place_piece(game.farc.bases, 1, ARAUCA) + place_piece(game.farc.bases, 1, META_EAST) + place_piece(game.farc.bases, 1, META_WEST) + place_piece(game.farc.bases, 1, GUAVIARE) + + place_piece(game.auc.guerrillas, 1, ATLANTICO) + place_piece(game.auc.guerrillas, 1, ANTIOQUIA) + place_piece(game.auc.guerrillas, 1, SANTANDER) + place_piece(game.auc.guerrillas, 1, ARAUCA) + place_piece(game.auc.guerrillas, 1, GUAVIARE) + place_piece(game.auc.guerrillas, 1, PUTUMAYO) + place_piece(game.auc.bases, 1, ANTIOQUIA) + + place_piece(game.cartels.guerrillas, 1, CALI) + place_piece(game.cartels.guerrillas, 1, PUTUMAYO) + place_piece(game.cartels.bases, 1, CALI) + place_piece(game.cartels.bases, 1, META_EAST) + place_piece(game.cartels.bases, 1, META_WEST) + place_piece(game.cartels.bases, 1, GUAVIARE) + place_piece(game.cartels.bases, 2, PUTUMAYO) +} + +function setup_quick() { + place_piece(game.cartels.guerrillas, 4, MEDELLIN) + place_piece(game.cartels.bases, 1, MEDELLIN) + + set_support(CALI, ACTIVE_SUPPORT) + place_piece(game.govt.police, 4, CALI) + remove_piece(game.cartels.guerrillas, 1, CALI) + remove_piece(game.cartels.bases, 1, CALI) + + place_piece(game.govt.troops, 6, BOGOTA) + + place_piece(game.auc.bases, 1, SANTANDER) + + set_support(ARAUCA, NEUTRAL) + place_piece(game.auc.guerrillas, 1, ARAUCA) + + set_add(game.misc.farc_zones, META_WEST) + place_piece(game.farc.guerrillas, 4, META_WEST) + + set_support(HUILA, ACTIVE_OPPOSITION) + place_piece(game.farc.guerrillas, 3, HUILA) + place_piece(game.auc.guerrillas, 2, HUILA) + place_piece(game.cartels.bases, 1, HUILA) + + place_piece(game.farc.guerrillas, 2, VAUPES) + + game.auc.resources = 5 + game.farc.resources = 10 + game.cartels.resources = 20 + game.govt.resources = 30 + + game.misc.president = PASTRANA +} + +function shuffle_all_cards() { + let deck = [] + for (let i = 1; i <= 72; ++i) + deck.push(i) + shuffle(deck) + return deck +} + +function setup_standard_deck() { + let cards = shuffle_all_cards() + let piles = [ + cards.slice(0, 15), + cards.slice(15, 15+15), + cards.slice(30, 30+15), + cards.slice(45, 45+15), + ] + piles[0].push(73) + piles[1].push(74) + piles[2].push(75) + piles[3].push(76) + shuffle(piles[0]) + shuffle(piles[1]) + shuffle(piles[2]) + shuffle(piles[3]) + game.deck = piles[0].concat(piles[1], piles[2], piles[3]) +} + +function setup_short_deck() { + let cards = shuffle_all_cards() + let piles = [ + cards.slice(0, 15), + cards.slice(15, 15+15), + cards.slice(30, 30+15), + ] + piles[0].push(73) + piles[1].push(74) + piles[2].push(75) + shuffle(piles[0]) + shuffle(piles[1]) + shuffle(piles[2]) + game.deck = piles[0].concat(piles[1], piles[2], piles[3]) +} + +function setup_quick_deck() { + let cards = shuffle_all_cards() + let piles = [ + cards.slice(0, 6), + cards.slice(6, 6+6), + cards.slice(12, 12+6), + cards.slice(24, 24+6), + ] + piles[1].push(73) + piles[3].push(74) + shuffle(piles[1]) + shuffle(piles[3]) + game.deck = piles[0].concat(piles[1], piles[2], piles[3]) +} + +function set_support(place, amount) { + game.misc.support[place] = amount +} + +function get_support(place, amount) { + return game.misc.support[place] +} + +function place_piece(list, count, where) { + for (let i = 0; i < list.length && count > 0; ++i) { + if (list[i] < 0) { + list[i] = where + --count + } + } + if (count !== 0) + throw Error("bad piece count") +} + +function remove_piece(list, count, where) { + for (let i = 0; i < list.length && count > 0; ++i) { + if (list[i] === where) { + list[i] = AVAILABLE + --count + } + } + if (count !== 0) + throw Error("bad piece count") +} + +function count_pieces_imp(s, list) { + let n = 0 + for (let i = 0; i < list.length; ++i) + if (list[i] === s) + ++n + return n +} + +function update_control() { + for (let s = 0; s <= last_dept; ++s) { + let g = count_pieces_imp(s, game.govt.troops) + + count_pieces_imp(s, game.govt.police) + + count_pieces_imp(s, game.govt.bases) + let a = count_pieces_imp(s, game.auc.guerrillas) + + count_pieces_imp(s, game.auc.bases) + let c = count_pieces_imp(s, game.cartels.guerrillas) + + count_pieces_imp(s, game.cartels.bases) + let f = count_pieces_imp(s, game.farc.guerrillas) + + count_pieces_imp(s, game.farc.bases) + if (g > a + c + f) + game.misc.control[s] = 1 + else if (f > g + a + c) + game.misc.control[s] = 2 + else + game.misc.control[s] = 0 + } +} + +// === SEQUENCE OF PLAY === + +function this_card() { + return game.deck[0] +} + +function goto_card() { + if (this_card() > 72) + goto_propaganda_card() + else + goto_event_card() +} + +function adjust_eligibility(faction) { + if (faction.cylinder === INELIGIBLE || faction.cylinder === SOP_PASS) + faction.cylinder = ELIGIBLE + else if (faction.cylinder !== ELIGIBLE) + faction.cylinder = INELIGIBLE +} + +function end_card() { + adjust_eligibility(game.govt) + adjust_eligibility(game.auc) + adjust_eligibility(game.cartels) + adjust_eligibility(game.farc) + + clear_undo() + array_remove(game.deck, 0) + goto_card() +} + +function current_faction() { + switch (game.active) { + case GOVT: return game.govt + case AUC: return game.auc + case CARTELS: return game.cartels + case FARC: return game.farc + } +} + +function is_eligible(faction) { + switch (faction) { + case GOVT: return game.govt.cylinder === ELIGIBLE + case AUC: return game.auc.cylinder === ELIGIBLE + case CARTELS: return game.cartels.cylinder === ELIGIBLE + case FARC: return game.farc.cylinder === ELIGIBLE + } + return false +} + +function next_eligible_faction() { + let order = data.cards[this_card()].order + for (let faction of order) + if (is_eligible(faction)) + return faction + return null +} + +function did_option(e) { + return ( + game.govt.cylinder === e || + game.auc.cylinder === e || + game.cartels.cylinder === e || + game.farc.cylinder === e + ) +} + +function goto_event_card() { + log_h1("C" + this_card()) + resume_event_card() +} + +function resume_event_card() { + clear_undo() + let did_1st = (did_option(SOP_1ST_OP_ONLY) || did_option(SOP_1ST_OP_AND_SA) || did_option(SOP_1ST_EVENT)) + let did_2nd = (did_option(SOP_2ND_LIMOP) || did_option(SOP_2ND_LIMOP_OR_EVENT) || did_option(SOP_2ND_OP_AND_SA)) + if (did_1st) { + if (did_2nd) + end_card() + else + goto_eligible2() + } else { + goto_eligible1() + } +} + +function goto_eligible1() { + game.active = next_eligible_faction() + if (game.active === null) + end_card() + else + game.state = "eligible1" +} + +function goto_eligible2() { + game.active = next_eligible_faction() + if (game.active === null) + end_card() + else + game.state = "eligible2" +} + +states.eligible1 = { + inactive: "1st Eligible", + prompt() { + view.prompt = "1st Eligible: Choose a Sequence of Play option." + gen_action("sop", SOP_1ST_OP_ONLY) + gen_action("sop", SOP_1ST_OP_AND_SA) + gen_action("sop", SOP_1ST_EVENT) + gen_action("sop", SOP_PASS) + }, + sop(e) { + push_undo() + let faction = current_faction() + faction.cylinder = e + switch (e) { + case SOP_PASS: + goto_pass() + break + case SOP_1ST_OP_ONLY: + goto_op_only() + break + case SOP_1ST_OP_AND_SA: + goto_op_and_sa() + break + case SOP_1ST_EVENT: + goto_event() + break + } + }, +} + +states.eligible2 = { + inactive: "2nd Eligible", + prompt() { + view.prompt = "2nd Eligible: Choose a Sequence of Play option." + if (did_option(SOP_1ST_OP_ONLY)) + gen_action("sop", SOP_2ND_LIMOP) + if (did_option(SOP_1ST_OP_AND_SA)) + gen_action("sop", SOP_2ND_LIMOP_OR_EVENT) + if (did_option(SOP_1ST_EVENT)) + gen_action("sop", SOP_2ND_OP_AND_SA) + gen_action("sop", SOP_PASS) + }, + sop(e) { + push_undo() + let faction = current_faction() + faction.cylinder = e + switch (e) { + case SOP_PASS: + goto_pass() + break + case SOP_2ND_LIMOP: + goto_op_only() + break + case SOP_2ND_LIMOP_OR_EVENT: + goto_limop_or_event() + break + case SOP_2ND_OP_AND_SA: + goto_op_and_sa() + break + } + }, +} + +function goto_pass() { + log_h2(game.active + " - Pass") + let faction = current_faction() + if (game.active === GOVT) + faction.resources += 3 + else + faction.resources += 1 + resume_event_card() +} + +function goto_limop_or_event() { + push_undo() + game.state = "limop_or_event" +} + +states.limop_or_event = { + prompt() { + view.prompt = "2nd Eligible: Event or Limited Operation?" + view.actions.event = 1 + view.actions.limop = 1 + }, + event() { + goto_event() + }, + limop() { + goto_limop() + } +} + +function goto_event() { + log_h2(game.active + " - Event") + log("TODO: Event") + resume_event_card() +} + +function goto_op_only() { + log_h2(game.active + " - Op only") + game.state = "op" + game.op_spaces = [] + game.sa_spaces = null +} + +function goto_op_and_sa() { + log_h2(game.active + " - Op + Special") + game.state = "op" + game.op_spaces = [] + game.sa_spaces = [] +} + +function goto_limop() { + log_h2(game.active + " - LimOp") + game.state = "op" + game.op_spaces = [] + game.sa_spaces = null +} + +function can_use_special_activity() { + let faction = current_faction() + if (faction.cylinder === SOP_1ST_OP_AND_SA || faction.cylinder === SOP_2ND_OP_AND_SA) + return true + return false +} + +states.op = { + prompt() { + view.prompt = "Choose an Operation." + if (game.active === GOVT) { + view.actions.train = 1 + view.actions.patrol = 1 + view.actions.sweep = 1 + view.actions.assault = 1 + } else { + view.actions.rally = 1 + view.actions.march = 1 + view.actions.attack = 1 + view.actions.terror = 1 + } + }, + + train() { + push_undo() + log_h3("Train") + game.state = "train" + }, + patrol() { + push_undo() + log_h3("Patrol") + game.state = "patrol" + }, + sweep() { + push_undo() + log_h3("Sweep") + game.state = "sweep" + }, + assault() { + push_undo() + log_h3("Assault") + game.state = "assault" + }, + + rally() { + push_undo() + log_h3("Rally") + game.state = "rally" + }, + march() { + push_undo() + log_h3("March") + game.state = "march" + }, + attack() { + push_undo() + log_h3("Attack") + game.state = "attack" + }, + terror() { + push_undo() + log_h3("Terror") + game.state = "terror" + }, +} + +states.train = { + prompt() { + let faction = current_faction() + + view.prompt = "Train: Select spaces." + + if (can_use_special_activity()) { + view.actions.air_lift = 1 + view.actions.eradicate = 1 + } + + // Any Departments or Cities + if (faction.resources >= 3) { + for (let s = 0; s <= last_dept; ++s) { + if (!set_has(game.op_spaces, s)) + gen_action("space", s) + } + } + }, + air_lift() { + push_undo() + game.state = "air_lift" + }, + eradicate() { + push_undo() + game.state = "eradicate" + }, + space(s) { + push_undo() + logi(`S${s}.`) + let faction = current_faction() + faction.resources -= 3 + set_add(game.op_spaces, s) + }, +} + +// === GAME OVER === + +function goto_game_over(result, victory) { + game = { ...game } // make a copy so we can add properties! + game.state = "game_over" + game.active = "None" + game.result = result + game.victory = victory + log_h1("Game Over") + log(game.victory) + return true +} + +states.game_over = { + get inactive() { + return game.victory + }, + prompt() { + view.prompt = game.victory + }, +} + +// === UNCOMMON TEMPLATE === + +function log_br() { + if (game.log.length > 0 && game.log[game.log.length - 1] !== "") + game.log.push("") +} + +function log(msg) { + game.log.push(msg) +} + +function logi(msg) { + game.log.push(">" + msg) +} + +function log_h1(msg) { + log_br() + log(".h1 " + msg) + log_br() +} + +function log_h2(msg) { + log_br() + log(".h2 " + msg) + log_br() +} + +function log_h3(msg) { + log_br() + log(".h3 " + msg) +} + +function log_h4(msg) { + log_br() + log(".h4 " + msg) +} + +function gen_action(action, argument) { + if (!(action in view.actions)) + view.actions[action] = [] + set_add(view.actions[action], argument) +} + +function is_current_active(current) { + switch (current) { + case GOVT_AUC: + return game.active === GOVT || game.active === AUC + case FARC_CARTELS: + return game.active === FARC || game.active === CARTELS + case AUC_CARTELS: + return game.active === AUC || game.active === CARTELS + default: + return game.active === current + } +} + +exports.view = function (state, current) { + load_game(state) + + let this_card = game.deck[0] + let next_card = game.deck[1] + let deck_size = Math.max(0, game.deck.length - 2) + + view = { + active: game.active, + prompt: null, + actions: null, + log: game.log, + + deck: [ this_card, next_card, deck_size ], + op_spaces: game.op_spaces, + sa_spaces: game.sa_spaces, + misc: game.misc, + govt: game.govt, + auc: game.auc, + cartels: game.cartels, + farc: game.farc, + } + + if (game.state === "game_over") { + view.prompt = game.victory + } else if (current === "Observer" || !is_current_active(current)) { + let inactive = states[game.state].inactive || game.state + view.prompt = `Waiting for ${game.active} \u2014 ${inactive}.` + } else { + view.actions = {} + view.who = game.who + if (states[game.state]) + states[game.state].prompt(current) + else + view.prompt = "Unknown state: " + game.state + if (view.actions.undo === undefined) { + if (game.undo && game.undo.length > 0) + view.actions.undo = 1 + else + view.actions.undo = 0 + } + } + + save_game() + return view +} + +exports.action = function (state, current, action, arg) { + load_game(state) + Object.seal(game) // XXX: don't allow adding properties + let S = states[game.state] + if (S && action in S) { + S[action](arg, current) + } else { + if (action === "undo" && game.undo && game.undo.length > 0) + pop_undo() + else + throw new Error("Invalid action: " + action) + } + return save_game() +} + +exports.is_checkpoint = function (a, b) { + return a.turn !== b.turn +} + +// === COMMON LIBRARY === + +// Packed array of small numbers in one word + +function pack1_get(word, n) { + return (word >>> n) & 1 +} + +function pack2_get(word, n) { + n = n << 1 + return (word >>> n) & 3 +} + +function pack4_get(word, n) { + n = n << 2 + return (word >>> n) & 15 +} + +function pack1_set(word, n, x) { + return (word & ~(1 << n)) | (x << n) +} + +function pack2_set(word, n, x) { + n = n << 1 + return (word & ~(3 << n)) | (x << n) +} + +function pack4_set(word, n, x) { + n = n << 2 + return (word & ~(15 << n)) | (x << n) +} + +function clear_undo() { + if (game.undo.length > 0) + game.undo = [] +} + +function push_undo() { + let copy = {} + for (let k in game) { + let v = game[k] + if (k === "undo") + continue + else if (k === "log") + v = v.length + else if (typeof v === "object" && v !== null) + v = object_copy(v) + copy[k] = v + } + game.undo.push(copy) +} + +function pop_undo() { + let save_log = game.log + let save_undo = game.undo + game = save_undo.pop() + save_log.length = game.log + game.log = save_log + game.undo = save_undo +} + +function random(range) { + // An MLCG using integer arithmetic with doubles. + // https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf + // m = 2**35 − 31 + return (game.seed = (game.seed * 200105) % 34359738337) % range +} + +function shuffle(list) { + // Fisher-Yates shuffle + for (let i = list.length - 1; i > 0; --i) { + let j = random(i + 1) + let tmp = list[j] + list[j] = list[i] + list[i] = tmp + } +} + +// Fast deep copy for objects without cycles +function object_copy(original) { + if (Array.isArray(original)) { + let n = original.length + let copy = new Array(n) + for (let i = 0; i < n; ++i) { + let v = original[i] + if (typeof v === "object" && v !== null) + copy[i] = object_copy(v) + else + copy[i] = v + } + return copy + } else { + let copy = {} + for (let i in original) { + let v = original[i] + if (typeof v === "object" && v !== null) + copy[i] = object_copy(v) + else + copy[i] = v + } + return copy + } +} + +// Array remove and insert (faster than splice) + +function array_remove_item(array, item) { + let n = array.length + for (let i = 0; i < n; ++i) + if (array[i] === item) + return array_remove(array, i) +} + +function array_remove(array, index) { + let n = array.length + for (let i = index + 1; i < n; ++i) + array[i - 1] = array[i] + array.length = n - 1 +} + +function array_insert(array, index, item) { + for (let i = array.length; i > index; --i) + array[i] = array[i - 1] + array[index] = item +} + +function array_remove_pair(array, index) { + let n = array.length + for (let i = index + 2; i < n; ++i) + array[i - 2] = array[i] + array.length = n - 2 +} + +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 +} + +// Set as plain sorted array + +function set_has(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return true + } + return false +} + +function set_add(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else + return + } + array_insert(set, a, item) +} + +function set_delete(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else { + array_remove(set, m) + return + } + } +} + +function set_toggle(set, item) { + let a = 0 + let b = set.length - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = set[m] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else { + array_remove(set, m) + return + } + } + array_insert(set, a, item) +} + +// Map as plain sorted array of key/value pairs + +function map_has(map, key) { + 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 true + } + 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 +} + +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) +} + +function map_delete(map, item) { + let a = 0 + let b = (map.length >> 1) - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = map[m << 1] + if (item < x) + b = m - 1 + else if (item > x) + a = m + 1 + else { + array_remove_pair(map, m << 1) + return + } + } +} diff --git a/tokens.1x/shipment.png b/tokens.1x/shipment.png new file mode 100644 index 0000000..52c9d90 Binary files /dev/null and b/tokens.1x/shipment.png differ diff --git a/tokens.2x/shipment.png b/tokens.2x/shipment.png new file mode 100644 index 0000000..dce5b6b Binary files /dev/null and b/tokens.2x/shipment.png differ diff --git a/tools/gendata.js b/tools/gendata.js index 58340af..5d59674 100644 --- a/tools/gendata.js +++ b/tools/gendata.js @@ -1,120 +1,122 @@ +let fs = require("fs") + let data = {} +function to_ascii(s) { + return s.normalize("NFD").replace(/[\u0300-\u036f]/g, "") +} + const IMAP = { G: "Government", F: "FARC", A: "AUC", C: "Cartels" } -let initiative = null +let order = null let cards = [ null ] -function def_initiative(s) { - initiative = [ IMAP[s[0]], IMAP[s[1]], IMAP[s[2]], IMAP[s[3]] ] +function def_order(s) { + order = [ IMAP[s[0]], IMAP[s[1]], IMAP[s[2]], IMAP[s[3]] ] } function def_card(number, name) { - cards[number] = { number, name, initiative } + cards[number] = { number, name, order } } -def_initiative("GFAC") +def_order("GFAC") def_card(1, "1st Division") def_card(2, "Ospina & Mora") def_card(3, "Tapias") -def_initiative("GFCA") +def_order("GFCA") def_card(4, "Caño Limón - Coveñas") def_card(5, "Occidental & Ecopetrol") def_card(6, "Oil Spill") -def_initiative("GAFC") +def_order("GAFC") def_card(7, "7th Special Forces") def_card(8, "Fuerza Aérea Colombiana") def_card(9, "High Mountain Battalions") -def_initiative("GACF") +def_order("GACF") def_card(10, "Blackhawks") def_card(11, "National Defense & Security Council") def_card(12, "Plan Colombia") -def_initiative("GCFA") +def_order("GCFA") def_card(13, "Plan Meteoro") def_card(14, "Tres Esquinas") def_card(15, "War Tax") -def_initiative("GCAF") +def_order("GCAF") def_card(16, "Coffee Prices") def_card(17, "Madrid Donors") def_card(18, "NSPD-18") -def_initiative("FGAC") +def_order("FGAC") def_card(19, "General Offensive") def_card(20, "Mono Jojoy") def_card(21, "Raúl Reyes") -def_initiative("FGCA") +def_order("FGCA") def_card(22, "Alfonso Cano") def_card(23, "DoD Contractors") def_card(24, "Operación Jaque") -def_initiative("FAGC") +def_order("FAGC") def_card(25, "Ejército de Liberación Nacional") def_card(26, "Gramaje") def_card(27, "Misil Antiaéreo") -def_initiative("FACG") +def_order("FACG") def_card(28, "Hugo Chávez") def_card(29, "Kill Zone") def_card(30, "Peace Commission") -def_initiative("FCGA") +def_order("FCGA") def_card(31, "Betancourt") def_card(32, "Secuestrados") def_card(33, "Sucumbíos") -def_initiative("FCAG") +def_order("FCAG") def_card(34, "Airdropped AKs") def_card(35, "Crop Substitution") def_card(36, "Zona de Convivencia") -def_initiative("AGFC") +def_order("AGFC") def_card(37, "Former Military") def_card(38, "National Coordination Center") -def_card(39, "Soldados campesinos") -def_initiative("AGCF") +def_card(39, "Soldados Campesinos") +def_order("AGCF") def_card(40, "Demobilization") def_card(41, "Mancuso") def_card(42, "Senado & Cámara") -def_initiative("AFGC") +def_order("AFGC") def_card(43, "Calima Front") def_card(44, "Colombia Nueva") def_card(45, "Los Derechos Humanos") -def_initiative("AFCG") +def_order("AFCG") def_card(46, "Limpieza") def_card(47, "Pinto & del Rosario") def_card(48, "Unión Sindical Obrera") -def_initiative("ACGF") +def_order("ACGF") def_card(49, "Bloques") def_card(50, "Carabineros") def_card(51, "Pipeline Repairs") -def_initiative("ACFG") +def_order("ACFG") def_card(52, "Castaño") def_card(53, "Criminal Air Force") def_card(54, "Deserters & Defectors") -def_initiative("CGFA") +def_order("CGFA") def_card(55, "DEA Agents") def_card(56, "Drogas La Rebaja") def_card(57, "Op Millennium") -def_initiative("CGAF") +def_order("CGAF") def_card(58, "General Serrano") def_card(59, "Salcedo") def_card(60, "The Chess Player") -def_initiative("CFGA") +def_order("CFGA") def_card(61, "Air Bridge") def_card(62, "Amazonía") def_card(63, "Narco-War") -def_initiative("CFAG") +def_order("CFAG") def_card(64, "Cocaine Labs") def_card(65, "Poppies") def_card(66, "Tingo María") -def_initiative("CAGF") +def_order("CAGF") def_card(67, "Mexican Traffickers") def_card(68, "Narco-Subs") def_card(69, "Riverines & Fast Boats") -def_initiative("CAFG") +def_order("CAFG") def_card(70, "Ayahuasca Tourism") def_card(71, "Darién") def_card(72, "Sicarios") -initiative = null +order = null def_card(73, "Propaganda!") def_card(74, "Propaganda!") def_card(75, "Propaganda!") def_card(76, "Propaganda!") -console.log("const cards = {") -for (let c of cards) console.log(JSON.stringify(c) + ",") -console.log("}") - let spaces = [ ] let space_names = [ ] @@ -124,12 +126,12 @@ function add(list, item) { } function def_space(type, pop, name) { - spaces.push({ type, name, pop, adjacent: [] }) + spaces.push({ type, id: to_ascii(name), name, pop, adjacent: [] }) space_names.push(name) } function def_town(name) { - spaces.push({ type: "town", name, adjacent: [] }) + spaces.push({ type: "town", id: to_ascii(name), name, adjacent: [] }) space_names.push(name) } @@ -138,7 +140,7 @@ function def_loc(type, econ, cities, depts) { let loc_names = cities.concat(depts) let loc_spaces = loc_names.map(n => space_names.indexOf(n)) let ix = spaces.length - spaces.push({ type, name, econ, adjacent: loc_spaces.filter(x=>x>0) }) + spaces.push({ type, name, id: to_ascii(name), econ, adjacent: loc_spaces.filter(x=>x>0) }) for (let loc of loc_spaces) if (loc >= 0) add(spaces[loc].adjacent, ix) @@ -159,12 +161,12 @@ data.first_city = spaces.length def_space("city", 8, "Bogotá") def_space("city", 3, "Cali") +def_space("city", 3, "Medellín") def_space("city", 2, "Bucaramanga") def_space("city", 2, "Ibagué") def_space("city", 2, "Santa Marta") def_space("city", 1, "Cartagena") def_space("city", 1, "Cúcuta") -def_space("city", 1, "Medellín") def_space("city", 1, "Neiva") def_space("city", 1, "Pasto") def_space("city", 1, "Sincelejo") @@ -382,9 +384,7 @@ data.coastal_spaces = [ "Cesar", "Atlántico", "Chocó", "Nariño" ].map(n=>spac for (let i = 1; i < spaces.length; ++i) spaces[i].adjacent.sort((a,b)=>a-b) -console.log("const spaces = [") -for (let x of spaces) console.log(JSON.stringify(x) + ",") -console.log("]") +data.cards = cards +data.spaces = spaces -for (let k in data) - console.log("const", k, "=", JSON.stringify(data[k])) +fs.writeFileSync("data.js", "const data = " + JSON.stringify(data, 0, "\t") + "\nif (typeof module !== 'undefined') module.exports = data\n") diff --git a/tools/genpieces.mjs b/tools/genpieces.mjs index ec478f6..cf157c5 100644 --- a/tools/genpieces.mjs +++ b/tools/genpieces.mjs @@ -282,6 +282,7 @@ border("#80643e", "#token_prop_card") border("#d74729", "#token_oppose_plus_bases") border("#004e81", "#token_el_presidente") border("#6a8796", "#token_aid") +border("#01904b", ".token.shipment") border("#4b87c0", ".token.passive_support") border("#b75f61", ".token.passive_opposition") border("#0054a6", ".token.active_support") diff --git a/tools/scale_tokens.sh b/tools/scale_tokens.sh index 83bffdf..f6ccdb4 100644 --- a/tools/scale_tokens.sh +++ b/tools/scale_tokens.sh @@ -1,46 +1,48 @@ mkdir -p tokens.1x tokens.2x function loop() { - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_1.ppm $OUT/govt_control.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_1.ppm $OUT/farc_control.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_6.ppm $OUT/farc_zone.png - - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_7.ppm $OUT/unshaded_ndsc.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_8.ppm $OUT/unshaded_ospina.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_15.ppm $OUT/unshaded_tapias.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_16.ppm $OUT/unshaded_1st_div.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_23.ppm $OUT/unshaded_black_hawks.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_24.ppm $OUT/unshaded_7th_sf.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_32.ppm $OUT/unshaded_meteoro.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_40.ppm $OUT/unshaded_mtn_bns.png - - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_7.ppm $OUT/shaded_ndsc.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_8.ppm $OUT/shaded_ospina.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_15.ppm $OUT/shaded_tapias.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_16.ppm $OUT/shaded_1st_div.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_23.ppm $OUT/shaded_black_hawks.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_24.ppm $OUT/shaded_7th_sf.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_32.ppm $OUT/shaded_meteoro.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_40.ppm $OUT/shaded_mtn_bns.png - - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_30.ppm $OUT/oppose_plus_bases.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_31.ppm $OUT/aid.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_37.ppm $OUT/el_presidente.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_38.ppm $OUT/total_support.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_39.ppm $OUT/prop_card.png - - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_1.ppm $OUT/active_support.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_2.ppm $OUT/terror.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_4.ppm $OUT/active_opposition.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_5.ppm $OUT/reminder_senado_cartels.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_6.ppm $OUT/reminder_darien.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_8.ppm $OUT/reminder_senado_auc.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_11.ppm $OUT/reminder_senado_farc.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_17.ppm $OUT/reminder_sucumbios.png - - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_b_1.ppm $OUT/passive_support.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_b_2.ppm $OUT/sabotage.png - convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_b_4.ppm $OUT/passive_opposition.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/shipment.png $OUT/shipment.png + + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_1.png $OUT/govt_control.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_1.png $OUT/farc_control.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_6.png $OUT/farc_zone.png + + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_7.png $OUT/unshaded_ndsc.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_8.png $OUT/unshaded_ospina.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_15.png $OUT/unshaded_tapias.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_16.png $OUT/unshaded_1st_div.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_23.png $OUT/unshaded_black_hawks.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_24.png $OUT/unshaded_7th_sf.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_32.png $OUT/unshaded_meteoro.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_40.png $OUT/unshaded_mtn_bns.png + + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_7.png $OUT/shaded_ndsc.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_8.png $OUT/shaded_ospina.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_15.png $OUT/shaded_tapias.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_16.png $OUT/shaded_1st_div.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_23.png $OUT/shaded_black_hawks.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_24.png $OUT/shaded_7th_sf.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_32.png $OUT/shaded_meteoro.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_b_40.png $OUT/shaded_mtn_bns.png + + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_30.png $OUT/oppose_plus_bases.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_31.png $OUT/aid.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_37.png $OUT/el_presidente.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_38.png $OUT/total_support.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/five_a_39.png $OUT/prop_card.png + + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_1.png $OUT/active_support.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_2.png $OUT/terror.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_4.png $OUT/active_opposition.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_5.png $OUT/reminder_senado_cartels.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_6.png $OUT/reminder_darien.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_8.png $OUT/reminder_senado_auc.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_11.png $OUT/reminder_senado_farc.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_a_17.png $OUT/reminder_sucumbios.png + + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_b_1.png $OUT/passive_support.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_b_2.png $OUT/sabotage.png + convert -colorspace RGB -resize $SCALE -colorspace sRGB HIRES/tokens/half_b_4.png $OUT/passive_opposition.png } OUT=tokens.1x diff --git a/tools/slice_tokens.sh b/tools/slice_tokens.sh index 5218792..f9ff041 100644 --- a/tools/slice_tokens.sh +++ b/tools/slice_tokens.sh @@ -19,15 +19,20 @@ # 1/2" 576x576+12+12 # 5/8" 720x720+15+15 +# Circles! 825x825 -> trim to 800x800 @75dpi is 50x50 +# 3887+8670 - 4712+9495 + pngtopnm HIRES/tokens/sheet_a.png > /tmp/big.ppm +pnmcut 3887 8670 825 825 /tmp/big.ppm | pnmcut 12 12 800 800 | pnmtopng > HIRES/tokens/shipment.png + I=1 for L in 592 4192 4792 5392 5992 6592 do for T in 1360 5260 5860 do echo half $I $L $T - pnmcut $L $T 600 600 /tmp/big.ppm | pnmcut 12 12 576 576 | pnmtopng > HIRES/tokens/half_a_$I.ppm + pnmcut $L $T 600 600 /tmp/big.ppm | pnmcut 12 12 576 576 | pnmtopng > HIRES/tokens/half_a_$I.png I=$(expr $I + 1) done done @@ -38,7 +43,7 @@ do for T in 760 1746 2732 3718 4704 5692 6678 7664 do echo five $I $L $T - pnmcut $L $T 750 750 /tmp/big.ppm | pnmcut 15 15 720 720 | pnmtopng > HIRES/tokens/five_a_$I.ppm + pnmcut $L $T 750 750 /tmp/big.ppm | pnmcut 15 15 720 720 | pnmtopng > HIRES/tokens/five_a_$I.png I=$(expr $I + 1) done done @@ -51,7 +56,7 @@ do for T in 1360 5260 5860 do echo half $I $L $T - pnmcut $L $T 600 600 /tmp/big.ppm | pnmcut 12 12 576 576 | pnmtopng > HIRES/tokens/half_b_$I.ppm + pnmcut $L $T 600 600 /tmp/big.ppm | pnmcut 12 12 576 576 | pnmtopng > HIRES/tokens/half_b_$I.png I=$(expr $I + 1) done done @@ -62,7 +67,7 @@ do for T in 760 1746 2732 3718 4704 5692 6678 7664 do echo five $I $L $T - pnmcut $L $T 750 750 /tmp/big.ppm | pnmcut 15 15 720 720 | pnmtopng > HIRES/tokens/five_b_$I.ppm + pnmcut $L $T 750 750 /tmp/big.ppm | pnmcut 15 15 720 720 | pnmtopng > HIRES/tokens/five_b_$I.png I=$(expr $I + 1) done done -- cgit v1.2.3