diff --git a/cmd/stats/main.go b/cmd/stats/main.go index c18ece4..c2121a4 100644 --- a/cmd/stats/main.go +++ b/cmd/stats/main.go @@ -17,8 +17,8 @@ func main() { log.Fatal("Please specify a map file!") } file := os.Args[1] - if !strings.HasSuffix(file, ".asc") { - file += ".asc" + if !strings.HasSuffix(file, ".json") { + file += ".json" } mapStr, err := os.ReadFile(file) if err != nil { diff --git a/data/maps/Coastline.asc b/data/maps/Coastline.asc deleted file mode 100644 index a826ad5..0000000 --- a/data/maps/Coastline.asc +++ /dev/null @@ -1,39 +0,0 @@ -6^ 20~ 1+ 14t 2r 50- -500 -landscape-architect fisherman-guild -A medium-sized (40x40) map with a coastline and a river. Plenty of all resources. -Available random tiles: 500. ----- -18 20 -.................~.....~................ ----------------tt~-^^^-~---------------- ---T------------~~~-^T^t~t--------------- --^^---t-------t~t--^^-t~~t-------------- --T^-----------t~~-T^T--t~t-------t------ --^---------UU-tt~t^^-rrt~t-------------- ------------UU--t~t^--t~~~r------tt------ ------tt--------t~~ttt~~tt------tTTT----- ------ttt------ttt~t~~~ttt-----tTTRt----- -----tt~~tt---t~~~~~~tttt------TTt------- ------t~~tt--tt~rtttttt------------------ ------ttttt-tTt~~tTTTt-----TT------------ -------tttt-TTTt~tTTT--t---TT------------ ----^^-----TTTtt~tTT-------^------------- ---^T^----tTttt~~t--------^-------------- ----^------^r~~~tt-t----TT---------ttt--- -----------tr~ttt-------TT---------ttt--- -----------r~~tt--------------------t---- -----------t~ttt-t----------------------- -----------t~ttt------------------------- -----------t~~tt---h--------------------- ----tTT----tt~tt-----------UU---ttt^^---- ---tTTTT----t~~~t----------UU--ttttt^^--- ---TTTt--tt--tt~t------t-------t~~~tt^--- ---------tt---t~------tt--~~----~~~ttt--- ----~~~~r--++-~~~--------r~~~r---tttt---- ----~~~~~~~r--~~~~~~~~~--~~~~~~r--------- --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--~~~--- -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/data/maps/Coastline.json b/data/maps/Coastline.json new file mode 100644 index 0000000..8a688e0 --- /dev/null +++ b/data/maps/Coastline.json @@ -0,0 +1,57 @@ +{ + "terrains": { + "+": 1, + "-": 50, + "^": 6, + "r": 2, + "t": 14, + "~": 20 + }, + "map": [ + ".................~.....~................", + "---------------tt~-^^^-~----------------", + "--T------------~~~-^T^t~t---------------", + "-^^---t-------t~t--^^-t~~t--------------", + "-T^-----------t~~-T^T--t~t-------t------", + "-^---------UU-tt~t^^-rrt~t--------------", + "-----------UU--t~t^--t~~~r------tt------", + "-----tt--------t~~ttt~~tt------tTTT-----", + "-----ttt------ttt~t~~~ttt-----tTTRt-----", + "----tt~~tt---t~~~~~~tttt------TTt-------", + "-----t~~tt--tt~rtttttt------------------", + "-----ttttt-tTt~~tTTTt-----TT------------", + "------tttt-TTTt~tTTT--t---TT------------", + "---^^-----TTTtt~tTT-------^-------------", + "--^T^----tTttt~~t--------^--------------", + "---^------^r~~~tt-t----TT---------ttt---", + "----------tr~ttt-------TT---------ttt---", + "----------r~~tt--------------------t----", + "----------t~ttt-t-----------------------", + "----------t~ttt-------------------------", + "----------t~~tt---h---------------------", + "---tTT----tt~tt-----------UU---ttt^^----", + "--tTTTT----t~~~t----------UU--ttttt^^---", + "--TTTt--tt--tt~t------t-------t~~~tt^---", + "--------tt---t~------tt--~~----~~~ttt---", + "---~~~~r--++-~~~--------r~~~r---tttt----", + "---~~~~~~~r--~~~~~~~~~--~~~~~~r---------", + "-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--~~~---", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + ], + "achievements": [ + "landscape-architect", + "fisherman-guild" + ], + "description": [ + "A medium-sized (40x40) map with a coastline and a river. Plenty of all resources.", + "Available random tiles: 500." + ], + "center": { + "X": 18, + "Y": 20 + }, + "initial_terrains": 500 +} \ No newline at end of file diff --git a/data/maps/Desert Valley.asc b/data/maps/Desert Valley.asc deleted file mode 100644 index d3ce52b..0000000 --- a/data/maps/Desert Valley.asc +++ /dev/null @@ -1,44 +0,0 @@ -15- 1^ 4~ 40+ 4t 3r -500 -landscape-architect -A medium-sized (40x40) map with a green valley through a vast desert. Very limited on building space. -Available random tiles: 500. ----- -22 19 -....................++++++++++++......... -................+++++++UU+++++++++....... -..............++++++++UU+++++++++++...... -............++++U++++++++++^--------..... -..........++++UU++++++++++---tt-------... -.........+++++UU+++++++++----~~~~tt----.. -........++U+++++++++++++^---t~tt~~~~~---. -.......++UU++++++++++++^---t~~tttttt~t--- -......+++++++++++++++++^---t~tt-----~~~~~ -.....+++++++++++++UU+++^---t~t-------t--- -....++++U++++++++++U+++---~~~----++^^---- -....+++UU++++++++++++++--t~tt--+++++++++- -...++++U++++++++++++++--t~~t--^+++UUU++++ -..+++++++++++++++++++---t~tt--^+++UU+++++ -.++U+++++++++UU+++++^---t~tt--^+++U++++++ -.++++++++++++UU+++++t----~~~--+++++++++U+ -.++++++++++++++++++tt-----t~--+++++++++++ -.------++++++-------------t~--+++++++++++ -.---~~~-^+++--ttt--------t~~--+U+++++++++ -~~~~~t~t----t~~~~ttt--h--t~t--+U+++++++++ -.-ttt-~t---tt~tt~~~~t----t~t-+++++++++++. -.-----~~ttt~~~---tt~ttt--~~--+++++++++++. -.------~~~~~tt-----~~~~~-~t-^++++++++U++. -.++^^---tt----------ttt~~~--++++++++UU++. -.++++^----+++++^-----------+++++++++UU+.. -..++++++++++++++^^^^+++++++++++++++UU++.. -...++U+++U++++++++++++++UU+++++++++++++.. -....+++++UUU+++++++++++++U++++++++++++... -.....+++++UUU+++++++++++++++++++++++++... -......+++++UU++++++UU++++++++++++U+++.... -.......++++++++++++++++++++++++++++++.... -........++++++++++++++++++++++++++++..... -.........++++++++++++++++++U+++++++...... -...........++++UU++++++++++++++++........ -.............+++UU++++++++++++++......... -................+++++++++++++............ -..................++++++++............... diff --git a/data/maps/Desert Valley.json b/data/maps/Desert Valley.json new file mode 100644 index 0000000..7c8eefe --- /dev/null +++ b/data/maps/Desert Valley.json @@ -0,0 +1,61 @@ +{ + "terrains": { + "+": 40, + "-": 15, + "^": 1, + "r": 3, + "t": 4, + "~": 4 + }, + "map": [ + "....................++++++++++++.........", + "................+++++++UU+++++++++.......", + "..............++++++++UU+++++++++++......", + "............++++U++++++++++^--------.....", + "..........++++UU++++++++++---tt-------...", + ".........+++++UU+++++++++----~~~~tt----..", + "........++U+++++++++++++^---t~tt~~~~~---.", + ".......++UU++++++++++++^---t~~tttttt~t---", + "......+++++++++++++++++^---t~tt-----~~~~~", + ".....+++++++++++++UU+++^---t~t-------t---", + "....++++U++++++++++U+++---~~~----++^^----", + "....+++UU++++++++++++++--t~tt--+++++++++-", + "...++++U++++++++++++++--t~~t--^+++UUU++++", + "..+++++++++++++++++++---t~tt--^+++UU+++++", + ".++U+++++++++UU+++++^---t~tt--^+++U++++++", + ".++++++++++++UU+++++t----~~~--+++++++++U+", + ".++++++++++++++++++tt-----t~--+++++++++++", + ".------++++++-------------t~--+++++++++++", + ".---~~~-^+++--ttt--------t~~--+U+++++++++", + "~~~~~t~t----t~~~~ttt--h--t~t--+U+++++++++", + ".-ttt-~t---tt~tt~~~~t----t~t-+++++++++++.", + ".-----~~ttt~~~---tt~ttt--~~--+++++++++++.", + ".------~~~~~tt-----~~~~~-~t-^++++++++U++.", + ".++^^---tt----------ttt~~~--++++++++UU++.", + ".++++^----+++++^-----------+++++++++UU+..", + "..++++++++++++++^^^^+++++++++++++++UU++..", + "...++U+++U++++++++++++++UU+++++++++++++..", + "....+++++UUU+++++++++++++U++++++++++++...", + ".....+++++UUU+++++++++++++++++++++++++...", + "......+++++UU++++++UU++++++++++++U+++....", + ".......++++++++++++++++++++++++++++++....", + "........++++++++++++++++++++++++++++.....", + ".........++++++++++++++++++U+++++++......", + "...........++++UU++++++++++++++++........", + ".............+++UU++++++++++++++.........", + "................+++++++++++++............", + "..................++++++++..............." + ], + "achievements": [ + "landscape-architect" + ], + "description": [ + "A medium-sized (40x40) map with a green valley through a vast desert. Very limited on building space.", + "Available random tiles: 500." + ], + "center": { + "X": 22, + "Y": 19 + }, + "initial_terrains": 500 +} \ No newline at end of file diff --git a/data/maps/Great Plains.asc b/data/maps/Great Plains.asc deleted file mode 100644 index 7156131..0000000 --- a/data/maps/Great Plains.asc +++ /dev/null @@ -1,50 +0,0 @@ -2~ 3^ 3r 20t 250- -250 -landscape-architect farmer-guild -A medium-sized (43x43) map with vast plains and a few hills and forest patches. Resources are rare. -Available random tiles: 250. ----- -21 21 -------------------------------------------- -----------------------------------tt------- --------------tt------------------tt-------- --------------tt---------------------------- -----t-------------------------------------- ----t~-------------------------------------- ----t~--------------------TR---------------- --------------------------R^---------------- -------------------------------------------- --------------ttt----------------------tt--- -------------ttttt--------------------tttt-- -------------tttT---------------------tttt-- --------------t^^------------tt--------rT--- ----------------------------tttt--------R--- ---------------------------tt~~t------------ ----------------------------t~~tt----------- ----------------------------ttttt----------- --------------r-------------RRtt------------ ---r----------r--------------R-------------- --rT---------------------------------------- ---^---------------------------------------- ----------------------h--------------------- ----------------tt-------------------------- ---------------tttt------------------------- ---------------ttttt------------------------ ----------------ttt------------------------- ----------------------------------rtt------- ----------------------------------ttt------- ----------------------------------tt-------- -------------------------------------------- -------------------------------------------- -------------ttt---------------------------- ------------ttttt--------------------------- ------------r~~tt--------------------------- ------------t~~tt--------------------------- ---tt-------t~~tt-----------TR-------------- ---tt--------ttt------------Tr-------------- ---------------------------------------tt--- ---------------------------------------ttt-- ---------------------------------------tt--- -------------------------------------------- -------------------------------------------- -------------------------------------------- diff --git a/data/maps/Great Plains.json b/data/maps/Great Plains.json new file mode 100644 index 0000000..507f5df --- /dev/null +++ b/data/maps/Great Plains.json @@ -0,0 +1,67 @@ +{ + "terrains": { + "-": 250, + "^": 3, + "r": 3, + "t": 20, + "~": 2 + }, + "map": [ + "-------------------------------------------", + "----------------------------------tt-------", + "-------------tt------------------tt--------", + "-------------tt----------------------------", + "----t--------------------------------------", + "---t~--------------------------------------", + "---t~--------------------TR----------------", + "-------------------------R^----------------", + "-------------------------------------------", + "-------------ttt----------------------tt---", + "------------ttttt--------------------tttt--", + "------------tttT---------------------tttt--", + "-------------t^^------------tt--------rT---", + "---------------------------tttt--------R---", + "--------------------------tt~~t------------", + "---------------------------t~~tt-----------", + "---------------------------ttttt-----------", + "-------------r-------------RRtt------------", + "--r----------r--------------R--------------", + "-rT----------------------------------------", + "--^----------------------------------------", + "---------------------h---------------------", + "---------------tt--------------------------", + "--------------tttt-------------------------", + "--------------ttttt------------------------", + "---------------ttt-------------------------", + "---------------------------------rtt-------", + "---------------------------------ttt-------", + "---------------------------------tt--------", + "-------------------------------------------", + "-------------------------------------------", + "------------ttt----------------------------", + "-----------ttttt---------------------------", + "-----------r~~tt---------------------------", + "-----------t~~tt---------------------------", + "--tt-------t~~tt-----------TR--------------", + "--tt--------ttt------------Tr--------------", + "--------------------------------------tt---", + "--------------------------------------ttt--", + "--------------------------------------tt---", + "-------------------------------------------", + "-------------------------------------------", + "-------------------------------------------" + ], + "achievements": [ + "landscape-architect", + "farmer-guild" + ], + "description": [ + "A medium-sized (43x43) map with vast plains and a few hills and forest patches. Resources are rare.", + "Available random tiles: 250." + ], + "center": { + "X": 21, + "Y": 21 + }, + "initial_terrains": 250 +} \ No newline at end of file diff --git a/data/maps/River Delta.asc b/data/maps/River Delta.asc deleted file mode 100644 index 1f73e4b..0000000 --- a/data/maps/River Delta.asc +++ /dev/null @@ -1,52 +0,0 @@ -4^ 10~ 0+ 12t 1r 50- -0 -landscape-architect wood-gnome fisherman-guild farmer-guild -A larger (53x46) map of a river delta. Plenty of resources, but a lot of waterways to bridge. -Available random tiles: 0! ----- -24 25 -........................~~........................... -------------------------~~--------------------------- ----tt-------------------~~--------------------------- ---tTTt-----------tT-----~~~----t^-----tTt------------ ---TTTt-----T----tTTt----~r~----^^----tTTTt----------- ---TTr-----------tTTt--tt~-~----------tTTTt----------- ---TT------------TTT----t~~~----------tTTr------------ ---T-----T-------TT---t~~~~~----------ttt------------- --------^^-----------~~~--~~------------------------tT --------------------t~--t-~~-----------------------tTT ----------------trrt~~---~~~---tTT----------------ttTT --------------t~~~~r~t---~~~---RTT-----------T----tTTT -----------tttt~tt~~~---t~~~---RTT----------------TTTT ----^-----tTTtt~~ttt----~~~~t--TT-----------------TTTt ----------TTTttr~tt-----~~~~t----------------------tt- ---------tTTT--~~t----tt~tt~tt------------tt---------- ------ttttTT---~ttttt~~~~tt~rt-----------tTTT--------- -----tTTTT----t~~~~~~~ttttt~~~t---------tTTTt--------- -----TTTt-----~~ttt~tttTTTttr~~t--------TTTt---------- -----TTt---ttr~tttt~ttTTTTTttt~ttt-------------------- -----------~~~~tt-t~~tTT----tt~~~~t------------------- --------~~~~tttt---t~~t-------trr~~~t--tt---tt-----T-- -------t~rrttTT-----t~t-------ttt~r~~~tr~~~~~~t----^-- -------t~~rtTTT------~----------t~-~t~~~~trr~~~t------ --T----tt~~tTTt----r~~-----------~~~tttttttt~r~t------ --^----ttt~tTT----~~~t---h-------t~tt---tTTt~-~------- ------tttt~tTt----~r~t-----------t~rt----TTt~~~t------ ------tt~~~t------~-~-----------tr~~~------tt~tt------ ------t~~t--------~~~-----------t~~t~~------t~~~tt---- ------t~~~--------~tt---RT-----~~~ttt~--------t~~~t--- -------~r~--------~tt---RT----t~t----~~---------t~t--- -------~-~--------~~~~t-------t~t----t~---------t~t--- ---T---~~~t-------t~t~~~------~~-----t~---------~~---- --------~~~-------~~--t~-----t~t------~~~-------~t---- ---------t~-------~t---~t----t~t-------t~~------~----- ----------~------~~----~~-----~t--------t~------~~~-~~ -~-------~~------~------~-----~----------~--------~~~~ -~~~-----~---~~~~~------~-----~~---------~-----~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~---~~~-----~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/data/maps/River Delta.json b/data/maps/River Delta.json new file mode 100644 index 0000000..5c1e654 --- /dev/null +++ b/data/maps/River Delta.json @@ -0,0 +1,71 @@ +{ + "terrains": { + "-": 50, + "^": 4, + "r": 1, + "t": 12, + "~": 10 + }, + "map": [ + "........................~~...........................", + "------------------------~~---------------------------", + "---tt-------------------~~---------------------------", + "--tTTt-----------tT-----~~~----t^-----tTt------------", + "--TTTt-----T----tTTt----~r~----^^----tTTTt-----------", + "--TTr-----------tTTt--tt~-~----------tTTTt-----------", + "--TT------------TTT----t~~~----------tTTr------------", + "--T-----T-------TT---t~~~~~----------ttt-------------", + "-------^^-----------~~~--~~------------------------tT", + "-------------------t~--t-~~-----------------------tTT", + "---------------trrt~~---~~~---tTT----------------ttTT", + "-------------t~~~~r~t---~~~---RTT-----------T----tTTT", + "----------tttt~tt~~~---t~~~---RTT----------------TTTT", + "---^-----tTTtt~~ttt----~~~~t--TT-----------------TTTt", + "---------TTTttr~tt-----~~~~t----------------------tt-", + "--------tTTT--~~t----tt~tt~tt------------tt----------", + "-----ttttTT---~ttttt~~~~tt~rt-----------tTTT---------", + "----tTTTT----t~~~~~~~ttttt~~~t---------tTTTt---------", + "----TTTt-----~~ttt~tttTTTttr~~t--------TTTt----------", + "----TTt---ttr~tttt~ttTTTTTttt~ttt--------------------", + "----------~~~~tt-t~~tTT----tt~~~~t-------------------", + "-------~~~~tttt---t~~t-------trr~~~t--tt---tt-----T--", + "------t~rrttTT-----t~t-------ttt~r~~~tr~~~~~~t----^--", + "------t~~rtTTT------~----------t~-~t~~~~trr~~~t------", + "-T----tt~~tTTt----r~~-----------~~~tttttttt~r~t------", + "-^----ttt~tTT----~~~t---h-------t~tt---tTTt~-~-------", + "-----tttt~tTt----~r~t-----------t~rt----TTt~~~t------", + "-----tt~~~t------~-~-----------tr~~~------tt~tt------", + "-----t~~t--------~~~-----------t~~t~~------t~~~tt----", + "-----t~~~--------~tt---RT-----~~~ttt~--------t~~~t---", + "------~r~--------~tt---RT----t~t----~~---------t~t---", + "------~-~--------~~~~t-------t~t----t~---------t~t---", + "--T---~~~t-------t~t~~~------~~-----t~---------~~----", + "-------~~~-------~~--t~-----t~t------~~~-------~t----", + "--------t~-------~t---~t----t~t-------t~~------~-----", + "---------~------~~----~~-----~t--------t~------~~~-~~", + "~-------~~------~------~-----~----------~--------~~~~", + "~~~-----~---~~~~~------~-----~~---------~-----~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~---~~~-----~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + ], + "achievements": [ + "landscape-architect", + "wood-gnome", + "fisherman-guild", + "farmer-guild" + ], + "description": [ + "A larger (53x46) map of a river delta. Plenty of resources, but a lot of waterways to bridge.", + "Available random tiles: 0!" + ], + "center": { + "X": 24, + "Y": 25 + }, + "initial_terrains": 0 +} \ No newline at end of file diff --git a/data/maps/River.asc b/data/maps/River.asc deleted file mode 100644 index c8e33fc..0000000 --- a/data/maps/River.asc +++ /dev/null @@ -1,25 +0,0 @@ -1r 20- 4^ 6~ 1+ 6t -500 -play-the-game -A small (20x20) starting area with a river. -Available random tiles: 500. ----- -8 8 -......---------~.... -....-----------~-... -...------------~t-.. -..-----TTT----t~t--. -.-----TTTT----t~~t-. -.----rTTT-----rt~t-- -------Tt------rt~t-- ----------------t~~-- ---ttt---h------tt~-- -~~~~~t--------ttt~-- ----t~~t----t~~~~t~-- -----t~t---tt~tt~~~-- -.----~~~~~~~~t------ -..--------ttt-^^---. -...---------^^----.. -....---tt--------... -.....--tt-------.... -......---------..... diff --git a/data/maps/River.json b/data/maps/River.json new file mode 100644 index 0000000..fa4660e --- /dev/null +++ b/data/maps/River.json @@ -0,0 +1,42 @@ +{ + "terrains": { + "+": 1, + "-": 20, + "^": 4, + "r": 1, + "t": 6, + "~": 6 + }, + "map": [ + "......---------~....", + "....-----------~-...", + "...------------~t-..", + "..-----TTT----t~t--.", + ".-----TTTT----t~~t-.", + ".----rTTT-----rt~t--", + "------Tt------rt~t--", + "---------------t~~--", + "--ttt---h------tt~--", + "~~~~~t--------ttt~--", + "---t~~t----t~~~~t~--", + "----t~t---tt~tt~~~--", + ".----~~~~~~~~t------", + "..--------ttt-^^---.", + "...---------^^----..", + "....---tt--------...", + ".....--tt-------....", + "......---------....." + ], + "achievements": [ + "play-the-game" + ], + "description": [ + "A small (20x20) starting area with a river.", + "Available random tiles: 500." + ], + "center": { + "X": 8, + "Y": 8 + }, + "initial_terrains": 500 +} \ No newline at end of file diff --git a/data/maps/Rolling Hills.asc b/data/maps/Rolling Hills.asc deleted file mode 100644 index 6c4014d..0000000 --- a/data/maps/Rolling Hills.asc +++ /dev/null @@ -1,33 +0,0 @@ -50- 20^ 6~ 20t 0+ 1r -500 -landscape-architect shepherd-guild -A small-ish (25x25) map with lots of hills and trees, and a river. -Available random tiles: 500. ----- -12 12 -TTTTT---TTTT-------ttt-TTT -TTTt-----TT-------tTTT--TT -TT----t-----------TTt----- -TT---TTT----------TT----~~ -R----TT------ttT^-----~~~- -----tTT--TT-ttTT------~t-t ----TTT--TTT-TTTT-----t~--T ---TTTT--TT--TTT---^--~~-TT ----TT------TTR---TT--~t-TT ------------TT--TTT---~t--T ----------T--R--T^----~~~-- -tt------TT---------T^--~-- -tTT----TT---h-----TTT--~-- -TTT----TT-------RTTT--~~-- -TTT-----T^------------~--- -TT--~~~~---------~~~~t~--- ----~~--~~~----t~~~--~~~--R -~~~~--T--~t~~~~~---------T ------TTT-~~~--------TR---T ----TTTTT--------^--TT----- -T--TTt-RR-----TTT-TTt----- -TT-----------TTT---TT----T -TT-----------TT---TTT--R-T -TT-TT-------TTT---TT----TT --TTTT-------T^----T----TTT --^TT------------------TTTT diff --git a/data/maps/Rolling Hills.json b/data/maps/Rolling Hills.json new file mode 100644 index 0000000..6e96440 --- /dev/null +++ b/data/maps/Rolling Hills.json @@ -0,0 +1,50 @@ +{ + "terrains": { + "-": 50, + "^": 20, + "r": 1, + "t": 20, + "~": 6 + }, + "map": [ + "TTTTT---TTTT-------ttt-TTT", + "TTTt-----TT-------tTTT--TT", + "TT----t-----------TTt-----", + "TT---TTT----------TT----~~", + "R----TT------ttT^-----~~~-", + "----tTT--TT-ttTT------~t-t", + "---TTT--TTT-TTTT-----t~--T", + "--TTTT--TT--TTT---^--~~-TT", + "---TT------TTR---TT--~t-TT", + "-----------TT--TTT---~t--T", + "---------T--R--T^----~~~--", + "tt------TT---------T^--~--", + "tTT----TT---h-----TTT--~--", + "TTT----TT-------RTTT--~~--", + "TTT-----T^------------~---", + "TT--~~~~---------~~~~t~---", + "---~~--~~~----t~~~--~~~--R", + "~~~~--T--~t~~~~~---------T", + "-----TTT-~~~--------TR---T", + "---TTTTT--------^--TT-----", + "T--TTt-RR-----TTT-TTt-----", + "TT-----------TTT---TT----T", + "TT-----------TT---TTT--R-T", + "TT-TT-------TTT---TT----TT", + "-TTTT-------T^----T----TTT", + "-^TT------------------TTTT" + ], + "achievements": [ + "landscape-architect", + "shepherd-guild" + ], + "description": [ + "A small-ish (25x25) map with lots of hills and trees, and a river.", + "Available random tiles: 500." + ], + "center": { + "X": 12, + "Y": 12 + }, + "initial_terrains": 500 +} \ No newline at end of file diff --git a/data/maps/Swamp Forest.asc b/data/maps/Swamp Forest.asc deleted file mode 100644 index 493b8f8..0000000 --- a/data/maps/Swamp Forest.asc +++ /dev/null @@ -1,34 +0,0 @@ -25t 1r 40- 1^ 6~ -500 -wood-gnome -A small-ish (27x27) map with a swampy forest full of ponds. -Available random tiles: 500. ----- -13 13 -............---............ -........-----t-----........ -......---ttttttttr---...... -.....--t~~~tt~~ttr-t--..... -....--ttttttt~~ttttt~--.... -...--tttttttttttt^^t~~--... -..-~~ttt~~~ttt--tt-tt~t--.. -..-~~ttt~~~ttt---tttt~tt-.. -.--ttttttttttt---t~tttttt-. -.-ttttr^-----tttttttttttt-. -.-ttttr--ttt--t~~ttt^^t~~-. -.-tt~tt-t~~tt-t~~ttt^-t~~-. ---tt~tt-tttttt--trttt--tt-- ---tt~t----ttth---ttt~t--tt- ----tttttt-tttt-----t~t--t-- -.--t-tt~~tttttt--ttttt~-t-. -.-tTttt~~tttrrttt~~ttt--t-. -.-tTrtt~~~~trr-tt~~tt--t--. -.-ttr-t~~~~tt--tt~~ttttt--. -..-tt-tttttttttttttttttt-.. -..--tt----tTt~~t--t~~ttt-.. -...--tttt-^^t~~t--ttttt-... -....--tt~t^^ttttttttt--.... -.....--t~tTttttttttt--..... -......---ttt-ttttt---...... -........-----t-----........ -............---............ diff --git a/data/maps/Swamp Forest.json b/data/maps/Swamp Forest.json new file mode 100644 index 0000000..7fbbb5e --- /dev/null +++ b/data/maps/Swamp Forest.json @@ -0,0 +1,50 @@ +{ + "terrains": { + "-": 40, + "^": 1, + "r": 1, + "t": 25, + "~": 6 + }, + "map": [ + "............---............", + "........-----t-----........", + "......---ttttttttr---......", + ".....--t~~~tt~~ttr-t--.....", + "....--ttttttt~~ttttt~--....", + "...--tttttttttttt^^t~~--...", + "..-~~ttt~~~ttt--tt-tt~t--..", + "..-~~ttt~~~ttt---tttt~tt-..", + ".--ttttttttttt---t~tttttt-.", + ".-ttttr^-----tttttttttttt-.", + ".-ttttr--ttt--t~~ttt^^t~~-.", + ".-tt~tt-t~~tt-t~~ttt^-t~~-.", + "--tt~tt-tttttt--trttt--tt--", + "--tt~t----ttth---ttt~t--tt-", + "---tttttt-tttt-----t~t--t--", + ".--t-tt~~tttttt--ttttt~-t-.", + ".-tTttt~~tttrrttt~~ttt--t-.", + ".-tTrtt~~~~trr-tt~~tt--t--.", + ".-ttr-t~~~~tt--tt~~ttttt--.", + "..-tt-tttttttttttttttttt-..", + "..--tt----tTt~~t--t~~ttt-..", + "...--tttt-^^t~~t--ttttt-...", + "....--tt~t^^ttttttttt--....", + ".....--t~tTttttttttt--.....", + "......---ttt-ttttt---......", + "........-----t-----........", + "............---............" + ], + "achievements": [ + "wood-gnome" + ], + "description": [ + "A small-ish (27x27) map with a swampy forest full of ponds.", + "Available random tiles: 500." + ], + "center": { + "X": 13, + "Y": 13 + }, + "initial_terrains": 500 +} \ No newline at end of file diff --git a/docs/SCENARIOS.md b/docs/SCENARIOS.md index 80ba52b..7f1c76c 100644 --- a/docs/SCENARIOS.md +++ b/docs/SCENARIOS.md @@ -25,43 +25,59 @@ as well as required achievement and the map description can be tweaked by editin ## Map Format -A small example map is shown below. +Maps are saved in JSON format. See the example below. -* The 1st line contains frequencies of random terrains. -* The second line contains the number of initially placable trains. -* The 3rd line contains a list of required achievements, separated by spaces. -* Subsequent lines contain the map description, up to the first line that starts with `----`. -* The 1st line after the delimiter `----` contains the relative coordinates of the starting position, from the top-left corner (0,0). -* All further lines are the actual map. +* `terrains` contains frequencies of random terrains. +* `initial_terrains` is the number of initially placable trains. +* `achievements` is a list of required achievements. +* `description` is the scenario description shown in the main menu tooltip. +* `center` is the relative starting position, from the top-left corner (0,0). +* `map` is the actual map. Terrain characters are defined in [`data/json/terrain.json`](https://github.com/mlange-42/tiny-world/blob/main/data/json/terrain.json). Achievements are defined in [`data/json/achievements.json`](https://github.com/mlange-42/tiny-world/blob/main/data/json/achievements.json) -``` -1r 20- 6^ 6~ 1+ 6t -500 -play-the-game -Description of the map. -Can be an arbitrary number of lines. -Terminated by a line starting with ---- ----- -8 8 -......---------~.... -....-----------~-... -...------------~t-.. -..-----TTT----t~t--. -.-----TTTT----t~~t-. -.----rTTT-----rt~t-- -------Tt------rt~t-- ----------------t~~-- ---ttt---h------tt~-- -~~~~~t--------ttt~-- ----t~~t----t~~~~t~-- -----t~t---tt~tt~~~-- -.----~~~~~~~~t------ -..--------ttt-^^---. -...---------^^----.. -....---tt--------... -.....--tt-------.... -......---------..... +```json +{ + "terrains": { + "+": 1, + "-": 20, + "^": 4, + "r": 1, + "t": 6, + "~": 6 + }, + "map": [ + "......---------~....", + "....-----------~-...", + "...------------~t-..", + "..-----TTT----t~t--.", + ".-----TTTT----t~~t-.", + ".----rTTT-----rt~t--", + "------Tt------rt~t--", + "---------------t~~--", + "--ttt---h------tt~--", + "~~~~~t--------ttt~--", + "---t~~t----t~~~~t~--", + "----t~t---tt~tt~~~--", + ".----~~~~~~~~t------", + "..--------ttt-^^---.", + "...---------^^----..", + "....---tt--------...", + ".....--tt-------....", + "......---------....." + ], + "achievements": [ + "play-the-game" + ], + "description": [ + "A small (20x20) starting area with a river.", + "Available random tiles: 500." + ], + "center": { + "X": 8, + "Y": 8 + }, + "initial_terrains": 500 +} ``` diff --git a/game/save/load.go b/game/save/load.go index df43c67..017bfd8 100644 --- a/game/save/load.go +++ b/game/save/load.go @@ -1,56 +1,19 @@ package save import ( + "encoding/json" "fmt" - "image" "io/fs" "path" "path/filepath" "slices" - "strconv" "strings" - "time" "github.com/mlange-42/arche/ecs" "github.com/mlange-42/tiny-world/game/comp" "github.com/mlange-42/tiny-world/game/maps" ) -type LoadType uint8 - -type MapLocation struct { - Name string - IsEmbedded bool -} - -type SaveGame struct { - Name string - Time time.Time -} - -type saveGame struct { - Resources saveGameResources -} - -type saveGameResources struct { - SaveTime saveTime `json:"res.SaveTime"` -} - -type saveTime struct { - Time time.Time -} - -type MapInfo struct { - Achievements []string - Description string -} - -const ( - LoadTypeNone LoadType = iota - LoadTypeGame - LoadTypeMap -) - func LoadWorld(world *ecs.World, folder, name string) error { _ = ecs.ComponentID[comp.Tile](world) _ = ecs.ComponentID[comp.Terrain](world) @@ -94,61 +57,26 @@ func LoadMap(f fs.FS, folder string, mapLoc MapLocation) (maps.Map, error) { } func ParseMap(mapStr string) (maps.Map, error) { - var result [][]rune - lines := strings.Split(strings.ReplaceAll(mapStr, "\r\n", "\n"), "\n") + helper := mapJs{} + err := json.Unmarshal([]byte(mapStr), &helper) + if err != nil { + return maps.Map{}, nil + } - terrainParts := strings.Split(lines[0], " ") terrains := []rune{} - for _, p := range terrainParts { - rn := []rune(p) - sym := rn[len(rn)-1] - cnt, err := strconv.Atoi(string(rn[:len(rn)-1])) - if err != nil { - panic(fmt.Sprintf("can't convert to integer in map symbols: `%s`", string(rn[:len(rn)-1]))) + for tStr, cnt := range helper.Terrains { + rn := []rune(tStr) + if len(rn) > 1 { + return maps.Map{}, fmt.Errorf("symbols must be single runes. Got '%s'", tStr) } + sym := rn[0] for i := 0; i < cnt; i++ { terrains = append(terrains, sym) } } - randTerr, err := strconv.Atoi(lines[1]) - if err != nil { - panic(fmt.Sprintf("can't convert to integer in map initial random terrains: `%s`", lines[1])) - } - - ach := strings.Split(lines[2], " ") - achievements := []string{} - for _, a := range ach { - if a != "" { - achievements = append(achievements, a) - } - } - - description := []string{} - lineIdx := 3 - for { - line := lines[lineIdx] - lineIdx++ - if strings.HasPrefix(line, mapDescriptionDelimiter) { - break - } - description = append(description, line) - } - - sizeLine := lines[lineIdx] - parts := strings.Split(sizeLine, " ") - cx, err := strconv.Atoi(parts[0]) - if err != nil { - panic(fmt.Sprintf("can't convert to integer: `%s`", parts[0])) - } - cy, err := strconv.Atoi(parts[1]) - if err != nil { - panic(fmt.Sprintf("can't convert to integer: `%s`", parts[1])) - } - - lines = lines[lineIdx+1:] - - for _, s := range lines { + var result [][]rune + for _, s := range helper.Map { if len(s) > 0 { runes := []rune(s) result = append(result, runes) @@ -158,10 +86,10 @@ func ParseMap(mapStr string) (maps.Map, error) { return maps.Map{ Data: result, Terrains: terrains, - InitialRandomTerrains: randTerr, - Center: image.Pt(cx, cy), - Achievements: achievements, - Description: strings.Join(description, "\n"), + InitialRandomTerrains: helper.InitialRandomTerrains, + Center: helper.Center, + Achievements: helper.Achievements, + Description: strings.Join(helper.Description, "\n"), }, nil } @@ -170,29 +98,13 @@ func LoadMapData(f fs.FS, folder string, mapLoc MapLocation) (MapInfo, error) { if err != nil { return MapInfo{}, err } - - lines := strings.Split(strings.ReplaceAll(mapStr, "\r\n", "\n"), "\n") - - ach := strings.Split(lines[2], " ") - achievements := []string{} - for _, a := range ach { - if a != "" { - achievements = append(achievements, a) - } - } - - description := []string{} - lineIdx := 3 - for { - line := lines[lineIdx] - lineIdx++ - if strings.HasPrefix(line, mapDescriptionDelimiter) { - break - } - description = append(description, line) + helper := mapInfoJs{} + err = json.Unmarshal([]byte(mapStr), &helper) + if err != nil { + return MapInfo{}, nil } - return MapInfo{Achievements: achievements, Description: strings.Join(description, "\n")}, nil + return MapInfo{Achievements: helper.Achievements, Description: strings.Join(helper.Description, "\n")}, nil } func ListMaps(f fs.FS, folder string) ([]MapLocation, error) { @@ -209,7 +121,7 @@ func ListMaps(f fs.FS, folder string) ([]MapLocation, error) { func loadMap(f fs.FS, folder string, mapLoc MapLocation) (string, error) { if mapLoc.IsEmbedded { - mapData, err := fs.ReadFile(f, path.Join("data", folder, mapLoc.Name)+".asc") + mapData, err := fs.ReadFile(f, path.Join("data", folder, mapLoc.Name)+".json") if err != nil { return "", err } @@ -233,8 +145,8 @@ func listMapsEmbed(f fs.FS, folder string) ([]MapLocation, error) { continue } ext := filepath.Ext(file.Name()) - if ext == ".asc" { - base := strings.TrimSuffix(file.Name(), ".asc") + if ext == ".json" { + base := strings.TrimSuffix(file.Name(), ".json") maps = append(maps, MapLocation{Name: base, IsEmbedded: true}) } } diff --git a/game/save/load_nowasm.go b/game/save/load_nowasm.go index 64122ed..d27b337 100644 --- a/game/save/load_nowasm.go +++ b/game/save/load_nowasm.go @@ -27,7 +27,7 @@ func loadSaveTime(folder, name string) (saveTime, error) { if err != nil { return saveTime{}, err } - helper := saveGame{} + helper := saveGameInfo{} err = json.Unmarshal(jsData, &helper) if err != nil { return saveTime{}, err @@ -84,8 +84,8 @@ func listMapsLocal(folder string) ([]MapLocation, error) { continue } ext := filepath.Ext(file.Name()) - if ext == ".asc" { - base := strings.TrimSuffix(file.Name(), ".asc") + if ext == ".json" { + base := strings.TrimSuffix(file.Name(), ".json") maps = append(maps, MapLocation{Name: base, IsEmbedded: false}) } } @@ -93,7 +93,7 @@ func listMapsLocal(folder string) ([]MapLocation, error) { } func loadMapLocal(folder string, name string) (string, error) { - mapData, err := os.ReadFile(path.Join(folder, name) + ".asc") + mapData, err := os.ReadFile(path.Join(folder, name) + ".json") if err != nil { return "", err } diff --git a/game/save/load_wasm.go b/game/save/load_wasm.go index d1eefc1..a987fe1 100644 --- a/game/save/load_wasm.go +++ b/game/save/load_wasm.go @@ -26,7 +26,7 @@ func loadSaveTime(folder, name string) (saveTime, error) { storage := js.Global().Get("localStorage") jsData := storage.Call("getItem", saveGamePrefix+name) - helper := saveGame{} + helper := saveGameInfo{} err := json.Unmarshal([]byte(jsData.String()), &helper) if err != nil { return saveTime{}, err diff --git a/game/save/save.go b/game/save/save.go index a8e6c31..d238a29 100644 --- a/game/save/save.go +++ b/game/save/save.go @@ -1,7 +1,9 @@ package save import ( + "encoding/json" "fmt" + "image" "regexp" "strings" @@ -12,8 +14,6 @@ import ( "github.com/mlange-42/tiny-world/game/terr" ) -const mapDescriptionDelimiter = "----" - func SaveWorld(folder, name string, world *ecs.World, skip []generic.Comp) error { js, err := as.Serialize(world, as.Opts.SkipResources( @@ -45,14 +45,12 @@ func DeleteGame(folder, name string) error { } func SaveMap(folder, name string, world *ecs.World) error { - b := strings.Builder{} - rules := ecs.GetResource[res.Rules](world) bounds := ecs.GetResource[res.WorldBounds](world) terrain := ecs.GetResource[res.Terrain](world) landUse := ecs.GetResource[res.LandUse](world) - terrains := map[rune]int{} + terrains := map[string]int{} for _, t := range rules.RandomTerrains { var tp terr.TerrainPair @@ -65,31 +63,18 @@ func SaveMap(folder, name string, world *ecs.World) error { if !ok { return fmt.Errorf("symbol not found for %s/%s", terr.Properties[tp.Terrain].Name, terr.Properties[tp.LandUse].Name) } - if cnt, ok := terrains[sym]; ok { - terrains[sym] = cnt + 1 + symStr := string(sym) + if cnt, ok := terrains[symStr]; ok { + terrains[symStr] = cnt + 1 } else { - terrains[sym] = 1 + terrains[symStr] = 1 } } - symbols := []string{} - for sym, cnt := range terrains { - symbols = append(symbols, fmt.Sprintf("%d%s", cnt, string(sym))) - } - b.WriteString(strings.Join(symbols, " ")) - b.WriteString("\n") - - b.WriteString(fmt.Sprintf("%d\n", rules.InitialRandomTerrains)) - - // Space for required achievements - b.WriteString("\n") - - // Delimiter for map description - b.WriteString(mapDescriptionDelimiter + "\n") - - cx, cy := terrain.Width()/2, terrain.Height()/2 - b.WriteString(fmt.Sprintf("%d %d\n", cx-bounds.Min.X, cy-bounds.Min.Y)) + center := image.Pt(terrain.Width()/2-bounds.Min.X, terrain.Height()/2-bounds.Min.Y) + rows := make([]string, bounds.Dy()+1) + b := strings.Builder{} for y := bounds.Min.Y; y <= bounds.Max.Y; y++ { for x := bounds.Min.X; x <= bounds.Max.X; x++ { ter := terrain.Get(x, y) @@ -103,8 +88,22 @@ func SaveMap(folder, name string, world *ecs.World) error { } b.WriteRune(sym) } - b.WriteString("\n") + rows[y-bounds.Min.Y] = b.String() + b.Reset() + } + + mapJs := mapJs{ + Terrains: terrains, + Center: center, + InitialRandomTerrains: rules.InitialRandomTerrains, + Achievements: []string{}, + Description: []string{}, + Map: rows, + } + jsData, err := json.MarshalIndent(mapJs, "", " ") + if err != nil { + return err } - return saveMapToFile(folder, name, b.String()) + return saveMapToFile(folder, name, string(jsData)) } diff --git a/game/save/save_nowasm.go b/game/save/save_nowasm.go index e83f9ef..3827fe0 100644 --- a/game/save/save_nowasm.go +++ b/game/save/save_nowasm.go @@ -57,7 +57,7 @@ func deleteGame(folder, name string) error { } func saveMapToFile(folder, name string, mapData string) error { - file := path.Join(folder, name) + ".asc" + file := path.Join(folder, name) + ".json" dir := filepath.Dir(file) err := os.MkdirAll(dir, os.ModePerm) if err != nil { diff --git a/game/save/types.go b/game/save/types.go new file mode 100644 index 0000000..a6731d3 --- /dev/null +++ b/game/save/types.go @@ -0,0 +1,55 @@ +package save + +import ( + "image" + "time" +) + +type LoadType uint8 + +const ( + LoadTypeNone LoadType = iota + LoadTypeGame + LoadTypeMap +) + +type MapLocation struct { + Name string + IsEmbedded bool +} + +type SaveGame struct { + Name string + Time time.Time +} + +type saveGameInfo struct { + Resources saveGameResources +} + +type saveGameResources struct { + SaveTime saveTime `json:"res.SaveTime"` +} + +type saveTime struct { + Time time.Time +} + +type MapInfo struct { + Achievements []string + Description string +} + +type mapInfoJs struct { + Achievements []string `json:"achievements"` + Description []string `json:"description"` +} + +type mapJs struct { + Terrains map[string]int `json:"terrains"` + Map []string `json:"map"` + Achievements []string `json:"achievements"` + Description []string `json:"description"` + Center image.Point `json:"center"` + InitialRandomTerrains int `json:"initial_terrains"` +}