mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-02-05 18:11:23 +01:00
Merge remote-tracking branch 'upstream/master' into geodata
This commit is contained in:
commit
0dc7d622ce
31 changed files with 1175 additions and 803 deletions
|
|
@ -762,9 +762,11 @@
|
|||
|
||||
if (s.form === "Monarchy") {
|
||||
const form = monarchy[expTiers[s.i]];
|
||||
// Default name depend on exponent tier, some culture bases have special names for tiers
|
||||
if (form === "Duchy" && s.neighbors.size > 1 && rand(6) < s.neighbors.size && s.diplomacy.includes("Vassal")) return "Marches"; // some vassal dutchies on borderland
|
||||
if (Math.random() < .3 && s.diplomacy.includes("Vassal")) return "Protectorate"; // some vassals
|
||||
// Default name depends on exponent tier, some culture bases have special names for tiers
|
||||
if (s.diplomacy) {
|
||||
if (form === "Duchy" && s.neighbors.size > 1 && rand(6) < s.neighbors.size && s.diplomacy.includes("Vassal")) return "Marches"; // some vassal dutchies on borderland
|
||||
if (Math.random() < .3 && s.diplomacy.includes("Vassal")) return "Protectorate"; // some vassals
|
||||
}
|
||||
|
||||
if (base === 16 && (form === "Empire" || form === "Kingdom")) return "Sultanate"; // Turkic
|
||||
if (base === 5 && (form === "Empire" || form === "Kingdom")) return "Tsardom"; // Ruthenian
|
||||
|
|
|
|||
|
|
@ -58,7 +58,10 @@
|
|||
|
||||
// check whether all bases are valid. If not, load default namesbase
|
||||
const invalidBase = pack.cultures.some(c => !nameBase[c.base]);
|
||||
if (invalidBase) applyDefaultNamesData();
|
||||
if (invalidBase) {
|
||||
nameBases = Names.getNameBases();
|
||||
nameBase = Names.getNameBase();
|
||||
}
|
||||
|
||||
function getRandomCultures(c) {
|
||||
const d = getDefault();
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
const generate = function() {
|
||||
console.time('generateHeightmap');
|
||||
cells = grid.cells;
|
||||
p = grid.points;
|
||||
cells = grid.cells, p = grid.points;
|
||||
cells.h = new Uint8Array(grid.points.length);
|
||||
|
||||
const input = document.getElementById("templateInput");
|
||||
|
|
@ -19,12 +18,13 @@
|
|||
"High Island": 22,
|
||||
"Low Island": 10,
|
||||
"Continents": 20,
|
||||
"Archipelago": 32,
|
||||
"Archipelago": 30,
|
||||
"Mediterranean":3,
|
||||
"Peninsula": 3,
|
||||
"Pangea": 2,
|
||||
"Isthmus": 2,
|
||||
"Atoll": 1};
|
||||
"Atoll": 1,
|
||||
"Shattered": 2};
|
||||
input.value = rw(templates);
|
||||
}
|
||||
|
||||
|
|
@ -39,6 +39,7 @@
|
|||
case "Peninsula": templatePeninsula(); break;
|
||||
case "Pangea": templatePangea(); break;
|
||||
case "Isthmus": templateIsthmus(); break;
|
||||
case "Shattered": templateShattered(); break;
|
||||
}
|
||||
|
||||
console.timeEnd('generateHeightmap');
|
||||
|
|
@ -193,6 +194,14 @@
|
|||
addStep("Trough", "4-8", "15-30", "70-100", "80-100");
|
||||
}
|
||||
|
||||
// Heighmap Template: Shattered
|
||||
function templateShattered() {
|
||||
addStep("Hill", "8", "35-40", "15-85", "30-70");
|
||||
addStep("Trough", "10-20", "40-50", "5-95", "5-95");
|
||||
addStep("Range", "5-7", "30-40", "10-90", "20-80");
|
||||
addStep("Pit", "12-20", "30-40", "15-85", "20-80");
|
||||
}
|
||||
|
||||
function getBlobPower() {
|
||||
switch (+densityInput.value) {
|
||||
case 1: return .98;
|
||||
|
|
|
|||
|
|
@ -104,7 +104,12 @@
|
|||
// generate short name for culture
|
||||
const getCultureShort = function(culture) {
|
||||
if (culture === undefined) {console.error("Please define a culture"); return;}
|
||||
const base = pack.cultures[culture].base;
|
||||
let base = pack.cultures[culture].base;
|
||||
if (nameBases[base] === undefined) {
|
||||
tip(`Namebase for culture ${pack.cultures[culture].name} does not exist.
|
||||
Please upload custom namebases of change the base in Cultures Editor`, false, "error");
|
||||
base = 1;
|
||||
}
|
||||
const min = nameBases[base].min-1;
|
||||
const max = Math.max(nameBases[base].max-2, min);
|
||||
return getBase(base, min, max, "", 0);
|
||||
|
|
@ -151,7 +156,10 @@
|
|||
else if (base === 17) suffix = rnd < .8 ? "a" : "ia"; // Berber
|
||||
else if (base === 18) suffix = rnd < .8 ? "a" : "ia"; // Arabic
|
||||
else suffix = "ia" // other
|
||||
return validateSuffix(name, suffix);
|
||||
}
|
||||
|
||||
function validateSuffix(name, suffix) {
|
||||
if (name.slice(-1 * suffix.length) === suffix) return name; // no suffix if name already ends with it
|
||||
const s1 = suffix.charAt(0);
|
||||
if (name.slice(-1) === s1) name = name.slice(0, -1); // remove name last letter if it's a suffix first letter
|
||||
|
|
@ -160,5 +168,100 @@
|
|||
return name + suffix;
|
||||
}
|
||||
|
||||
return {getBase, getCulture, getCultureShort, getState, updateChain, updateChains};
|
||||
// generato name for the map
|
||||
const getMapName = function(force) {
|
||||
if (!force && locked("mapName")) return;
|
||||
if (force && locked("mapName")) unlock("mapName");
|
||||
const base = Math.random() < .7 ? 2 : Math.random() < .5 ? rand(0, 6) : rand(0, 31);
|
||||
if (!nameBases[base]) {tip("Namebase is not found", false, "error"); return ""};
|
||||
const min = nameBases[base].min-1;
|
||||
const max = Math.max(nameBases[base].max-3, min);
|
||||
const baseName = getBase(base, min, max, "", 0);
|
||||
const name = Math.random() < .7 ? addSuffix(baseName) : baseName;
|
||||
mapName.value = name;
|
||||
}
|
||||
|
||||
function addSuffix(name) {
|
||||
const suffix = Math.random() < .8 ? "ia" : "land";
|
||||
if (suffix === "ia" && name.length > 6) name = name.slice(0, -(name.length-3)); else
|
||||
if (suffix === "land" && name.length > 6) name = name.slice(0, -(name.length-5));
|
||||
return validateSuffix(name, suffix);
|
||||
}
|
||||
|
||||
const getNameBases = function() {
|
||||
// name, min length, max length, letters to allow duplication, multi-word name rate
|
||||
return [
|
||||
{name: "German", min: 5, max: 12, d: "lt", m: 0},
|
||||
{name: "English", min: 6, max: 11, d: "", m: 0.1},
|
||||
{name: "French", min: 5, max: 13, d: "nlrs", m: 0.1},
|
||||
{name: "Italian", min: 5, max: 12, d: "cltr", m: 0.1},
|
||||
{name: "Castillian", min: 5, max: 11, d: "lr", m: 0},
|
||||
{name: "Ruthenian", min: 5, max: 10, d: "", m: 0},
|
||||
{name: "Nordic", min: 6, max: 10, d: "kln", m: 0.1},
|
||||
{name: "Greek", min: 5, max: 11, d: "s", m: 0.1},
|
||||
{name: "Roman", min: 6, max: 11, d: "ln", m: 0.1},
|
||||
{name: "Finnic", min: 5, max: 11, d: "akiut", m: 0},
|
||||
{name: "Korean", min: 5, max: 11, d: "", m: 0},
|
||||
{name: "Chinese", min: 5, max: 10, d: "", m: 0},
|
||||
{name: "Japanese", min: 4, max: 10, d: "", m: 0},
|
||||
{name: "Portuguese", min: 5, max: 11, d: "", m: 0.1},
|
||||
{name: "Nahuatl", min: 6, max: 13, d: "l", m: 0},
|
||||
{name: "Hungarian", min: 6, max: 13, d: "", m: 0.1},
|
||||
{name: "Turkish", min: 4, max: 10, d: "", m: 0},
|
||||
{name: "Berber", min: 4, max: 10, d: "s", m: 0.2},
|
||||
{name: "Arabic", min: 4, max: 9, d: "ae", m: 0.2},
|
||||
{name: "Inuit", min: 5, max: 15, d: "alutsn", m: 0},
|
||||
{name: "Basque", min: 4, max: 11, d: "r", m: 0.1},
|
||||
{name: "Nigerian", min: 4, max: 10, d: "", m: 0.3},
|
||||
{name: "Celtic", min: 4, max: 12, d: "nld", m: 0},
|
||||
{name: "Mesopotamian", min: 4, max: 9, d: "srpl", m: 0.1},
|
||||
{name: "Iranian", min: 5, max: 11, d: "", m: 0.1},
|
||||
{name: "Hawaiian", min: 5, max: 10, d: "auo", m: 1},
|
||||
{name: "Karnataka", min: 5, max: 11, d: "tnl", m: 0},
|
||||
{name: "Quechua", min: 6, max: 12, d: "l", m: 0},
|
||||
{name: "Swahili", min: 4, max: 9, d: "", m: 0},
|
||||
{name: "Vietnamese", min: 3, max: 12, d: "", m: 1},
|
||||
{name: "Cantonese", min: 5, max: 11, d: "", m: 0},
|
||||
{name: "Mongolian", min: 5, max: 12, d: "aou", m: .3}
|
||||
];
|
||||
}
|
||||
|
||||
const getNameBase = function() {
|
||||
return [
|
||||
["Achern","Aichhalden","Aitern","Albbruck","Alpirsbach","Altensteig","Althengstett","Appenweier","Auggen","Wildbad","Badenen","Badenweiler","Baiersbronn","Ballrechten","Bellingen","Berghaupten","Bernau","Biberach","Biederbach","Binzen","Birkendorf","Birkenfeld","Bischweier","Blumberg","Bollen","Bollschweil","Bonndorf","Bosingen","Braunlingen","Breisach","Breisgau","Breitnau","Brigachtal","Buchenbach","Buggingen","Buhl","Buhlertal","Calw","Dachsberg","Dobel","Donaueschingen","Dornhan","Dornstetten","Dottingen","Dunningen","Durbach","Durrheim","Ebhausen","Ebringen","Efringen","Egenhausen","Ehrenkirchen","Ehrsberg","Eimeldingen","Eisenbach","Elzach","Elztal","Emmendingen","Endingen","Engelsbrand","Enz","Enzklosterle","Eschbronn","Ettenheim","Ettlingen","Feldberg","Fischerbach","Fischingen","Fluorn","Forbach","Freiamt","Freiburg","Freudenstadt","Friedenweiler","Friesenheim","Frohnd","Furtwangen","Gaggenau","Geisingen","Gengenbach","Gernsbach","Glatt","Glatten","Glottertal","Gorwihl","Gottenheim","Grafenhausen","Grenzach","Griesbach","Gutach","Gutenbach","Hag","Haiterbach","Hardt","Harmersbach","Hasel","Haslach","Hausach","Hausen","Hausern","Heitersheim","Herbolzheim","Herrenalb","Herrischried","Hinterzarten","Hochenschwand","Hofen","Hofstetten","Hohberg","Horb","Horben","Hornberg","Hufingen","Ibach","Ihringen","Inzlingen","Kandern","Kappel","Kappelrodeck","Karlsbad","Karlsruhe","Kehl","Keltern","Kippenheim","Kirchzarten","Konigsfeld","Krozingen","Kuppenheim","Kussaberg","Lahr","Lauchringen","Lauf","Laufenburg","Lautenbach","Lauterbach","Lenzkirch","Liebenzell","Loffenau","Loffingen","Lorrach","Lossburg","Mahlberg","Malsburg","Malsch","March","Marxzell","Marzell","Maulburg","Monchweiler","Muhlenbach","Mullheim","Munstertal","Murg","Nagold","Neubulach","Neuenburg","Neuhausen","Neuried","Neuweiler","Niedereschach","Nordrach","Oberharmersbach","Oberkirch","Oberndorf","Oberbach","Oberried","Oberwolfach","Offenburg","Ohlsbach","Oppenau","Ortenberg","otigheim","Ottenhofen","Ottersweier","Peterstal","Pfaffenweiler","Pfalzgrafenweiler","Pforzheim","Rastatt","Renchen","Rheinau","Rheinfelden","Rheinmunster","Rickenbach","Rippoldsau","Rohrdorf","Rottweil","Rummingen","Rust","Sackingen","Sasbach","Sasbachwalden","Schallbach","Schallstadt","Schapbach","Schenkenzell","Schiltach","Schliengen","Schluchsee","Schomberg","Schonach","Schonau","Schonenberg","Schonwald","Schopfheim","Schopfloch","Schramberg","Schuttertal","Schwenningen","Schworstadt","Seebach","Seelbach","Seewald","Sexau","Simmersfeld","Simonswald","Sinzheim","Solden","Staufen","Stegen","Steinach","Steinen","Steinmauern","Straubenhardt","Stuhlingen","Sulz","Sulzburg","Teinach","Tiefenbronn","Tiengen","Titisee","Todtmoos","Todtnau","Todtnauberg","Triberg","Tunau","Tuningen","uhlingen","Unterkirnach","Reichenbach","Utzenfeld","Villingen","Villingendorf","Vogtsburg","Vohrenbach","Waldachtal","Waldbronn","Waldkirch","Waldshut","Wehr","Weil","Weilheim","Weisenbach","Wembach","Wieden","Wiesental","Wildberg","Winzeln","Wittlingen","Wittnau","Wolfach","Wutach","Wutoschingen","Wyhlen","Zavelstein"],
|
||||
["Abingdon","Albrighton","Alcester","Almondbury","Altrincham","Amersham","Andover","Appleby","Ashboume","Atherstone","Aveton","Axbridge","Aylesbury","Baldock","Bamburgh","Barton","Basingstoke","Berden","Bere","Berkeley","Berwick","Betley","Bideford","Bingley","Birmingham","Blandford","Blechingley","Bodmin","Bolton","Bootham","Boroughbridge","Boscastle","Bossinney","Bramber","Brampton","Brasted","Bretford","Bridgetown","Bridlington","Bromyard","Bruton","Buckingham","Bungay","Burton","Calne","Cambridge","Canterbury","Carlisle","Castleton","Caus","Charmouth","Chawleigh","Chichester","Chillington","Chinnor","Chipping","Chisbury","Cleobury","Clifford","Clifton","Clitheroe","Cockermouth","Coleshill","Combe","Congleton","Crafthole","Crediton","Cuddenbeck","Dalton","Darlington","Dodbrooke","Drax","Dudley","Dunstable","Dunster","Dunwich","Durham","Dymock","Exeter","Exning","Faringdon","Felton","Fenny","Finedon","Flookburgh","Fowey","Frampton","Gateshead","Gatton","Godmanchester","Grampound","Grantham","Guildford","Halesowen","Halton","Harbottle","Harlow","Hatfield","Hatherleigh","Haydon","Helston","Henley","Hertford","Heytesbury","Hinckley","Hitchin","Holme","Hornby","Horsham","Kendal","Kenilworth","Kilkhampton","Kineton","Kington","Kinver","Kirby","Knaresborough","Knutsford","Launceston","Leighton","Lewes","Linton","Louth","Luton","Lyme","Lympstone","Macclesfield","Madeley","Malborough","Maldon","Manchester","Manningtree","Marazion","Marlborough","Marshfield","Mere","Merryfield","Middlewich","Midhurst","Milborne","Mitford","Modbury","Montacute","Mousehole","Newbiggin","Newborough","Newbury","Newenden","Newent","Norham","Northleach","Noss","Oakham","Olney","Orford","Ormskirk","Oswestry","Padstow","Paignton","Penkneth","Penrith","Penzance","Pershore","Petersfield","Pevensey","Pickering","Pilton","Pontefract","Portsmouth","Preston","Quatford","Reading","Redcliff","Retford","Rockingham","Romney","Rothbury","Rothwell","Salisbury","Saltash","Seaford","Seasalter","Sherston","Shifnal","Shoreham","Sidmouth","Skipsea","Skipton","Solihull","Somerton","Southam","Southwark","Standon","Stansted","Stapleton","Stottesdon","Sudbury","Swavesey","Tamerton","Tarporley","Tetbury","Thatcham","Thaxted","Thetford","Thornbury","Tintagel","Tiverton","Torksey","Totnes","Towcester","Tregoney","Trematon","Tutbury","Uxbridge","Wallingford","Wareham","Warenmouth","Wargrave","Warton","Watchet","Watford","Wendover","Westbury","Westcheap","Weymouth","Whitford","Wickwar","Wigan","Wigmore","Winchelsea","Winkleigh","Wiscombe","Witham","Witheridge","Wiveliscombe","Woodbury","Yeovil"],
|
||||
["Adon","Aillant","Amilly","Andonville","Ardon","Artenay","Ascheres","Ascoux","Attray","Aubin","Audeville","Aulnay","Autruy","Auvilliers","Auxy","Aveyron","Baccon","Bardon","Barville","Batilly","Baule","Bazoches","Beauchamps","Beaugency","Beaulieu","Beaune","Bellegarde","Boesses","Boigny","Boiscommun","Boismorand","Boisseaux","Bondaroy","Bonnee","Bonny","Bordes","Bou","Bougy","Bouilly","Boulay","Bouzonville","Bouzy","Boynes","Bray","Breteau","Briare","Briarres","Bricy","Bromeilles","Bucy","Cepoy","Cercottes","Cerdon","Cernoy","Cesarville","Chailly","Chaingy","Chalette","Chambon","Champoulet","Chanteau","Chantecoq","Chapell","Charme","Charmont","Charsonville","Chateau","Chateauneuf","Chatel","Chatenoy","Chatillon","Chaussy","Checy","Chevannes","Chevillon","Chevilly","Chevry","Chilleurs","Choux","Chuelles","Clery","Coinces","Coligny","Combleux","Combreux","Conflans","Corbeilles","Corquilleroy","Cortrat","Coudroy","Coullons","Coulmiers","Courcelles","Courcy","Courtemaux","Courtempierre","Courtenay","Cravant","Crottes","Dadonville","Dammarie","Dampierre","Darvoy","Desmonts","Dimancheville","Donnery","Dordives","Dossainville","Douchy","Dry","Echilleuses","Egry","Engenville","Epieds","Erceville","Ervauville","Escrennes","Escrignelles","Estouy","Faverelles","Fay","Feins","Ferolles","Ferrieres","Fleury","Fontenay","Foret","Foucherolles","Freville","Gatinais","Gaubertin","Gemigny","Germigny","Gidy","Gien","Girolles","Givraines","Gondreville","Grangermont","Greneville","Griselles","Guigneville","Guilly","Gyleslonains","Huetre","Huisseau","Ingrannes","Ingre","Intville","Isdes","Jargeau","Jouy","Juranville","Bussiere","Laas","Ladon","Lailly","Langesse","Leouville","Ligny","Lombreuil","Lorcy","Lorris","Loury","Louzouer","Malesherbois","Marcilly","Mardie","Mareau","Marigny","Marsainvilliers","Melleroy","Menestreau","Merinville","Messas","Meung","Mezieres","Migneres","Mignerette","Mirabeau","Montargis","Montbarrois","Montbouy","Montcresson","Montereau","Montigny","Montliard","Mormant","Morville","Moulinet","Moulon","Nancray","Nargis","Nesploy","Neuville","Neuvy","Nevoy","Nibelle","Nogent","Noyers","Ocre","Oison","Olivet","Ondreville","Onzerain","Orleans","Ormes","Orville","Oussoy","Outarville","Ouzouer","Pannecieres","Pannes","Patay","Paucourt","Pers","Pierrefitte","Pithiverais","Pithiviers","Poilly","Potier","Prefontaines","Presnoy","Pressigny","Puiseaux","Quiers","Ramoulu","Rebrechien","Rouvray","Rozieres","Rozoy","Ruan","Sandillon","Santeau","Saran","Sceaux","Seichebrieres","Semoy","Sennely","Sermaises","Sigloy","Solterre","Sougy","Sully","Sury","Tavers","Thignonville","Thimory","Thorailles","Thou","Tigy","Tivernon","Tournoisis","Trainou","Treilles","Trigueres","Trinay","Vannes","Varennes","Vennecy","Vieilles","Vienne","Viglain","Vignes","Villamblain","Villemandeur","Villemoutiers","Villemurlin","Villeneuve","Villereau","Villevoques","Villorceau","Vimory","Vitry","Vrigny","Ivre"],
|
||||
["Accumoli","Acquafondata","Acquapendente","Acuto","Affile","Agosta","Alatri","Albano","Allumiere","Alvito","Amaseno","Amatrice","Anagni","Anguillara","Anticoli","Antrodoco","Anzio","Aprilia","Aquino","Arce","Arcinazzo","Ardea","Ariccia","Arlena","Arnara","Arpino","Arsoli","Artena","Ascrea","Atina","Ausonia","Bagnoregio","Barbarano","Bassano","Bassiano","Bellegra","Belmonte","Blera","Bolsena","Bomarzo","Borbona","Borgo","Borgorose","Boville","Bracciano","Broccostella","Calcata","Camerata","Campagnano","Campodimele","Campoli","Canale","Canepina","Canino","Cantalice","Cantalupo","Canterano","Capena","Capodimonte","Capranica","Caprarola","Carbognano","Casalattico","Casalvieri","Casape","Casaprota","Casperia","Cassino","Castelforte","Castelliri","Castello","Castelnuovo","Castiglione","Castro","Castrocielo","Cave","Ceccano","Celleno","Cellere","Ceprano","Cerreto","Cervara","Cervaro","Cerveteri","Ciampino","Ciciliano","Cineto","Cisterna","Cittaducale","Cittareale","Civita","Civitavecchia","Civitella","Colfelice","Collalto","Colle","Colleferro","Collegiove","Collepardo","Collevecchio","Colli","Colonna","Concerviano","Configni","Contigliano","Corchiano","Coreno","Cori","Cottanello","Esperia","Fabrica","Faleria","Fara","Farnese","Ferentino","Fiamignano","Fiano","Filacciano","Filettino","Fiuggi","Fiumicino","Fondi","Fontana","Fonte","Fontechiari","Forano","Formello","Formia","Frascati","Frasso","Frosinone","Fumone","Gaeta","Gallese","Gallicano","Gallinaro","Gavignano","Genazzano","Genzano","Gerano","Giuliano","Gorga","Gradoli","Graffignano","Greccio","Grottaferrata","Grotte","Guarcino","Guidonia","Ischia","Isola","Itri","Jenne","Labico","Labro","Ladispoli","Lanuvio","Lariano","Latera","Lenola","Leonessa","Licenza","Longone","Lubriano","Maenza","Magliano","Mandela","Manziana","Marano","Marcellina","Marcetelli","Marino","Marta","Mazzano","Mentana","Micigliano","Minturno","Mompeo","Montalto","Montasola","Monte","Montebuono","Montefiascone","Monteflavio","Montelanico","Monteleone","Montelibretti","Montenero","Monterosi","Monterotondo","Montopoli","Montorio","Moricone","Morlupo","Morolo","Morro","Nazzano","Nemi","Nepi","Nerola","Nespolo","Nettuno","Norma","Olevano","Onano","Oriolo","Orte","Orvinio","Paganico","Palestrina","Paliano","Palombara","Pastena","Patrica","Percile","Pescorocchiano","Pescosolido","Petrella","Piansano","Picinisco","Pico","Piedimonte","Piglio","Pignataro","Pisoniano","Pofi","Poggio","Poli","Pomezia","Pontecorvo","Pontinia","Ponza","Ponzano","Posta","Pozzaglia","Priverno","Proceno","Prossedi","Riano","Rieti","Rignano","Riofreddo","Ripi","Rivodutri","Rocca","Roccagiovine","Roccagorga","Roccantica","Roccasecca","Roiate","Ronciglione","Roviano","Sabaudia","Sacrofano","Salisano","Sambuci","Santa","Santi","Santopadre","Saracinesco","Scandriglia","Segni","Selci","Sermoneta","Serrone","Settefrati","Sezze","Sgurgola","Sonnino","Sora","Soriano","Sperlonga","Spigno","Stimigliano","Strangolagalli","Subiaco","Supino","Sutri","Tarano","Tarquinia","Terelle","Terracina","Tessennano","Tivoli","Toffia","Tolfa","Torre","Torri","Torrice","Torricella","Torrita","Trevi","Trevignano","Trivigliano","Turania","Tuscania","Vacone","Valentano","Vallecorsa","Vallemaio","Vallepietra","Vallerano","Vallerotonda","Vallinfreda","Valmontone","Varco","Vasanello","Vejano","Velletri","Ventotene","Veroli","Vetralla","Vicalvi","Vico","Vicovaro","Vignanello","Viterbo","Viticuso","Vitorchiano","Vivaro","Zagarolo"],
|
||||
["Abanades","Ablanque","Adobes","Ajofrin","Alameda","Alaminos","Alarilla","Albalate","Albares","Albarreal","Albendiego","Alcabon","Alcanizo","Alcaudete","Alcocer","Alcolea","Alcoroches","Aldea","Aldeanueva","Algar","Algora","Alhondiga","Alique","Almadrones","Almendral","Almoguera","Almonacid","Almorox","Alocen","Alovera","Alustante","Angon","Anguita","Anover","Anquela","Arbancon","Arbeteta","Arcicollar","Argecilla","Arges","Armallones","Armuna","Arroyo","Atanzon","Atienza","Aunon","Azuqueca","Azutan","Baides","Banos","Banuelos","Barcience","Bargas","Barriopedro","Belvis","Berninches","Borox","Brihuega","Budia","Buenaventura","Bujalaro","Burguillos","Burujon","Bustares","Cabanas","Cabanillas","Calera","Caleruela","Calzada","Camarena","Campillo","Camunas","Canizar","Canredondo","Cantalojas","Cardiel","Carmena","Carranque","Carriches","Casa","Casarrubios","Casas","Casasbuenas","Caspuenas","Castejon","Castellar","Castilforte","Castillo","Castilnuevo","Cazalegas","Cebolla","Cedillo","Cendejas","Centenera","Cervera","Checa","Chequilla","Chillaron","Chiloeches","Chozas","Chueca","Cifuentes","Cincovillas","Ciruelas","Ciruelos","Cobeja","Cobeta","Cobisa","Cogollor","Cogolludo","Condemios","Congostrina","Consuegra","Copernal","Corduente","Corral","Cuerva","Domingo","Dosbarrios","Driebes","Duron","El","Embid","Erustes","Escalona","Escalonilla","Escamilla","Escariche","Escopete","Espinosa","Espinoso","Esplegares","Esquivias","Estables","Estriegana","Fontanar","Fuembellida","Fuensalida","Fuentelsaz","Gajanejos","Galve","Galvez","Garciotum","Gascuena","Gerindote","Guadamur","Henche","Heras","Herreria","Herreruela","Hijes","Hinojosa","Hita","Hombrados","Hontanar","Hontoba","Horche","Hormigos","Huecas","Huermeces","Huerta","Hueva","Humanes","Illan","Illana","Illescas","Iniestola","Irueste","Jadraque","Jirueque","Lagartera","Las","Layos","Ledanca","Lillo","Lominchar","Loranca","Los","Lucillos","Lupiana","Luzaga","Luzon","Madridejos","Magan","Majaelrayo","Malaga","Malaguilla","Malpica","Mandayona","Mantiel","Manzaneque","Maqueda","Maranchon","Marchamalo","Marjaliza","Marrupe","Mascaraque","Masegoso","Matarrubia","Matillas","Mazarete","Mazuecos","Medranda","Megina","Mejorada","Mentrida","Mesegar","Miedes","Miguel","Millana","Milmarcos","Mirabueno","Miralrio","Mocejon","Mochales","Mohedas","Molina","Monasterio","Mondejar","Montarron","Mora","Moratilla","Morenilla","Muduex","Nambroca","Navalcan","Negredo","Noblejas","Noez","Nombela","Noves","Numancia","Nuno","Ocana","Ocentejo","Olias","Olmeda","Ontigola","Orea","Orgaz","Oropesa","Otero","Palmaces","Palomeque","Pantoja","Pardos","Paredes","Pareja","Parrillas","Pastrana","Pelahustan","Penalen","Penalver","Pepino","Peralejos","Peralveche","Pinilla","Pioz","Piqueras","Polan","Portillo","Poveda","Pozo","Pradena","Prados","Puebla","Puerto","Pulgar","Quer","Quero","Quintanar","Quismondo","Rebollosa","Recas","Renera","Retamoso","Retiendas","Riba","Rielves","Rillo","Riofrio","Robledillo","Robledo","Romanillos","Romanones","Rueda","Sacecorbo","Sacedon","Saelices","Salmeron","San","Santa","Santiuste","Santo","Sartajada","Sauca","Sayaton","Segurilla","Selas","Semillas","Sesena","Setiles","Sevilleja","Sienes","Siguenza","Solanillos","Somolinos","Sonseca","Sotillo","Sotodosos","Talavera","Tamajon","Taragudo","Taravilla","Tartanedo","Tembleque","Tendilla","Terzaga","Tierzo","Tordellego","Tordelrabano","Tordesilos","Torija","Torralba","Torre","Torrecilla","Torrecuadrada","Torrejon","Torremocha","Torrico","Torrijos","Torrubia","Tortola","Tortuera","Tortuero","Totanes","Traid","Trijueque","Trillo","Turleque","Uceda","Ugena","Ujados","Urda","Utande","Valdarachas","Valdesotos","Valhermoso","Valtablado","Valverde","Velada","Viana","Vinuelas","Yebes","Yebra","Yelamos","Yeles","Yepes","Yuncler","Yunclillos","Yuncos","Yunquera","Zaorejas","Zarzuela","Zorita"],
|
||||
["Belgorod","Beloberezhye","Belyi","Belz","Berestiy","Berezhets","Berezovets","Berezutsk","Bobruisk","Bolonets","Borisov","Borovsk","Bozhesk","Bratslav","Bryansk","Brynsk","Buryn","Byhov","Chechersk","Chemesov","Cheremosh","Cherlen","Chern","Chernigov","Chernitsa","Chernobyl","Chernogorod","Chertoryesk","Chetvertnia","Demyansk","Derevesk","Devyagoresk","Dichin","Dmitrov","Dorogobuch","Dorogobuzh","Drestvin","Drokov","Drutsk","Dubechin","Dubichi","Dubki","Dubkov","Dveren","Galich","Glebovo","Glinsk","Goloty","Gomiy","Gorodets","Gorodische","Gorodno","Gorohovets","Goroshin","Gorval","Goryshon","Holm","Horobor","Hoten","Hotin","Hotmyzhsk","Ilovech","Ivan","Izborsk","Izheslavl","Kamenets","Kanev","Karachev","Karna","Kavarna","Klechesk","Klyapech","Kolomyya","Kolyvan","Kopyl","Korec","Kornik","Korochunov","Korshev","Korsun","Koshkin","Kotelno","Kovyla","Kozelsk","Kozelsk","Kremenets","Krichev","Krylatsk","Ksniatin","Kulatsk","Kursk","Kursk","Lebedev","Lida","Logosko","Lomihvost","Loshesk","Loshichi","Lubech","Lubno","Lubutsk","Lutsk","Luchin","Luki","Lukoml","Luzha","Lvov","Mtsensk","Mdin","Medniki","Melecha","Merech","Meretsk","Mescherskoe","Meshkovsk","Metlitsk","Mezetsk","Mglin","Mihailov","Mikitin","Mikulino","Miloslavichi","Mogilev","Mologa","Moreva","Mosalsk","Moschiny","Mozyr","Mstislav","Mstislavets","Muravin","Nemech","Nemiza","Nerinsk","Nichan","Novgorod","Novogorodok","Obolichi","Obolensk","Obolensk","Oleshsk","Olgov","Omelnik","Opoka","Opoki","Oreshek","Orlets","Osechen","Oster","Ostrog","Ostrov","Perelai","Peremil","Peremyshl","Pererov","Peresechen","Perevitsk","Pereyaslav","Pinsk","Ples","Polotsk","Pronsk","Proposhesk","Punia","Putivl","Rechitsa","Rodno","Rogachev","Romanov","Romny","Roslavl","Rostislavl","Rostovets","Rsha","Ruza","Rybchesk","Rylsk","Rzhavesk","Rzhev","Rzhischev","Sambor","Serensk","Serensk","Serpeysk","Shilov","Shuya","Sinech","Sizhka","Skala","Slovensk","Slutsk","Smedin","Sneporod","Snitin","Snovsk","Sochevo","Sokolec","Starica","Starodub","Stepan","Sterzh","Streshin","Sutesk","Svinetsk","Svisloch","Terebovl","Ternov","Teshilov","Teterin","Tiversk","Torchevsk","Toropets","Torzhok","Tripolye","Trubchevsk","Tur","Turov","Usvyaty","Uteshkov","Vasilkov","Velil","Velye","Venev","Venicha","Verderev","Vereya","Veveresk","Viazma","Vidbesk","Vidychev","Voino","Volodimer","Volok","Volyn","Vorobesk","Voronich","Voronok","Vorotynsk","Vrev","Vruchiy","Vselug","Vyatichsk","Vyatka","Vyshegorod","Vyshgorod","Vysokoe","Yagniatin","Yaropolch","Yasenets","Yuryev","Yuryevets","Zaraysk","Zhitomel","Zholvazh","Zizhech","Zubkov","Zudechev","Zvenigorod"],
|
||||
["Akureyri","Aldra","Alftanes","Andenes","Austbo","Auvog","Bakkafjordur","Ballangen","Bardal","Beisfjord","Bifrost","Bildudalur","Bjerka","Bjerkvik","Bjorkosen","Bliksvaer","Blokken","Blonduos","Bolga","Bolungarvik","Borg","Borgarnes","Bosmoen","Bostad","Bostrand","Botsvika","Brautarholt","Breiddalsvik","Bringsli","Brunahlid","Budardalur","Byggdakjarni","Dalvik","Djupivogur","Donnes","Drageid","Drangsnes","Egilsstadir","Eiteroga","Elvenes","Engavogen","Ertenvog","Eskifjordur","Evenes","Eyrarbakki","Fagernes","Fallmoen","Fellabaer","Fenes","Finnoya","Fjaer","Fjelldal","Flakstad","Flateyri","Flostrand","Fludir","Gardaber","Gardur","Gimstad","Givaer","Gjeroy","Gladstad","Godoya","Godoynes","Granmoen","Gravdal","Grenivik","Grimsey","Grindavik","Grytting","Hafnir","Halsa","Hauganes","Haugland","Hauknes","Hella","Helland","Hellissandur","Hestad","Higrav","Hnifsdalur","Hofn","Hofsos","Holand","Holar","Holen","Holkestad","Holmavik","Hopen","Hovden","Hrafnagil","Hrisey","Husavik","Husvik","Hvammstangi","Hvanneyri","Hveragerdi","Hvolsvollur","Igeroy","Indre","Inndyr","Innhavet","Innes","Isafjordur","Jarklaustur","Jarnsreykir","Junkerdal","Kaldvog","Kanstad","Karlsoy","Kavosen","Keflavik","Kjelde","Kjerstad","Klakk","Kopasker","Kopavogur","Korgen","Kristnes","Krutoga","Krystad","Kvina","Lande","Laugar","Laugaras","Laugarbakki","Laugarvatn","Laupstad","Leines","Leira","Leiren","Leland","Lenvika","Loding","Lodingen","Lonsbakki","Lopsmarka","Lovund","Luroy","Maela","Melahverfi","Meloy","Mevik","Misvaer","Mornes","Mosfellsber","Moskenes","Myken","Naurstad","Nesberg","Nesjahverfi","Nesset","Nevernes","Obygda","Ofoten","Ogskardet","Okervika","Oknes","Olafsfjordur","Oldervika","Olstad","Onstad","Oppeid","Oresvika","Orsnes","Orsvog","Osmyra","Overdal","Prestoya","Raudalaekur","Raufarhofn","Reipo","Reykholar","Reykholt","Reykjahlid","Rif","Rinoya","Rodoy","Rognan","Rosvika","Rovika","Salhus","Sanden","Sandgerdi","Sandoker","Sandset","Sandvika","Saudarkrokur","Selfoss","Selsoya","Sennesvik","Setso","Siglufjordur","Silvalen","Skagastrond","Skjerstad","Skonland","Skorvogen","Skrova","Sleneset","Snubba","Softing","Solheim","Solheimar","Sorarnoy","Sorfugloy","Sorland","Sormela","Sorvaer","Sovika","Stamsund","Stamsvika","Stave","Stokka","Stokkseyri","Storjord","Storo","Storvika","Strand","Straumen","Strendene","Sudavik","Sudureyri","Sundoya","Sydalen","Thingeyri","Thorlakshofn","Thorshofn","Tjarnabyggd","Tjotta","Tosbotn","Traelnes","Trofors","Trones","Tverro","Ulvsvog","Unnstad","Utskor","Valla","Vandved","Varmahlid","Vassos","Vevelstad","Vidrek","Vik","Vikholmen","Vogar","Vogehamn","Vopnafjordur"],
|
||||
["Abdera","Abila","Abydos","Acanthus","Acharnae","Actium","Adramyttium","Aegae","Aegina","Aegium","Aenus","Agrinion","Aigosthena","Akragas","Akrai","Akrillai","Akroinon","Akrotiri","Alalia","Alexandreia","Alexandretta","Alexandria","Alinda","Amarynthos","Amaseia","Ambracia","Amida","Amisos","Amnisos","Amphicaea","Amphigeneia","Amphipolis","Amphissa","Ankon","Antigona","Antipatrea","Antioch","Antioch","Antiochia","Andros","Apamea","Aphidnae","Apollonia","Argos","Arsuf","Artanes","Artemita","Argyroupoli","Asine","Asklepios","Aspendos","Assus","Astacus","Athenai","Athmonia","Aytos","Ancient","Baris","Bhrytos","Borysthenes","Berge","Boura","Bouthroton","Brauron","Byblos","Byllis","Byzantium","Bythinion","Callipolis","Cebrene","Chalcedon","Calydon","Carystus","Chamaizi","Chalcis","Chersonesos","Chios","Chytri","Clazomenae","Cleonae","Cnidus","Colosse","Corcyra","Croton","Cyme","Cyrene","Cythera","Decelea","Delos","Delphi","Demetrias","Dicaearchia","Dimale","Didyma","Dion","Dioscurias","Dodona","Dorylaion","Dyme","Edessa","Elateia","Eleusis","Eleutherna","Emporion","Ephesus","Ephyra","Epidamnos","Epidauros","Eresos","Eretria","Erythrae","Eubea","Gangra","Gaza","Gela","Golgi","Gonnos","Gorgippia","Gournia","Gortyn","Gythium","Hagios","Hagia","Halicarnassus","Halieis","Helike","Heliopolis","Hellespontos","Helorus","Hemeroskopeion","Heraclea","Hermione","Hermonassa","Hierapetra","Hierapolis","Himera","Histria","Hubla","Hyele","Ialysos","Iasus","Idalium","Imbros","Iolcus","Itanos","Ithaca","Juktas","Kallipolis","Kamares","Kameiros","Kannia","Kamarina","Kasmenai","Katane","Kerkinitida","Kepoi","Kimmerikon","Kios","Klazomenai","Knidos","Knossos","Korinthos","Kos","Kourion","Kume","Kydonia","Kynos","Kyrenia","Lamia","Lampsacus","Laodicea","Lapithos","Larissa","Lato","Laus","Lebena","Lefkada","Lekhaion","Leibethra","Leontinoi","Lepreum","Lessa","Lilaea","Lindus","Lissus","Epizephyrian","Madytos","Magnesia","Mallia","Mantineia","Marathon","Marmara","Maroneia","Masis","Massalia","Megalopolis","Megara","Mesembria","Messene","Metapontum","Methana","Methone","Methumna","Miletos","Misenum","Mochlos","Monastiraki","Morgantina","Mulai","Mukenai","Mylasa","Myndus","Myonia","Myra","Myrmekion","Mutilene","Myos","Nauplios","Naucratis","Naupactus","Naxos","Neapoli","Neapolis","Nemea","Nicaea","Nicopolis","Nirou","Nymphaion","Nysa","Oenoe","Oenus","Odessos","Olbia","Olous","Olympia","Olynthus","Opus","Orchomenus","Oricos","Orestias","Oreus","Oropus","Onchesmos","Pactye","Pagasae","Palaikastro","Pandosia","Panticapaeum","Paphos","Parium","Paros","Parthenope","Patrae","Pavlopetri","Pegai","Pelion","Peiraies","Pella","Percote","Pergamum","Petsofa","Phaistos","Phaleron","Phanagoria","Pharae","Pharnacia","Pharos","Phaselis","Philippi","Pithekussa","Philippopolis","Platanos","Phlius","Pherae","Phocaea","Pinara","Pisa","Pitane","Pitiunt","Pixous","Plataea","Poseidonia","Potidaea","Priapus","Priene","Prousa","Pseira","Psychro","Pteleum","Pydna","Pylos","Pyrgos","Rhamnus","Rhegion","Rhithymna","Rhodes","Rhypes","Rizinia","Salamis","Same","Samos","Scyllaeum","Selinus","Seleucia","Semasus","Sestos","Scidrus","Sicyon","Side","Sidon","Siteia","Sinope","Siris","Sklavokampos","Smyrna","Soli","Sozopolis","Sparta","Stagirus","Stratos","Stymphalos","Sybaris","Surakousai","Taras","Tanagra","Tanais","Tauromenion","Tegea","Temnos","Tenedos","Tenea","Teos","Thapsos","Thassos","Thebai","Theodosia","Therma","Thespiae","Thronion","Thoricus","Thurii","Thyreum","Thyria","Tiruns","Tithoraea","Tomis","Tragurion","Trapeze","Trapezus","Tripolis","Troizen","Troliton","Troy","Tylissos","Tyras","Tyros","Tyritake","Vasiliki","Vathypetros","Zakynthos","Zakros","Zankle"],
|
||||
["Abila","Adflexum","Adnicrem","Aelia","Aelius","Aeminium","Aequum","Agrippina","Agrippinae","Ala","Albanianis","Ambianum","Andautonia","Apulum","Aquae","Aquaegranni","Aquensis","Aquileia","Aquincum","Arae","Argentoratum","Ariminum","Ascrivium","Atrebatum","Atuatuca","Augusta","Aurelia","Aurelianorum","Batavar","Batavorum","Belum","Biriciana","Blestium","Bonames","Bonna","Bononia","Borbetomagus","Bovium","Bracara","Brigantium","Burgodunum","Caesaraugusta","Caesarea","Caesaromagus","Calleva","Camulodunum","Cannstatt","Cantiacorum","Capitolina","Castellum","Castra","Castrum","Cibalae","Clausentum","Colonia","Concangis","Condate","Confluentes","Conimbriga","Corduba","Coria","Corieltauvorum","Corinium","Coriovallum","Cornoviorum","Danum","Deva","Divodurum","Dobunnorum","Drusi","Dubris","Dumnoniorum","Durnovaria","Durocobrivis","Durocornovium","Duroliponte","Durovernum","Durovigutum","Eboracum","Edetanorum","Emerita","Emona","Euracini","Faventia","Flaviae","Florentia","Forum","Gerulata","Gerunda","Glevensium","Hadriani","Herculanea","Isca","Italica","Iulia","Iuliobrigensium","Iuvavum","Lactodurum","Lagentium","Lauri","Legionis","Lemanis","Lentia","Lepidi","Letocetum","Lindinis","Lindum","Londinium","Lopodunum","Lousonna","Lucus","Lugdunum","Luguvalium","Lutetia","Mancunium","Marsonia","Martius","Massa","Matilo","Mattiacorum","Mediolanum","Mod","Mogontiacum","Moridunum","Mursa","Naissus","Nervia","Nida","Nigrum","Novaesium","Noviomagus","Olicana","Ovilava","Parisiorum","Partiscum","Paterna","Pistoria","Placentia","Pollentia","Pomaria","Pons","Portus","Praetoria","Praetorium","Pullum","Ragusium","Ratae","Raurica","Regina","Regium","Regulbium","Rigomagus","Roma","Romula","Rutupiae","Salassorum","Salernum","Salona","Scalabis","Segovia","Silurum","Sirmium","Siscia","Sorviodurum","Sumelocenna","Tarraco","Taurinorum","Theranda","Traiectum","Treverorum","Tungrorum","Turicum","Ulpia","Valentia","Venetiae","Venta","Verulamium","Vesontio","Vetera","Victoriae","Victrix","Villa","Viminacium","Vindelicorum","Vindobona","Vinovia","Viroconium"],
|
||||
["Aanekoski","Abjapaluoja","Ahlainen","Aholanvaara","Ahtari","Aijala","Aimala","Akaa","Alajarvi","Alatornio","Alavus","Antsla","Aspo","Bennas","Bjorkoby","Elva","Emasalo","Espoo","Esse","Evitskog","Forssa","Haapajarvi","Haapamaki","Haapavesi","Haapsalu","Haavisto","Hameenlinna","Hameenmaki","Hamina","Hanko","Harjavalta","Hattuvaara","Haukipudas","Hautajarvi","Havumaki","Heinola","Hetta","Hinkabole","Hirmula","Hossa","Huittinen","Husula","Hyryla","Hyvinkaa","Iisalmi","Ikaalinen","Ilmola","Imatra","Inari","Iskmo","Itakoski","Jamsa","Jarvenpaa","Jeppo","Jioesuu","Jiogeva","Joensuu","Jokela","Jokikyla","Jokisuu","Jormua","Juankoski","Jungsund","Jyvaskyla","Kaamasmukka","Kaarina","Kajaani","Kalajoki","Kallaste","Kankaanpaa","Kannus","Kardla","Karesuvanto","Karigasniemi","Karkkila","Karkku","Karksinuia","Karpankyla","Kaskinen","Kasnas","Kauhajoki","Kauhava","Kauniainen","Kauvatsa","Kehra","Keila","Kellokoski","Kelottijarvi","Kemi","Kemijarvi","Kerava","Keuruu","Kiikka","Kiipu","Kilinginiomme","Kiljava","Kilpisjarvi","Kitee","Kiuruvesi","Kivesjarvi","Kiviioli","Kivisuo","Klaukkala","Klovskog","Kohtlajarve","Kokemaki","Kokkola","Kolho","Koria","Koskue","Kotka","Kouva","Kouvola","Kristiina","Kaupunki","Kuhmo","Kunda","Kuopio","Kuressaare","Kurikka","Kusans","Kuusamo","Kylmalankyla","Lahti","Laitila","Lankipohja","Lansikyla","Lappeenranta","Lapua","Laurila","Lautiosaari","Lepsama","Liedakkala","Lieksa","Lihula","Littoinen","Lohja","Loimaa","Loksa","Loviisa","Luohuanylipaa","Lusi","Maardu","Maarianhamina","Malmi","Mantta","Masaby","Masala","Matasvaara","Maula","Miiluranta","Mikkeli","Mioisakula","Munapirtti","Mustvee","Muurahainen","Naantali","Nappa","Narpio","Nickby","Niinimaa","Niinisalo","Nikkila","Nilsia","Nivala","Nokia","Nummela","Nuorgam","Nurmes","Nuvvus","Obbnas","Oitti","Ojakkala","Ollola","onningeby","Orimattila","Orivesi","Otanmaki","Otava","Otepaa","Oulainen","Oulu","Outokumpu","Paavola","Paide","Paimio","Pakankyla","Paldiski","Parainen","Parkano","Parkumaki","Parola","Perttula","Pieksamaki","Pietarsaari","Pioltsamaa","Piolva","Pohjavaara","Porhola","Pori","Porrasa","Porvoo","Pudasjarvi","Purmo","Pussi","Pyhajarvi","Raahe","Raasepori","Raisio","Rajamaki","Rakvere","Rapina","Rapla","Rauma","Rautio","Reposaari","Riihimaki","Rovaniemi","Roykka","Ruonala","Ruottala","Rutalahti","Saarijarvi","Salo","Sastamala","Saue","Savonlinna","Seinajoki","Sillamae","Sindi","Siuntio","Somero","Sompujarvi","Suonenjoki","Suurejaani","Syrjantaka","Tampere","Tamsalu","Tapa","Temmes","Tiorva","Tormasenvaara","Tornio","Tottijarvi","Tulppio","Turenki","Turi","Tuukkala","Tuurala","Tuuri","Tuuski","Ulvila","Unari","Upinniemi","Utti","Uusikaarlepyy","Uusikaupunki","Vaaksy","Vaalimaa","Vaarinmaja","Vaasa","Vainikkala","Valga","Valkeakoski","Vantaa","Varkaus","Vehkapera","Vehmasmaki","Vieki","Vierumaki","Viitasaari","Viljandi","Vilppula","Viohma","Vioru","Virrat","Ylike","Ylivieska","Ylojarvi"],
|
||||
["Aewor","Andong","Angang","Anjung","Anmyeon","Ansan","Anseong","Anyang","Aphae","Apo","Asan","Baebang","Baekseok","Baeksu","Beobwon","Beolgyo","Beomseo","Boeun","Bongdam","Bongdong","Bonghwa","Bongyang","Boryeong","Boseong","Buan","Bubal","Bucheon","Buksam","Busan","Busan","Busan","Buyeo","Changnyeong","Changwon","Cheonan","Cheongdo","Cheongjin","Cheongju","Cheongju","Cheongsong","Cheongyang","Cheorwon","Chirwon","Chowol","Chuncheon","Chuncheon","Chungju","Chungmu","Daecheon","Daedeok","Daegaya","Daegu","Daegu","Daegu","Daejeon","Daejeon","Daejeon","Daejeong","Daesan","Damyang","Dangjin","Danyang","Dasa","Dogye","Dolsan","Dong","Dongducheon","Donggwangyang","Donghae","Dongsong","Doyang","Eonyang","Eumseong","Gaeseong","Galmal","Gampo","Ganam","Ganggyeong","Ganghwa","Gangjin","Gangneung","Ganseong","Gapyeong","Gaun","Gaya","Geochang","Geoje","Geojin","Geoncheon","Geumho","Geumil","Geumsan","Geumseong","Geumwang","Gijang","Gimcheon","Gimhae","Gimhwa","Gimje","Gimpo","Goa","Gochang","Gochon","Goesan","Gohan","Goheung","Gokseong","Gongdo","Gongju","Gonjiam","Goseong","Goyang","Gujwa","Gumi","Gungnae","Gunpo","Gunsan","Gunsan","Gunwi","Guri","Gurye","Guryongpo","Gwacheon","Gwangcheon","Gwangju","Gwangju","Gwangju","Gwangju","Gwangmyeong","Gwangyang","Gwansan","Gyeongju","Gyeongsan","Gyeongseong","Gyeongseong","Gyeryong","Hadong","Haeju","Haenam","Hamchang","Hamheung","Hampyeong","Hamyang","Hamyeol","Hanam","Hanrim","Hapcheon","Hapdeok","Hayang","Heunghae","Heungnam","Hoengseong","Hongcheon","Hongnong","Hongseong","Hwacheon","Hwado","Hwando","Hwaseong","Hwasun","Hwawon","Hyangnam","Icheon","Iksan","Illo","Imsil","Incheon","Incheon","Incheon","Inje","Iri","Iri","Jangan","Janghang","Jangheung","Janghowon","Jangseong","Jangseungpo","Jangsu","Jecheon","Jeju","Jeomchon","Jeongeup","Jeonggwan","Jeongju","Jeongok","Jeongseon","Jeonju","Jeonju","Jeungpyeong","Jido","Jiksan","Jillyang","Jinan","Jincheon","Jindo","Jingeon","Jinhae","Jinjeop","Jinju","Jinju","Jinnampo","Jinyeong","Jocheon","Jochiwon","Jori","Judeok","Jumunjin","Maepo","Mangyeong","Masan","Masan","Migeum","Miryang","Mokcheon","Mokpo","Mokpo","Muan","Muju","Mungyeong","Munmak","Munsan","Munsan","Naeseo","Naesu","Najin","Naju","Namhae","Namji","Nampyeong","Namwon","Namyang","Namyangju","Nohwa","Nongong","Nonsan","Ochang","Ocheon","Oedong","Okcheon","Okgu","Onam","Onsan","Onyang","Opo","Osan","Osong","Paengseong","Paju","Pocheon","Pogok","Pohang","Poseung","Punggi","Pungsan","Pyeongchang","Pyeonghae","Pyeongtaek","Pyeongyang","Sabi","Sabuk","Sacheon","Samcheok","Samcheonpo","Samho","Samhyang","Samnangjin","Samrye","Sancheong","Sangdong","Sangju","Sanyang","Sapgyo","Sariwon","Sejong","Seocheon","Seogwipo","Seokjeok","Seonggeo","Seonghwan","Seongjin","Seongju","Seongnam","Seongsan","Seonsan","Seosan","Seoul","Seungju","Siheung","Sinbuk","Sindong","Sineuiju","Sintaein","Soheul","Sokcho","Songak","Songjeong","Songnim","Songtan","Sunchang","Suncheon","Suwon","Taean","Taebaek","Tongjin","Tongyeong","Uijeongbu","Uiryeong","Uiseong","Uiwang","Ujeong","Uljin","Ulleung","Ulsan","Ulsan","Unbong","Ungcheon","Ungjin","Wabu","Waegwan","Wando","Wanggeomseong","Wiryeseong","Wondeok","Wonju","Wonsan","Yangchon","Yanggu","Yangju","Yangpyeong","Yangsan","Yangyang","Yecheon","Yeocheon","Yeoju","Yeomchi","Yeoncheon","Yeongam","Yeongcheon","Yeongdeok","Yeongdong","Yeonggwang","Yeongju","Yeongwol","Yeongyang","Yeonil","Yeonmu","Yeosu","Yesan","Yongin","Yongjin","Yugu","Wayang"],
|
||||
["Anding","Anlu","Anqing","Anshun","Baan","Baixing","Banyang","Baoding","Baoqing","Binzhou","Caozhou","Changbai","Changchun","Changde","Changling","Changsha","Changtu","Changzhou","Chaozhou","Cheli","Chengde","Chengdu","Chenzhou","Chizhou","Chongqing","Chuxiong","Chuzhou","Dading","Dali","Daming","Datong","Daxing","Dean","Dengke","Dengzhou","Deqing","Dexing","Dihua","Dingli","Dongan","Dongchang","Dongchuan","Dongping","Duyun","Fengtian","Fengxiang","Fengyang","Fenzhou","Funing","Fuzhou","Ganzhou","Gaoyao","Gaozhou","Gongchang","Guangnan","Guangning","Guangping","Guangxin","Guangzhou","Guide","Guilin","Guiyang","Hailong","Hailun","Hangzhou","Hanyang","Hanzhong","Heihe","Hejian","Henan","Hengzhou","Hezhong","Huaian","Huaide","Huaiqing","Huanglong","Huangzhou","Huining","Huizhou","Hulan","Huzhou","Jiading","Jian","Jianchang","Jiande","Jiangning","Jiankang","Jianning","Jiaxing","Jiayang","Jilin","Jinan","Jingjiang","Jingzhao","Jingzhou","Jinhua","Jinzhou","Jiujiang","Kaifeng","Kaihua","Kangding","Kuizhou","Laizhou","Lanzhou","Leizhou","Liangzhou","Lianzhou","Liaoyang","Lijiang","Linan","Linhuang","Linjiang","Lintao","Liping","Liuzhou","Longan","Longjiang","Longqing","Longxing","Luan","Lubin","Lubin","Luzhou","Mishan","Nanan","Nanchang","Nandian","Nankang","Nanning","Nanyang","Nenjiang","Ningan","Ningbo","Ningguo","Ninguo","Ningwu","Ningxia","Ningyuan","Pingjiang","Pingle","Pingliang","Pingyang","Puer","Puzhou","Qianzhou","Qingyang","Qingyuan","Qingzhou","Qiongzhou","Qujing","Quzhou","Raozhou","Rende","Ruian","Ruizhou","Runing","Shafeng","Shajing","Shaoqing","Shaowu","Shaoxing","Shaozhou","Shinan","Shiqian","Shouchun","Shuangcheng","Shulei","Shunde","Shunqing","Shuntian","Shuoping","Sicheng","Sien","Sinan","Sizhou","Songjiang","Suiding","Suihua","Suining","Suzhou","Taian","Taibei","Tainan","Taiping","Taiwan","Taiyuan","Taizhou","Taonan","Tengchong","Tieli","Tingzhou","Tongchuan","Tongqing","Tongren","Tongzhou","Weihui","Wensu","Wenzhou","Wuchang","Wuding","Wuzhou","Xian","Xianchun","Xianping","Xijin","Xiliang","Xincheng","Xingan","Xingde","Xinghua","Xingjing","Xingqing","Xingyi","Xingyuan","Xingzhong","Xining","Xinmen","Xiping","Xuanhua","Xunzhou","Xuzhou","Yanan","Yangzhou","Yanji","Yanping","Yanqi","Yanzhou","Yazhou","Yichang","Yidu","Yilan","Yili","Yingchang","Yingde","Yingtian","Yingzhou","Yizhou","Yongchang","Yongping","Yongshun","Yongzhou","Yuanzhou","Yuezhou","Yulin","Yunnan","Yunyang","Zezhou","Zhangde","Zhangzhou","Zhaoqing","Zhaotong","Zhenan","Zhending","Zhengding","Zhenhai","Zhenjiang","Zhenxi","Zhenyun","Zhongshan","Zunyi"],
|
||||
["Abira","Aga","Aikawa","Aizumisato","Ajigasawa","Akkeshi","Amagi","Ami","Anan","Ando","Asakawa","Ashikita","Bandai","Biratori","China","Chonan","Esashi","Fuchu","Fujimi","Funagata","Genkai","Godo","Goka","Gonohe","Gyokuto","Haboro","Hamatonbetsu","Happo","Harima","Hashikami","Hayashima","Heguri","Hidaka","Higashiagatsuma","Higashiura","Hiranai","Hirogawa","Hiroo","Hodatsushimizu","Hoki","Hokuei","Hokuryu","Horokanai","Ibigawa","Ichikai","Ichikawamisato","Ichinohe","Iide","Iijima","Iizuna","Ikawa","Inagawa","Itakura","Iwaizumi","Iwate","Kagamino","Kaisei","Kamifurano","Kamiita","Kamijima","Kamikawa","Kamikawa","Kamikawa","Kaminokawa","Kamishihoro","Kamitonda","Kamiyama","Kanda","Kanna","Kasagi","Kasuya","Katsuura","Kawabe","Kawagoe","Kawajima","Kawamata","Kawamoto","Kawanehon","Kawanishi","Kawara","Kawasaki","Kawasaki","Kawatana","Kawazu","Kihoku","Kikonai","Kin","Kiso","Kitagata","Kitajima","Kiyama","Kiyosato","Kofu","Koge","Kohoku","Kokonoe","Kora","Kosa","Kosaka","Kotohira","Kudoyama","Kumejima","Kumenan","Kumiyama","Kunitomi","Kurate","Kushimoto","Kutchan","Kyonan","Kyotamba","Mashike","Matsumae","Mifune","Mihama","Minabe","Minami","Minamiechizen","Minamioguni","Minamiosumi","Minamitane","Misaki","Misasa","Misato","Miyashiro","Miyoshi","Mori","Moseushi","Mutsuzawa","Nagaizumi","Nagatoro","Nagayo","Nagomi","Nakadomari","Nakanojo","Nakashibetsu","Nakatosa","Namegawa","Namie","Nanbu","Nanporo","Naoshima","Nasu","Niseko","Nishihara","Nishiizu","Nishikatsura","Nishikawa","Nishinoshima","Nishiwaga","Nogi","Noto","Nyuzen","Oarai","Obuse","Odai","Ogawara","Oharu","Oi","Oirase","Oishida","Oiso","Oizumi","Oji","Okagaki","Oketo","Okutama","Omu","Ono","Osaki","Osakikamijima","Otobe","Otsuki","Owani","Reihoku","Rifu","Rikubetsu","Rishiri","Rokunohe","Ryuo","Saka","Sakuho","Samani","Satsuma","Sayo","Saza","Setana","Shakotan","Shibayama","Shikama","Shimamoto","Shimizu","Shimokawa","Shintomi","Shirakawa","Shisui","Shitara","Sobetsu","Sue","Sumita","Suooshima","Suttsu","Tabuse","Tachiarai","Tadami","Tadaoka","Taiji","Taiki","Takachiho","Takahama","Taketoyo","Tako","Taragi","Tateshina","Tatsugo","Tawaramoto","Teshikaga","Tobe","Toin","Tokigawa","Toma","Tomioka","Tonosho","Tosa","Toyo","Toyokoro","Toyotomi","Toyoyama","Tsubata","Tsubetsu","Tsukigata","Tsunan","Tsuno","Tsuwano","Umi","Wakasa","Yamamoto","Yamanobe","Yamatsuri","Yanaizu","Yasuda","Yoichi","Yonaguni","Yoro","Yoshino","Yubetsu","Yugawara","Yuni","Yusuhara","Yuza"],
|
||||
["Abrigada","Afonsoeiro","Agueda","Aguiar","Aguilada","Alagoas","Alagoinhas","Albufeira","Alcacovas","Alcanhoes","Alcobaca","Alcochete","Alcoutim","Aldoar","Alexania","Alfeizerao","Algarve","Alenquer","Almada","Almagreira","Almeirim","Alpalhao","Alpedrinha","Alvalade","Alverca","Alvor","Alvorada","Amadora","Amapa","Amieira","Anapolis","Anhangueira","Ansiaes","Apelacao","Aracaju","Aranhas","Arega","Areira","Araguaina","Araruama","Arganil","Armacao","Arouca","Asfontes","Assenceira","Avelar","Aveiro","Azambuja","Azinheira","Azueira","Bahia","Bairros","Balsas","Barcarena","Barreiras","Barreiro","Barretos","Batalha","Beira","Beja","Benavente","Betim","Boticas","Braga","Braganca","Brasilia","Brejo","Cabecao","Cabeceiras","Cabedelo","Cabofrio","Cachoeiras","Cadafais","Calheta","Calihandriz","Calvao","Camacha","Caminha","Campinas","Canidelo","Canha","Canoas","Capinha","Carmoes","Cartaxo","Carvalhal","Carvoeiro","Cascavel","Castanhal","Castelobranco","Caueira","Caxias","Chapadinha","Chaves","Celheiras","Cocais","Coimbra","Comporta","Coentral","Conde","Copacabana","Coqueirinho","Coruche","Corumba","Couco","Cubatao","Curitiba","Damaia","Doisportos","Douradilho","Dourados","Enxames","Enxara","Erada","Erechim","Ericeira","Ermidasdosado","Ervidel","Escalhao","Escariz","Esmoriz","Estombar","Espinhal","Espinho","Esposende","Esquerdinha","Estela","Estoril","Eunapolis","Evora","Famalicao","Famoes","Fanhoes","Fanzeres","Fatela","Fatima","Faro","Felgueiras","Ferreira","Figueira","Flecheiras","Florianopolis","Fornalhas","Fortaleza","Freiria","Freixeira","Frielas","Fronteira","Funchal","Fundao","Gaeiras","Gafanhadaboahora","Goa","Goiania","Gracas","Gradil","Grainho","Gralheira","Guarulhos","Guetim","Guimaraes","Horta","Iguacu","Igrejanova","Ilhavo","Ilheus","Ipanema","Iraja","Itaboral","Itacuruca","Itaguai","Itanhaem","Itapevi","Juazeiro","Lagos","Lavacolchos","Laies","Lamego","Laranjeiras","Leiria","Limoeiro","Linhares","Lisboa","Lomba","Lorvao","Lourencomarques","Lourical","Lourinha","Luziania","Macao","Macapa","Macedo","Machava","Malveira","Manaus","Mangabeira","Mangaratiba","Marambaia","Maranhao","Maringue","Marinhais","Matacaes","Matosinhos","Maxial","Maxias","Mealhada","Meimoa","Meires","Milharado","Mira","Miranda","Mirandela","Mogadouro","Montalegre","Montesinho","Moura","Mourao","Mozelos","Negroes","Neiva","Nespereira","Nilopolis","Niteroi","Nordeste","Obidos","Odemira","Odivelas","Oeiras","Oleiros","Olhao","Olhalvo","Olhomarinho","Olinda","Olival","Oliveira","Oliveirinha","Oporto","Ourem","Ovar","Palhais","Palheiros","Palmeira","Palmela","Palmital","Pampilhosa","Pantanal","Paradinha","Parelheiros","Paripueira","Paudalho","Pedrosinho","Penafiel","Peniche","Pedrogao","Pegoes","Pinhao","Pinheiro","Pinhel","Pombal","Pontal","Pontinha","Portel","Portimao","Poxim","Quarteira","Queijas","Queluz","Quiaios","Ramalhal","Reboleira","Recife","Redinha","Ribadouro","Ribeira","Ribeirao","Rosais","Roteiro","Sabugal","Sacavem","Sagres","Sandim","Sangalhos","Santarem","Santos","Sarilhos","Sarzedas","Satao","Satuba","Seixal","Seixas","Seixezelo","Seixo","Selmes","Sepetiba","Serta","Setubal","Silvares","Silveira","Sinhaem","Sintra","Sobral","Sobralinho","Sorocaba","Tabuacotavir","Tabuleiro","Taveiro","Teixoso","Telhado","Telheiro","Tomar","Torrao","Torreira","Torresvedras","Tramagal","Trancoso","Troviscal","Vagos","Valpacos","Varzea","Vassouras","Velas","Viana","Vidigal","Vidigueira","Vidual","Viladerei","Vilamar","Vimeiro","Vinhais","Vinhos","Viseu","Vitoria","Vlamao","Vouzela"],
|
||||
["Acaltepec","Acaltepecatl","Acapulco","Acatlan","Acaxochitlan","Ajuchitlan","Atotonilco","Azcapotzalco","Camotlan","Campeche","Chalco","Chapultepec","Chiapan","Chiapas","Chihuahua","Cihuatlan","Cihuatlancihuatl","Coahuila","Coatepec","Coatlan","Coatzacoalcos","Colima","Colotlan","Coyoacan","Cuauhillan","Cuauhnahuac","Cuauhtemoc","Cuernavaca","Ecatepec","Epatlan","Guanajuato","Huaxacac","Huehuetlan","Hueyapan","Ixtapa","Iztaccihuatl","Iztapalapa","Jalisco","Jocotepec","Jocotepecxocotl","Matixco","Mazatlan","Michhuahcan","Michoacan","Michoacanmichin","Minatitlan","Naucalpan","Nayarit","Nezahualcoyotl","Oaxaca","Ocotepec","Ocotlan","Olinalan","Otompan","Popocatepetl","Queretaro","Sonora","Tabasco","Tamaulipas","Tecolotlan","Tenochtitlan","Teocuitlatlan","Teocuitlatlanteotl","Teotlalco","Teotlalcoteotl","Tepotzotlan","Tepoztlantepoztli","Texcoco","Tlachco","Tlalocan","Tlaxcala","Tlaxcallan","Tollocan","Tolutepetl","Tonanytlan","Tototlan","Tuchtlan","Tuxpan","Uaxacac","Xalapa","Xochimilco","Xolotlan","Yaotlan","Yopico","Yucatan","Yztac","Zacatecas","Zacualco"],
|
||||
["Aba","Abadszalok","Abony","Adony","Ajak","Albertirsa","Alsozsolca","Aszod","Babolna","Bacsalmas","Baktaloranthaza","Balassagyarmat","Balatonalmadi","Balatonboglar","Balatonfured","Balatonfuzfo","Balkany","Balmazujvaros","Barcs","Bataszek","Batonyterenye","Battonya","Bekes","Berettyoujfalu","Berhida","Biatorbagy","Bicske","Biharkeresztes","Bodajk","Boly","Bonyhad","Budakalasz","Budakeszi","Celldomolk","Csakvar","Csenger","Csongrad","Csorna","Csorvas","Csurgo","Dabas","Demecser","Derecske","Devavanya","Devecser","Dombovar","Dombrad","Dorogullo","Dunafoldvar","Dunaharaszti","Dunavarsany","Dunavecse","Edeleny","Elek","Emod","Encs","Enying","Ercsi","Fegyvernek","Fehergyarmat","Felsozsolca","Fertoszentmiklos","Fonyod","Fot","Fuzesabony","Fuzesgyarmat","Gardony","God","Gyal","Gyomaendrod","Gyomro","Hajdudorog","Hajduhadhaz","Hajdunanas","Hajdusamson","Hajduszoboszlo","Halasztelek","Harkany","Hatvan","Heves","Heviz","Ibrany","Isaszeg","Izsak","Janoshalma","Janossomorja","Jaszapati","Jaszarokszallas","Jaszfenyszaru","Jaszkiser","Kaba","Kalocsa","Kapuvar","Karcag","Kecel","Kemecse","Kenderes","Kerekegyhaza","Kerepes","Keszthely","Kisber","Kiskoros","Kiskunmajsa","Kistarcsa","Kistelek","Kisujszallas","Kisvarda","Komadi","Komarom","Komlo","Kormend","Korosladany","Koszeg","Kozarmisleny","Kunhegyes","Kunszentmarton","Kunszentmiklos","Labatlan","Lajosmizse","Lenti","Letavertes","Letenye","Lorinci","Maglod","Mako","Mandok","Marcali","Martfu","Martonvasar","Mateszalka","Melykut","Mezobereny","Mezocsat","Mezohegyes","Mezokeresztes","Mezokovacshaza","Mezokovesd","Mezotur","Mindszent","Mohacs","Monor","Mor","Morahalom","Nadudvar","Nagyatad","Nagyecsed","Nagyhalasz","Nagykallo","Nagykata","Nagykoros","Nagymaros","Nyekladhaza","Nyergesujfalu","Nyiradony","Nyirbator","Nyirmada","Nyirtelek","Ocsa","Orkeny","Oroszlany","Paks","Pannonhalma","Paszto","Pecel","Pecsvarad","Pilis","Pilisvorosvar","Polgar","Polgardi","Pomaz","Puspokladany","Pusztaszabolcs","Putnok","Racalmas","Rackeve","Rakamaz","Rakoczifalva","Sajoszentpeter","Sandorfalva","Sarbogard","Sarkad","Sarospatak","Sarvar","Satoraljaujhely","Siklos","Simontornya","Solt","Soltvadkert","Sumeg","Szabadszallas","Szarvas","Szazhalombatta","Szecseny","Szeghalom","Szendro","Szentgotthard","Szentlorinc","Szerencs","Szigethalom","Szigetvar","Szikszo","Tab","Tamasi","Tapioszele","Tapolca","Tat","Tata","Teglas","Tet","Tiszacsege","Tiszafoldvar","Tiszafured","Tiszakecske","Tiszalok","Tiszaujvaros","Tiszavasvari","Tokaj","Tokol","Tolna","Tompa","Torokbalint","Torokszentmiklos","Totkomlos","Tura","Turkeve","Ujkigyos","ujszasz","Vamospercs","Varpalota","Vasarosnameny","Vasvar","Vecses","Velence","Veresegyhaz","Verpelet","Veszto","Zahony","Zalaszentgrot","Zirc","Zsambek"],
|
||||
["Adapazari","Adiyaman","Afshin","Afyon","Ari","Akchaabat","Akchakale","Akchakoca","Akdamadeni","Akhisar","Aksaray","Akshehir","Alaca","Alanya","Alapli","Alashehir","Amasya","Anamur","Antakya","Ardeshen","Artvin","Aydin","Ayvalik","Babaeski","Bafra","Balikesir","Bandirma","Bartin","Bashiskele","Batman","Bayburt","Belen","Bergama","Besni","Beypazari","Beyshehir","Biga","Bilecik","Bingul","Birecik","Bismil","Bitlis","Bodrum","Bolu","Bolvadin","Bor","Bostanichi","Boyabat","Bozuyuk","Bucak","Bulancak","Bulanik","Burdur","Burhaniye","Chan","Chanakkale","Chankiri","Charshamba","Chaycuma","Chayeli","Chayirova","Cherkezkuy","Cheshme","Ceyhan","Ceylanpinar","Chine","Chivril","Cizre","Chorlu","Chumra","Dalaman","Darica","Denizli","Derik","Derince","Develi","Devrek","Didim","Dilovasi","Dinar","Diyadin","Diyarbakir","Doubayazit","Durtyol","Duzce","Duzichi","Edirne","Edremit","Elazi","Elbistan","Emirda","Erbaa","Ercish","Erdek","Erdemli","Ereli","Ergani","Erzin","Erzincan","Erzurum","Eskishehir","Fatsa","Fethiye","Gazipasha","Gebze","Gelibolu","Gerede","Geyve","Giresun","Guksun","Gulbashi","Gulcuk","Gurnen","Gumushhane","Guroymak","Hakkari","Harbiye","Havza","Hayrabolu","Hilvan","Idil","Idir","Ilgin","Imamolu","Incirliova","Inegul","Iskenderun","Iskilip","Islahiye","Isparta","Izmit","Iznik","Kadirli","Kahramanmarash","Kahta","Kaman","Kapakli","Karabuk","Karacabey","Karadeniz Ereli","Karakupru","Karaman","Karamursel","Karapinar","Karasu","Kars","Kartepe","Kastamonu","Kemer","Keshan","Kilimli","Kilis","Kirikhan","Kirikkale","Kirklareli","Kirshehir","Kiziltepe","Kurfez","Korkuteli","Kovancilar","Kozan","Kozlu","Kozluk","Kulu","Kumluca","Kurtalan","Kushadasi","Kutahya","Luleburgaz","Malatya","Malazgirt","Malkara","Manavgat","Manisa","Mardin","Marmaris","Mersin","Merzifon","Midyat","Milas","Mula","Muratli","Mush","Mut","Nazilli","Nevshehir","Nide","Niksar","Nizip","Nusaybin","udemish","Oltu","Ordu","Orhangazi","Ortaca","Osmancik","Osmaniye","Patnos","Payas","Pazarcik","Polatli","Reyhanli","Rize","Safranbolu","Salihli","Samanda","Samsun","Sandikli","shanliurfa","Saray","Sarikamish","Sarikaya","sharkishla","shereflikochhisar","Serik","Serinyol","Seydishehir","Siirt","Silifke","Silopi","Silvan","Simav","Sinop","shirnak","Sivas","Siverek","Surke","Soma","Sorgun","Suluova","Sungurlu","Suruch","Susurluk","Tarsus","Tatvan","Tavshanli","Tekirda","Terme","Tire","Tokat","Tosya","Trabzon","Tunceli","Turgutlu","Turhal","Unye","Ushak","Uzunkurpru","Van","Vezirkurpru","Viranshehir","Yahyali","Yalova","Yenishehir","Yerkury","Yozgat","Yuksekova","Zile","Zonguldak"],
|
||||
["Abkhouch","Adrar","Agadir","Agelmam","Aghmat","Agrakal","Agulmam","Ahaggar","Almou","Anfa","Annaba","Aousja","Arbat","Argoub","Arif","Asfi","Assamer","Assif","Azaghar","Azmour","Azrou","Beccar","Beja","Bennour","Benslimane","Berkane","Berrechid","Bizerte","Bouskoura","Boutferda","Dar Bouazza","Darallouch","Darchaabane","Dcheira","Denden","Djebel","Djedeida","Drargua","Essaouira","Ezzahra","Fas","Fnideq","Ghezeze","Goubellat","Grisaffen","Guelmim","Guercif","Hammamet","Harrouda","Hoceima","Idurar","Ifendassen","Ifoghas","Imilchil","Inezgane","Izoughar","Jendouba","Kacem","Kelibia","Kenitra","Kerrando","Khalidia","Khemisset","Khenifra","Khouribga","Kidal","Korba","Korbous","Lahraouyine","Larache","Leyun","Lqliaa","Manouba","Martil","Mazagan","Mcherga","Mdiq","Megrine","Mellal","Melloul","Midelt","Mohammedia","Mornag","Mrrakc","Nabeul","Nadhour","Nador","Nawaksut","Nefza","Ouarzazate","Ouazzane","Oued Zem","Oujda","Ouladteima","Qsentina","Rades","Rafraf","Safi","Sefrou","Sejnane","Settat","Sijilmassa","Skhirat","Slimane","Somaa","Sraghna","Susa","Tabarka","Taferka","Tafza","Tagbalut","Tagerdayt","Takelsa","Tanja","Tantan","Taourirt","Taroudant","Tasfelalayt","Tattiwin","Taza","Tazerka","Tazizawt","Tebourba","Teboursouk","Temara","Testour","Tetouan","Tibeskert","Tifelt","Tinariwen","Tinduf","Tinja","Tiznit","Toubkal","Trables","Tubqal","Tunes","Urup","Watlas","Wehran","Wejda","Youssoufia","Zaghouan","Zahret","Zemmour","Zriba"],
|
||||
["Abadilah","Abayt","Abha","Abud","Aden","Ahwar","Ajman","Alabadilah","Alabar","Alahjer","Alain","Alaraq","Alarish","Alarjam","Alashraf","Alaswaaq","Alawali","Albarar","Albawadi","Albirk","Aldhabiyah","Alduwaid","Alfareeq","Algayed","Alhada","Alhafirah","Alhamar","Alharam","Alharidhah","Alhawtah","Alhazim","Alhrateem","Alhudaydah","Alhujun","Alhuwaya","Aljahra","Aljohar","Aljubail","Alkawd","Alkhalas","Alkhawaneej","Alkhen","Alkhhafah","Alkhobar","Alkhuznah","Alkiranah","Allisafah","Allith","Almadeed","Almardamah","Almarwah","Almasnaah","Almejammah","Almojermah","Almshaykh","Almurjan","Almuwayh","Almuzaylif","Alnaheem","Alnashifah","Alqadeimah","Alqah","Alqahma","Alqalh","Alqouz","Alquaba","Alqunfudhah","Alqurayyat","Alradha","Alraqmiah","Alsadyah","Alsafa","Alshagab","Alshoqiq","Alshuqaiq","Alsilaa","Althafeer","Alwakrah","Alwasqah","Amaq","Amran","Annaseem","Aqbiyah","Arafat","Arar","Ardah","Arrawdah","Asfan","Ashayrah","Ashshahaniyah","Askar","Assaffaniyah","Ayaar","Aziziyah","Baesh","Bahrah","Baish","Balhaf","Banizayd","Baqaa","Baqal","Bidiyah","Bisha","Biyatah","Buqhayq","Burayda","Dafiyat","Damad","Dammam","Dariyah","Daynah","Dhafar","Dhahran","Dhalkut","Dhamar","Dhubab","Dhurma","Dibab","Dirab","Doha","Dukhan","Duwaibah","Enaker","Fadhla","Fahaheel","Fanateer","Farasan","Fardah","Fujairah","Ghalilah","Ghar","Ghizlan","Ghomgyah","Ghran","Hababah","Habil","Hadiyah","Haffah","Hajanbah","Hajrah","Halban","Haqqaq","Haradh","Hasar","Hathah","Hawarwar","Hawaya","Hawiyah","Hebaa","Hefar","Hijal","Husnah","Huwailat","Huwaitah","Irqah","Isharah","Ithrah","Jamalah","Jarab","Jareef","Jarwal","Jash","Jazan","Jeddah","Jiblah","Jihanah","Jilah","Jizan","Joha","Joraibah","Juban","Jubbah","Juddah","Jumeirah","Kamaran","Keyad","Khab","Khabtsaeed","Khaiybar","Khasab","Khathirah","Khawarah","Khulais","Khulays","Klayah","Kumzar","Limah","Linah","Mabar","Madrak","Mahab","Mahalah","Makhtar","Makshosh","Manfuhah","Manifah","Manshabah","Mareah","Masdar","Mashwar","Masirah","Maskar","Masliyah","Mastabah","Maysaan","Mazhar","Mdina","Meeqat","Mirbah","Mirbat","Mokhtara","Muharraq","Muladdah","Musandam","Musaykah","Muscat","Mushayrif","Musrah","Mussafah","Mutrah","Nafhan","Nahdah","Nahwa","Najran","Nakhab","Nizwa","Oman","Qadah","Qalhat","Qamrah","Qasam","Qatabah","Qawah","Qosmah","Qurain","Quraydah","Quriyat","Qurwa","Rabigh","Radaa","Rafha","Rahlah","Rakamah","Rasheedah","Rasmadrakah","Risabah","Rustaq","Ryadh","Saabah","Saabar","Sabtaljarah","Sabya","Sadad","Sadah","Safinah","Saham","Sahlat","Saihat","Salalah","Salmalzwaher","Salmiya","Sanaa","Sanaban","Sayaa","Sayyan","Shabayah","Shabwah","Shafa","Shalim","Shaqra","Sharjah","Sharkat","Sharurah","Shatifiyah","Shibam","Shidah","Shifiyah","Shihar","Shoqra","Shoqsan","Shuwaq","Sibah","Sihmah","Sinaw","Sirwah","Sohar","Suhailah","Sulaibiya","Sunbah","Tabuk","Taif","Taqah","Tarif","Tharban","Thumrait","Thuqbah","Thuwal","Tubarjal","Turaif","Turbah","Tuwaiq","Ubar","Umaljerem","Urayarah","Urwah","Wabrah","Warbah","Yabreen","Yadamah","Yafur","Yarim","Yemen","Yiyallah","Zabid","Zahwah","Zallaq","Zinjibar","Zulumah"],
|
||||
["Aaluik","Aappilattoq","Aasiaat","Agdleruussakasit","Aggas","Akia","Akilia","Akuliaruseq","Akuliarutsip","Akunnaaq","Agissat","Agssaussat","Alluitsup","Alluttoq","Aluit","Aluk","Ammassalik","Amarortalik","Amitsorsuaq","Anarusuk","Angisorsuaq","Anguniartarfik","Annertussoq","Annikitsoq","Anoraliuirsoq","Appat","Apparsuit","Apusiaajik","Arsivik","Arsuk","Ataa","Atammik","Ateqanngitsorsuaq","Atilissuaq","Attu","Aukarnersuaq","Augpalugtoq, Aumat","Auvilikavsak","Auvilkikavsaup","Avadtlek","Avallersuaq","Bjornesk","Blabaerdalen","Blomsterdalen","Brattalhid","Bredebrae","Brededal","Claushavn","Edderfulegoer","Egger","Eqalugalinnguit","Eqalugarssuit","Eqaluit","Eqqua","Etah","Graah","Hakluyt","Haredalen","Hareoen","Hundeo","Igdlorssuit","Igaliku","Igdlugdlip","Igdluluarssuk","Iginniafik","Ikamiuk","Ikamiut","Ikarissat","Ikateq","Ikeq","Ikerasak","Ikerasaarsuk","Ikermiut","Ikermoissuaq","Ikertivaq","Ikorfarssuit","Ikorfat","Ilimanaq","Illorsuit","Iluileq","Iluiteq","Ilulissat","Illunnguit","Imaarsivik","Imartunarssuk","Immikkoortukajik","Innaarsuit","Ingjald","Inneruulalik","Inussullissuaq","Iqek","Ikerasakassak","Iperaq","Ippik","Isortok","Isungartussoq","Itileq","Itivdleq","Itissaalik","Ittit","Ittoqqortoormiit","Ivingmiut","Ivittuut","Kanajoorartuut","Kangaamiut","Kangaarsuk","Kangaatsiaq","Kangeq","Kangerluk","Kangerlussuaq","Kanglinnguit","Kapisillit","Karrat","Kekertamiut","Kiatak","Kiatassuaq","Kiataussaq","Kigatak","Kigdlussat","Kinaussak","Kingittorsuaq","Kitak","Kitsissuarsuit","Kitsissut","Klenczner","Kook","Kraulshavn","Kujalleq","Kullorsuaq","Kulusuk","Kuurmiit","Kuusuaq","Laksedalen","Maniitsoq","Marrakajik","Mattaangassut","Mernoq","Mittivakkat","Moriusaq","Myggbukta","Naajaat","Nako","Nangissat","Nanortalik","Nanuuseq","Nappassoq","Narsarmijt","Narssaq","Narsarsuaq","Narssarssuk","Nasaussaq","Nasiffik","Natsiarsiorfik","Naujanguit","Niaqornaarsuk","Niaqornat","Nordfjordspasset","Nugatsiaq","Nuluuk","Nunaa","Nunarssit","Nunarsuaq","Nunataaq","Nunatakavsaup","Nutaarmiut","Nuugaatsiaq","Nuuk","Nuukullak","Nuuluk","Nuussuaq","Olonkinbyen","Oqaatsut","Oqaitsúnguit","Oqonermiut","Oodaaq","Paagussat","Palungataq","Pamialluk","Paamiut","Paatuut","Patuersoq","Perserajoq","Paornivik","Pituffik","Puugutaa","Puulkuip","Qaanaq","Qaarsorsuaq","Qaarsorsuatsiaq","Qaasuitsup","Qaersut","Qajartalik","Qallunaat","Qaneq","Qaqaarissorsuaq","Qaqit","Qaqortok","Qasigiannguit","Qasse","Qassimiut","Qeertartivaq","Qeertartivatsiaq","Qeqertaq","Qeqertarssdaq","Qeqertarsuaq","Qeqertasussuk","Qeqertarsuatsiaat","Qeqertat","Qeqqata","Qernertoq","Qernertunnguit","Qianarreq","Qilalugkiarfik","Qingagssat","Qingaq","Qoornuup","Qorlortorsuaq","Qullikorsuit","Qunnerit","Qutdleq","Ravnedalen","Ritenbenk","Rypedalen","Sarfannguit","Saarlia","Saarloq","Saatoq","Saatorsuaq","Saatup","Saattut","Sadeloe","Salleq","Salliaruseq","Sammeqqat","Sammisoq","Sanningassoq","Saqqaq","Saqqarlersuaq","Saqqarliit","Sarqaq","Sattiaatteq","Savissivik","Serfanguaq","Sermersooq","Sermersut","Sermilik","Sermiligaaq","Sermitsiaq","Simitakaja","Simiutaq","Singamaq","Siorapaluk","Sisimiut","Sisuarsuit","Skal","Skarvefjeld","Skjoldungen","Storoen","Sullorsuaq","Suunikajik","Sverdrup","Taartoq","Takiseeq","Talerua","Tarqo","Tasirliaq","Tasiusak","Tiilerilaaq","Timilersua","Timmiarmiut","Tingmjarmiut","Traill","Tukingassoq","Tuttorqortooq","Tuujuk","Tuttulissuup","Tussaaq","Uigordlit","Uigorlersuaq","Uilortussoq","Uiivaq","Ujuaakajiip","Ukkusissat","Umanat","Upernavik","Upernattivik","Upepnagssivik","Upernivik","Uttorsiutit","Uumannaq","Uummannaarsuk","Uunartoq","Uvkusigssat","Ymer"],
|
||||
["Abadio","Abaltzisketa","Abanto Zierbena","Aduna","Agurain","Aia","Aiara","Aizarnazabal","Ajangiz","Albiztur","Alegia","Alkiza","Alonsotegi","Altzaga","Altzo","Amezketa","Amorebieta","Amoroto","Amurrio","Andoain","Anoeta","Antzuola","Arakaldo","Arama","Aramaio","Arantzazu","Arbatzegi ","Areatza","Aretxabaleta","Arraia","Arrankudiaga","Arrasate","Arratzu","Arratzua","Arrieta","Arrigorriaga","Artea","Artzentales","Artziniega","Asparrena","Asteasu","Astigarraga","Ataun","Atxondo","Aulesti","Azkoitia","Azpeitia","Bakio","Baliarrain","Balmaseda","Barakaldo","Barrika","Barrundia","Basauri","Bastida","Beasain","Bedia","Beizama","Belauntza","Berango","Berantevilla","Berastegi","Bergara","Bermeo","Bernedo","Berriatua","Berriz","Berrobi","Bidania","Bilar","Bilbao","Burgelu","Busturia","Deba","Derio","Dima","Donemiliaga","Donostia","Dulantzi","Durango","Ea","Eibar","Elantxobe","Elduain","Elgeta","Elgoibar","Elorrio","Erandio","Ere–o","Ermua","Errenteria","Errezil","Erribera Beitia","Erriberagoitia","Errigoiti","Eskoriatza","Eskuernaga","Etxebarri","Etxebarria","Ezkio","Fika","Forua","Fruiz","Gabiria","Gaintza","Galdakao","Galdames","Gamiz","Garai","Gasteiz","Gatika","Gatzaga","Gaubea","Gauna","Gautegiz Arteaga","Gaztelu","Gernika","Gerrikaitz","Getaria","Getxo","Gizaburuaga","Goiatz","Gordexola","Gorliz","Harana","Hernani","Hernialde","Hondarribia","Ibarra","Ibarrangelu","Idiazabal","Iekora","Igorre","Ikaztegieta","Iru–a Oka","Irun","Irura","Iruraiz","Ispaster","Itsaso","Itsasondo","Iurreta","Izurtza","Jatabe","Kanpezu","Karrantza Harana","Kortezubi","Kripan","Kuartango","Lanestosa","Lantziego","Larrabetzu","Larraul","Lasarte","Laudio","Laukiz","Lazkao","Leaburu","Legazpi","Legorreta","Legutio","Leintz","Leioa","Lekeitio","Lemoa","Lemoiz","Leza","Lezama","Lezo","Lizartza","Loiu","Lumo","Ma–aria","Maeztu","Mallabia","Markina","Maruri","Ma–ueta","Me–aka","Mendaro","Mendata","Mendexa","Moreda Araba","Morga","Mundaka","Mungia","Munitibar","Murueta","Muskiz","Mutiloa","Mutriku","Muxika","Nabarniz","O–ati","Oiartzun","Oion","Okondo","Olaberria","Ondarroa","Ordizia","Orendain","Orexa","Oria","Orio","Ormaiztegi","Orozko","Ortuella","Otxandio","Pasaia","Plentzia","Portugalete","Samaniego","Santurtzi","Segura","Sestao","Sondika","Sopela","Sopuerta","Soraluze","Sukarrieta","Tolosa","Trapagaran","Turtzioz","Ubarrundia","Ubide","Ugao","Urdua","Urduliz","Urizaharra","Urkabustaiz","Urnieta","Urretxu","Usurbil","Xemein","Zaia","Zaldibar","Zaldibia","Zalduondo","Zambrana","Zamudio","Zaratamo","Zarautz","Zeanuri","Zeberio","Zegama","Zerain","Zestoa","Zierbena","Zigoitia","Ziortza","Zizurkil","Zuia","Zumaia","Zumarraga"],
|
||||
["Abadogo","Abafon","Abdu","Acharu","Adaba","Adealesu","Adeto","Adyongo","Afaga","Afamju","Afuje","Agbelagba","Agigbigi","Agogoke","Ahute","Aiyelaboro","Ajebe","Ajola","Akarekwu","Akessan","Akunuba","Alawode","Alkaijji","Amangam","Amaoji","Amgbaye","Amtasa","Amunigun","Anase","Aniho","Animahun","Antul","Anyoko","Apekaa","Arapagi","Asamagidi","Asande","Ataibang","Awgbagba","Awhum","Awodu","Babanana","Babateduwa","Bagu","Bakura","Bandakwai","Bangdi","Barbo","Barkeje","Basa","Basabra","Basansagawa","Bieleshin","Bilikani","Birnindodo","Braidu","Bulakawa","Buriburi","Burisidna","Busum","Bwoi","Cainnan","Chakum","Charati","Chondugh","Dabibikiri","Dagwarga","Dallok","Danalili","Dandala","Darpi","Dhayaki","Dokatofa","Doma","Dozere","Duci","Dugan","Ebelibri","Efem","Efoi","Egudu","Egundugbo","Ekoku","Ekpe","Ekwere","Erhua","Eteu","Etikagbene","Ewhoeviri","Ewhotie","Ezemaowa","Fatima","Gadege","Galakura","Galea","Gamai","Gamen","Ganjin","Gantetudu","Garangamawa","Garema","Gargar","Gari","Garinbode","Garkuwa","Garu Kime","Gazabu","Gbure","Gerti","Gidan","Giringwe","Gitabaremu","Giyagiri","Giyawa","Gmawa","Golakochi","Golumba","Guchi","Gudugu","Gunji","Gusa","Gwambula","Gwamgwam","Gwodoti","Hayinlere","Hayinmaialewa","Hirishi","Hombo","Ibefum","Iberekodo","Ibodeipa","Icharge","Ideoro","Idofin","Idofinoka","Idya","Iganmeji","Igbetar","Igbogo","Ijoko","Ijuwa","Ikawga","Ikekogbe","Ikhin","Ikoro","Ikotefe","Ikotokpora","Ikpakidout","Ikpeoniong","Ilofa","Imuogo","Inyeneke","Iorsugh","Ipawo","Ipinlerere","Isicha","Itakpa","Itoki","Iyedeame","Jameri","Jangi","Jara","Jare","Jataudakum","Jaurogomki","Jepel","Jibam","Jirgu","Jirkange","Kafinmalama","Kamkem","Katab","Katanga","Katinda","Katirije","Kaurakimba","Keffinshanu","Kellumiri","Kiagbodor","Kibiare","Kingking","Kirbutu","Kita","Kogbo","Kogogo","Kopje","Koriga","Koroko","Korokorosei","Kotoku","Kuata","Kujum","Kukau","Kunboon","Kuonubogbene","Kurawe","Kushinahu","Kwaramakeri","Ladimeji","Lafiaro","Lahaga","Laindebajanle","Laindegoro","Lajere","Lakati","Ligeri","Litenswa","Lokobimagaji","Lusabe","Maba","Madarzai","Magoi","Maialewa","Maianita","Maijuja","Mairakuni","Maleh","Malikansaa","Mallamkola","Mallammaduri","Marmara","Masagu","Masoma","Mata","Matankali","Mbalare","Megoyo","Meku","Miama","Mige","Mkporagwu","Modi","Molafa","Mshi","Msugh","Muduvu","Murnachehu","Namnai","Nanumawa","Nasudu","Ndagawo","Ndamanma","Ndiebeleagu","Ndiwulunbe","Ndonutim","Ngaruwa","Ngbande","Nguengu","Nto Ekpe","Nubudi","Nyajo","Nyido","Nyior","Obafor","Obazuwa","Odajie","Odiama","Ofunatam","Ogali","Ogan","Ogbaga","Ogbahu","Ogultu","Ogunbunmi","Ogunmakin","Ojaota","Ojirami","Ojopode","Okehin","Olugunna","Omotunde","Onipede","Onisopi","Onma","Orhere","Orya","Oshotan","Otukwang","Otunade","Pepegbene","Poros","Rafin","Rampa","Rimi","Rinjim","Robertkiri","Rugan","Rumbukawa","Sabiu","Sabon","Sabongari","Sai","Salmatappare","Sangabama","Sarabe","Seboregetore","Seibiri","Sendowa","Shafar","Shagwa","Shata","Shefunda","Shengu","Sokoron","Sunnayu","Taberlma","Tafoki","Takula","Talontan","Taraku","Tarhemba","Tayu","Ter","Timtim","Timyam","Tindirke","Tirkalou","Tokunbo","Tonga","Torlwam","Tseakaadza","Tseanongo","Tseavungu","Tsebeeve","Tsekov","Tsepaegh","Tuba","Tumbo","Tungalombo","Tungamasu","Tunganrati","Tunganyakwe","Tungenzuri","Ubimimi","Uhkirhi","Umoru","Umuabai","Umuaja","Umuajuju","Umuimo","Umuojala","Unchida","Ungua","Unguwar","Unongo","Usha","Ute","Utongbo","Vembera","Vorokotok","Wachin","Walebaga","Wurawura","Wuro","Yanbashi","Yanmedi","Yenaka","Yoku","Zamangera","Zarunkwari","Zilumo","Zulika"],
|
||||
["Aberaman","Aberangell","Aberarth","Aberavon","Aberbanc","Aberbargoed","Aberbeeg","Abercanaid","Abercarn","Abercastle","Abercegir","Abercraf","Abercregan","Abercych","Abercynon","Aberdare","Aberdaron","Aberdaugleddau","Aberdeen","Aberdulais","Aberdyfi","Aberedw","Abereiddy","Abererch","Abereron","Aberfan","Aberffraw","Aberffrwd","Abergavenny","Abergele","Aberglasslyn","Abergorlech","Abergwaun","Abergwesyn","Abergwili","Abergwynfi","Abergwyngregyn","Abergynolwyn","Aberhafesp","Aberhonddu","Aberkenfig","Aberllefenni","Abermain","Abermaw","Abermorddu","Abermule","Abernant","Aberpennar","Aberporth","Aberriw","Abersoch","Abersychan","Abertawe","Aberteifi","Aberthin","Abertillery","Abertridwr","Aberystwyth","Achininver","Afonhafren","Alisaha","Antinbhearmor","Ardenna","Attacon","Beira","Bhrura","Boioduro","Bona","Boudobriga","Bravon","Brigant","Briganta","Briva","Cambodunum","Cambra","Caracta","Catumagos","Centobriga","Ceredigion","Chalain","Dinn","Diwa","Dubingen","Duro","Ebora","Ebruac","Eburodunum","Eccles","Eighe","Eireann","Ferkunos","Genua","Ghrainnse","Inbhear","Inbhir","Inbhirair","Innerleithen","Innerleven","Innerwick","Inver","Inveraldie","Inverallan","Inveralmond","Inveramsay","Inveran","Inveraray","Inverarnan","Inverbervie","Inverclyde","Inverell","Inveresk","Inverfarigaig","Invergarry","Invergordon","Invergowrie","Inverhaddon","Inverkeilor","Inverkeithing","Inverkeithney","Inverkip","Inverleigh","Inverleith","Inverloch","Inverlochlarig","Inverlochy","Invermay","Invermoriston","Inverness","Inveroran","Invershin","Inversnaid","Invertrossachs","Inverugie","Inveruglas","Inverurie","Kilninver","Kirkcaldy","Kirkintilloch","Krake","Latense","Leming","Lindomagos","Llanaber","Lochinver","Lugduno","Magoduro","Monmouthshire","Narann","Novioduno","Nowijonago","Octoduron","Penning","Pheofharain","Ricomago","Rossinver","Salodurum","Seguia","Sentica","Theorsa","Uige","Vitodurum","Windobona"],
|
||||
["Adab","Akkad","Akshak","Amnanum","Arbid","Arpachiyah","Arrapha","Assur","Babilim","Badtibira","Balawat","Barsip","Borsippa","Carchemish","Chagar Bazar","Chuera","Ctesiphon ","Der","Dilbat","Diniktum","Doura","Durkurigalzu","Ekallatum","Emar","Erbil","Eridu","Eshnunn","Fakhariya ","Gawra","Girsu","Hadatu","Hamoukar","Haradum","Harran","Hatra","Idu","Irisagrig","Isin","Jemdet","Kahat","Kartukulti","Khaiber","Kish ","Kisurra","Kuara","Kutha","Lagash","Larsa ","Leilan","Marad","Mardaman","Mari","Mashkan","Mumbaqat ","Nabada","Nagar","Nerebtum","Nimrud","Nineveh","Nippur","Nuzi","Qalatjarmo","Qatara","Rawda","Seleucia","Shaduppum","Shanidar","Sharrukin","Shemshara","Shibaniba","Shuruppak","Sippar","Tarbisu","Tellagrab","Tellessawwan","Tellessweyhat","Tellhassuna","Telltaya","Telul","Terqa","Thalathat","Tutub","Ubaid ","Umma","Ur","Urfa","Urkesh","Uruk","Urum","Zabalam","Zenobia"],
|
||||
["Abali","Abrisham","Absard","Abuzeydabad","Afus","Alavicheh","Alikosh","Amol","Anarak","Anbar","Andisheh","Anshan","Aran","Ardabil","Arderica","Ardestan","Arjomand","Asgaran","Asgharabad","Ashian","Awan","Babajan","Badrud","Bafran","Baghestan","Baghshad","Bahadoran","Baharan Shahr","Baharestan","Bakun","Bam","Baqershahr","Barzok","Bastam","Behistun","Bitistar","Bumahen","Bushehr","Chadegan","Chahardangeh","Chamgardan","Chermahin","Choghabonut","Chugan","Damaneh","Damavand","Darabgard","Daran","Dastgerd","Dehaq","Dehaqan","Dezful","Dizicheh","Dorcheh","Dowlatabad","Duruntash","Ecbatana","Eslamshahr","Estakhr","Ezhiyeh","Falavarjan","Farrokhi","Fasham","Ferdowsieh","Fereydunshahr","Ferunabad","Firuzkuh","Fuladshahr","Ganjdareh","Ganzak","Gaz","Geoy","Godin","Goldasht","Golestan","Golpayegan","Golshahr","Golshan","Gorgab","Guged","Habibabad","Hafshejan","Hajjifiruz","Hana","Harand","Hasanabad","Hasanlu","Hashtgerd","Hecatompylos","Hormirzad","Imanshahr","Isfahan","Jandaq","Javadabad","Jiroft","Jowsheqan ","Jowzdan","Kabnak","Kahriz Sang","Kahrizak","Kangavar","Karaj","Karkevand","Kashan","Kelishad","Kermanshah","Khaledabad","Khansar","Khorramabad","Khur","Khvorzuq","Kilan","Komeh","Komeshcheh","Konar","Kuhpayeh","Kul","Kushk","Lavasan","Laybid","Liyan","Lyan","Mahabad","Mahallat","Majlesi","Malard","Manzariyeh","Marlik","Meshkat","Meymeh","Miandasht","Mish","Mobarakeh","Nahavand","Nain","Najafabad","Naqshe","Narezzash","Nasimshahr","Nasirshahr","Nasrabad","Natanz","Neyasar","Nikabad","Nimvar","Nushabad","Pakdasht","Parand","Pardis","Parsa","Pasargadai","Patigrabana","Pir Bakran","Pishva","Qahderijan","Qahjaverestan","Qamsar","Qarchak","Qods","Rabat","Ray-shahr","Rezvanshahr","Rhages","Robat Karim","Rozveh","Rudehen","Sabashahr","Safadasht","Sagzi","Salehieh","Sandal","Sarvestan","Sedeh","Sefidshahr","Semirom","Semnan","Shadpurabad","Shah","Shahdad","Shahedshahr","Shahin","Shahpour","Shahr","Shahreza","Shahriar","Sharifabad","Shemshak","Shiraz","Shushan","Shushtar","Sialk","Sin","Sukhteh","Tabas","Tabriz","Takhte","Talkhuncheh","Talli","Tarq","Temukan","Tepe","Tiran","Tudeshk","Tureng","Urmia","Vahidieh","Vahrkana","Vanak","Varamin","Varnamkhast","Varzaneh","Vazvan","Yahya","Yarim","Yasuj","Zarrin Shahr","Zavareh","Zayandeh","Zazeran","Ziar","Zibashahr","Zranka"],
|
||||
["Aapueo","Ahoa","Ahuakaio","Ahuakamalii","Ahuakeio","Ahupau","Aki","Alaakua","Alae","Alaeloa","Alaenui","Alamihi","Aleamai","Alena","Alio","Aupokopoko","Auwahi","Hahakea","Haiku","Halakaa","Halehaku","Halehana","Halemano","Haleu","Haliimaile","Hamakuapoko","Hamoa","Hanakaoo","Hanaulu","Hanawana","Hanehoi","Haneoo","Haou","Hikiaupea","Hoalua","Hokuula","Honohina","Honokahua","Honokala","Honokalani","Honokeana","Honokohau","Honokowai","Honolua","Honolulu","Honolulunui","Honomaele","Honomanu","Hononana","Honopou","Hoolawa","Hopenui","Hualele","Huelo","Hulaia","Ihuula","Ilikahi","Interisland","Kaalaea","Kaalelehinale","Kaapahu","Kaehoeho","Kaeleku","Kaeo","Kahakuloa","Kahalawe","Kahalawe","Kahalehili","Kahana","Kahilo","Kahuai","Kaiaula","Kailihiakoko","Kailua","Kainehe","Kakalahale","Kakanoni","Kakio","Kakiweka","Kalena","Kalenanui","Kaleoaihe","Kalepa","Kaliae","Kalialinui","Kalihi","Kalihi","Kalihi","Kalimaohe","Kaloi","Kamani","Kamaole","Kamehame","Kanahena","Kanaio","Kaniaula","Kaonoulu","Kaopa","Kapaloa","Kapaula","Kapewakua","Kapohue","Kapuaikini","Kapunakea","Kapuuomahuka","Kauau","Kauaula","Kaukuhalahala","Kaulalo","Kaulanamoa","Kauluohana","Kaumahalua","Kaumakani","Kaumanu","Kaunauhane","Kaunuahane","Kaupakulua","Kawaipapa","Kawaloa","Kawaloa","Kawalua","Kawela","Keaa","Keaalii","Keaaula","Keahua","Keahuapono","Keakuapauaela","Kealahou","Keanae","Keauhou","Kekuapawela","Kelawea","Keokea","Keopuka","Kepio","Kihapuhala","Kikoo","Kilolani","Kipapa","Koakupuna","Koali","Koananai","Koheo","Kolea","Kolokolo","Kooka","Kopili","Kou","Kualapa","Kuhiwa","Kuholilea","Kuhua","Kuia","Kuiaha","Kuikui","Kukoae","Kukohia","Kukuiaeo","Kukuioolu","Kukuipuka","Kukuiula","Kulahuhu","Kumunui","Lapakea","Lapalapaiki","Lapueo","Launiupoko","Loiloa","Lole","Lualailua","Maalo","Mahinahina","Mahulua","Maiana","Mailepai","Makaakini","Makaalae","Makaehu","Makaiwa","Makaliua","Makapipi","Makapuu","Makawao","Makila","Mala","Maluaka","Mamalu","Manawaiapiki","Manawainui","Maulili","Mehamenui","Miana","Mikimiki","Moalii","Moanui","Mohopili","Mohopilo","Mokae","Mokuia","Mokupapa","Mooiki","Mooloa","Moomuku","Muolea","Nahuakamalii","Nailiilipoko","Nakaaha","Nakalepo","Nakaohu","Nakapehu","Nakula","Napili","Niniau","Niumalu","Nuu","Ohia","Oloewa","Olowalu","Omaopio","Onau","Onouli","Opaeula","Opana","Opikoula","Paakea","Paeahu","Paehala","Paeohi","Pahoa","Paia","Pakakia","Pakala","Palauea","Palemo","Panaewa","Paniau","Papaaea","Papaanui","Papaauhau","Papahawahawa","Papaka","Papauluana","Pauku","Paunau","Pauwalu","Pauwela","Peahi","Piapia","Pohakanele","Pohoula","Polaiki","Polanui","Polapola","Polua","Poopoo","Popoiwi","Popoloa","Poponui","Poupouwela","Puaa","Puaaluu","Puahoowali","Puakea","Puako","Pualaea","Puehuehu","Puekahi","Pueokauiki","Pukaauhuhu","Pukalani","Pukuilua","Pulehu","Pulehuiki","Pulehunui","Punaluu","Puolua","Puou","Puuhaehae","Puuhaoa","Puuiki","Puuki","Puukohola","Puulani","Puumaneoneo","Puunau","Puunoa","Puuomaiai","Puuomaile","Uaoa","Uhao","Ukumehame","Ulaino","Ulumalu","Unknown","Various","Wahikuli","Waiahole","Waiakoa","Waianae","Waianu","Waiawa","Waiehu","Waieli","Waihee","Waikapu","Wailamoa","Wailaulau","Wailua","Wailuku","Wainee","Waiohole","Waiohonu","Waiohue","Waiohuli","Waiokama","Waiokila","Waiopai","Waiopua","Waipao","Waipio","Waipioiki","Waipionui","Waipouli","Wakiu","Wananalua"],
|
||||
["Adityapatna","Adyar","Afzalpur","Aland","Alnavar","Alur","Ambikanagara","Anekal","Ankola","Annigeri","Arkalgud","Arsikere","Athni","Aurad","Badami","Bagalkot","Bagepalli","Bail","Bajpe","Bangalore","Bangarapet","Bankapura","Bannur","Bantval","Basavakalyan","Basavana","Belgaum","Beltangadi","Belur","Bhadravati","Bhalki","Bhatkal","Bhimarayanagudi","Bidar","Bijapur","Bilgi","Birur","Bommasandra","Byadgi","Challakere","Chamarajanagar","Channagiri","Channapatna","Channarayapatna","Chik","Chikmagalur","Chiknayakanhalli","Chikodi","Chincholi","Chintamani","Chitapur","Chitgoppa","Chitradurga","Dandeli","Dargajogihalli","Devadurga","Devanahalli","Dod","Donimalai","Gadag","Gajendragarh","Gangawati","Gauribidanur","Gokak","Gonikoppal","Gubbi","Gudibanda","Gulbarga","Guledgudda","Gundlupet","Gurmatkal","Haliyal","Hangal","Harapanahalli","Harihar","Hassan","Hatti","Haveri","Hebbagodi","Heggadadevankote","Hirekerur","Holalkere","Hole","Homnabad","Honavar","Honnali","Hoovina","Hosakote","Hosanagara","Hosdurga","Hospet","Hubli","Hukeri","Hungund","Hunsur","Ilkal","Indi","Jagalur","Jamkhandi","Jevargi","Jog","Kadigenahalli","Kadur","Kalghatgi","Kamalapuram","Kampli","Kanakapura","Karkal","Karwar","Khanapur","Kodiyal","Kolar","Kollegal","Konnur","Koppa","Koppal","Koratagere","Kotturu","Krishnarajanagara","Krishnarajasagara","Krishnarajpet","Kudchi","Kudligi","Kudremukh","Kumta","Kundapura","Kundgol","Kunigal","Kurgunta","Kushalnagar","Kushtagi","Lakshmeshwar","Lingsugur","Londa","Maddur","Madhugiri","Madikeri","Mahalingpur","Malavalli","Mallar","Malur","Mandya","Mangalore","Manvi","Molakalmuru","Mudalgi","Mudbidri","Muddebihal","Mudgal","Mudhol","Mudigere","Mulbagal","Mulgund","Mulki","Mulur","Mundargi","Mundgod","Munirabad","Mysore","Nagamangala","Nanjangud","Narasimharajapura","Naregal","Nargund","Navalgund","Nipani","Pandavapura","Pavagada","Piriyapatna","Pudu","Puttur","Rabkavi","Raichur","Ramanagaram","Ramdurg","Ranibennur","Raybag","Robertson","Ron","Sadalgi","Sagar","Sakleshpur","Saligram","Sandur","Sankeshwar","Saundatti","Savanur","Sedam","Shahabad","Shahpur","Shaktinagar","Shiggaon","Shikarpur","Shirhatti","Shorapur","Shrirangapattana","Siddapur","Sidlaghatta","Sindgi","Sindhnur","Sira","Siralkoppa","Sirsi","Siruguppa","Somvarpet","Sorab","Sringeri","Srinivaspur","Sulya","Talikota","Tarikere","Tekkalakote","Terdal","Thumbe","Tiptur","Tirthahalli","Tirumakudal","Tumkur","Turuvekere","Udupi","Vijayapura","Wadi","Yadgir","Yelandur","Yelbarga","Yellapur","Yenagudde"],
|
||||
["Altomisayoq","Ancash","Andahuaylas","Apachekta","Apachita","Apu ","Apurimac","Arequipa","Atahuallpa","Atawalpa","Atico","Ayacucho","Ayllu","Cajamarca","Carhuac","Carhuacatac","Cashan","Caullaraju","Caxamalca","Cayesh","Chacchapunta","Chacraraju","Champara","Chanchan","Chekiacraju","Chinchey","Chontah","Chopicalqui","Chucuito","Chuito","Chullo","Chumpi","Chuncho","Chuquiapo","Churup","Cochapata","Cojup","Collota","Conococha","Copa","Corihuayrachina","Cusichaca","Despacho","Haika","Hanpiq","Hatun","Haywarisqa","Huaca","Hualcan","Huamanga","Huamashraju","Huancarhuas","Huandoy","Huantsan","Huarmihuanusca","Huascaran","Huaylas","Huayllabamba","Huichajanca","Huinayhuayna","Huinioch","Illiasca","Intipunku","Ishinca","Jahuacocha","Jirishanca","Juli","Jurau","Kakananpunta","Kamasqa","Karpay","Kausay","Khuya ","Kuelap","Llaca","Llactapata","Llanganuco","Llaqta","Llupachayoc","Machu","Mallku","Matarraju","Mikhuy","Milluacocha","Munay","Ocshapalca","Ollantaytambo","Pacamayo","Paccharaju","Pachacamac","Pachakamaq","Pachakuteq","Pachakuti","Pachamama ","Paititi","Pajaten","Palcaraju","Pampa","Panaka","Paqarina","Paqo","Parap","Paria","Patallacta","Phuyupatamarca","Pisac","Pongos","Pucahirca","Pucaranra","Puscanturpa","Putaca","Qawaq ","Qayqa","Qochamoqo","Qollana","Qorihuayrachina","Qorimoqo","Quenuaracra","Queshque","Quillcayhuanca","Quillya","Quitaracsa","Quitaraju","Qusqu","Rajucolta","Rajutakanan","Rajutuna","Ranrahirca","Ranrapalca","Raria","Rasac","Rimarima","Riobamba","Runkuracay","Rurec","Sacsa","Saiwa","Sarapo","Sayacmarca","Sinakara","TamboColorado","Tamboccocha","Taripaypacha","Taulliraju","Tawantinsuyu","Taytanchis","Tiwanaku","Tocllaraju","Tsacra","Tuco","Tullparaju","Tumbes","Ulta","Uruashraju","Vallunaraju","Vilcabamba","Wacho ","Wankawillka","Wayra","Yachay","Yahuarraju","Yanamarey","Yanesha","Yerupaja"],
|
||||
["Abim","Adjumani","Alebtong","Amolatar","Amuria","Amuru","Apac","Arua","Arusha","Babati","Baragoi","Bombo","Budaka","Bugembe","Bugiri","Buikwe","Bukedea","Bukoba","Bukomansimbi","Bukungu","Buliisa","Bundibugyo","Bungoma","Busembatya","Bushenyi","Busia","Busia","Busolwe","Butaleja","Butambala","Butere","Buwenge","Buyende","Dadaab","Dodoma","Dokolo","Eldoret","Elegu","Emali","Embu","Entebbe","Garissa","Gede","Gulu","Handeni","Hima","Hoima","Hola","Ibanda","Iganga","Iringa","Isingiro","Isiolo","Jinja","Kaabong","Kabale","Kaberamaido","Kabuyanda","Kabwohe","Kagadi","Kahama","Kajiado","Kakamega","Kakinga","Kakira","Kakiri","Kakuma","Kalangala","Kaliro","Kalisizo","Kalongo","Kalungu","Kampala","Kamuli","Kamwenge","Kanoni","Kanungu","Kapchorwa","Kapenguria","Kasese","Kasulu","Katakwi","Kayunga","Kericho","Keroka","Kiambu","Kibaale","Kibaha","Kibingo","Kiboga","Kibwezi","Kigoma","Kihiihi","Kilifi","Kira","Kiruhura","Kiryandongo","Kisii","Kisoro","Kisumu","Kitale","Kitgum","Kitui","Koboko","Korogwe","Kotido","Kumi","Kyazanga","Kyegegwa","Kyenjojo","Kyotera","Lamu","Langata","Lindi","Lodwar","Lokichoggio","Londiani","Loyangalani","Lugazi","Lukaya","Luweero","Lwakhakha","Lwengo","Lyantonde","Machakos","Mafinga","Makambako","Makindu","Malaba","Malindi","Manafwa","Mandera","Maralal","Marsabit","Masaka","Masindi","MasindiPort","Masulita","Matugga","Mayuge","Mbale","Mbarara","Mbeya","Meru","Mitooma","Mityana","Mombasa","Morogoro","Moroto","Moshi","Moyale","Moyo","Mpanda","Mpigi","Mpondwe","Mtwara","Mubende","Mukono","Mumias","Muranga","Musoma","Mutomo","Mutukula","Mwanza","Nagongera","Nairobi","Naivasha","Nakapiripirit","Nakaseke","Nakasongola","Nakuru","Namanga","Namayingo","Namutumba","Nansana","Nanyuki","Narok","Naromoru","Nebbi","Ngora","Njeru","Njombe","Nkokonjeru","Ntungamo","Nyahururu","Nyeri","Oyam","Pader","Paidha","Pakwach","Pallisa","Rakai","Ruiru","Rukungiri","Rwimi","Sanga","Sembabule","Shimoni","Shinyanga","Singida","Sironko","Songea","Soroti","Ssabagabo","Sumbawanga","Tabora","Takaungu","Tanga","Thika","Tororo","Tunduma","Vihiga","Voi","Wajir","Wakiso","Watamu","Webuye","Wobulenzi","Wote","Wundanyi","Yumbe","Zanzibar"],
|
||||
["An Khe","An Nhon","Ayun Pa","Ba Don","Ba Ria","Bac Giang","Bac Kan","Bac Lieu","Bac Ninh","Bao Loc","Ben Cat","Ben Tre","Bien Hoa","Bim Son","Binh Long","Binh Minh","Buon Ho","Buon Ma Thuot","Ca Mau","Cai Lay","Cam Pha","Cam Ranh","Can Tho","Cao Bang","Cao Lanh","Chau Doc","Chi Linh","Cua Lo","Da Lat","Da Nang","Di An","Dien Ban","Dien Bien Phu","Dong Ha","Dong Hoi","Dong Trieu","Duyen Hai","Gia Nghia","Gia Rai","Go Cong","Ha Giang","Ha Long","Ha Noi","Ha Tinh","Hai Duong","Hai Phong","Hoa Binh","Hoang Mai","Hoi An","Hong Linh","Hong Ngu","Hue","Hung Yen","Huong Thuy","Huong Tra","Kien Tuong","Kon Tum","Ky Anh","La Gi","Lai Chau","Lang Son","Lao Cai","Long Khanh","Long My","Long Xuyen","Mong Cai","Muong Lay","My Hao","My Tho","Nam Dinh","Nga Bay","Nga Nam","Nghia Lo","Nha Trang","Ninh Binh","Ninh Hoa","Phan Rang Thap Cham","Phan Thiet","Pho Yen","Phu Ly","Phu My","Phu Tho","Phuoc Long","Pleiku","Quang Ngai","Quang Tri","Quang Yen","Quy Nhon","Rach Gia","Sa Dec","Sam Son","Soc Trang","Son La","Son Tay","Song Cau","Song Cong","Tam Diep","Tam Ky","Tan An","Tan Chau","Tan Uyen","Tay Ninh","Thai Binh","Thai Hoa","Thai Nguyen","Thanh Hoa","Thu Dau Mot","Thuan An","Tra Vinh","Tu Son","Tuy Hoa","Tuyen Quang","Uong Bi","Vi Thanh","Viet Tri","Vinh","Vinh Chau","Vinh Long","Vinh Yen","Vung Tau","Yen Bai"],
|
||||
["Chaiwan", "Chekham", "Cheungshawan", "Chingchung", "Chinghoi", "Chingsen", "Chingshing", "Chiunam", "Chiuon", "Chiuyeung", "Chiyuen", "Choihung", "Chuehoi", "Chuiman", "Chungfa", "Chungfu", "Chungsan", "Chunguktsuen", "Dakhing", "Daopo", "Daumun", "Dingwu", "Dinpak", "Donggun", "Dongyuen", "Duenchau", "Fachau", "Fado", "Fanling", "Fatgong", "Fatshan", "Fotan", "Fuktien", "Fumun", "Funggong", "Funghoi", "Fungshun", "Fungtei", "Gamtin", "Gochau", "Goming", "Gonghoi", "Gongshing", "Goyiu", "Hanghau", "Hangmei", "Hashan", "Hengfachuen", "Hengon", "Heungchau", "Heunggong", "Heungkiu", "Hingning", "Hohfuktong", "Hoichue", "Hoifung", "Hoiping", "Hokong", "Hokshan", "Homantin", "Hotin", "Hoyuen", "Hunghom", "Hungshuikiu", "Jiuling", "Kamping", "Kamsheung", "Kamwan", "Kaulongtong", "Keilun", "Kinon", "Kinsang", "Kityeung", "Kongmun", "Kukgong", "Kwaifong", "Kwaihing", "Kwongchau", "Kwongling", "Kwongming", "Kwuntong", "Laichikok", "Laiking", "Laiwan", "Lamtei", "Lamtin", "Leitung", "Leungking", "Limkong", "Linchau", "Linnam", "Linping", "Linshan", "Loding", "Lokcheong", "Lokfu", "Lokmachau", "Longchuen", "Longgong", "Longmun", "Longping", "Longwa", "Longwu", "Lowu", "Luichau", "Lukfung", "Lukho", "Lungmun", "Macheung", "Maliushui", "Maonshan", "Mauming", "Maunam", "Meifoo", "Mingkum", "Mogong", "Mongkok", "Muichau", "Muigong", "Muiyuen", "Naiwai", "Namcheong", "Namhoi", "Namhong", "Namo", "Namsha", "Namshan", "Nganwai", "Ngchuen", "Ngoumun", "Ngwa", "Nngautaukok", "Onting", "Pakwun", "Paotoishan", "Pingshan", "Pingyuen", "Poklo", "Polam", "Pongon", "Poning", "Potau", "Puito", "Punyue", "Saiwanho", "Saiyingpun", "Samshing", "Samshui", "Samtsen", "Samyuenlei", "Sanfung", "Sanhing", "Sanhui", "Sanwai", "Sanwui", "Seiwui", "Shamshuipo", "Shanmei", "Shantau", "Shatin", "Shatinwai", "Shaukeiwan", "Shauking", "Shekkipmei", "Shekmun", "Shekpai", "Sheungshui", "Shingkui", "Shiuhing", "Shundak", "Shunyi", "Shupinwai", "Simshing", "Siuhei", "Siuhong", "Siukwan", "Siulun", "Suikai", "Taihing", "Taikoo", "Taipo", "Taishuihang", "Taiwai", "Taiwo", "Taiwohau", "Tinhau", "Tinho", "Tinking", "Tinshuiwai", "Tiukengleng", "Toishan", "Tongfong", "Tonglowan", "Tsakyoochung", "Tsamgong", "Tsangshing", "Tseungkwano", "Tsihing", "Tsimshatsui", "Tsinggong", "Tsingshantsuen", "Tsingwun", "Tsingyi", "Tsingyuen", "Tsiuchau", "Tsuenshekshan", "Tsuenwan", "Tuenmun", "Tungchung", "Waichap", "Waichau", "Waidong", "Wailoi", "Waishing", "Waiyeung", "Wanchai", "Wanfau", "Wanon", "Wanshing", "Wingon", "Wongchukhang", "Wongpo", "Wongtaisin", "Woping", "Wukaisha", "Yano", "Yaumatei", "Yauoi", "Yautong", "Yenfa", "Yeungchun", "Yeungdong", "Yeunggong", "Yeungsai", "Yeungshan", "Yimtin", "Yingdak", "Yiuping", "Yongshing", "Yongyuen", "Yuenlong", "Yuenshing", "Yuetsau", "Yuknam", "Yunping", "Yuyuen"],
|
||||
["Adaatsag", "Airag", "Alag Erdene", "Altai", "Altanshiree", "Altantsogts", "Arbulag", "Baatsagaan", "Batnorov", "Batshireet", "Battsengel", "Bayan Adarga", "Bayan Agt", "Bayanbulag", "Bayandalai", "Bayandun", "Bayangovi", "Bayanjargalan", "Bayankhongor", "Bayankhutag", "Bayanlig", "Bayanmonkh", "Bayannuur", "Bayan Ondor", "Bayan Ovoo", "Bayantal", "Bayantsagaan", "Bayantumen", "Bayan Uul", "Bayanzurkh", "Berkh", "Biger", "Binder", "Bogd", "Bombogor", "Bor Ondor", "Bugat", "Bulgan", "Buregkhangai", "Burentogtokh", "Buutsagaan", "Buyant", "Chandmani", "Chandmani Ondor", "Choibalsan", "Chuluunkhoroot", "Chuluut", "Dadal", "Dalanjargalan", "Dalanzadgad", "Darkhan", "Darvi", "Dashbalbar", "Dashinchilen", "Delger", "Delgerekh", "Delgerkhaan", "Delgerkhangai", "Delgertsogt", "Deluun", "Deren", "Dorgon", "Duut", "Erdene", "Erdenebulgan", "Erdeneburen", "Erdenedalai", "Erdenemandal", "Erdenetsogt", "Galshar", "Galt", "Galuut", "Govi Ugtaal", "Gurvan", "Gurvanbulag", "Gurvansaikhan", "Gurvanzagal", "Ikhkhet", "Ikh Tamir", "Ikh Uul", "Jargalan", "Jargalant", "Jargaltkhaan", "Jinst", "Khairkhan", "Khalhgol", "Khaliun", "Khanbogd", "Khangai", "Khangal", "Khankh", "Khankhongor", "Khashaat", "Khatanbulag", "Khatgal", "Kherlen", "Khishig Ondor", "Khokh", "Kholonbuir", "Khongor", "Khotont", "Khovd", "Khovsgol", "Khuld", "Khureemaral", "Khurmen", "Khutag Ondor", "Luus", "Mandakh", "Mandal Ovoo", "Mankhan", "Manlai", "Matad", "Mogod", "Monkhkhairkhan", "Moron", "Most", "Myangad", "Nogoonnuur", "Nomgon", "Norovlin", "Noyon", "Ogii", "Olgii", "Olziit", "Omnodelger", "Ondorkhaan", "Ondorshil", "Ondor Ulaan", "Orgon", "Orkhon", "Rashaant", "Renchinlkhumbe", "Sagsai", "Saikhan", "Saikhandulaan", "Saikhan Ovoo", "Sainshand", "Saintsagaan", "Selenge", "Sergelen", "Sevrei", "Sharga", "Sharyngol", "Shine Ider", "Shinejinst", "Shiveegovi", "Sumber", "Taishir", "Tarialan", "Tariat", "Teshig", "Togrog", "Tolbo", "Tomorbulag", "Tonkhil", "Tosontsengel", "Tsagaandelger", "Tsagaannuur", "Tsagaan Ovoo", "Tsagaan Uur", "Tsakhir", "Tseel", "Tsengel", "Tsenkher", "Tsenkhermandal", "Tsetseg", "Tsetserleg", "Tsogt", "Tsogt Ovoo", "Tsogttsetsii", "Tunel", "Tuvshruulekh", "Ulaanbadrakh", "Ulaankhus", "Ulaan Uul", "Uyench", "Yesonbulag", "Zag", "Zamyn Uud", "Zereg"]
|
||||
];
|
||||
}
|
||||
|
||||
return {getBase, getCulture, getCultureShort, getState, updateChain, updateChains, getNameBase, getNameBases, getMapName};
|
||||
})));
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
Heresy:{"Heresy":1}
|
||||
};
|
||||
|
||||
const methods = {"Random + type":3, "Random + ism":1, "Supreme + ism":5, "Faith of + Supreme":3, "Place + ism":1, "Culture + ism":2, "Place + ian + type":6, "Culture + type":4};
|
||||
const methods = {"Random + type":3, "Random + ism":1, "Supreme + ism":5, "Faith of + Supreme":5, "Place + ism":1, "Culture + ism":2, "Place + ian + type":6, "Culture + type":4};
|
||||
|
||||
const types = {
|
||||
"Shamanism":{"Beliefs":3, "Shamanism":2, "Spirits":1},
|
||||
|
|
@ -65,11 +65,14 @@
|
|||
const form = rw(forms.Folk);
|
||||
const name = c.name + " " + rw(types[form]);
|
||||
const deity = form === "Animism" ? null : getDeityName(c.i);
|
||||
const color = getRandomColor(); // `url(#hatch${rand(8,13)})`;
|
||||
religions.push({i: c.i, name, color, culture: c.i, type:"Folk", form, deity});
|
||||
const color = getMixedColor(c.color, .1, 0); // `url(#hatch${rand(8,13)})`;
|
||||
religions.push({i: c.i, name, color, culture: c.i, type:"Folk", form, deity, center: c.center, origin:0});
|
||||
});
|
||||
|
||||
if (religionsInput.value == 0 || pack.cultures.length < 2) return;
|
||||
if (religionsInput.value == 0 || pack.cultures.length < 2) {
|
||||
religions.filter(r => r.i).forEach(r => r.code = getCode(r.name));
|
||||
return;
|
||||
}
|
||||
|
||||
const sorted = cells.i.filter(i => cells.s[i] > 2).sort((a, b) => cells.s[b] - cells.s[a]); // filtered and sorted array of indexes
|
||||
const religionsTree = d3.quadtree();
|
||||
|
|
@ -99,14 +102,14 @@
|
|||
if (religionsTree.find(x, y, s) !== undefined) continue; // to close to existing religion
|
||||
|
||||
// add "Old" to name of the folk religion on this culture
|
||||
const folk = religions.find(r => expansion === "culture" && r.culture === culture && r.type === "Folk");
|
||||
if (folk && folk.name.slice(0,3) !== "Old") folk.name = "Old " + folk.name;
|
||||
const folk = religions.find(r => r.culture === culture && r.type === "Folk");
|
||||
if (folk && expansion === "culture" && folk.name.slice(0,3) !== "Old") folk.name = "Old " + folk.name;
|
||||
const origin = folk ? folk.i : 0;
|
||||
|
||||
const expansionism = rand(3, 8);
|
||||
const color = getRandomColor(); // `url(#hatch${rand(0,5)})`;
|
||||
religions.push({i: religions.length, name, color, culture, type:"Organized", form, deity, expansion, expansionism, center});
|
||||
const color = getMixedColor(religions[origin].color, .3, 0); // `url(#hatch${rand(0,5)})`;
|
||||
religions.push({i: religions.length, name, color, culture, type:"Organized", form, deity, expansion, expansionism, center, origin});
|
||||
religionsTree.add([x, y]);
|
||||
//debug.append("circle").attr("cx", x).attr("cy", y).attr("r", 2).attr("fill", "blue");
|
||||
}
|
||||
|
||||
// generate cults
|
||||
|
|
@ -120,11 +123,13 @@
|
|||
if (religionsTree.find(x, y, s) !== undefined) continue; // to close to existing religion
|
||||
|
||||
const culture = cells.culture[center];
|
||||
const folk = religions.find(r => r.culture === culture && r.type === "Folk");
|
||||
const origin = folk ? folk.i : 0;
|
||||
const deity = getDeityName(culture);
|
||||
const name = getCultName(form, center);
|
||||
const expansionism = gauss(1.1, .5, 0, 5);
|
||||
const color = getRandomColor(); // "url(#hatch7)";
|
||||
religions.push({i: religions.length, name, color, culture, type:"Cult", form, deity, expansion:"global", expansionism, center});
|
||||
const color = getMixedColor(cultures[culture].color, .5, 0); // "url(#hatch7)";
|
||||
religions.push({i: religions.length, name, color, culture, type:"Cult", form, deity, expansion:"global", expansionism, center, origin});
|
||||
religionsTree.add([x, y]);
|
||||
//debug.append("circle").attr("cx", x).attr("cy", y).attr("r", 2).attr("fill", "red");
|
||||
}
|
||||
|
|
@ -145,14 +150,15 @@
|
|||
const culture = cells.culture[center];
|
||||
const name = getCultName("Heresy", center);
|
||||
const expansionism = gauss(1.2, .5, 0, 5);
|
||||
const color = getRandomColor(); // "url(#hatch6)";
|
||||
religions.push({i: religions.length, name, color, culture, type:"Heresy", form:"Heresy", deity: r.deity, expansion:"global", expansionism, center});
|
||||
const color = getMixedColor(r.color, .4, .2); // "url(#hatch6)";
|
||||
religions.push({i: religions.length, name, color, culture, type:"Heresy", form:r.form, deity: r.deity, expansion:"global", expansionism, center, origin:r.i});
|
||||
religionsTree.add([x, y]);
|
||||
//debug.append("circle").attr("cx", x).attr("cy", y).attr("r", 2).attr("fill", "green");
|
||||
}
|
||||
});
|
||||
|
||||
expandHeresies();
|
||||
checkCenters();
|
||||
|
||||
console.timeEnd('generateReligions');
|
||||
}
|
||||
|
|
@ -162,22 +168,23 @@
|
|||
const r = cells.religion[center];
|
||||
const i = religions.length;
|
||||
const culture = cells.culture[center];
|
||||
const color = getRandomColor();
|
||||
const color = getMixedColor(religions[r].color, .3, 0);
|
||||
|
||||
const type = religions[r].type === "Organized" ? rw({Organized:4, Cult:1, Heresy:2}) : rw({Organized:5, Cult:2});
|
||||
const form = rw(forms[type]);
|
||||
const deity = form === "Heresy" ? religions[r].deity : form === "Non-theism" ? null : getDeityName(culture);
|
||||
|
||||
const deity = type === "Heresy" ? religions[r].deity : form === "Non-theism" ? null : getDeityName(culture);
|
||||
|
||||
let name, expansion;
|
||||
if (type === "Organized") [name, expansion] = getReligionName(form, deity, center)
|
||||
else {name = getCultName(form, center); expansion = "global";}
|
||||
|
||||
religions.push({i, name, color, culture, type, form, deity, expansion, expansionism:0, center, area: 0, rural: 0, urban: 0});
|
||||
const formName = type === "Heresy" ? religions[r].form : form;
|
||||
const code = getCode(name);
|
||||
religions.push({i, name, color, culture, type, form:formName, deity, expansion, expansionism:0, center, cells:0, area:0, rural:0, urban:0, origin:r, code});
|
||||
cells.religion[center] = i;
|
||||
}
|
||||
|
||||
// growth algorithm to assign cells to religions
|
||||
const expandReligions = function() {
|
||||
console.time("expandReligions");
|
||||
const cells = pack.cells, religions = pack.religions;
|
||||
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
||||
const cost = [];
|
||||
|
|
@ -215,17 +222,15 @@
|
|||
}
|
||||
});
|
||||
}
|
||||
console.timeEnd("expandReligions");
|
||||
}
|
||||
|
||||
// growth algorithm to assign cells to heresies
|
||||
// growth algorithm to assign cells to heresies
|
||||
const expandHeresies = function() {
|
||||
console.time("expandHeresies");
|
||||
const cells = pack.cells, religions = pack.religions;
|
||||
const queue = new PriorityQueue({comparator: (a, b) => a.p - b.p});
|
||||
const cost = [];
|
||||
|
||||
religions.filter(r => r.form === "Heresy").forEach(r => {
|
||||
religions.filter(r => r.type === "Heresy").forEach(r => {
|
||||
const b = cells.religion[r.center]; // "base" religion id
|
||||
cells.religion[r.center] = r.i; // heresy id
|
||||
queue.queue({e:r.center, p:0, r:r.i, b});
|
||||
|
|
@ -253,8 +258,31 @@
|
|||
}
|
||||
});
|
||||
}
|
||||
//debug.selectAll(".text").data(cost).enter().append("text").attr("x", (d, e) => cells.p[e][0]-1).attr("y", (d, e) => cells.p[e][1]-1).text(d => d ? rn(d) : "").attr("font-size", 2);
|
||||
console.timeEnd("expandHeresies");
|
||||
}
|
||||
|
||||
function checkCenters() {
|
||||
const cells = pack.cells, religions = pack.religions;
|
||||
|
||||
religions.filter(r => r.i).forEach(r => {
|
||||
r.code = getCode(r.name);
|
||||
|
||||
// move religion center if it's not within religion area after expansion
|
||||
if (cells.religion[r.center] === r.i) return; // in area
|
||||
const religCells = cells.i.filter(i => cells.religion[i] === r.i);
|
||||
if (!religCells.length) return; // extinct religion
|
||||
r.center = religCells.sort((a,b) => b.pop - a.pop)[0];
|
||||
});
|
||||
}
|
||||
|
||||
// assign a unique two-letters code (abbreviation)
|
||||
function getCode(rawName) {
|
||||
const name = rawName.replace("Old ", ""); // remove Old prefix
|
||||
const words = name.split(" "), letters = words.join("");
|
||||
let code = words.length === 2 ? words[0][0]+words[1][0] : letters.slice(0,2);
|
||||
for (let i=1; i < letters.length-1 && pack.religions.some(r => r.code === code); i++) {
|
||||
code = letters[0] + letters[i].toUpperCase();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
// get supreme deity name
|
||||
|
|
@ -299,7 +327,7 @@
|
|||
if (m === "Random + type") return [random() + " " + type(), "global"];
|
||||
if (m === "Random + ism") return [trimVowels(random()) + "ism", "global"];
|
||||
if (m === "Supreme + ism" && deity) return [trimVowels(supreme()) + "ism", "global"];
|
||||
if (m === "Faith of + Supreme" && deity) return ["Faith of " + supreme(), "global"];
|
||||
if (m === "Faith of + Supreme" && deity) return [ra(['Faith', 'Way', 'Path', 'Word', 'Witnesses']) + " of " + supreme(), "global"];
|
||||
if (m === "Place + ism") return [place() + "ism", "state"];
|
||||
if (m === "Culture + ism") return [trimVowels(culture()) + "ism", "culture"];
|
||||
if (m === "Place + ian + type") return [place("adj") + " " + type(), "state"];
|
||||
|
|
|
|||
|
|
@ -222,7 +222,9 @@ function saveAsImage(type) {
|
|||
// load fonts as dataURI so they will be available in downloaded svg/png
|
||||
GFontToDataURI(getFontsToLoad()).then(cssRules => {
|
||||
clone.select("defs").append("style").text(cssRules.join('\n'));
|
||||
const svg_xml = (new XMLSerializer()).serializeToString(clone.node());
|
||||
clone.append("metadata").text("<dc:format>image/svg+xml</dc:format>");
|
||||
const serialized = (new XMLSerializer()).serializeToString(clone.node());
|
||||
const svg_xml = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + serialized;
|
||||
clone.remove();
|
||||
const blob = new Blob([svg_xml], {type: 'image/svg+xml;charset=utf-8'});
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
|
|
@ -239,7 +241,7 @@ function saveAsImage(type) {
|
|||
img.onload = function() {
|
||||
window.URL.revokeObjectURL(url);
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
link.download = "fantasy_map_" + Date.now() + ".png";
|
||||
link.download = getFileName() + ".png";
|
||||
canvas.toBlob(function(blob) {
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
document.body.appendChild(link);
|
||||
|
|
@ -251,7 +253,7 @@ function saveAsImage(type) {
|
|||
});
|
||||
}
|
||||
} else {
|
||||
link.download = "fantasy_map_" + Date.now() + ".svg";
|
||||
link.download = getFileName() + ".svg";
|
||||
link.href = url;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
|
@ -323,7 +325,6 @@ function GFontToDataURI(url) {
|
|||
|
||||
// prepare map data for saving
|
||||
function getMapData() {
|
||||
if (customization) return false;
|
||||
console.time("createMapDataBlob");
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
|
@ -331,9 +332,13 @@ function getMapData() {
|
|||
const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
|
||||
const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
|
||||
const params = [version, license, dateString, seed, graphWidth, graphHeight].join("|");
|
||||
const options = [distanceUnitInput.value, distanceScaleInput.value, areaUnit.value, heightUnit.value, heightExponentInput.value, temperatureScale.value,
|
||||
barSize.value, barLabel.value, barBackOpacity.value, barBackColor.value, barPosX.value, barPosY.value, populationRate.value, urbanization.value,
|
||||
mapSizeOutput.value, latitudeOutput.value, temperatureEquatorOutput.value, temperaturePoleOutput.value, precOutput.value, JSON.stringify(winds)].join("|");
|
||||
const options = [distanceUnitInput.value, distanceScaleInput.value, areaUnit.value,
|
||||
heightUnit.value, heightExponentInput.value, temperatureScale.value,
|
||||
barSize.value, barLabel.value, barBackOpacity.value, barBackColor.value,
|
||||
barPosX.value, barPosY.value, populationRate.value, urbanization.value,
|
||||
mapSizeOutput.value, latitudeOutput.value, temperatureEquatorOutput.value,
|
||||
temperaturePoleOutput.value, precOutput.value, JSON.stringify(winds),
|
||||
mapName.value].join("|");
|
||||
const coords = JSON.stringify(mapCoordinates);
|
||||
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");
|
||||
const notesData = JSON.stringify(notes);
|
||||
|
|
@ -356,13 +361,21 @@ function getMapData() {
|
|||
const religions = JSON.stringify(pack.religions);
|
||||
const provinces = JSON.stringify(pack.provinces);
|
||||
|
||||
// store name array only if it is not the same as default
|
||||
const defaultNB = Names.getNameBase();
|
||||
const namesData = nameBases.map((b,i) => {
|
||||
const names = defaultNB[i] && defaultNB[i].join("") === nameBase[i].join("") ? "" : nameBase[i];
|
||||
return `${b.name}|${b.min}|${b.max}|${b.d}|${b.m}|${names}`;
|
||||
}).join("/");
|
||||
|
||||
// data format as below
|
||||
const data = [params, options, coords, biomes, notesData, svg_xml,
|
||||
gridGeneral, grid.cells.h, grid.cells.prec, grid.cells.f, grid.cells.t, grid.cells.temp,
|
||||
features, cultures, states, burgs,
|
||||
pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl,
|
||||
pack.cells.pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state,
|
||||
pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces].join("\r\n");
|
||||
pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces,
|
||||
namesData].join("\r\n");
|
||||
const blob = new Blob([data], {type: "text/plain"});
|
||||
|
||||
console.timeEnd("createMapDataBlob");
|
||||
|
|
@ -374,12 +387,12 @@ function getMapData() {
|
|||
// Download .map file
|
||||
async function saveMap() {
|
||||
if (customization) {tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error"); return;}
|
||||
closeDialogs();
|
||||
closeDialogs("#alert");
|
||||
|
||||
const blob = await getMapData();
|
||||
const URL = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.download = "fantasy_map_" + Date.now() + ".map";
|
||||
link.download = getFileName() + ".map";
|
||||
link.href = URL;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
|
@ -392,7 +405,7 @@ function saveGeoJSON() {
|
|||
alertMessage.innerHTML = `You can export map data in GeoJSON format used in GIS tools such as QGIS.
|
||||
Check out <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/GIS-data-export" target="_blank">wiki-page</a> for guidance`;
|
||||
|
||||
$("#alert").dialog({title: "GIS data export", resizable: false, width: 320, position: {my: "center", at: "center", of: "svg"},
|
||||
$("#alert").dialog({title: "GIS data export", resizable: false, width: "32em", position: {my: "center", at: "center", of: "svg"},
|
||||
buttons: {
|
||||
Cells: saveGeoJSON_Cells,
|
||||
Routes: saveGeoJSON_Roads,
|
||||
|
|
@ -422,7 +435,7 @@ function saveGeoJSON_Roads() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "fmg_routes_" + Date.now() + ".geojson";
|
||||
link.download = getFileName("Routes") + ".geojson";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
@ -447,7 +460,7 @@ function saveGeoJSON_Rivers() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "fmg_rivers_" + Date.now() + ".geojson";
|
||||
link.download = getFileName("Rivers") + ".geojson";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
@ -483,6 +496,92 @@ function getRiverPoints(node) {
|
|||
return points;
|
||||
}
|
||||
|
||||
async function quickSave() {
|
||||
if (customization) {tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error"); return;}
|
||||
const blob = await getMapData();
|
||||
if (blob) ldb.set("lastMap", blob); // auto-save map
|
||||
tip("Map is saved to browser memory", true, "success", 2000);
|
||||
}
|
||||
|
||||
function quickLoad() {
|
||||
ldb.get("lastMap", blob => {
|
||||
if (blob) {
|
||||
loadMapPrompt(blob);
|
||||
} else {
|
||||
tip("No map stored. Save map to storage first", true, "error", 2000);
|
||||
console.error("No map stored");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadMapPrompt(blob) {
|
||||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||
if (workingTime < 5) {loadLastSavedMap(); return;}
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to load saved map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
$("#alert").dialog({resizable: false, title: "Load saved map",
|
||||
buttons: {
|
||||
Cancel: function() {$(this).dialog("close");},
|
||||
Load: function() {loadLastSavedMap(); $(this).dialog("close");}
|
||||
}
|
||||
});
|
||||
|
||||
function loadLastSavedMap() {
|
||||
console.warn("Load last saved map");
|
||||
try {
|
||||
uploadFile(blob);
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
tip("Cannot load last saved map", true, "error", 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const saveReminder = function() {
|
||||
if (localStorage.getItem("noReminder")) return;
|
||||
const message = ["Please don't forget to save your work as a .map file",
|
||||
"Please remember to save work as a .map file",
|
||||
"Saving in .map format will ensure your data won't be lost in case of issues",
|
||||
"Safety is number one priority. Please save the map",
|
||||
"Don't forget to save your map on a regular basis!",
|
||||
"Just a gentle reminder for you to save the map",
|
||||
"Please forget to save your progress (saving as .map is the best option)",
|
||||
"Don't want to be reminded about need to save? Press CTRL+Q"];
|
||||
|
||||
saveReminder.reminder = setInterval(() => {
|
||||
if (customization) return;
|
||||
tip(ra(message), true, "warn", 2500);
|
||||
}, 1e6);
|
||||
saveReminder.status = 1;
|
||||
}
|
||||
|
||||
saveReminder();
|
||||
|
||||
function toggleSaveReminder() {
|
||||
if (saveReminder.status) {
|
||||
tip("Save reminder is turned off. Press CTRL+Q again to re-initiate", true, "warn", 2000);
|
||||
clearInterval(saveReminder.reminder);
|
||||
localStorage.setItem("noReminder", true);
|
||||
saveReminder.status = 0;
|
||||
} else {
|
||||
tip("Save reminder is turned on. Press CTRL+Q to turn off", true, "warn", 2000);
|
||||
localStorage.removeItem("noReminder");
|
||||
saveReminder();
|
||||
}
|
||||
}
|
||||
|
||||
function getFileName(dataType) {
|
||||
const name = mapName.value;
|
||||
const type = dataType ? dataType + " " : "";
|
||||
const date = new Date();
|
||||
const datFormatter = new Intl.DateTimeFormat("en", {month: "short", day: "numeric"});
|
||||
const timeFormatter = new Intl.DateTimeFormat("ru", {hour: "numeric", minute: "numeric"});
|
||||
const day = datFormatter.format(date).replace(" ", "");
|
||||
const time = timeFormatter.format(date).replace(":", "-");
|
||||
return name + " " + type + day + " " + time;
|
||||
}
|
||||
|
||||
function saveGeoJSON_Cells() {
|
||||
let data = "{ \"type\": \"FeatureCollection\", \"features\": [\n";
|
||||
|
|
@ -521,7 +620,7 @@ function saveGeoJSON_Cells() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "fmg_cells_" + Date.now() + ".geojson";
|
||||
link.download = getFileName("Cells") + ".geojson";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
@ -553,7 +652,7 @@ function uploadFile(file, callback) {
|
|||
<br>The map will be auto-updated. In case of issues please keep using an ${archive} of the Generator`;
|
||||
}
|
||||
alertMessage.innerHTML = message;
|
||||
$("#alert").dialog({title: "Version conflict", width: 380, buttons: {
|
||||
$("#alert").dialog({title: "Version conflict", width: "38em", buttons: {
|
||||
OK: function() {$(this).dialog("close"); if (load) parseLoadedData(data);}
|
||||
}});
|
||||
};
|
||||
|
|
@ -564,6 +663,11 @@ function uploadFile(file, callback) {
|
|||
|
||||
function parseLoadedData(data) {
|
||||
try {
|
||||
// exit customization
|
||||
closeDialogs();
|
||||
customization = 0;
|
||||
if (customizationMenu.offsetParent) styleTab.click();
|
||||
|
||||
const reliefIcons = document.getElementById("defs-relief").innerHTML; // save relief icons
|
||||
const hatching = document.getElementById("hatching").cloneNode(true); // save hatching
|
||||
|
||||
|
|
@ -598,6 +702,7 @@ function parseLoadedData(data) {
|
|||
if (options[17]) temperaturePoleInput.value = temperaturePoleOutput.value = options[17];
|
||||
if (options[18]) precInput.value = precOutput.value = options[18];
|
||||
if (options[19]) winds = JSON.parse(options[19]);
|
||||
if (options[20]) mapName.value = options[20];
|
||||
}()
|
||||
|
||||
void function parseConfiguration() {
|
||||
|
|
@ -710,6 +815,16 @@ function parseLoadedData(data) {
|
|||
cells.religion = data[26] ? Uint16Array.from(data[26].split(",")) : new Uint16Array(cells.i.length);
|
||||
cells.province = data[27] ? Uint16Array.from(data[27].split(",")) : new Uint16Array(cells.i.length);
|
||||
cells.crossroad = data[28] ? Uint16Array.from(data[28].split(",")) : new Uint16Array(cells.i.length);
|
||||
|
||||
if (data[31]) {
|
||||
const namesDL = data[31].split("/");
|
||||
namesDL.forEach((d, i) => {
|
||||
const e = d.split("|");
|
||||
if (!e.length) return;
|
||||
nameBases[i] = {name:e[0], min:e[1], max:e[2], d:e[3], m:e[4]};
|
||||
if(e[5]) nameBase[i] = e[5].split(",");
|
||||
});
|
||||
}
|
||||
}()
|
||||
|
||||
void function restoreLayersState() {
|
||||
|
|
@ -838,6 +953,17 @@ function parseLoadedData(data) {
|
|||
if (!s.diplomacy) continue;
|
||||
s.diplomacy = s.diplomacy.map(r => r === "Sympathy" ? "Friendly" : r);
|
||||
}
|
||||
|
||||
// labels should be toggled via style attribute, so remove display attribute
|
||||
labels.attr("display", null);
|
||||
|
||||
// v 1.0 added religions heirarchy tree
|
||||
if (pack.religions[1] && !pack.religions[1].code) {
|
||||
pack.religions.filter(r => r.i).forEach(r => {
|
||||
r.origin = 0;
|
||||
r.code = r.name.slice(0, 2);
|
||||
});
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -858,7 +984,7 @@ function parseLoadedData(data) {
|
|||
<br>generate a new random map or cancel the loading
|
||||
<p id="errorBox">${parseError(error)}</p>`;
|
||||
$("#alert").dialog({
|
||||
resizable: false, title: "Loading error", maxWidth:500, buttons: {
|
||||
resizable: false, title: "Loading error", maxWidth:"50em", buttons: {
|
||||
"Select file": function() {$(this).dialog("close"); mapToLoad.click();},
|
||||
"New map": function() {$(this).dialog("close"); regenerateMap();},
|
||||
Cancel: function() {$(this).dialog("close")}
|
||||
|
|
@ -866,80 +992,4 @@ function parseLoadedData(data) {
|
|||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function quickSave() {
|
||||
const blob = await getMapData();
|
||||
if (blob) ldb.set("lastMap", blob); // auto-save map
|
||||
tip("Map is saved to browser memory", true, "success", 2000);
|
||||
}
|
||||
|
||||
function quickLoad() {
|
||||
ldb.get("lastMap", blob => {
|
||||
if (blob) {
|
||||
loadMapPrompt(blob);
|
||||
} else {
|
||||
tip("No map stored. Save map to storage first", true, "error", 2000);
|
||||
console.error("No map stored");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadMapPrompt(blob) {
|
||||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||
if (workingTime < 10) {loadLastSavedMap(); return;}
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to load saved map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
$("#alert").dialog({resizable: false, title: "Load saved map",
|
||||
buttons: {
|
||||
Cancel: function() {$(this).dialog("close");},
|
||||
Load: function() {loadLastSavedMap(); $(this).dialog("close");}
|
||||
}
|
||||
});
|
||||
|
||||
function loadLastSavedMap() {
|
||||
console.warn("Load last saved map");
|
||||
closeDialogs();
|
||||
try {
|
||||
uploadFile(blob);
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
tip("Cannot load last saved map", true, "error", 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const saveReminder = function() {
|
||||
if (localStorage.getItem("noReminder")) return;
|
||||
const message = ["Please don't forget to save your work as a .map file",
|
||||
"Please remember to save work as a .map file",
|
||||
"Saving in .map format will ensure your data won't be lost in case of issues",
|
||||
"Safety is number one priority. Please save the map",
|
||||
"Don't forget to save your map on a regular basis!",
|
||||
"Just a gentle reminder for you to save the map",
|
||||
"Please forget to save your progress (saving as .map is the best option)",
|
||||
"Don't want to be reminded about need to save? Press CTRL+Q"];
|
||||
|
||||
saveReminder.reminder = setInterval(() => {
|
||||
if (customization) return;
|
||||
tip(ra(message), true, "warn", 2500);
|
||||
}, 1e6);
|
||||
saveReminder.status = 1;
|
||||
}
|
||||
|
||||
saveReminder();
|
||||
|
||||
function toggleSaveReminder() {
|
||||
if (saveReminder.status) {
|
||||
tip("Save reminder is turned off. Press CTRL+Q again to re-initiate", true, "warn", 2000);
|
||||
clearInterval(saveReminder.reminder);
|
||||
localStorage.setItem("noReminder", true);
|
||||
saveReminder.status = 0;
|
||||
} else {
|
||||
tip("Save reminder is turned on. Press CTRL+Q to turn off", true, "warn", 2000);
|
||||
localStorage.removeItem("noReminder");
|
||||
saveReminder();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ function editBiomes() {
|
|||
|
||||
lines += `<div class="states biomes" data-id="${i}" data-name="${b.name[i]}" data-habitability="${b.habitability[i]}"
|
||||
data-cells=${b.cells[i]} data-area=${area} data-population=${population} data-color=${b.color[i]}>
|
||||
<svg data-tip="Biomes fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${b.color[i]}" class="zoneFill"></svg>
|
||||
<svg data-tip="Biomes fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${b.color[i]}" class="zoneFill"></svg>
|
||||
<input data-tip="Biome name. Click and type to change" class="biomeName" value="${b.name[i]}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Biome habitability percent" class="hide">%</span>
|
||||
<input data-tip="Biome habitability percent. Click and set new value to change" type="number" min=0 max=9999 step=1 class="biomeHabitability hide" value=${b.habitability[i]}>
|
||||
|
|
@ -205,7 +205,7 @@ function editBiomes() {
|
|||
|
||||
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
|
||||
const line = `<div class="states biomes" data-id="${i}" data-name="${b.name[i]}" data-habitability=${b.habitability[i]} data-cells=0 data-area=0 data-population=0 data-color=${b.color[i]}>
|
||||
<svg data-tip="Biomes fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${b.color[i]}" class="zoneFill"></svg>
|
||||
<svg data-tip="Biomes fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${b.color[i]}" class="zoneFill"></svg>
|
||||
<input data-tip="Biome name. Click and type to change" class="biomeName" value="${b.name[i]}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Biome habitability percent" class="hide">%</span>
|
||||
<input data-tip="Biome habitability percent. Click and set new value to change" type="number" min=0 max=9999 step=1 class="biomeHabitability hide" value=${b.habitability[i]}>
|
||||
|
|
@ -253,7 +253,7 @@ function editBiomes() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "biomes_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("Biomes") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ function editBurgs() {
|
|||
lines += `<div class="states" data-id=${b.i} data-name=${b.name} data-state=${state} data-culture=${culture} data-population=${population} data-type=${type}>
|
||||
<span data-tip="Click to zoom into view" class="icon-dot-circled pointer"></span>
|
||||
<input data-tip="Burg name. Click and type to change" class="burgName" value="${b.name}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Burg state" class="burgState ${showState}">${state}</span>
|
||||
<select data-tip="Dominant culture. Click to change" class="stateCulture">${getCultureOptions(b.culture)}</select>
|
||||
<span data-tip="Burg population" class="icon-male"></span>
|
||||
<input data-tip="Burg population. Type to change" class="burgPopulation" value=${si(population)}>
|
||||
|
|
@ -83,6 +82,7 @@ function editBurgs() {
|
|||
<span data-tip="${b.capital ? ' This burg is a state capital' : 'Click to assign a capital status'}" class="icon-star-empty${b.capital ? '' : ' inactive pointer'}"></span>
|
||||
<span data-tip="Click to toggle port status" class="icon-anchor pointer${b.port ? '' : ' inactive'}" style="font-size:.9em"></span>
|
||||
</div>
|
||||
<span data-tip="Burg state" class="burgState ${showState}">${state}</span>
|
||||
<span data-tip="Remove burg" class="icon-trash-empty"></span>
|
||||
</div>`;
|
||||
}
|
||||
|
|
@ -252,7 +252,7 @@ function editBurgs() {
|
|||
}
|
||||
|
||||
function downloadBurgsData() {
|
||||
let data = "Id,Burg,State,Culture,Population,Capital,Port,Longitude,Latitude,Elevation\n"; // headers
|
||||
let data = "Id,Burg,State,Culture,Population,Longitude,Latitude,Elevation ("+heightUnit.value+"),Capital,Port\n"; // headers
|
||||
const valid = pack.burgs.filter(b => b.i && !b.removed); // all valid burgs
|
||||
|
||||
valid.forEach(b => {
|
||||
|
|
@ -261,20 +261,22 @@ function editBurgs() {
|
|||
data += pack.states[b.state].name + ",";
|
||||
data += pack.cultures[b.culture].name + ",";
|
||||
data += rn(b.population * populationRate.value * urbanization.value) + ",";
|
||||
data += b.capital ? "capital," : ",";
|
||||
data += b.port ? "port," : ",";
|
||||
|
||||
// add geography data
|
||||
data += mapCoordinates.lonW + (b.x / graphWidth) * mapCoordinates.lonT + ",";
|
||||
data += mapCoordinates.latN - (b.y / graphHeight) * mapCoordinates.latT + ","; // this is inverted in QGIS otherwise
|
||||
data += parseInt(getFriendlyHeight(pack.cells.h[b.cell])) + "\n";
|
||||
data += parseInt(getHeight(pack.cells.h[b.cell])) + ",";
|
||||
|
||||
// add status data
|
||||
data += b.capital ? "capital," : ",";
|
||||
data += b.port ? "port\n" : "\n";
|
||||
});
|
||||
|
||||
const dataBlob = new Blob([data], {type: "text/plain"});
|
||||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "burgs_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("Burgs") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
|
|||
|
|
@ -89,13 +89,13 @@ function editCultures() {
|
|||
|
||||
lines += `<div class="states cultures" data-id=${c.i} data-name="${c.name}" data-color="${c.color}" data-cells=${c.cells}
|
||||
data-area=${area} data-population=${population} data-base=${c.base} data-type=${c.type} data-expansionism=${c.expansionism}>
|
||||
<svg data-tip="Culture fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${c.color}" class="zoneFill"></svg>
|
||||
<svg data-tip="Culture fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${c.color}" class="zoneFill"></svg>
|
||||
<input data-tip="Culture name. Click and type to change" class="cultureName" value="${c.name}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells hide">${c.cells}</div>
|
||||
<span data-tip="Culture expansionism (defines competitive size)" class="icon-resize-full hide"></span>
|
||||
<input data-tip="Expansionism (defines competitive size)" class="statePower hide" type="number" min=0 max=99 step=.1 value=${c.expansionism}>
|
||||
<select data-tip="Culture type" class="cultureType">${getTypeOptions(c.type)}</select>
|
||||
<span data-tip="Culture expansionism. Defines competitive size" class="icon-resize-full hide"></span>
|
||||
<input data-tip="Culture expansionism. Defines competitive size. Click to change" class="statePower hide" type="number" min=0 max=99 step=.1 value=${c.expansionism}>
|
||||
<select data-tip="Culture type. Defines growth model. Click to change" class="cultureType">${getTypeOptions(c.type)}</select>
|
||||
<span data-tip="Culture area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Culture area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
|
|
@ -302,6 +302,7 @@ function editCultures() {
|
|||
debug.select("#cultureCenters").style("display", "none");
|
||||
|
||||
culturesEditor.querySelectorAll(".hide").forEach(el => el.classList.add("hidden"));
|
||||
culturesHeader.querySelector("div[data-sortby='type']").style.left = "6.8em";
|
||||
culturesFooter.style.display = "none";
|
||||
culturesHeader.querySelector("div[data-sortby='base']").style.marginLeft = "21px";
|
||||
body.querySelectorAll("div > input, select, span, svg").forEach(e => e.style.pointerEvents = "none");
|
||||
|
|
@ -398,6 +399,7 @@ function editCultures() {
|
|||
document.getElementById("culturesManuallyButtons").style.display = "none";
|
||||
|
||||
culturesEditor.querySelectorAll(".hide").forEach(el => el.classList.remove("hidden"));
|
||||
culturesHeader.querySelector("div[data-sortby='type']").style.left = "15.8em";
|
||||
culturesFooter.style.display = "block";
|
||||
culturesHeader.querySelector("div[data-sortby='base']").style.marginLeft = "2px";
|
||||
body.querySelectorAll("div > input, select, span, svg").forEach(e => e.style.pointerEvents = "all");
|
||||
|
|
@ -477,7 +479,7 @@ function editCultures() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "cultures_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("Cultures") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ function editDiplomacy() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "state_relations_history" + Date.now() + ".txt";
|
||||
link.download = getFileName("Relations history") + ".txt";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
@ -252,7 +252,7 @@ function editDiplomacy() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "state_relations_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("Relations") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
|
|||
|
|
@ -145,15 +145,18 @@ function updateCellInfo(point, i, g) {
|
|||
|
||||
// get user-friendly (real-world) height value from map data
|
||||
function getFriendlyHeight(p) {
|
||||
const packH = pack.cells.h[findCell(p[0], p[1])];
|
||||
const gridH = grid.cells.h[findGridCell(p[0], p[1])];
|
||||
const h = packH < 20 ? gridH : packH;
|
||||
return getHeight(h);
|
||||
}
|
||||
|
||||
function getHeight(h) {
|
||||
const unit = heightUnit.value;
|
||||
let unitRatio = 3.281; // default calculations are in feet
|
||||
if (unit === "m") unitRatio = 1; // if meter
|
||||
else if (unit === "f") unitRatio = 0.5468; // if fathom
|
||||
|
||||
const packH = pack.cells.h[findCell(p[0], p[1])];
|
||||
const gridH = grid.cells.h[findGridCell(p[0], p[1])];
|
||||
const h = packH < 20 ? gridH : packH;
|
||||
|
||||
let height = -990;
|
||||
if (h >= 20) height = Math.pow(h - 18, +heightExponentInput.value);
|
||||
else if (h < 20 && h > 0) height = (h - 20) / h * 50;
|
||||
|
|
@ -226,14 +229,21 @@ function applyOption(select, option) {
|
|||
select.value = option;
|
||||
}
|
||||
|
||||
// prevent default browser behavior for FMG-used hotkeys
|
||||
document.addEventListener("keydown", event => {
|
||||
if ([112, 113, 117, 120, 9].includes(event.keyCode)) event.preventDefault(); // F1, F2, F6, F9, Tab
|
||||
});
|
||||
|
||||
// Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys
|
||||
document.addEventListener("keydown", function(event) {
|
||||
document.addEventListener("keyup", event => {
|
||||
const active = document.activeElement.tagName;
|
||||
if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; // don't trigger if user inputs a text
|
||||
if (active === "DIV" && document.activeElement.contentEditable === "true") return; // don't trigger if user inputs a text
|
||||
event.stopPropagation();
|
||||
|
||||
const key = event.keyCode, ctrl = event.ctrlKey, shift = event.shiftKey, meta = event.metaKey;
|
||||
if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
|
||||
else if (key === 9) {toggleOptions(event); event.preventDefault();} // Tab to toggle options
|
||||
else if (key === 9) toggleOptions(event); // Tab to toggle options
|
||||
|
||||
else if (key === 113) regeneratePrompt(); // "F2" for new map
|
||||
else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ function editHeightmap() {
|
|||
<p>If you need to change the coastline and keep the data, you may try the <i>risk</i> edit option.
|
||||
The data will be restored as much as possible, but the coastline change can cause unexpected fluctuations and errors.</p>
|
||||
|
||||
<p>Check out <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization" target="_blank">wiki</a> for guidance.</p>`;
|
||||
<p>Check out <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization" target="_blank">wiki</a> for guidance.</p>
|
||||
|
||||
<p>Please <span class="pseudoLink" onclick=saveMap(); editHeightmap();>save the map</span> before edditing the heightmap!</p>`;
|
||||
|
||||
$("#alert").dialog({resizable: false, title: "Edit Heightmap", width: 300,
|
||||
$("#alert").dialog({resizable: false, title: "Edit Heightmap", width: "28em",
|
||||
buttons: {
|
||||
Erase: function() {enterHeightmapEditMode("erase");},
|
||||
Keep: function() {enterHeightmapEditMode("keep");},
|
||||
|
|
@ -34,7 +36,6 @@ function editHeightmap() {
|
|||
document.getElementById("applyTemplate").addEventListener("click", openTemplateEditor);
|
||||
document.getElementById("convertImage").addEventListener("click", openImageConverter);
|
||||
document.getElementById("heightmapPreview").addEventListener("click", toggleHeightmapPreview);
|
||||
document.getElementById("perspectiveView").addEventListener("click", openPerspectivePanel);
|
||||
document.getElementById("finalizeHeightmap").addEventListener("click", finalizeHeightmap);
|
||||
document.getElementById("renderOcean").addEventListener("click", mockHeightmap);
|
||||
document.getElementById("templateUndo").addEventListener("click", () => restoreHistory(edits.n-1));
|
||||
|
|
@ -389,7 +390,6 @@ function getHeight(h) {
|
|||
if (!noStat) updateStatistics();
|
||||
|
||||
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if ($("#perspectivePanel").is(":visible")) drawPerspective(); // update perspective view if opened
|
||||
}
|
||||
|
||||
// restoreHistory
|
||||
|
|
@ -403,7 +403,6 @@ function getHeight(h) {
|
|||
updateStatistics();
|
||||
|
||||
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||
if ($("#perspectivePanel").is(":visible")) drawPerspective(); // update perspective view if opened
|
||||
}
|
||||
|
||||
// restart edits from 1st step
|
||||
|
|
@ -418,7 +417,7 @@ function getHeight(h) {
|
|||
function openBrushesPanel() {
|
||||
if ($("#brushesPanel").is(":visible")) return;
|
||||
$("#brushesPanel").dialog({
|
||||
title: "Paint Brushes", minHeight: 40, width: "auto", maxWidth: 200, resizable: false,
|
||||
title: "Paint Brushes", resizable: false,
|
||||
position: {my: "right top", at: "right-10 top+10", of: "svg"}
|
||||
}).on('dialogclose', exitBrushMode);
|
||||
|
||||
|
|
@ -570,7 +569,7 @@ function getHeight(h) {
|
|||
if (modules.openTemplateEditor) return;
|
||||
modules.openTemplateEditor = true;
|
||||
|
||||
$("#templateBody").sortable({items: "div", handle: ".icon-resize-vertical", containment: "parent", axis: "y"});
|
||||
$("#templateBody").sortable({items: "> div", handle: ".icon-resize-vertical", containment: "#templateBody", axis: "y"});
|
||||
|
||||
// add listeners
|
||||
body.addEventListener("click", function(ev) {
|
||||
|
|
@ -799,6 +798,13 @@ function getHeight(h) {
|
|||
addStep("Trough", "4-8", "15-30", "70-100", "80-100");
|
||||
}
|
||||
|
||||
else if (template === "templateShattered") {
|
||||
addStep("Hill", "8", "35-40", "15-85", "30-70");
|
||||
addStep("Trough", "10-20", "40-50", "5-95", "5-95");
|
||||
addStep("Range", "5-7", "30-40", "10-90", "20-80");
|
||||
addStep("Pit", "12-20", "30-40", "15-85", "20-80");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function executeTemplate() {
|
||||
|
|
@ -896,7 +902,7 @@ function getHeight(h) {
|
|||
closeDialogs("#imageConverter");
|
||||
|
||||
$("#imageConverter").dialog({
|
||||
title: "Image Converter", minHeight: "auto", width: "22.5em", resizable: false,
|
||||
title: "Image Converter", minHeight: "auto", width: "19.5em", resizable: false,
|
||||
position: {my: "right top", at: "right-10 top+10", of: "svg"}
|
||||
}).on('dialogclose', closeImageConverter);
|
||||
|
||||
|
|
@ -924,7 +930,7 @@ function getHeight(h) {
|
|||
const container = d3.select("#colorScheme");
|
||||
container.selectAll("div").data(d3.range(101)).enter().append("div").attr("data-color", i => i)
|
||||
.style("background-color", i => color(1-i/100))
|
||||
.style("width", i => i < 20 || i > 70 ? "3px" : "1px")
|
||||
.style("width", i => i < 20 || i > 70 ? ".2em" : ".1em")
|
||||
.on("touchmove mousemove", showPalleteHeight).on("click", assignHeight);
|
||||
}()
|
||||
|
||||
|
|
@ -1117,7 +1123,7 @@ function getHeight(h) {
|
|||
preview.width = grid.cellsX;
|
||||
preview.height = grid.cellsY;
|
||||
document.body.insertBefore(preview, optionsContainer);
|
||||
preview.addEventListener("mouseover", () => tip("Heightmap preview. Click to download the image"));
|
||||
preview.addEventListener("mouseover", () => tip("Heightmap preview. Click to download a screen-sized image"));
|
||||
preview.addEventListener("click", downloadPreview);
|
||||
drawHeightmapPreview();
|
||||
}
|
||||
|
|
@ -1153,19 +1159,30 @@ function getHeight(h) {
|
|||
document.body.insertBefore(canvas, optionsContainer);
|
||||
ctx.drawImage(img, 0, 0, svgWidth, svgHeight);
|
||||
|
||||
// const simplex = new SimplexNoise(); // SimplexNoise by Jonas Wagner
|
||||
// const noise = (nx, ny) => simplex.noise2D(nx, ny) / 2 + .5;
|
||||
|
||||
// const imageData = ctx.getImageData(0, 0, svgWidth, svgHeight);
|
||||
// for (let i=0; i < imageData.data.length; i+=4) {
|
||||
// const v = Math.min(rn(imageData.data[i] * gauss(1, .05, .9, 1.1, 3)), 255);
|
||||
// imageData.data[i] = v;
|
||||
// imageData.data[i+1] = v;
|
||||
// imageData.data[i+2] = v;
|
||||
// const v = imageData.data[i];
|
||||
// if (v < 51) {
|
||||
// // water
|
||||
// // imageData.data[i] = imageData.data[i+1] = imageData.data[i+2] = 46;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// const x = i / 4 % svgWidth, y = Math.floor(i / 4 / svgWidth);
|
||||
// const nx = x / svgWidth - .5, ny = y / svgHeight - .5;
|
||||
// const n = noise(4 * nx, 4 * ny) / 4 + noise(16 * nx, 16 * ny) / 16;
|
||||
// const nv = Math.max(Math.min((v + 255 * n) / 2, 255), 51);
|
||||
// imageData.data[i] = imageData.data[i+1] = imageData.data[i+2] = nv;
|
||||
// }
|
||||
// ctx.putImageData(imageData, 0, 0);
|
||||
|
||||
const imgBig = canvas.toDataURL("image/png");
|
||||
const link = document.createElement("a");
|
||||
link.target = "_blank";
|
||||
link.download = "heightmap_" + Date.now() + ".png";
|
||||
link.download = getFileName("Heightmap") + ".png";
|
||||
link.href = imgBig;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
|
@ -1173,68 +1190,4 @@ function getHeight(h) {
|
|||
}
|
||||
}
|
||||
|
||||
function openPerspectivePanel() {
|
||||
if ($("#perspectivePanel").is(":visible")) return;
|
||||
$("#perspectivePanel").dialog({
|
||||
title: "Perspective View", minHeight: "auto", width: 510, height: 200,
|
||||
position: {my: "center center", at: "center center", of: "svg"}
|
||||
});
|
||||
|
||||
drawPerspective();
|
||||
}
|
||||
|
||||
function drawPerspective() {
|
||||
const width = 320, height = 180;
|
||||
const wRatio = graphWidth / width, hRatio = graphHeight / height;
|
||||
const lineCount = 320, lineGranularity = 90;
|
||||
const perspective = document.getElementById("perspective");
|
||||
const pContext = perspective.getContext("2d");
|
||||
const lines = [];
|
||||
|
||||
let i = lineCount;
|
||||
while (i--) {
|
||||
const x = i / lineCount * width | 0;
|
||||
const canvasPoints = [];
|
||||
lines.push(canvasPoints);
|
||||
let j = Math.floor(lineGranularity);
|
||||
while (j--) {
|
||||
const y = j / lineGranularity * height | 0;
|
||||
let index = findGridCell(x * wRatio, y * hRatio);
|
||||
let h = grid.cells.h[index] - 20;
|
||||
if (h < 1) h = 0;
|
||||
canvasPoints.push([x, y, h]);
|
||||
}
|
||||
}
|
||||
|
||||
pContext.clearRect(0, 0, perspective.width, perspective.height);
|
||||
for (let canvasPoints of lines) {
|
||||
for (let i = 0; i < canvasPoints.length - 1; i++) {
|
||||
const pt1 = canvasPoints[i];
|
||||
const pt2 = canvasPoints[i + 1];
|
||||
const avHeight = (pt1[2] + pt2[2]) / 200;
|
||||
pContext.beginPath();
|
||||
pContext.moveTo(...transformPt(pt1));
|
||||
pContext.lineTo(...transformPt(pt2));
|
||||
let clr = "rgb(81, 103, 169)"; // water
|
||||
if (avHeight !== 0) {clr = color(1 - avHeight - 0.2);}
|
||||
pContext.strokeStyle = clr;
|
||||
pContext.stroke();
|
||||
}
|
||||
for (let i = 0; i < canvasPoints.length - 1; i++) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function transformPt(pt) {
|
||||
const width = 320, maxHeight = 0.2;
|
||||
var [x, y] = projectIsometric(pt[0],pt[1]);
|
||||
return [x + width / 2 + 10, y + 10 - pt[2] * maxHeight];
|
||||
}
|
||||
|
||||
function projectIsometric(x, y) {
|
||||
const scale = 1, yProj = 4;
|
||||
return [(x - y) * scale, (x + y) / yProj * scale];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -104,6 +104,7 @@ function getCurrentPreset() {
|
|||
if (JSON.stringify(presets[preset]) !== JSON.stringify(layers)) continue;
|
||||
layersPreset.value = preset;
|
||||
removePresetButton.style.display = defaultPresets[preset] ? "none" : "inline-block";
|
||||
savePresetButton.style.display = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -849,8 +850,8 @@ function drawGrid() {
|
|||
const d = points.map(p => "M" + p + hex).join("");
|
||||
gridOverlay.append("path").attr("d", d);
|
||||
} else if (type === "square") {
|
||||
const pathX = d3.range(size, svgWidth, size).map(x => "M" + rn(x, 2) + ",0v" + svgHeight);
|
||||
const pathY = d3.range(size, svgHeight, size).map(y => "M0," + rn(y, 2) + "h" + svgWidth);
|
||||
const pathX = d3.range(size, svgWidth, size).map(x => "M" + rn(x, 2) + ",0v" + svgHeight).join(" ");
|
||||
const pathY = d3.range(size, svgHeight, size).map(y => "M0," + rn(y, 2) + "h" + svgWidth).join(" ");
|
||||
gridOverlay.append("path").attr("d", pathX + pathY);
|
||||
}
|
||||
|
||||
|
|
@ -881,7 +882,7 @@ function drawGrid() {
|
|||
x0 = x1, y0 = y1;
|
||||
return [rn(dx, 2), rn(dy, 2)];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.timeEnd("drawGrid");
|
||||
}
|
||||
|
|
@ -944,6 +945,9 @@ function toggleCompass() {
|
|||
const tr = `translate(80 80) scale(.25)`;
|
||||
d3.select("#rose").attr("transform", tr);
|
||||
compass.append("use").attr("xlink:href","#rose");
|
||||
// prolongate rose lines
|
||||
svg.select("g#rose > g#sL > line#sL1").attr("y1", -19000).attr("y2", 19000);
|
||||
svg.select("g#rose > g#sL > line#sL2").attr("x1", -19000).attr("x2", 19000);
|
||||
}
|
||||
} else {
|
||||
$('#compass').fadeOut();
|
||||
|
|
@ -1011,11 +1015,11 @@ function toggleMarkers() {
|
|||
function toggleLabels() {
|
||||
if (!layerIsOn("toggleLabels")) {
|
||||
turnButtonOn("toggleLabels");
|
||||
labels.attr("display", null)
|
||||
labels.style("display", null)
|
||||
invokeActiveZooming();
|
||||
} else {
|
||||
turnButtonOff("toggleLabels");
|
||||
labels.attr("display", "none");
|
||||
labels.style("display", "none");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -268,9 +268,9 @@ function drawScaleBar() {
|
|||
|
||||
// fit ScaleBar to map size
|
||||
function fitScaleBar() {
|
||||
if (!scaleBar.select("rect").size()) return;
|
||||
const px = isNaN(+barPosX.value) ? 99 : barPosX.value / 100;
|
||||
const py = isNaN(+barPosY.value) ? 99 : barPosY.value / 100;
|
||||
if (!scaleBar.select("rect").size() || scaleBar.style("display") === "none") return;
|
||||
const px = isNaN(+barPosX.value) ? .99 : barPosX.value / 100;
|
||||
const py = isNaN(+barPosY.value) ? .99 : barPosY.value / 100;
|
||||
const bbox = scaleBar.select("rect").node().getBBox();
|
||||
const x = rn(svgWidth * px - bbox.width + 10), y = rn(svgHeight * py - bbox.height + 20);
|
||||
scaleBar.attr("transform", `translate(${x},${y})`);
|
||||
|
|
|
|||
|
|
@ -27,17 +27,14 @@ function editNamesbase() {
|
|||
updateInputs();
|
||||
|
||||
$("#namesbaseEditor").dialog({
|
||||
title: "Namesbase Editor", width: 468,
|
||||
title: "Namesbase Editor", width: "42.5em",
|
||||
position: {my: "center", at: "center", of: "svg"}
|
||||
});
|
||||
|
||||
function createBasesList() {
|
||||
const select = document.getElementById("namesbaseSelect");
|
||||
select.innerHTML = "";
|
||||
nameBases.forEach(function(b, i) {
|
||||
const option = new Option(b.name, i);
|
||||
select.options.add(option);
|
||||
});
|
||||
nameBases.forEach((b, i) => select.options.add(new Option(b.name, i)));
|
||||
}
|
||||
|
||||
function updateInputs() {
|
||||
|
|
@ -130,7 +127,8 @@ function editNamesbase() {
|
|||
buttons: {
|
||||
Restore: function() {
|
||||
$(this).dialog("close");
|
||||
applyDefaultNamesData();
|
||||
nameBases = Names.getNameBases();
|
||||
nameBase = Names.getNameBase();
|
||||
createBasesList();
|
||||
updateInputs();
|
||||
Names.updateChains();
|
||||
|
|
@ -145,7 +143,7 @@ function editNamesbase() {
|
|||
const dataBlob = new Blob([data.join("\r\n")], {type:"text/plain"});
|
||||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
link.download = "namesbase" + Date.now() + ".txt";
|
||||
link.download = getFileName("Namesbase") + ".txt";
|
||||
link.href = url;
|
||||
link.click();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ function editNotes(id, name) {
|
|||
|
||||
// open a dialog
|
||||
$("#notesEditor").dialog({
|
||||
title: "Notes Editor", minWidth: Math.min(svgWidth, 400),
|
||||
title: "Notes Editor", minWidth: "40em",
|
||||
position: {my: "center", at: "center", of: "svg"}
|
||||
});
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ function editNotes(id, name) {
|
|||
const dataBlob = new Blob([legendString],{type:"text/plain"});
|
||||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
link.download = "notes" + Date.now() + ".txt";
|
||||
link.download = getFileName("Notes") + ".txt";
|
||||
link.href = url;
|
||||
link.click();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,9 @@ options.querySelector("div.tab").addEventListener("click", function(event) {
|
|||
|
||||
if (id === "styleTab") styleContent.style.display = "block"; else
|
||||
if (id === "optionsTab") optionsContent.style.display = "block"; else
|
||||
if (id === "toolsTab" && (!customization || customization === 10)) toolsContent.style.display = "block"; else
|
||||
if (id === "toolsTab" && customization && customization !== 10) customizationMenu.style.display = "block"; else
|
||||
if (id === "toolsTab") customization === 1
|
||||
? customizationMenu.style.display = "block"
|
||||
: toolsContent.style.display = "block"; else
|
||||
if (id === "aboutTab") aboutContent.style.display = "block";
|
||||
});
|
||||
|
||||
|
|
@ -343,17 +344,18 @@ styleClippingInput.addEventListener("change", function() {
|
|||
|
||||
styleGridType.addEventListener("change", function() {
|
||||
if (layerIsOn("toggleGrid")) drawGrid();
|
||||
calculateFriendlyGridSize();
|
||||
});
|
||||
|
||||
styleGridSize.addEventListener("input", function() {
|
||||
if (layerIsOn("toggleGrid")) drawGrid();
|
||||
styleGridSizeOutput.value = this.value;
|
||||
calculateFriendlyGridSize();
|
||||
});
|
||||
|
||||
function calculateFriendlyGridSize() {
|
||||
const size = styleGridSize.value * Math.cos(30 * Math.PI / 180) * 2;;
|
||||
const friendly = "(" + rn(size * distanceScaleInput.value) + " " + distanceUnitInput.value + ")";
|
||||
const square = styleGridType.value === "square";
|
||||
const size = square ? styleGridSize.value : styleGridSize.value * Math.cos(30 * Math.PI / 180) * 2;
|
||||
const friendly = `${rn(size * distanceScaleInput.value, 2)} ${distanceUnitInput.value}`;
|
||||
styleGridSizeFriendly.value = friendly;
|
||||
}
|
||||
|
||||
|
|
@ -584,6 +586,7 @@ styleStatesHaloOpacity.addEventListener("input", function() {
|
|||
|
||||
// request to restore default style on button click
|
||||
function askToRestoreDefaultStyle() {
|
||||
if (customization) {tip("Please exit the customization mode first", false, "error"); return;}
|
||||
alertMessage.innerHTML = "Are you sure you want to restore default style for all elements?";
|
||||
$("#alert").dialog({resizable: false, title: "Restore default style",
|
||||
buttons: {
|
||||
|
|
@ -600,9 +603,9 @@ function askToRestoreDefaultStyle() {
|
|||
// request a URL to image to be used as a texture
|
||||
function textureProvideURL() {
|
||||
alertMessage.innerHTML = `Provide an image URL to be used as a texture:
|
||||
<input id="textureURL" type="url" style="width: 254px" placeholder="http://www.example.com/image.jpg" oninput="fetchTextureURL(this.value)">
|
||||
<input id="textureURL" type="url" style="width: 24em" placeholder="http://www.example.com/image.jpg" oninput="fetchTextureURL(this.value)">
|
||||
<div style="border: 1px solid darkgrey; height: 144px; margin-top: 2px"><canvas id="preview" width="256px" height="144px"></canvas></div>`;
|
||||
$("#alert").dialog({resizable: false, title: "Load custom texture", width: 280,
|
||||
$("#alert").dialog({resizable: false, title: "Load custom texture", width: "26em",
|
||||
buttons: {
|
||||
Apply: function() {
|
||||
const name = textureURL.value.split("/").pop();
|
||||
|
|
@ -677,7 +680,8 @@ optionsContent.addEventListener("input", function(event) {
|
|||
else if (id === "neutralOutput") neutralInput.value = value;
|
||||
else if (id === "manorsInput") changeBurgsNumberSlider(value);
|
||||
else if (id === "religionsInput") religionsOutput.value = value;
|
||||
else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUIsize(value);
|
||||
else if (id === "uiSizeInput") uiSizeOutput.value = value;
|
||||
else if (id === "uiSizeOutput") changeUIsize(value);
|
||||
else if (id === "tooltipSizeInput" || id === "tooltipSizeOutput") changeTooltipSize(value);
|
||||
else if (id === "transparencyInput") changeDialogsTransparency(value);
|
||||
else if (id === "pngResolutionInput") pngResolutionOutput.value = value;
|
||||
|
|
@ -689,6 +693,7 @@ optionsContent.addEventListener("change", function(event) {
|
|||
const id = event.target.id, value = event.target.value;
|
||||
if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value);
|
||||
else if (id === "optionsSeed") generateMapWithSeed();
|
||||
else if (id === "uiSizeInput") changeUIsize(value);
|
||||
});
|
||||
|
||||
optionsContent.addEventListener("click", function(event) {
|
||||
|
|
@ -801,9 +806,10 @@ function changeBurgsNumberSlider(value) {
|
|||
}
|
||||
|
||||
function changeUIsize(value) {
|
||||
if (isNaN(+value) || +value > 4 || +value < .5) return;
|
||||
uiSizeInput.value = uiSizeOutput.value = value;
|
||||
document.getElementsByTagName("body")[0].style.fontSize = value * 11 + "px";
|
||||
document.getElementById("options").style.width = (value - 1) * 300 / 2 + 300 + "px";
|
||||
document.getElementById("options").style.width = value * 300 + "px";
|
||||
}
|
||||
|
||||
function changeTooltipSize(value) {
|
||||
|
|
@ -855,9 +861,11 @@ function applyStoredOptions() {
|
|||
if (localStorage.getItem("winds")) winds = localStorage.getItem("winds").split(",").map(w => +w);
|
||||
|
||||
changeDialogsTransparency(localStorage.getItem("transparency") || 15);
|
||||
if (localStorage.getItem("uiSize")) changeUIsize(localStorage.getItem("uiSize"));
|
||||
if (localStorage.getItem("tooltipSize")) changeTooltipSize(localStorage.getItem("tooltipSize"));
|
||||
if (localStorage.getItem("regions")) changeStatesNumber(localStorage.getItem("regions"));
|
||||
|
||||
if (localStorage.getItem("uiSize")) changeUIsize(localStorage.getItem("uiSize"));
|
||||
else changeUIsize(Math.max(Math.min(rn(mapWidthInput.value / 1280, 1), 2.5), 1));
|
||||
}
|
||||
|
||||
// randomize options if randomization is allowed (not locked)
|
||||
|
|
@ -885,7 +893,7 @@ function randomizeOptions() {
|
|||
const US = navigator.language === "en-US";
|
||||
const UK = navigator.language === "en-GB";
|
||||
if (!locked("distanceScale")) distanceScaleOutput.value = distanceScaleInput.value = gauss(3, 1, 1, 5);
|
||||
if (!stored("distanceUnit")) distanceUnitInput.value = distanceUnitOutput.value = US || UK ? "mi" : "km";
|
||||
if (!stored("distanceUnit")) distanceUnitInput.value = US || UK ? "mi" : "km";
|
||||
if (!stored("heightUnit")) heightUnit.value = US || UK ? "ft" : "m";
|
||||
if (!stored("temperatureScale")) temperatureScale.value = US ? "°F" : "°C";
|
||||
}
|
||||
|
|
@ -1004,7 +1012,7 @@ document.getElementById("sticked").addEventListener("click", function(event) {
|
|||
|
||||
function regeneratePrompt() {
|
||||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||
if (workingTime < 10) {regenerateMap(); return;}
|
||||
if (workingTime < 5) {regenerateMap(); return;}
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to generate a new map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
|
|
@ -1035,22 +1043,6 @@ function toggleSavePane() {
|
|||
}
|
||||
}
|
||||
|
||||
// async function saveDropbox() {
|
||||
// const filename = "fantasy_map_" + Date.now() + ".map";
|
||||
// const options = {
|
||||
// files: [{'url': '...', 'filename': 'fantasy_map.map'}],
|
||||
// success: function () {alert("Success! Files saved to your Dropbox.")},
|
||||
// progress: function (progress) {console.log(progress)},
|
||||
// cancel: function (cancel) {console.log(cancel)},
|
||||
// error: function (error) {console.log(error)}
|
||||
// };
|
||||
|
||||
// // working file: "https://dl.dropbox.com/s/llg93mwyonyzdmu/test.map?dl=1";
|
||||
// const dataBlob = await getMapData();
|
||||
// const URL = window.URL.createObjectURL(dataBlob);
|
||||
// Dropbox.save(URL, filename, options);
|
||||
// }
|
||||
|
||||
function toggleLoadPane() {
|
||||
if (loadDropdown.style.display === "block") {loadDropdown.style.display = "none"; return;}
|
||||
loadDropdown.style.display = "block";
|
||||
|
|
@ -1059,15 +1051,14 @@ function toggleLoadPane() {
|
|||
function loadURL() {
|
||||
const pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
|
||||
const inner = `Provide URL to a .map file:
|
||||
<input id="mapURL" type="url" style="width: 254px" placeholder="https://e-cloud.com/test.map">
|
||||
<input id="mapURL" type="url" style="width: 24em" placeholder="https://e-cloud.com/test.map">
|
||||
<br><i>Please note server should allow CORS for file to be loaded. If CORS is not allowed, save file to Dropbox and provide a direct link</i>`;
|
||||
alertMessage.innerHTML = inner;
|
||||
$("#alert").dialog({resizable: false, title: "Load map from URL", width: 280,
|
||||
$("#alert").dialog({resizable: false, title: "Load map from URL", width: "26em",
|
||||
buttons: {
|
||||
Load: function() {
|
||||
const value = mapURL.value;
|
||||
if (!pattern.test(value)) {tip("Please provide a valid URL", false, "error"); return;}
|
||||
closeDialogs();
|
||||
loadMapFromURL(value);
|
||||
$(this).dialog("close");
|
||||
},
|
||||
|
|
@ -1076,26 +1067,6 @@ function loadURL() {
|
|||
});
|
||||
}
|
||||
|
||||
// function loadDropbox() {
|
||||
// const options = {
|
||||
// success: function(file) {send_files(file)},
|
||||
// cancel: function() {},
|
||||
// linkType: "preview",
|
||||
// multiselect: false,
|
||||
// extensions:['.map'],
|
||||
// };
|
||||
// Dropbox.choose(options);
|
||||
|
||||
// function send_files(file) {
|
||||
// const subject = "Shared File Links";
|
||||
// let body = "";
|
||||
// for (let i=0; i < file.length; i++) {
|
||||
// body += file[i].name + "\n" + file[i].link + "\n\n";
|
||||
// }
|
||||
// location.href = 'mailto:coworker@example.com?Subject=' + escape(subject) + '&body='+ escape(body),'200','200';
|
||||
// }
|
||||
// }
|
||||
|
||||
// load map
|
||||
document.getElementById("mapToLoad").addEventListener("change", function() {
|
||||
const fileToLoad = this.files[0];
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ function editProvinces() {
|
|||
document.getElementById("provincesEditorRefresh").addEventListener("click", refreshProvincesEditor);
|
||||
document.getElementById("provincesFilterState").addEventListener("change", provincesEditorAddLines);
|
||||
document.getElementById("provincesPercentage").addEventListener("click", togglePercentageMode);
|
||||
document.getElementById("provincesChart").addEventListener("click", showChart);
|
||||
document.getElementById("provincesToggleLabels").addEventListener("click", toggleLabels);
|
||||
document.getElementById("provincesExport").addEventListener("click", downloadProvincesData);
|
||||
document.getElementById("provincesRemoveAll").addEventListener("click", removeAllProvinces);
|
||||
|
|
@ -106,15 +107,15 @@ function editProvinces() {
|
|||
const capital = p.burg ? pack.burgs[p.burg].name : '';
|
||||
const focused = defs.select("#fog #focusProvince"+p.i).size();
|
||||
lines += `<div class="states" data-id=${p.i} data-name=${p.name} data-form=${p.formName} data-color="${p.color}" data-capital="${capital}" data-state="${stateName}" data-area=${area} data-population=${population}>
|
||||
<svg data-tip="Province fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${p.color}" class="zoneFill"></svg>
|
||||
<svg data-tip="Province fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${p.color}" class="zoneFill"></svg>
|
||||
<input data-tip="Province name. Click and type to change" class="stateName" value="${p.name}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Click to re-generate province name" class="icon-arrows-cw stateName hoverButton placeholder"></span>
|
||||
<span data-tip="Click to open province COA in the Iron Arachne Heraldry Generator" class="icon-fleur pointer hide"></span>
|
||||
<input data-tip="Province form name. Click and type to change" class="stateForm" value="${p.formName}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="Province form name. Click and type to change" class="stateForm hide" value="${p.formName}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Click to re-generate form name" class="icon-arrows-cw stateForm hoverButton placeholder"></span>
|
||||
<span data-tip="Province capital. Click to zoom into view" class="icon-star-empty pointer hide ${p.burg?'':'placeholder'}"></span>
|
||||
<select data-tip="Province capital. Click to select from burgs within the state. No capital means the province is governed from the state capital" class="cultureBase hide ${p.burgs.length?'':'placeholder'}">${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ''}</select>
|
||||
<input data-tip="Province owner" class="provinceOwner" value="${stateName}" disabled hide">
|
||||
<input data-tip="Province owner" class="provinceOwner" value="${stateName}" disabled">
|
||||
<span data-tip="Province area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="Province area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
|
|
@ -151,17 +152,25 @@ function editProvinces() {
|
|||
|
||||
function provinceHighlightOn(event) {
|
||||
if (!customization) event.target.querySelectorAll(".hoverButton").forEach(el => el.classList.remove("placeholder"));
|
||||
|
||||
const province = +event.target.dataset.id;
|
||||
const el = body.querySelector(`div[data-id='${province}']`);
|
||||
if (el) el.classList.add("active");
|
||||
|
||||
if (!layerIsOn("toggleProvinces")) return;
|
||||
if (customization) return;
|
||||
const province = +event.target.dataset.id;
|
||||
const animate = d3.transition().duration(2000).ease(d3.easeSinIn);
|
||||
provs.select("#province"+province).raise().transition(animate).attr("stroke-width", 2.5).attr("stroke", "#d0240f");
|
||||
}
|
||||
|
||||
function provinceHighlightOff(event) {
|
||||
if (!customization) event.target.querySelectorAll(".hoverButton").forEach(el => el.classList.add("placeholder"));
|
||||
if (!layerIsOn("toggleProvinces")) return;
|
||||
|
||||
const province = +event.target.dataset.id;
|
||||
const el = body.querySelector(`div[data-id='${province}']`);
|
||||
if (el) el.classList.remove("active");
|
||||
|
||||
if (!layerIsOn("toggleProvinces")) return;
|
||||
provs.select("#province"+province).transition().attr("stroke-width", null).attr("stroke", null);
|
||||
}
|
||||
|
||||
|
|
@ -272,6 +281,119 @@ function editProvinces() {
|
|||
}
|
||||
}
|
||||
|
||||
function showChart() {
|
||||
// build hierarchy tree
|
||||
const states = pack.states.map(s => {
|
||||
return {id:s.i, state: s.i?0:null, color: s.i && s.color[0] === "#" ? d3.color(s.color).darker() : "#666"}
|
||||
});
|
||||
const provinces = pack.provinces.filter(p => p.i && !p.removed);
|
||||
provinces.forEach(p => p.id = p.i + states.length - 1);
|
||||
const data = states.concat(provinces);
|
||||
const root = d3.stratify().parentId(d => d.state)(data).sum(d => d.area);
|
||||
|
||||
const width = 300 + 300 * uiSizeOutput.value, height = 90 + 90 * uiSizeOutput.value;
|
||||
const margin = {top: 10, right: 10, bottom: 0, left: 10};
|
||||
const w = width - margin.left - margin.right;
|
||||
const h = height - margin.top - margin.bottom;
|
||||
const treeLayout = d3.treemap().size([w, h]).padding(2);
|
||||
|
||||
// prepare svg
|
||||
alertMessage.innerHTML = `<select id="provincesTreeType" style="display:block; margin-left:13px; font-size:11px">
|
||||
<option value="area" selected>Area</option>
|
||||
<option value="population">Total population</option>
|
||||
<option value="rural">Rural population</option>
|
||||
<option value="urban">Urban population</option>
|
||||
</select>`;
|
||||
alertMessage.innerHTML += `<div id='provinceInfo' class='chartInfo'>‍</div>`;
|
||||
const svg = d3.select("#alertMessage").insert("svg", "#provinceInfo").attr("id", "provincesTree")
|
||||
.attr("width", width).attr("height", height).attr("font-size", "10px");
|
||||
const graph = svg.append("g").attr("transform", `translate(10, 0)`);
|
||||
document.getElementById("provincesTreeType").addEventListener("change", updateChart);
|
||||
|
||||
treeLayout(root);
|
||||
|
||||
const node = graph.selectAll("g").data(root.leaves()).enter()
|
||||
.append("g").attr("data-id", d => d.data.i)
|
||||
.on("mouseenter", d => showInfo(event, d))
|
||||
.on("mouseleave", d => hideInfo(event, d));
|
||||
|
||||
function showInfo(ev, d) {
|
||||
d3.select(ev.target).select("rect").classed("selected", 1);
|
||||
const name = d.data.fullName;
|
||||
const state = pack.states[d.data.state].fullName;
|
||||
|
||||
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
|
||||
const area = d.data.area * (distanceScaleInput.value ** 2) + unit;
|
||||
const rural = rn(d.data.rural * populationRate.value);
|
||||
const urban = rn(d.data.urban * populationRate.value * urbanization.value);
|
||||
|
||||
const value = provincesTreeType.value === "area" ? "Area: " + area
|
||||
: provincesTreeType.value === "rural" ? "Rural population: " + si(rural)
|
||||
: provincesTreeType.value === "urban" ? "Urban population: " + si(urban)
|
||||
: "Population: " + si(rural + urban);
|
||||
|
||||
provinceInfo.innerHTML = `${name}. ${state}. ${value}`;
|
||||
provinceHighlightOn(ev);
|
||||
}
|
||||
|
||||
function hideInfo(ev) {
|
||||
provinceHighlightOff(ev);
|
||||
if (!document.getElementById("provinceInfo")) return;
|
||||
provinceInfo.innerHTML = "‍";
|
||||
d3.select(ev.target).select("rect").classed("selected", 0);
|
||||
}
|
||||
|
||||
node.append("rect").attr("stroke", d => d.parent.data.color)
|
||||
.attr("stroke-width", 1).attr("fill", d => d.data.color)
|
||||
.attr("x", d => d.x0).attr("y", d => d.y0)
|
||||
.attr("width", d => d.x1 - d.x0).attr("height", d => d.y1 - d.y0);
|
||||
|
||||
node.append("text").attr("dx", ".2em").attr("dy", "1em")
|
||||
.attr("x", d => d.x0).attr("y", d => d.y0);
|
||||
|
||||
function hideNonfittingLabels() {
|
||||
node.select("text").each(function(d) {
|
||||
this.innerHTML = d.data.name;
|
||||
let b = this.getBBox();
|
||||
if (b.y + b.height > d.y1 + 1) this.innerHTML = "";
|
||||
|
||||
for(let i=0; i < 15 && b.width > 0 && b.x + b.width > d.x1; i++) {
|
||||
if (this.innerHTML.length < 3) {this.innerHTML = ""; break;}
|
||||
this.innerHTML = this.innerHTML.slice(0, -2) + "…";
|
||||
b = this.getBBox();
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function updateChart() {
|
||||
const value = this.value === "area" ? d => d.area
|
||||
: this.value === "rural" ? d => d.rural
|
||||
: this.value === "urban" ? d => d.urban
|
||||
: d => d.rural + d.urban;
|
||||
|
||||
const newRoot = d3.stratify().parentId(d => d.state)(data).sum(value);
|
||||
node.data(treeLayout(newRoot).leaves())
|
||||
|
||||
node.select("rect").transition().duration(1500)
|
||||
.attr("x", d => d.x0).attr("y", d => d.y0)
|
||||
.attr("width", d => d.x1 - d.x0).attr("height", d => d.y1 - d.y0);
|
||||
|
||||
node.select("text").attr("opacity", 1).transition().duration(1500)
|
||||
.attr("x", d => d.x0).attr("y", d => d.y0);
|
||||
|
||||
setTimeout(hideNonfittingLabels, 2000);
|
||||
}
|
||||
|
||||
$("#alert").dialog({
|
||||
title: "Provinces chart", width: fitContent(),
|
||||
position: {my: "left bottom", at: "left+10 bottom-10", of: "svg"}, buttons: {},
|
||||
close: () => {alertMessage.innerHTML = "";}
|
||||
});
|
||||
|
||||
hideNonfittingLabels();
|
||||
}
|
||||
|
||||
function toggleLabels() {
|
||||
const hidden = provs.select("#provinceLabels").style("display") === "none";
|
||||
provs.select("#provinceLabels").style("display", `${hidden ? "block" : "none"}`);
|
||||
|
|
@ -291,6 +413,7 @@ function editProvinces() {
|
|||
document.getElementById("provincesManuallyButtons").style.display = "inline-block";
|
||||
|
||||
provincesEditor.querySelectorAll(".hide").forEach(el => el.classList.add("hidden"));
|
||||
provincesHeader.querySelector("div[data-sortby='state']").style.left = "7.7em";
|
||||
provincesFooter.style.display = "none";
|
||||
body.querySelectorAll("div > input, select, span, svg").forEach(e => e.style.pointerEvents = "none");
|
||||
$("#provincesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
|
||||
|
|
@ -399,6 +522,7 @@ function editProvinces() {
|
|||
document.getElementById("provincesManuallyButtons").style.display = "none";
|
||||
|
||||
provincesEditor.querySelectorAll(".hide:not(.show)").forEach(el => el.classList.remove("hidden"));
|
||||
provincesHeader.querySelector("div[data-sortby='state']").style.left = "22em";
|
||||
provincesFooter.style.display = "block";
|
||||
body.querySelectorAll("div > input, select, span, svg").forEach(e => e.style.pointerEvents = "all");
|
||||
if(!close) $("#provincesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
|
||||
|
|
@ -482,7 +606,7 @@ function editProvinces() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "provinces_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("Provinces") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ function editReliefIcon() {
|
|||
updateReliefSizeInput();
|
||||
|
||||
$("#reliefEditor").dialog({
|
||||
title: "Edit Relief Icons", resizable: false, width: 294,
|
||||
title: "Edit Relief Icons", resizable: false, width: "27em",
|
||||
position: {my: "left top", at: "left+10 top+10", of: "#map"},
|
||||
close: closeReliefEditor
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ function editReligions() {
|
|||
|
||||
const body = document.getElementById("religionsBody");
|
||||
const animate = d3.transition().duration(1500).ease(d3.easeSinIn);
|
||||
drawReligionCenters();
|
||||
refreshReligionsEditor();
|
||||
drawReligionCenters();
|
||||
|
||||
if (modules.editReligions) return;
|
||||
modules.editReligions = true;
|
||||
|
|
@ -25,6 +25,7 @@ function editReligions() {
|
|||
document.getElementById("religionsEditorRefresh").addEventListener("click", refreshReligionsEditor);
|
||||
document.getElementById("religionsLegend").addEventListener("click", toggleLegend);
|
||||
document.getElementById("religionsPercentage").addEventListener("click", togglePercentageMode);
|
||||
document.getElementById("religionsHeirarchy").addEventListener("click", showHierarchy);
|
||||
document.getElementById("religionsExtinct").addEventListener("click", toggleExtinct);
|
||||
document.getElementById("religionsManually").addEventListener("click", enterReligionsManualAssignent);
|
||||
document.getElementById("religionsManuallyApply").addEventListener("click", applyReligionsManualAssignent);
|
||||
|
|
@ -39,11 +40,12 @@ function editReligions() {
|
|||
|
||||
function religionsCollectStatistics() {
|
||||
const cells = pack.cells, religions = pack.religions;
|
||||
religions.forEach(r => r.area = r.rural = r.urban = 0);
|
||||
religions.forEach(r => r.cells = r.area = r.rural = r.urban = 0);
|
||||
|
||||
for (const i of cells.i) {
|
||||
if (cells.h[i] < 20) continue;
|
||||
const r = cells.religion[i];
|
||||
religions[r].cells += 1;
|
||||
religions[r].area += cells.area[i];
|
||||
religions[r].rural += cells.pop[i];
|
||||
if (cells.burg[i]) religions[r].urban += pack.burgs[cells.burg[i]].population;
|
||||
|
|
@ -62,7 +64,7 @@ function editReligions() {
|
|||
const rural = r.rural * populationRate.value;
|
||||
const urban = r.urban * populationRate.value * urbanization.value;
|
||||
const population = rn(rural + urban);
|
||||
if (r.i && !population && body.dataset.extinct !== "show") continue; // hide extinct religions
|
||||
if (r.i && !r.cells && body.dataset.extinct !== "show") continue; // hide extinct religions
|
||||
const populationTip = `Believers: ${si(population)}; Rural areas: ${si(rural)}; Urban areas: ${si(urban)}`;
|
||||
totalArea += area;
|
||||
totalPopulation += population;
|
||||
|
|
@ -70,7 +72,7 @@ function editReligions() {
|
|||
if (r.i) {
|
||||
lines += `<div class="states religions" data-id=${r.i} data-name="${r.name}" data-color="${r.color}" data-area=${area}
|
||||
data-population=${population} data-type=${r.type} data-form=${r.form} data-deity="${r.deity?r.deity:''}" data-expansionism=${r.expansionism}>
|
||||
<svg data-tip="Religion fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${r.color}" class="zoneFill"></svg>
|
||||
<svg data-tip="Religion fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${r.color}" class="zoneFill"></svg>
|
||||
<input data-tip="Religion name. Click and type to change" class="religionName" value="${r.name}" autocorrect="off" spellcheck="false">
|
||||
<select data-tip="Religion type" class="religionType">${getTypeOptions(r.type)}</select>
|
||||
<input data-tip="Religion form" class="religionForm hide" value="${r.form}" autocorrect="off" spellcheck="false">
|
||||
|
|
@ -136,18 +138,44 @@ function editReligions() {
|
|||
}
|
||||
|
||||
function religionHighlightOn(event) {
|
||||
const religion = +event.target.dataset.id;
|
||||
const info = document.getElementById("religionInfo");
|
||||
if (info) {
|
||||
d3.select("#religionHierarchy").select("g[data-id='"+religion+"'] > path").classed("selected", 1);
|
||||
const r = pack.religions[religion];
|
||||
const type = r.name.includes(r.type) ? ""
|
||||
: r.type === "Folk" || r.type === "Organized"
|
||||
? ". " + r.type + " religion" : ". " + r.type;
|
||||
const form = r.form === r.type || r.name.includes(r.form) ? "" : ". " + r.form;
|
||||
const rural = r.rural * populationRate.value;
|
||||
const urban = r.urban * populationRate.value * urbanization.value;
|
||||
const population = rural + urban > 0 ? ". " + si(rn(rural + urban)) + " believers" : ". Extinct";
|
||||
const hint = ". Drag to change the origin";
|
||||
info.innerHTML = `${r.name}${type}${form}${population}${hint}`;
|
||||
}
|
||||
|
||||
const el = body.querySelector(`div[data-id='${religion}']`);
|
||||
if (el) el.classList.add("active");
|
||||
|
||||
if (!layerIsOn("toggleReligions")) return;
|
||||
if (customization) return;
|
||||
const religion = +event.target.dataset.id;
|
||||
relig.select("#religion"+religion).raise().transition(animate).attr("stroke-width", 2.5).attr("stroke", "#c13119");
|
||||
debug.select("#cultureCenter"+religion).raise().transition(animate).attr("r", 8).attr("stroke", "#c13119");
|
||||
debug.select("#religionsCenter"+religion).raise().transition(animate).attr("r", 8).attr("stroke-width", 2).attr("stroke", "#c13119");
|
||||
}
|
||||
|
||||
function religionHighlightOff(event) {
|
||||
if (!layerIsOn("toggleReligions")) return;
|
||||
const religion = +event.target.dataset.id;
|
||||
const info = document.getElementById("religionInfo");
|
||||
if (info) {
|
||||
d3.select("#religionHierarchy").select("g[data-id='"+religion+"'] > path").classed("selected", 0);
|
||||
info.innerHTML = "‍";
|
||||
}
|
||||
|
||||
const el = body.querySelector(`div[data-id='${religion}']`)
|
||||
if (el) el.classList.remove("active");
|
||||
|
||||
relig.select("#religion"+religion).transition().attr("stroke-width", null).attr("stroke", null);
|
||||
debug.select("#cultureCenter"+religion).transition().attr("r", 6).attr("stroke", null);
|
||||
debug.select("#religionsCenter"+religion).transition().attr("r", 4).attr("stroke-width", 1.2).attr("stroke", null);
|
||||
}
|
||||
|
||||
function religionChangeColor() {
|
||||
|
|
@ -159,7 +187,7 @@ function editReligions() {
|
|||
el.setAttribute("fill", fill);
|
||||
pack.religions[religion].color = fill;
|
||||
relig.select("#religion"+religion).attr("fill", fill);
|
||||
debug.select("#cultureCenter"+religion).attr("fill", fill);
|
||||
debug.select("#religionsCenter"+religion).attr("fill", fill);
|
||||
}
|
||||
|
||||
openPicker(currentFill, callback);
|
||||
|
|
@ -202,28 +230,33 @@ function editReligions() {
|
|||
if (customization) return;
|
||||
const religion = +this.parentNode.dataset.id;
|
||||
relig.select("#religion"+religion).remove();
|
||||
debug.select("#cultureCenter"+religion).remove();
|
||||
debug.select("#religionsCenter"+religion).remove();
|
||||
|
||||
pack.cells.religion.forEach((r, i) => {if(r === religion) pack.cells.religion[i] = 0;});
|
||||
pack.religions[religion].removed = true;
|
||||
const origin = pack.religions[religion].origin;
|
||||
pack.religions.forEach(r => {if(r.origin === religion) r.origin = origin;});
|
||||
|
||||
refreshReligionsEditor();
|
||||
}
|
||||
|
||||
function drawReligionCenters() {
|
||||
const tooltip = "Drag to move the religion center (it won't affect religions distribution)";
|
||||
debug.select("#religionCenters").remove();
|
||||
const religionCenters = debug.append("g").attr("id", "religionCenters")
|
||||
.attr("stroke-width", 2).attr("stroke", "#444444").style("cursor", "move");
|
||||
.attr("stroke-width", 1.2).attr("stroke", "#444444").style("cursor", "move");
|
||||
|
||||
const data = pack.religions.filter(r => r.center && !r.removed);
|
||||
const data = pack.religions.filter(r => r.i && r.center && r.cells && !r.removed);
|
||||
religionCenters.selectAll("circle").data(data).enter().append("circle")
|
||||
.attr("id", d => "cultureCenter"+d.i).attr("data-id", d => d.i)
|
||||
.attr("r", 6).attr("fill", d => pack.religions[d.i].color)
|
||||
.attr("id", d => "religionsCenter"+d.i).attr("data-id", d => d.i)
|
||||
.attr("r", 4).attr("fill", d => d.color)
|
||||
.attr("cx", d => pack.cells.p[d.center][0]).attr("cy", d => pack.cells.p[d.center][1])
|
||||
.on("mouseenter", d => {tip(tooltip, true); body.querySelector(`div[data-id='${d.i}']`).classList.add("selected"); religionHighlightOn(event);})
|
||||
.on("mouseleave", d => {tip('', true); body.querySelector(`div[data-id='${d.i}']`).classList.remove("selected"); religionHighlightOff(event);})
|
||||
.call(d3.drag().on("start", religionCenterDrag));
|
||||
.on("mouseenter", d => {
|
||||
tip(d.name+ ". Drag to move the religion center", true);
|
||||
religionHighlightOn(event);
|
||||
}).on("mouseleave", d => {
|
||||
tip('', true);
|
||||
religionHighlightOff(event);
|
||||
}).call(d3.drag().on("start", religionCenterDrag));
|
||||
}
|
||||
|
||||
function religionCenterDrag() {
|
||||
|
|
@ -259,6 +292,87 @@ function editReligions() {
|
|||
}
|
||||
}
|
||||
|
||||
function showHierarchy() {
|
||||
// build hierarchy tree
|
||||
pack.religions[0].origin = null;
|
||||
const religions = pack.religions.filter(r => !r.removed);
|
||||
const root = d3.stratify().id(d => d.i).parentId(d => d.origin)(religions);
|
||||
const treeWidth = root.leaves().length;
|
||||
const treeHeight = root.height;
|
||||
const width = treeWidth * 40, height = treeHeight * 60;
|
||||
|
||||
const margin = {top: 10, right: 10, bottom: -5, left: 10};
|
||||
const w = width - margin.left - margin.right;
|
||||
const h = height + 30 - margin.top - margin.bottom;
|
||||
const treeLayout = d3.tree().size([w, h]);
|
||||
|
||||
// prepare svg
|
||||
alertMessage.innerHTML = "<div id='religionInfo' class='chartInfo'>‍</div>";
|
||||
const svg = d3.select("#alertMessage").insert("svg", "#religionInfo").attr("id", "religionHierarchy")
|
||||
.attr("width", width).attr("height", height).style("text-anchor", "middle");
|
||||
const graph = svg.append("g").attr("transform", `translate(10, -45)`);
|
||||
const links = graph.append("g").attr("fill", "none").attr("stroke", "#aaaaaa");
|
||||
const nodes = graph.append("g");
|
||||
|
||||
renderTree();
|
||||
function renderTree() {
|
||||
treeLayout(root);
|
||||
links.selectAll('path').data(root.links()).enter()
|
||||
.append('path').attr("d", d => {return "M" + d.source.x + "," + d.source.y
|
||||
+ "C" + d.source.x + "," + (d.source.y * 3 + d.target.y) / 4
|
||||
+ " " + d.target.x + "," + (d.source.y * 2 + d.target.y) / 3
|
||||
+ " " + d.target.x + "," + d.target.y;});
|
||||
|
||||
const node = nodes.selectAll('g').data(root.descendants()).enter()
|
||||
.append('g').attr("data-id", d => d.data.i).attr("stroke", "#333333")
|
||||
.attr("transform", d => `translate(${d.x}, ${d.y})`)
|
||||
.on("mouseenter", () => religionHighlightOn(event))
|
||||
.on("mouseleave", () => religionHighlightOff(event))
|
||||
.call(d3.drag().on("start", d => dragToReorigin(d)));
|
||||
|
||||
node.append("path").attr("d", d => {
|
||||
if (d.data.type === "Folk") return "M11.3,0A11.3,11.3,0,1,1,-11.3,0A11.3,11.3,0,1,1,11.3,0"; else // circle
|
||||
if (d.data.type === "Heresy") return "M0,-14L14,0L0,14L-14,0Z"; else // diamond
|
||||
if (d.data.type === "Cult") return "M-6.5,-11.26l13,0l6.5,11.26l-6.5,11.26l-13,0l-6.5,-11.26Z"; else // hex
|
||||
if (!d.data.i) return "M5,0A5,5,0,1,1,-5,0A5,5,0,1,1,5,0"; else // small circle
|
||||
return "M-11,-11h22v22h-22Z"; // square
|
||||
}).attr("fill", d => d.data.i ? d.data.color : "#ffffff")
|
||||
.attr("stroke-dasharray", d => d.data.cells ? "null" : "1");
|
||||
|
||||
node.append("text").attr("dy", ".35em").text(d => d.data.i ? d.data.code : '');
|
||||
}
|
||||
|
||||
$("#alert").dialog({
|
||||
title: "Religions tree", width: fitContent(), resizable: false,
|
||||
position: {my: "left center", at: "left+10 center", of: "svg"}, buttons: {},
|
||||
close: () => {alertMessage.innerHTML = "";}
|
||||
});
|
||||
|
||||
function dragToReorigin(d) {
|
||||
console.log("dragToReorigin");
|
||||
const originLine = graph.append("path")
|
||||
.attr("class", "dragLine").attr("d", `M${d.x},${d.y}L${d.x},${d.y}`);
|
||||
|
||||
d3.event.on("drag", () => {
|
||||
originLine.attr("d", `M${d.x},${d.y}L${d3.event.x},${d3.event.y}`)
|
||||
});
|
||||
|
||||
d3.event.on("end", () => {
|
||||
originLine.remove();
|
||||
const selected = graph.select("path.selected");
|
||||
if (!selected.size()) return;
|
||||
const religion = d.data.i;
|
||||
const oldOrigin = d.data.origin;
|
||||
let newOrigin = selected.datum().data.i;
|
||||
if (newOrigin == oldOrigin) return; // already a child of the selected node
|
||||
if (newOrigin == religion) newOrigin = 0; // move to top
|
||||
if (newOrigin && d.descendants().some(node => node.id == newOrigin)) return; // cannot be a child of its own child
|
||||
pack.religions[religion].origin = d.data.origin = newOrigin; // change data
|
||||
showHierarchy() // update hierarchy
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleExtinct() {
|
||||
body.dataset.extinct = body.dataset.extinct !== "show" ? "show" : "hide";
|
||||
religionsEditorAddLines();
|
||||
|
|
@ -354,6 +468,7 @@ function editReligions() {
|
|||
if (changed.size()) {
|
||||
drawReligions();
|
||||
refreshReligionsEditor();
|
||||
drawReligionCenters();
|
||||
}
|
||||
exitReligionsManualAssignment();
|
||||
}
|
||||
|
|
@ -402,10 +517,11 @@ function editReligions() {
|
|||
if (occupied) {tip("This cell is already a religion center. Please select a different cell", false, "error"); return;}
|
||||
|
||||
if (d3.event.shiftKey === false) exitAddReligionMode();
|
||||
|
||||
Religions.add(center);
|
||||
|
||||
drawReligions();
|
||||
refreshReligionsEditor();
|
||||
drawReligionCenters();
|
||||
religionsEditorAddLines();
|
||||
}
|
||||
|
||||
function downloadReligionsData() {
|
||||
|
|
@ -427,7 +543,7 @@ function editReligions() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "religions_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("Religions") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
|
|||
|
|
@ -91,24 +91,24 @@ function editStates() {
|
|||
<span class="icon-star-empty placeholder hide"></span>
|
||||
<input class="stateCapital placeholder hide">
|
||||
<select class="stateCulture placeholder hide">${getCultureOptions(0)}</select>
|
||||
<select class="cultureType ${hidden} placeholder show hide">${getTypeOptions(0)}</select>
|
||||
<span class="icon-resize-full ${hidden} placeholder show hide"></span>
|
||||
<input class="statePower ${hidden} placeholder show hide" type="number" value=0>
|
||||
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
||||
<span data-tip="Burgs count" style="padding-right: 1px" class="icon-dot-circled hide"></span>
|
||||
<div data-tip="Burgs count" class="stateBurgs hide">${s.burgs}</div>
|
||||
<span data-tip="State area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="State area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<select class="cultureType ${hidden} placeholder show hide">${getTypeOptions(0)}</select>
|
||||
<span class="icon-resize-full ${hidden} placeholder show hide"></span>
|
||||
<input class="statePower ${hidden} placeholder show hide" type="number" value=0>
|
||||
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
||||
</div>`;
|
||||
continue;
|
||||
}
|
||||
const capital = pack.burgs[s.capital].name;
|
||||
lines += `<div class="states" data-id=${s.i} data-name="${s.name}" data-form="${s.formName}" data-capital="${capital}" data-color="${s.color}" data-cells=${s.cells}
|
||||
data-area=${area} data-population=${population} data-burgs=${s.burgs} data-culture=${pack.cultures[s.culture].name} data-type=${s.type} data-expansionism=${s.expansionism}>
|
||||
<svg data-tip="State fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${s.color}" class="zoneFill"></svg>
|
||||
<svg data-tip="State fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${s.color}" class="zoneFill"></svg>
|
||||
<input data-tip="State name. Click and type to change" class="stateName" value="${s.name}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Click to re-generate name" class="icon-arrows-cw stateName hoverButton placeholder"></span>
|
||||
<span data-tip="Click to open state COA in the Iron Arachne Heraldry Generator" class="icon-fleur pointer hide"></span>
|
||||
|
|
@ -117,17 +117,17 @@ function editStates() {
|
|||
<span data-tip="State capital. Click to zoom into view" class="icon-star-empty pointer hide"></span>
|
||||
<input data-tip="Capital name. Click and type to rename" class="stateCapital hide" value="${capital}" autocorrect="off" spellcheck="false"/>
|
||||
<select data-tip="Dominant culture. Click to change" class="stateCulture hide">${getCultureOptions(s.culture)}</select>
|
||||
<select data-tip="State type. Click to change" class="cultureType ${hidden} show hide">${getTypeOptions(s.type)}</select>
|
||||
<span data-tip="State expansionism" class="icon-resize-full ${hidden} show hide"></span>
|
||||
<input data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value" class="statePower ${hidden} show hide" type="number" min=0 max=99 step=.1 value=${s.expansionism}>
|
||||
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
||||
<span data-tip="Burgs count" style="padding-right: 1px" class="icon-dot-circled hide"></span>
|
||||
<div data-tip="Burgs count" class="stateBurgs hide">${s.burgs}</div>
|
||||
<span data-tip="State area" style="padding-right: 4px" class="icon-map-o hide"></span>
|
||||
<div data-tip="State area" class="biomeArea hide">${si(area) + unit}</div>
|
||||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<select data-tip="State type. Defines growth model. Click to change" class="cultureType ${hidden} show hide">${getTypeOptions(s.type)}</select>
|
||||
<span data-tip="State expansionism" class="icon-resize-full ${hidden} show hide"></span>
|
||||
<input data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value" class="statePower ${hidden} show hide" type="number" min=0 max=99 step=.1 value=${s.expansionism}>
|
||||
<span data-tip="Cells count" class="icon-check-empty ${hidden} show hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells ${hidden} show hide">${s.cells}</div>
|
||||
<span data-tip="Toggle state focus" class="icon-pin ${focused?'':' inactive'} hide"></span>
|
||||
<span data-tip="Remove the state" class="icon-trash-empty hide"></span>
|
||||
</div>`;
|
||||
|
|
@ -690,7 +690,7 @@ function editStates() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "states_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("States") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
|
|
|
|||
|
|
@ -30,14 +30,15 @@ toolsContent.addEventListener("click", function(event) {
|
|||
Proceed: function() {processFeatureRegeneration(button); $(this).dialog("close");},
|
||||
Cancel: function() {$(this).dialog("close");}
|
||||
},
|
||||
create: function() {
|
||||
open: function() {
|
||||
const pane = $(this).dialog("widget").find(".ui-dialog-buttonpane");
|
||||
$('<input id="dontAsk" class="checkbox" type="checkbox"><label for="dontAsk" class="checkbox-label dontAsk"><i>do not ask again</i></label>').prependTo(pane);
|
||||
$('<span><input id="dontAsk" class="checkbox" type="checkbox"><label for="dontAsk" class="checkbox-label dontAsk"><i>do not ask again</i></label><span>').prependTo(pane);
|
||||
},
|
||||
close: function() {
|
||||
const box = $(this).dialog("widget").find(".checkbox")[0];
|
||||
if (!box) return;
|
||||
if (box.checked) sessionStorage.setItem("regenerateFeatureDontAsk", true);
|
||||
$(this).dialog("destroy");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -59,7 +60,8 @@ function processFeatureRegeneration(button) {
|
|||
if (button === "regenerateBurgs") regenerateBurgs(); else
|
||||
if (button === "regenerateStates") regenerateStates(); else
|
||||
if (button === "regenerateProvinces") regenerateProvinces(); else
|
||||
if (button === "regenerateReligions") regenerateReligions();
|
||||
if (button === "regenerateReligions") regenerateReligions(); else
|
||||
if (button === "regenerateMarkers") regenerateMarkers();
|
||||
}
|
||||
|
||||
function regenerateRivers() {
|
||||
|
|
@ -199,6 +201,11 @@ function regenerateReligions() {
|
|||
if (!layerIsOn("toggleReligions")) toggleReligions(); else drawReligions();
|
||||
}
|
||||
|
||||
function regenerateMarkers() {
|
||||
markers.selectAll("use").remove();
|
||||
addMarkers(gauss(1, .5, .3, 5, 2));
|
||||
}
|
||||
|
||||
function unpressClickToAddButton() {
|
||||
addFeature.querySelectorAll("button.pressed").forEach(b => b.classList.remove("pressed"));
|
||||
restoreDefaultEvents();
|
||||
|
|
@ -340,7 +347,7 @@ function addRiverOnClick() {
|
|||
alertMessage.innerHTML = `<p>Heightmap is depressed and the system had to change the heightmap to allow water flux.</p>
|
||||
Would you like to <i>keep</i> the changes or <i>restore</i> the initial heightmap?`;
|
||||
|
||||
$("#alert").dialog({resizable: false, title: "Heightmap is changed", width: 300, modal: true,
|
||||
$("#alert").dialog({resizable: false, title: "Heightmap is changed", width: "30em", modal: true,
|
||||
buttons: {
|
||||
Keep: function() {$(this).dialog("close");},
|
||||
Restore: function() {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ function editUnits() {
|
|||
document.getElementById("distanceUnitInput").addEventListener("change", changeDistanceUnit);
|
||||
document.getElementById("distanceScaleOutput").addEventListener("input", changeDistanceScale);
|
||||
document.getElementById("distanceScaleInput").addEventListener("change", changeDistanceScale);
|
||||
document.getElementById("distanceScaleInput").addEventListener("mouseenter", hideDistanceUnitOutput);
|
||||
document.getElementById("distanceScaleInput").addEventListener("mouseleave", showDistanceUnitOutput);
|
||||
document.getElementById("areaUnit").addEventListener("change", () => lock("areaUnit"));
|
||||
document.getElementById("heightUnit").addEventListener("change", changeHeightUnit);
|
||||
document.getElementById("heightExponentInput").addEventListener("input", changeHeightExponent);
|
||||
|
|
@ -45,10 +43,8 @@ function editUnits() {
|
|||
if (this.value === "custom_name") {
|
||||
const custom = prompt("Provide a custom name for distance unit");
|
||||
if (custom) this.options.add(new Option(custom, custom, false, true));
|
||||
else {this.value = document.getElementById("distanceUnitOutput").innerHTML; return;};
|
||||
}
|
||||
|
||||
document.getElementById("distanceUnitOutput").innerHTML = this.value;
|
||||
lock("distanceUnit");
|
||||
drawScaleBar();
|
||||
calculateFriendlyGridSize();
|
||||
|
|
@ -71,9 +67,6 @@ function editUnits() {
|
|||
calculateFriendlyGridSize();
|
||||
}
|
||||
|
||||
function hideDistanceUnitOutput() {document.getElementById("distanceUnitOutput").style.opacity = .2;}
|
||||
function showDistanceUnitOutput() {document.getElementById("distanceUnitOutput").style.opacity = 1;}
|
||||
|
||||
function changeHeightUnit() {
|
||||
if (this.value === "custom_name") {
|
||||
const custom = prompt("Provide a custom name for height unit");
|
||||
|
|
@ -163,7 +156,7 @@ function editUnits() {
|
|||
// units
|
||||
const US = navigator.language === "en-US";
|
||||
const UK = navigator.language === "en-GB";
|
||||
distanceUnitInput.value = distanceUnitOutput.value = US || UK ? "mi" : "km";
|
||||
distanceUnitInput.value = US || UK ? "mi" : "km";
|
||||
heightUnit.value = US || UK ? "ft" : "m";
|
||||
temperatureScale.value = US ? "°F" : "°C";
|
||||
areaUnit.value = "square";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
function editWorld() {
|
||||
if (customization) return;
|
||||
$("#worldConfigurator").dialog({title: "Configure World", resizable: false, width: 460,
|
||||
$("#worldConfigurator").dialog({title: "Configure World", resizable: false, width: "42em",
|
||||
buttons: {
|
||||
"Whole World": () => applyPreset(100, 50),
|
||||
"Northern": () => applyPreset(33, 25),
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ function editZones() {
|
|||
const focused = defs.select("#fog #focus"+this.id).size();
|
||||
|
||||
lines += `<div class="states" data-id="${this.id}" data-fill="${fill}" data-description="${description}" data-cells=${c.length} data-area=${area} data-population=${population}>
|
||||
<svg data-tip="Zone fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${fill}" class="zoneFill"></svg>
|
||||
<svg data-tip="Zone fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${fill}" class="zoneFill"></svg>
|
||||
<input data-tip="Zone description. Click and type to change" class="religionName" value="${description}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells hide">${c.length}</div>
|
||||
|
|
@ -310,7 +310,7 @@ function editZones() {
|
|||
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
|
||||
|
||||
const line = `<div class="states" data-id="${id}" data-fill="${fill}" data-description="${description}" data-cells=0 data-area=0 data-population=0>
|
||||
<svg data-tip="Zone fill style. Click to change" width="9" height="9" style="margin-bottom:-1px"><rect x="0" y="0" width="9" height="9" fill="${fill}" class="zoneFill"></svg>
|
||||
<svg data-tip="Zone fill style. Click to change" width=".9em" height=".9em" style="margin-bottom:-1px"><rect x="0" y="0" width="100%" height="100%" fill="${fill}" class="zoneFill"></svg>
|
||||
<input data-tip="Zone description. Click and type to change" class="religionName" value="${description}" autocorrect="off" spellcheck="false">
|
||||
<span data-tip="Cells count" class="icon-check-empty hide"></span>
|
||||
<div data-tip="Cells count" class="stateCells hide">0</div>
|
||||
|
|
@ -345,10 +345,10 @@ function editZones() {
|
|||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "zones_data" + Date.now() + ".csv";
|
||||
link.download = getFileName("Zones") + ".csv";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
}
|
||||
|
||||
function toggleEraseMode() {
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ function getRandomColor() {
|
|||
|
||||
// mix a color with a random color
|
||||
function getMixedColor(color, mix = .2, bright = .3) {
|
||||
const c = color[0] === "#" ? color : getRandomColor(); // if provided color is not hex (e.g. harching), generate random one
|
||||
const c = color && color[0] === "#" ? color : getRandomColor(); // if provided color is not hex (e.g. harching), generate random one
|
||||
return d3.color(d3.interpolate(c, getRandomColor())(mix)).brighter(bright).hex();
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +478,7 @@ function analizeNamesbase() {
|
|||
if (string[i] === string[i-1]) doubleArray[string[i]]++;
|
||||
}
|
||||
for (const l in doubleArray) {if(doubleArray[l] > size/35) double += l;}
|
||||
const multi = rn(d3.mean(d.map(n => (n.match(/ /g)||[]).length)),2);
|
||||
const multi = rn(d3.mean(d.map(n => (n.match(/ /g)||[]).length-1)),2);
|
||||
result.push({name:b.name, size, min, max, mean, median, common, double, multi});
|
||||
});
|
||||
console.table(result);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue