From 9d83025db3b888a414537f9c3bac29ca097d4889 Mon Sep 17 00:00:00 2001 From: carnotcrash2 Date: Tue, 11 Jun 2024 18:25:28 +1000 Subject: [PATCH 1/4] Quechua namesbase fix - see reddit (#1081) https://www.reddit.com/r/FantasyMapGenerator/comments/1dcy4ux/error_in_quechua_namesbase/ fixed: added "carapo" as a seperate entry and removed ".carapo" from "pacaycasa.carapo" idk if this was intended to be double-barreled in some way (pacaycasa-carapo or pacaycasa carapo) but assumed not given the rest of the namesbase. --- modules/names-generator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/names-generator.js b/modules/names-generator.js index 0ba44ed7..52bea286 100644 --- a/modules/names-generator.js +++ b/modules/names-generator.js @@ -290,7 +290,7 @@ window.Names = (function () { {name: "Iranian", i: 24, min: 5, max: 11, d: "", m: .1, b: "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,Kahrizak,Kahriz Sang,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"}, {name: "Hawaiian", i: 25, min: 5, max: 10, d: "auo", m: 1, b: "Aapueo,Ahoa,Ahuakaio,Ahupau,Alaakua,Alae,Alaeloa,Alamihi,Aleamai,Alena,Alio,Aupokopoko,Halakaa,Haleu,Haliimaile,Hamoa,Hanakaoo,Hanaulu,Hanawana,Hanehoi,Haou,Hikiaupea,Hokuula,Honohina,Honokahua,Honokeana,Honokohau,Honolulu,Honomaele,Hononana,Honopou,Hoolawa,Huelo,Kaalaea,Kaapahu,Kaeo,Kahalehili,Kahana,Kahuai,Kailua,Kainehe,Kakalahale,Kakanoni,Kalenanui,Kaleoaihe,Kalialinui,Kalihi,Kalimaohe,Kaloi,Kamani,Kamehame,Kanahena,Kaniaula,Kaonoulu,Kapaloa,Kapohue,Kapuaikini,Kapunakea,Kauau,Kaulalo,Kaulanamoa,Kauluohana,Kaumakani,Kaumanu,Kaunauhane,Kaupakulua,Kawaloa,Keaa,Keaaula,Keahua,Keahuapono,Kealahou,Keanae,Keauhou,Kelawea,Keokea,Keopuka,Kikoo,Kipapa,Koakupuna,Koali,Kolokolo,Kopili,Kou,Kualapa,Kuhiwa,Kuholilea,Kuhua,Kuia,Kuikui,Kukoae,Kukohia,Kukuiaeo,Kukuipuka,Kukuiula,Kulahuhu,Lapakea,Lapueo,Launiupoko,Lole,Maalo,Mahinahina,Mailepai,Makaakini,Makaalae,Makaehu,Makaiwa,Makaliua,Makapipi,Makapuu,Maluaka,Manawainui,Mehamenui,Moalii,Moanui,Mohopili,Mokae,Mokuia,Mokupapa,Mooiki,Mooloa,Moomuku,Muolea,Nakaaha,Nakalepo,Nakaohu,Nakapehu,Nakula,Napili,Niniau,Nuu,Oloewa,Olowalu,Omaopio,Onau,Onouli,Opaeula,Opana,Opikoula,Paakea,Paeahu,Paehala,Paeohi,Pahoa,Paia,Pakakia,Palauea,Palemo,Paniau,Papaaea,Papaanui,Papaauhau,Papaka,Papauluana,Pauku,Paunau,Pauwalu,Pauwela,Pohakanele,Polaiki,Polanui,Polapola,Poopoo,Poponui,Poupouwela,Puahoowali,Puakea,Puako,Pualaea,Puehuehu,Pueokauiki,Pukaauhuhu,Pukuilua,Pulehu,Puolua,Puou,Puuhaehae,Puuiki,Puuki,Puulani,Puunau,Puuomaile,Uaoa,Uhao,Ukumehame,Ulaino,Ulumalu,Wahikuli,Waianae,Waianu,Waiawa,Waiehu,Waieli,Waikapu,Wailamoa,Wailaulau,Wainee,Waiohole,Waiohonu,Waiohuli,Waiokama,Waiokila,Waiopai,Waiopua,Waipao,Waipionui,Waipouli"}, {name: "Karnataka", i: 26, min: 5, max: 11, d: "tnl", m: 0, b: "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"}, - {name: "Quechua", i: 27, min: 6, max: 12, d: "l", m: 0, b: "Alpahuaycco,Anchihuay,Anqea,Apurimac,Arequipa,Atahuallpa,Atawalpa,Atico,Ayacucho,Ayahuanco,Ayllu,Cajamarca,Canayre,Canchacancha,Carhuac,Carhuacatac,Cashan,Caullaraju,Caxamalca,Cayesh,Ccahuasno,Ccarhuacc,Ccopayoc,Chacchapunta,Chacraraju,Challhuamayo,Champara,Chanchan,Chekiacraju,Chillihua,Chinchey,Chontah,Chopicalqui,Chucuito,Chuito,Chullo,Chumpi,Chuncho,Chupahuacho,Chuquiapo,Chuquisaca,Churup,Cocapata,Cochabamba,Cojup,Collota,Conococha,Corihuayrachina,Cuchoquesera,Cusichaca,Haika,Hanpiq,Hatun,Haywarisqa,Huaca,Huachinga,Hualcan,Hualchancca,Huamanga,Huamashraju,Huancarhuas,Huandoy,Huantsan,Huanupampa,Huarmihuanusca,Huascaran,Huaylas,Huayllabamba,Huayrana,Huaytara,Huichajanca,Huinayhuayna,Huinche,Huinioch,Illiasca,Intipunku,Iquicha,Ishinca,Jahuacocha,Jirishanca,Juli,Jurau,Kakananpunta,Kamasqa,Karpay,Kausay,Khuya,Kuelap,Lanccochayocc,Llaca,Llactapata,Llanganuco,Llaqta,Lloqllasca,Llupachayoc,Luricocha,Machu,Mallku,Matarraju,Mechecc,Mikhuy,Milluacocha,Morochuco,Munay,Ocshapalca,Ollantaytambo,Oroccahua,Oronccoy,Oyolo,Pacamayo,Pacaycasa.Carapo,Paccharaju,Pachacamac,Pachakamaq,Pachakuteq,Pachakuti,Pachamama,Paititi,Pajaten,Palcaraju,Pallccas,Pampa,Panaka,Paqarina,Paqo,Parap,Paria,Patahuasi,Patallacta,Patibamba,Pisac,Pisco,Pongos,Pucacolpa,Pucahirca,Pucaranra,Pumatambo,Puscanturpa,Putaca,Puyupatamarca,Qawaq,Qayqa,Qochamoqo,Qollana,Qorihuayrachina,Qorimoqo,Qotupuquio,Quenuaracra,Queshque,Quillcayhuanca,Quillya,Quitaracsa,Quitaraju,Qusqu,Rajucolta,Rajutakanan,Rajutuna,Ranrahirca,Ranrapalca,Raria,Rasac,Rimarima,Riobamba,Runkuracay,Rurec,Sacsa,Sacsamarca,Saiwa,Sarapo,Sayacmarca,Sayripata,Sinakara,Sonccopa,Taripaypacha,Taulliraju,Tawantinsuyu,Taytanchis,Tiwanaku,Tocllaraju,Tsacra,Tuco,Tucubamba,Tullparaju,Tumbes,Uchuraccay,Uchuraqay,Ulta,Urihuana,Uruashraju,Vallunaraju,Vilcabamba,Wacho,Wankawillka,Wayra,Yachay,Yahuarraju,Yanamarey,Yanaqucha,Yanesha,Yerupaja"}, + {name: "Quechua", i: 27, min: 6, max: 12, d: "l", m: 0, b: "Alpahuaycco,Anchihuay,Anqea,Apurimac,Arequipa,Atahuallpa,Atawalpa,Atico,Ayacucho,Ayahuanco,Ayllu,Cajamarca,Canayre,Canchacancha,Carapo,Carhuac,Carhuacatac,Cashan,Caullaraju,Caxamalca,Cayesh,Ccahuasno,Ccarhuacc,Ccopayoc,Chacchapunta,Chacraraju,Challhuamayo,Champara,Chanchan,Chekiacraju,Chillihua,Chinchey,Chontah,Chopicalqui,Chucuito,Chuito,Chullo,Chumpi,Chuncho,Chupahuacho,Chuquiapo,Chuquisaca,Churup,Cocapata,Cochabamba,Cojup,Collota,Conococha,Corihuayrachina,Cuchoquesera,Cusichaca,Haika,Hanpiq,Hatun,Haywarisqa,Huaca,Huachinga,Hualcan,Hualchancca,Huamanga,Huamashraju,Huancarhuas,Huandoy,Huantsan,Huanupampa,Huarmihuanusca,Huascaran,Huaylas,Huayllabamba,Huayrana,Huaytara,Huichajanca,Huinayhuayna,Huinche,Huinioch,Illiasca,Intipunku,Iquicha,Ishinca,Jahuacocha,Jirishanca,Juli,Jurau,Kakananpunta,Kamasqa,Karpay,Kausay,Khuya,Kuelap,Lanccochayocc,Llaca,Llactapata,Llanganuco,Llaqta,Lloqllasca,Llupachayoc,Luricocha,Machu,Mallku,Matarraju,Mechecc,Mikhuy,Milluacocha,Morochuco,Munay,Ocshapalca,Ollantaytambo,Oroccahua,Oronccoy,Oyolo,Pacamayo,Pacaycasa,Paccharaju,Pachacamac,Pachakamaq,Pachakuteq,Pachakuti,Pachamama,Paititi,Pajaten,Palcaraju,Pallccas,Pampa,Panaka,Paqarina,Paqo,Parap,Paria,Patahuasi,Patallacta,Patibamba,Pisac,Pisco,Pongos,Pucacolpa,Pucahirca,Pucaranra,Pumatambo,Puscanturpa,Putaca,Puyupatamarca,Qawaq,Qayqa,Qochamoqo,Qollana,Qorihuayrachina,Qorimoqo,Qotupuquio,Quenuaracra,Queshque,Quillcayhuanca,Quillya,Quitaracsa,Quitaraju,Qusqu,Rajucolta,Rajutakanan,Rajutuna,Ranrahirca,Ranrapalca,Raria,Rasac,Rimarima,Riobamba,Runkuracay,Rurec,Sacsa,Sacsamarca,Saiwa,Sarapo,Sayacmarca,Sayripata,Sinakara,Sonccopa,Taripaypacha,Taulliraju,Tawantinsuyu,Taytanchis,Tiwanaku,Tocllaraju,Tsacra,Tuco,Tucubamba,Tullparaju,Tumbes,Uchuraccay,Uchuraqay,Ulta,Urihuana,Uruashraju,Vallunaraju,Vilcabamba,Wacho,Wankawillka,Wayra,Yachay,Yahuarraju,Yanamarey,Yanaqucha,Yanesha,Yerupaja"}, {name: "Swahili", i: 28, min: 4, max: 9, d: "", m: 0, b: "Abim,Adjumani,Alebtong,Amolatar,Amuru,Apac,Arua,Arusha,Babati,Baragoi,Bombo,Budaka,Bugembe,Bugiri,Buikwe,Bukedea,Bukoba,Bukomansimbi,Bukungu,Buliisa,Bundibugyo,Bungoma,Busembatya,Bushenyi,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,Kabuyanda,Kabwohe,Kagadi,Kajiado,Kakinga,Kakiri,Kakuma,Kalangala,Kaliro,Kalongo,Kalungu,Kampala,Kamwenge,Kanungu,Kapchorwa,Kasese,Kasulu,Katakwi,Kayunga,Keroka,Kiambu,Kibaale,Kibaha,Kibingo,Kibwezi,Kigoma,Kihiihi,Kilifi,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,Marsabit,Masaka,Masindi,Masulita,Matugga,Mayuge,Mbale,Mbarara,Mbeya,Meru,Mitooma,Mityana,Mombasa,Morogoro,Moroto,Moyale,Moyo,Mpanda,Mpigi,Mpondwe,Mtwara,Mubende,Mukono,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"}, {name: "Vietnamese", i: 29, min: 3, max: 12, d: "", m: 1, b: "An Giang,Anh Son,An Khe,An Nhon,Ayun Pa,Bac Giang,Bac Kan,Bac Lieu,Bac Ninh,Ba Don,Bao Loc,Ba Ria,Ba Ria-Vung Tau,Ba Thuoc,Ben Cat,Ben Tre,Bien Hoa,Bim Son,Binh Dinh,Binh Duong,Binh Long,Binh Minh,Binh Phuoc,Binh Thuan,Buon Ho,Buon Ma Thuot,Cai Lay,Ca Mau,Cam Khe,Cam Pha,Cam Ranh,Cam Thuy,Can Tho,Cao Bang,Cao Lanh,Cao Phong,Chau Doc,Chi Linh,Con Cuong,Cua Lo,Da Bac,Dak Lak,Da Lat,Da Nang,Di An,Dien Ban,Dien Bien,Dien Bien Phu,Dien Chau,Do Luong,Dong Ha,Dong Hoi,Dong Trieu,Duc Pho,Duyen Hai,Duy Tien,Gia Lai,Gia Nghia,Gia Rai,Go Cong,Ha Giang,Ha Hoa,Hai Duong,Hai Phong,Ha Long,Ha Nam,Ha Noi,Ha Tinh,Ha Trung,Hau Giang,Hoa Binh,Hoang Mai,Hoa Thanh,Ho Chi Minh,Hoi An,Hong Linh,Hong Ngu,Hue,Hung Nguyen,Hung Yen,Huong Thuy,Huong Tra,Khanh Hoa,Kien Tuong,Kim Boi,Kinh Mon,Kon Tum,Ky Anh,Ky Son,Lac Son,Lac Thuy,La Gi,Lai Chau,Lam Thao,Lang Chanh,Lang Son,Lao Cai,Long An,Long Khanh,Long My,Long Xuyen,Luong Son,Mai Chau,Mong Cai,Muong Lat,Muong Lay,My Hao,My Tho,Nam Dan,Nam Dinh,Nga Bay,Nga Nam,Nga Son,Nghe An,Nghia Dan,Nghia Lo,Nghi Loc,Nghi Son,Ngoc Lac,Nha Trang,Nhu Thanh,Nhu Xuan,Ninh Binh,Ninh Hoa,Nong Cong,Phan Rang Thap Cham,Phan Thiet,Pho Yen,Phu Ly,Phu My,Phu Ninh,Phuoc Long,Phu Tho,Phu Yen,Pleiku,Quang Binh,Quang Nam,Quang Ngai,Quang Ninh,Quang Tri,Quang Xuong,Quang Yen,Quan Hoa,Quan Son,Que Phong,Quy Chau,Quy Hop,Quynh Luu,Quy Nhon,Rach Gia,Sa Dec,Sai Gon,Sam Son,Sa Pa,Soc Trang,Song Cau,Song Cong,Son La,Son Tay,Tam Diep,Tam Ky,Tan An,Tan Chau,Tan Ky,Tan Lac,Tan Son,Tan Uyen,Tay Ninh,Thach Thanh,Thai Binh,Thai Hoa,Thai Nguyen,Thanh Chuong,Thanh Hoa,Thieu Hoa,Thuan An,Thua Thien-Hue,Thu Dau Mot,Thu Duc,Thuong Xuan,Tien Giang,Trang Bang,Tra Vinh,Trieu Son,Tu Son,Tuyen Quang,Tuy Hoa,Uong Bi,Viet Tri,Vinh,Vinh Chau,Vinh Loc,Vinh Long,Vinh Yen,Vi Thanh,Vung Tau,Yen Bai,Yen Dinh,Yen Thanh,Yen Thuy"}, {name: "Cantonese", i: 30, min: 5, max: 11, d: "", m: 0, b: "Chaiwan,Chingchung,Chinghoi,Chingsen,Chingshing,Chiunam,Chiuon,Chiuyeung,Chiyuen,Choihung,Chuehoi,Chuiman,Chungfu,Chungsan,Chunguktsuen,Dakhing,Daopo,Daumun,Dingwu,Dinpak,Donggun,Dongyuen,Duenchau,Fachau,Fanling,Fatgong,Fatshan,Fotan,Fuktien,Fumun,Funggong,Funghoi,Fungshun,Fungtei,Gamtin,Gochau,Goming,Gonghoi,Gongshing,Goyiu,Hanghau,Hangmei,Hengon,Heungchau,Heunggong,Heungkiu,Hingning,Hohfuktong,Hoichue,Hoifung,Hoiping,Hokong,Hokshan,Hoyuen,Hunghom,Hungshuikiu,Jiuling,Kamsheung,Kamwan,Kaulongtong,Keilun,Kinon,Kinsang,Kityeung,Kongmun,Kukgong,Kwaifong,Kwaihing,Kwongchau,Kwongling,Kwongming,Kwuntong,Laichikok,Laiking,Laiwan,Lamtei,Lamtin,Leitung,Leungking,Limkong,Linping,Linshan,Loding,Lokcheong,Lokfu,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,Namsha,Nganwai,Ngautaukok,Ngchuen,Ngwa,Onting,Pakwun,Paotoishan,Pingshan,Pingyuen,Poklo,Pongon,Poning,Potau,Puito,Punyue,Saiwanho,Saiyingpun,Samshing,Samshui,Samtsen,Samyuenlei,Sanfung,Sanhing,Sanhui,Sanwai,Seiwui,Shamshuipo,Shanmei,Shantau,Shauking,Shekmun,Shekpai,Sheungshui,Shingkui,Shiuhing,Shundak,Shunyi,Shupinwai,Simshing,Siuhei,Siuhong,Siukwan,Siulun,Suikai,Taihing,Taikoo,Taipo,Taishuihang,Taiwai,Taiwohau,Tinhau,Tinshuiwai,Tiukengleng,Toishan,Tongfong,Tonglowan,Tsakyoochung,Tsamgong,Tsangshing,Tseungkwano,Tsimshatsui,Tsinggong,Tsingshantsuen,Tsingwun,Tsingyi,Tsingyuen,Tsiuchau,Tsuenshekshan,Tsuenwan,Tuenmun,Tungchung,Waichap,Waichau,Waidong,Wailoi,Waishing,Waiyeung,Wanchai,Wanfau,Wanshing,Wingon,Wongpo,Wongtaisin,Woping,Wukaisha,Yano,Yaumatei,Yautong,Yenfa,Yeungchun,Yeungdong,Yeungsai,Yeungshan,Yimtin,Yingdak,Yiuping,Yongshing,Yongyuen,Yuenlong,Yuenshing,Yuetsau,Yuknam,Yunping"}, From d1c09935a9ae330498758dec5be7f60e14973d83 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Fri, 14 Jun 2024 13:09:43 +0200 Subject: [PATCH 2/4] fix: regenerate burgs - remove burg notes, keep locked notes --- index.html | 4 +-- modules/ui/editors.js | 17 ++++++------ modules/ui/tools.js | 62 ++++++++++++++++++++++++++++--------------- versioning.js | 2 +- 4 files changed, 52 insertions(+), 33 deletions(-) diff --git a/index.html b/index.html index 08b532b0..4b8041f4 100644 --- a/index.html +++ b/index.html @@ -8067,8 +8067,8 @@ - - + + diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 3b9181d1..2e68596d 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -223,18 +223,19 @@ function addBurgsGroup(group) { } function removeBurg(id) { - const label = document.querySelector("#burgLabels [data-id='" + id + "']"); - const icon = document.querySelector("#burgIcons [data-id='" + id + "']"); - const anchor = document.querySelector("#anchors [data-id='" + id + "']"); - if (label) label.remove(); - if (icon) icon.remove(); - if (anchor) anchor.remove(); + document.querySelector("#burgLabels [data-id='" + id + "']")?.remove(); + document.querySelector("#burgIcons [data-id='" + id + "']")?.remove(); + document.querySelector("#anchors [data-id='" + id + "']")?.remove(); + + const cells = pack.cells; + const burg = pack.burgs[id]; - const cells = pack.cells, - burg = pack.burgs[id]; burg.removed = true; cells.burg[burg.cell] = 0; + const noteId = notes.findIndex(note => note.id === `burg${id}`); + if (noteId !== -1) notes.splice(noteId, 1); + if (burg.coa) { const coaId = "burgCOA" + id; if (byId(coaId)) byId(coaId).remove(); diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 4d62305c..30f9b2ee 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -335,29 +335,44 @@ function regenerateProvinces() { } function regenerateBurgs() { - const {cells, states} = pack; - const lockedburgs = pack.burgs.filter(b => b.i && !b.removed && b.lock); + const {cells, features, burgs, states, provinces} = pack; + rankCells(); - cells.burg = new Uint16Array(cells.i.length); - const burgs = (pack.burgs = [0]); // clear burgs array - states.filter(s => s.i).forEach(s => (s.capital = 0)); // clear state capitals - pack.provinces.filter(p => p.i).forEach(p => (p.burg = 0)); // clear province capitals + // remove notes for unlocked burgs + notes = notes.filter(note => { + if (note.id.startsWith("burg")) { + const burgId = +note.id.slice(4); + return burgs[burgId]?.lock; + } + return true; + }); + + const newBurgs = [0]; // new burgs array const burgsTree = d3.quadtree(); - // add locked burgs + cells.burg = new Uint16Array(cells.i.length); // clear cells burg data + states.filter(s => s.i).forEach(s => (s.capital = 0)); // clear state capitals + provinces.filter(p => p.i).forEach(p => (p.burg = 0)); // clear province capitals + + // readd locked burgs + const lockedburgs = burgs.filter(burg => burg.i && !burg.removed && burg.lock); for (let j = 0; j < lockedburgs.length; j++) { - const id = burgs.length; const lockedBurg = lockedburgs[j]; - lockedBurg.i = id; - burgs.push(lockedBurg); + const newId = newBurgs.length; + + const noteIndex = notes.findIndex(note => note.id === `burg${lockedBurg.i}`); + if (noteIndex !== -1) notes[noteIndex].id = `burg${newId}`; + + lockedBurg.i = newId; + newBurgs.push(lockedBurg); burgsTree.add([lockedBurg.x, lockedBurg.y]); - cells.burg[lockedBurg.cell] = id; + cells.burg[lockedBurg.cell] = newId; if (lockedBurg.capital) { const stateId = lockedBurg.state; - states[stateId].capital = id; + states[stateId].capital = newId; states[stateId].center = lockedBurg.cell; } } @@ -370,8 +385,8 @@ function regenerateBurgs() { existingStatesCount; const spacing = (graphWidth + graphHeight) / 150 / (burgsCount ** 0.7 / 66); // base min distance between towns - for (let i = 0; i < sorted.length && burgs.length < burgsCount; i++) { - const id = burgs.length; + for (let i = 0; i < sorted.length && newBurgs.length < burgsCount; i++) { + const id = newBurgs.length; const cell = sorted[i]; const [x, y] = cells.p[cell]; @@ -387,24 +402,27 @@ function regenerateBurgs() { const culture = cells.culture[cell]; const name = Names.getCulture(culture); - burgs.push({cell, x, y, state: stateId, i: id, culture, name, capital, feature: cells.f[cell]}); + newBurgs.push({cell, x, y, state: stateId, i: id, culture, name, capital, feature: cells.f[cell]}); burgsTree.add([x, y]); cells.burg[cell] = id; } + pack.burgs = newBurgs; // assign new burgs array + // add a capital at former place for states without added capitals states .filter(s => s.i && !s.removed && !s.capital) .forEach(s => { - const burg = addBurg([cells.p[s.center][0], cells.p[s.center][1]]); // add new burg - s.capital = burg; - s.center = pack.burgs[burg].cell; - pack.burgs[burg].capital = 1; - pack.burgs[burg].state = s.i; - moveBurgToGroup(burg, "cities"); + const [x, y] = cells.p[s.center]; + const burgId = addBurg([x, y]); + s.capital = burgId; + s.center = pack.burgs[burgId].cell; + pack.burgs[burgId].capital = 1; + pack.burgs[burgId].state = s.i; + moveBurgToGroup(burgId, "cities"); }); - pack.features.forEach(f => { + features.forEach(f => { if (f.port) f.port = 0; // reset features ports counter }); diff --git a/versioning.js b/versioning.js index 69787c21..068ca0f1 100644 --- a/versioning.js +++ b/versioning.js @@ -1,7 +1,7 @@ "use strict"; // version and caching control -const version = "1.97.11"; // generator version, update each time +const version = "1.97.12"; // generator version, update each time { document.title += " v" + version; From dd3599506f0ff29020f5d83ee8873829ddff6bbb Mon Sep 17 00:00:00 2001 From: Azgaar Date: Fri, 14 Jun 2024 13:49:19 +0200 Subject: [PATCH 3/4] feat: zones editor - option to edit land only --- index.html | 68 +++++++++++--------- modules/ui/zones-editor.js | 127 ++++++++++++++++++++++++------------- versioning.js | 2 +- 3 files changed, 122 insertions(+), 75 deletions(-) diff --git a/index.html b/index.html index 4b8041f4..06c1363d 100644 --- a/index.html +++ b/index.html @@ -4912,34 +4912,44 @@ @@ -8088,7 +8098,7 @@ - + diff --git a/modules/ui/zones-editor.js b/modules/ui/zones-editor.js index 759447dd..0e0bc6b6 100644 --- a/modules/ui/zones-editor.js +++ b/modules/ui/zones-editor.js @@ -3,7 +3,7 @@ function editZones() { closeDialogs(); if (!layerIsOn("toggleZones")) toggleZones(); - const body = document.getElementById("zonesBodySection"); + const body = byId("zonesBodySection"); updateFilters(); zonesEditorAddLines(); @@ -20,20 +20,20 @@ function editZones() { }); // add listeners - document.getElementById("zonesFilterType").addEventListener("click", updateFilters); - document.getElementById("zonesFilterType").addEventListener("change", filterZonesByType); - document.getElementById("zonesEditorRefresh").addEventListener("click", zonesEditorAddLines); - document.getElementById("zonesEditStyle").addEventListener("click", () => editStyle("zones")); - document.getElementById("zonesLegend").addEventListener("click", toggleLegend); - document.getElementById("zonesPercentage").addEventListener("click", togglePercentageMode); - document.getElementById("zonesManually").addEventListener("click", enterZonesManualAssignent); - document.getElementById("zonesManuallyApply").addEventListener("click", applyZonesManualAssignent); - document.getElementById("zonesManuallyCancel").addEventListener("click", cancelZonesManualAssignent); - document.getElementById("zonesAdd").addEventListener("click", addZonesLayer); - document.getElementById("zonesExport").addEventListener("click", downloadZonesData); - document.getElementById("zonesRemove").addEventListener("click", toggleEraseMode); + byId("zonesFilterType").on("click", updateFilters); + byId("zonesFilterType").on("change", filterZonesByType); + byId("zonesEditorRefresh").on("click", zonesEditorAddLines); + byId("zonesEditStyle").on("click", () => editStyle("zones")); + byId("zonesLegend").on("click", toggleLegend); + byId("zonesPercentage").on("click", togglePercentageMode); + byId("zonesManually").on("click", enterZonesManualAssignent); + byId("zonesManuallyApply").on("click", applyZonesManualAssignent); + byId("zonesManuallyCancel").on("click", cancelZonesManualAssignent); + byId("zonesAdd").on("click", addZonesLayer); + byId("zonesExport").on("click", downloadZonesData); + byId("zonesRemove").on("click", toggleEraseMode); - body.addEventListener("click", function (ev) { + body.on("click", function (ev) { const el = ev.target, cl = el.classList, zone = el.parentNode.dataset.id; @@ -45,7 +45,7 @@ function editZones() { if (customization) selectZone(el); }); - body.addEventListener("input", function (ev) { + body.on("input", function (ev) { const el = ev.target; const zone = zones.select("#" + el.parentNode.dataset.id); @@ -58,10 +58,11 @@ function editZones() { const zones = Array.from(document.querySelectorAll("#zones > g")); const types = unique(zones.map(zone => zone.dataset.type)); - const filterSelect = document.getElementById("zonesFilterType"); + const filterSelect = byId("zonesFilterType"); const typeToFilterBy = types.includes(zonesFilterType.value) ? zonesFilterType.value : "all"; - filterSelect.innerHTML = "" + types.map(type => ``).join(""); + filterSelect.innerHTML = + "" + types.map(type => ``).join(""); filterSelect.value = typeToFilterBy; } @@ -69,7 +70,7 @@ function editZones() { function zonesEditorAddLines() { const unit = " " + getAreaUnit(); - const typeToFilterBy = document.getElementById("zonesFilterType").value; + const typeToFilterBy = byId("zonesFilterType").value; const zones = Array.from(document.querySelectorAll("#zones > g")); const filteredZones = typeToFilterBy === "all" ? zones : zones.filter(zone => zone.dataset.type === typeToFilterBy); @@ -80,9 +81,12 @@ function editZones() { const fill = zoneEl.getAttribute("fill"); const area = getArea(d3.sum(c.map(i => pack.cells.area[i]))); const rural = d3.sum(c.map(i => pack.cells.pop[i])) * populationRate; - const urban = d3.sum(c.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization; + const urban = + d3.sum(c.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization; const population = rural + urban; - const populationTip = `Total population: ${si(population)}; Rural population: ${si(rural)}; Urban population: ${si(urban)}. Click to change`; + const populationTip = `Total population: ${si(population)}; Rural population: ${si( + rural + )}; Urban population: ${si(urban)}. Click to change`; const inactive = zoneEl.style.display === "none"; const focused = defs.select("#fog #focus" + zoneEl.id).size(); @@ -98,8 +102,12 @@ function editZones() {
${si(population)}
- - + + `; }); @@ -109,7 +117,9 @@ function editZones() { // update footer const totalArea = getArea(graphWidth * graphHeight); zonesFooterArea.dataset.area = totalArea; - const totalPop = (d3.sum(pack.cells.pop) + d3.sum(pack.burgs.filter(b => !b.removed).map(b => b.population)) * urbanization) * populationRate; + const totalPop = + (d3.sum(pack.cells.pop) + d3.sum(pack.burgs.filter(b => !b.removed).map(b => b.population)) * urbanization) * + populationRate; zonesFooterPopulation.dataset.population = totalPop; zonesFooterNumber.innerHTML = /* html */ `${filteredZones.length} of ${zones.length}`; zonesFooterCells.innerHTML = pack.cells.i.length; @@ -117,8 +127,8 @@ function editZones() { zonesFooterPopulation.innerHTML = si(totalPop); // add listeners - body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseenter", ev => zoneHighlightOn(ev))); - body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseleave", ev => zoneHighlightOff(ev))); + body.querySelectorAll("div.states").forEach(el => el.on("mouseenter", ev => zoneHighlightOn(ev))); + body.querySelectorAll("div.states").forEach(el => el.on("mouseleave", ev => zoneHighlightOff(ev))); if (body.dataset.type === "percentage") { body.dataset.type = "absolute"; @@ -150,7 +160,13 @@ function editZones() { zonesEditorAddLines(); } - $(body).sortable({items: "div.states", handle: ".icon-resize-vertical", containment: "parent", axis: "y", update: movezone}); + $(body).sortable({ + items: "div.states", + handle: ".icon-resize-vertical", + containment: "parent", + axis: "y", + update: movezone + }); function movezone(ev, ui) { const zone = $("#" + ui.item.attr("data-id")); const prev = $("#" + ui.item.prev().attr("data-id")); @@ -166,7 +182,7 @@ function editZones() { if (!layerIsOn("toggleZones")) toggleZones(); customization = 10; document.querySelectorAll("#zonesBottom > *").forEach(el => (el.style.display = "none")); - document.getElementById("zonesManuallyButtons").style.display = "inline-block"; + byId("zonesManuallyButtons").style.display = "inline-block"; zonesEditor.querySelectorAll(".hide").forEach(el => el.classList.add("hidden")); zonesFooter.style.display = "none"; @@ -174,7 +190,11 @@ function editZones() { $("#zonesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}}); tip("Click to select a zone, drag to paint a zone", true); - viewbox.style("cursor", "crosshair").on("click", selectZoneOnMapClick).call(d3.drag().on("start", dragZoneBrush)).on("touchmove mousemove", moveZoneBrush); + viewbox + .style("cursor", "crosshair") + .on("click", selectZoneOnMapClick) + .call(d3.drag().on("start", dragZoneBrush)) + .on("touchmove mousemove", moveZoneBrush); body.querySelector("div").classList.add("selected"); zones.selectAll("g").each(function () { @@ -195,24 +215,27 @@ function editZones() { } function dragZoneBrush() { - const r = +zonesBrush.value; + const radius = +byId("zonesBrush").value; + const eraseMode = byId("zonesRemove").classList.contains("pressed"); + const landOnly = byId("zonesBrushLandOnly").checked; + + const selected = body.querySelector("div.selected"); + const zone = zones.select("#" + selected.dataset.id); + const base = zone.attr("id") + "_"; // id generic part d3.event.on("drag", () => { if (!d3.event.dx && !d3.event.dy) return; - const p = d3.mouse(this); - moveCircle(p[0], p[1], r); + const [x, y] = d3.mouse(this); + moveCircle(x, y, radius); - const selection = r > 5 ? findAll(p[0], p[1], r) : [findCell(p[0], p[1], r)]; + let selection = radius > 5 ? findAll(x, y, radius) : [findCell(x, y, radius)]; + if (landOnly) selection = selection.filter(i => pack.cells.h[i] >= 20); if (!selection) return; - const selected = body.querySelector("div.selected"); - const zone = zones.select("#" + selected.dataset.id); - const base = zone.attr("id") + "_"; // id generic part const dataCells = zone.attr("data-cells"); let cells = dataCells ? dataCells.split(",").map(i => +i) : []; - const erase = document.getElementById("zonesRemove").classList.contains("pressed"); - if (erase) { + if (eraseMode) { // remove selection.forEach(i => { const index = cells.indexOf(i); @@ -280,12 +303,13 @@ function editZones() { customization = 0; removeCircle(); document.querySelectorAll("#zonesBottom > *").forEach(el => (el.style.display = "inline-block")); - document.getElementById("zonesManuallyButtons").style.display = "none"; + byId("zonesManuallyButtons").style.display = "none"; zonesEditor.querySelectorAll(".hide:not(.show)").forEach(el => el.classList.remove("hidden")); zonesFooter.style.display = "block"; body.querySelectorAll("div > input, select, svg").forEach(e => (e.style.pointerEvents = "all")); - if (!close) $("#zonesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}}); + if (!close) + $("#zonesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}}); restoreDefaultEvents(); clearMainTip(); @@ -300,7 +324,7 @@ function editZones() { const fill = el.getAttribute("fill"); const callback = newFill => { el.fill = newFill; - document.getElementById(el.parentNode.dataset.id).setAttribute("fill", newFill); + byId(el.parentNode.dataset.id).setAttribute("fill", newFill); }; openPicker(fill, callback); @@ -356,7 +380,8 @@ function editZones() { body.querySelectorAll(":scope > div").forEach(function (el) { el.querySelector(".stateCells").innerHTML = rn((+el.dataset.cells / totalCells) * 100, 2) + "%"; el.querySelector(".biomeArea").innerHTML = rn((+el.dataset.area / totalArea) * 100, 2) + "%"; - el.querySelector(".culturePopulation").innerHTML = rn((+el.dataset.population / totalPopulation) * 100, 2) + "%"; + el.querySelector(".culturePopulation").innerHTML = + rn((+el.dataset.population / totalPopulation) * 100, 2) + "%"; }); } else { body.dataset.type = "absolute"; @@ -369,7 +394,13 @@ function editZones() { const description = "Unknown zone"; const type = "Unknown"; const fill = "url(#hatch" + (id.slice(4) % 42) + ")"; - zones.append("g").attr("id", id).attr("data-description", description).attr("data-type", type).attr("data-cells", "").attr("fill", fill); + zones + .append("g") + .attr("id", id) + .attr("data-description", description) + .attr("data-type", type) + .attr("data-cells", "") + .attr("fill", fill); zonesEditorAddLines(); } @@ -411,13 +442,19 @@ function editZones() { const burgs = pack.burgs.filter(b => !b.removed && cells.includes(b.cell)); const rural = rn(d3.sum(cells.map(i => pack.cells.pop[i])) * populationRate); - const urban = rn(d3.sum(cells.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization); + const urban = rn( + d3.sum(cells.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization + ); const total = rural + urban; const l = n => Number(n).toLocaleString(); alertMessage.innerHTML = /* html */ `Rural: Urban: - -

Total population: ${l(total)} ⇒ ${l(total)} (100%)

`; + +

Total population: ${l(total)} ⇒ ${l( + total + )} (100%)

`; const update = function () { const totalNew = ruralPop.valueAsNumber + urbanPop.valueAsNumber; diff --git a/versioning.js b/versioning.js index 068ca0f1..0dbe3647 100644 --- a/versioning.js +++ b/versioning.js @@ -1,7 +1,7 @@ "use strict"; // version and caching control -const version = "1.97.12"; // generator version, update each time +const version = "1.97.13"; // generator version, update each time { document.title += " v" + version; From 147d57640ebea404bbc7e8158288d99c2e14fa77 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 16 Jun 2024 00:15:49 +0200 Subject: [PATCH 4/4] feat: ability to rotate regiments --- index.html | 4 +- modules/military-generator.js | 8 ++- modules/ui/elevation-profile.js | 5 +- modules/ui/regiment-editor.js | 112 ++++++++++++++++++++++---------- versioning.js | 2 +- 5 files changed, 86 insertions(+), 45 deletions(-) diff --git a/index.html b/index.html index 06c1363d..9ad71c88 100644 --- a/index.html +++ b/index.html @@ -8059,7 +8059,7 @@ - + @@ -8104,7 +8104,7 @@ - + diff --git a/modules/military-generator.js b/modules/military-generator.js index a480bfaa..df2f2892 100644 --- a/modules/military-generator.js +++ b/modules/military-generator.js @@ -358,7 +358,9 @@ window.Military = (function () { .attr("id", d => "regiment" + s + "-" + d.i) .attr("data-name", d => d.name) .attr("data-state", s) - .attr("data-id", d => d.i); + .attr("data-id", d => d.i) + .attr("transform", d => (d.angle ? `rotate(${d.angle})` : null)) + .attr("transform-origin", d => `${d.x}px ${d.y}px`); g.append("rect") .attr("x", d => x(d)) .attr("y", d => y(d)) @@ -404,7 +406,9 @@ window.Military = (function () { .attr("id", "regiment" + stateId + "-" + reg.i) .attr("data-name", reg.name) .attr("data-state", stateId) - .attr("data-id", reg.i); + .attr("data-id", reg.i) + .attr("transform", `rotate(${reg.angle || 0})`) + .attr("transform-origin", `${reg.x}px ${reg.y}px`); g.append("rect").attr("x", x1).attr("y", y1).attr("width", w).attr("height", h); g.append("text").attr("x", reg.x).attr("y", reg.y).text(getTotal(reg)); g.append("rect") diff --git a/modules/ui/elevation-profile.js b/modules/ui/elevation-profile.js index d08b4e16..5e565a43 100644 --- a/modules/ui/elevation-profile.js +++ b/modules/ui/elevation-profile.js @@ -339,10 +339,7 @@ function showElevationProfile(data, routeLen, isRiver) { .attr("transform", "translate(" + xOffset + "," + parseInt(chartHeight + +yOffset + 20) + ")") .call(xAxis) .selectAll("text") - .style("text-anchor", "center") - .attr("transform", function (d) { - return "rotate(0)"; // used to rotate labels, - anti-clockwise, + clockwise - }); + .style("text-anchor", "center"); chart .append("g") diff --git a/modules/ui/regiment-editor.js b/modules/ui/regiment-editor.js index 359cca91..5c38a07a 100644 --- a/modules/ui/regiment-editor.js +++ b/modules/ui/regiment-editor.js @@ -8,9 +8,10 @@ function editRegiment(selector) { armies.selectAll(":scope > g > g").call(d3.drag().on("drag", dragRegiment)); elSelected = selector ? document.querySelector(selector) : d3.event.target.parentElement; // select g element if (!pack.states[elSelected.dataset.state]) return; - if (!regiment()) return; - updateRegimentData(regiment()); + if (!getRegiment()) return; + updateRegimentData(getRegiment()); drawBase(); + drawRotationControl(); $("#regimentEditor").dialog({ title: "Edit Regiment", @@ -37,8 +38,8 @@ function editRegiment(selector) { document.getElementById("regimentRemove").addEventListener("click", removeRegiment); // get regiment data element - function regiment() { - return pack.states[elSelected.dataset.state].military.find(r => r.i == elSelected.dataset.id); + function getRegiment() { + return pack.states[elSelected.dataset.state]?.military.find(r => r.i == elSelected.dataset.id); } function updateRegimentData(regiment) { @@ -60,7 +61,7 @@ function editRegiment(selector) { } function drawBase() { - const reg = regiment(); + const reg = getRegiment(); const clr = pack.states[elSelected.dataset.state].color; const base = viewbox .insert("g", "g#armies") @@ -69,12 +70,8 @@ function editRegiment(selector) { .attr("stroke", "#000") .attr("cursor", "move"); base - .on("mouseenter", () => { - tip("Regiment base. Drag to re-base the regiment", true); - }) - .on("mouseleave", () => { - tip("", true); - }); + .on("mouseenter", () => tip("Regiment base. Drag to re-base the regiment", true)) + .on("mouseleave", () => tip("", true)); base .append("line") @@ -92,8 +89,42 @@ function editRegiment(selector) { .call(d3.drag().on("drag", dragBase)); } + function drawRotationControl() { + const reg = getRegiment(); + const {x, width, y, height} = elSelected.getBBox(); + + debug + .append("circle") + .attr("id", "rotationControl") + .attr("cx", x + width) + .attr("cy", y + height / 2) + .attr("r", 1) + .attr("opacity", 1) + .attr("fill", "yellow") + .attr("stroke-width", 0.3) + .attr("stroke", "black") + .attr("cursor", "alias") + .attr("transform", `rotate(${reg.angle || 0})`) + .attr("transform-origin", `${reg.x}px ${reg.y}px`) + .on("mouseenter", () => tip("Drag to rotate the regiment", true)) + .on("mouseleave", () => tip("", true)) + .call(d3.drag().on("start", rotateRegiment)); + } + + function rotateRegiment() { + const reg = getRegiment(); + + d3.event.on("drag", function () { + const {x, y} = d3.event; + const angle = rn(Math.atan2(y - reg.y, x - reg.x) * (180 / Math.PI), 2); + elSelected.setAttribute("transform", `rotate(${angle})`); + this.setAttribute("transform", `rotate(${angle})`); + reg.angle = rn(angle, 2); + }); + } + function changeType() { - const reg = regiment(); + const reg = getRegiment(); reg.n = +!reg.n; document.getElementById("regimentType").className = reg.n ? "icon-anchor" : "icon-users"; @@ -110,11 +141,11 @@ function editRegiment(selector) { } function changeName() { - elSelected.dataset.name = regiment().name = this.value; + elSelected.dataset.name = getRegiment().name = this.value; } function restoreName() { - const reg = regiment(), + const reg = getRegiment(), regs = pack.states[elSelected.dataset.state].military; const name = Military.getName(reg, regs); elSelected.dataset.name = reg.name = document.getElementById("regimentName").value = name; @@ -129,12 +160,12 @@ function editRegiment(selector) { function changeEmblem() { const emblem = document.getElementById("regimentEmblem").value; - regiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem; + getRegiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem; } function changeUnit() { const u = this.dataset.u; - const reg = regiment(); + const reg = getRegiment(); reg.u[u] = +this.value || 0; reg.a = d3.sum(Object.values(reg.u)); elSelected.querySelector("text").innerHTML = Military.getTotal(reg); @@ -143,7 +174,7 @@ function editRegiment(selector) { } function splitRegiment() { - const reg = regiment(), + const reg = getRegiment(), u1 = reg.u; const state = +elSelected.dataset.state, military = pack.states[state].military; @@ -206,8 +237,7 @@ function editRegiment(selector) { function addRegimentOnClick() { const point = d3.mouse(this); const cell = findCell(point[0], point[1]); - const x = pack.cells.p[cell][0], - y = pack.cells.p[cell][1]; + const [x, y] = pack.cells.p[cell]; const state = +elSelected.dataset.state, military = pack.states[state].military; const i = military.length ? last(military).i + 1 : 0; @@ -254,7 +284,7 @@ function editRegiment(selector) { return; } - const attacker = regiment(); + const attacker = getRegiment(); const defender = pack.states[regSelected.dataset.state].military.find(r => r.i == regSelected.dataset.id); if (!attacker.a || !defender.a) { tip("Regiment has no troops to battle", false, "error"); @@ -322,7 +352,7 @@ function editRegiment(selector) { return; } - const reg = regiment(); // reg to be attached + const reg = getRegiment(); // reg to be attached const sel = pack.states[newState].military.find(r => r.i == regSelected.dataset.id); // reg to attach to for (const unit of options.military) { @@ -349,11 +379,11 @@ function editRegiment(selector) { if (index != -1) notes.splice(index, 1); const s = pack.states[elSelected.dataset.state]; - Military.generateNote(regiment(), s); + Military.generateNote(getRegiment(), s); } function editLegend() { - editNotes(elSelected.id, regiment().name); + editNotes(elSelected.id, getRegiment().name); } function removeRegiment() { @@ -365,7 +395,7 @@ function editRegiment(selector) { Remove: function () { $(this).dialog("close"); const military = pack.states[elSelected.dataset.state].military; - const regIndex = military.indexOf(regiment()); + const regIndex = military.indexOf(getRegiment()); if (regIndex === -1) return; military.splice(regIndex, 1); @@ -392,8 +422,6 @@ function editRegiment(selector) { const size = +armies.attr("box-size"); const w = reg.n ? size * 4 : size * 6; const h = size * 2; - const x1 = x => rn(x - w / 2, 2); - const y1 = y => rn(y - size, 2); const baseRect = this.querySelector("rect"); const text = this.querySelector("text"); @@ -402,26 +430,37 @@ function editRegiment(selector) { const self = elSelected === this; const baseLine = viewbox.select("g#regimentBase > line"); + const rotationControl = debug.select("#rotationControl"); d3.event.on("drag", function () { - const x = (reg.x = d3.event.x), - y = (reg.y = d3.event.y); + const {x, y} = d3.event; + reg.x = x; + reg.y = y; + const x1 = rn(x - w / 2, 2); + const y1 = rn(y - size, 2); - baseRect.setAttribute("x", x1(x)); - baseRect.setAttribute("y", y1(y)); + this.setAttribute("transform-origin", `${x}px ${y}px`); + baseRect.setAttribute("x", x1); + baseRect.setAttribute("y", y1); text.setAttribute("x", x); text.setAttribute("y", y); - iconRect.setAttribute("x", x1(x) - h); - iconRect.setAttribute("y", y1(y)); - icon.setAttribute("x", x1(x) - size); + iconRect.setAttribute("x", x1 - h); + iconRect.setAttribute("y", y1); + icon.setAttribute("x", x1 - size); icon.setAttribute("y", y); - if (self) baseLine.attr("x2", x).attr("y2", y); + if (self) { + baseLine.attr("x2", x).attr("y2", y); + rotationControl + .attr("cx", x1 + w) + .attr("cy", y) + .attr("transform-origin", `${x}px ${y}px`); + } }); } function dragBase() { const baseLine = viewbox.select("g#regimentBase > line"); - const reg = regiment(); + const reg = getRegiment(); d3.event.on("drag", function () { this.setAttribute("cx", d3.event.x); @@ -436,9 +475,10 @@ function editRegiment(selector) { } function closeEditor() { + debug.selectAll("*").remove(); + viewbox.selectAll("g#regimentBase").remove(); armies.selectAll(":scope > g").classed("draggable", false); armies.selectAll("g>g").call(d3.drag().on("drag", null)); - viewbox.selectAll("g#regimentBase").remove(); document.getElementById("regimentAdd").classList.remove("pressed"); document.getElementById("regimentAttack").classList.remove("pressed"); document.getElementById("regimentAttach").classList.remove("pressed"); diff --git a/versioning.js b/versioning.js index 0dbe3647..af9ff6e5 100644 --- a/versioning.js +++ b/versioning.js @@ -1,7 +1,7 @@ "use strict"; // version and caching control -const version = "1.97.13"; // generator version, update each time +const version = "1.97.14"; // generator version, update each time { document.title += " v" + version;