1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Merge pull request #3714 from vcmi/biome_system

Biome system implementation
This commit is contained in:
DjWarmonger
2024-04-13 21:32:13 +02:00
committed by GitHub
19 changed files with 1623 additions and 3 deletions

View File

@@ -37,6 +37,7 @@ void CGameInfo::setFromLib()
terrainTypeHandler = VLC->terrainTypeHandler;
battleFieldHandler = VLC->battlefieldsHandler;
obstacleHandler = VLC->obstacleHandler;
//TODO: biomeHandler?
}
const ArtifactService * CGameInfo::artifacts() const

689
config/biomes.json Normal file
View File

@@ -0,0 +1,689 @@
{
"templateSet2":{
"biome":{
"terrain" : "dirt",
"objectType" : "crater"
},
"templates" : ["AVLct1d0", "AVLct2d0", "AVLct3d0", "AVLct4d0", "AVLct5d0", "AVLctrd0"]
},
"dirtRedFlowers":{
"biome":{
"terrain" : "dirt",
"objectType" : "plant"
},
"templates" : ["AVLfl1d0", "AVLfl6d0", "AVLfl7d0"]
},
"dirtLightFlowers":{
"biome":{
"terrain" : "dirt",
"objectType" : "plant"
},
"templates" : ["AVLfl4d0", "AVLfl5d0"]
},
"dirtYellowFlowers":{
"biome":{
"terrain" : "dirt",
"objectType" : "plant"
},
"templates" : ["AVLfl3d0", "AVLfl8d0"]
},
"dirtPurpleFlowers":{
"biome":{
"terrain" : "dirt",
"objectType" : "plant"
},
"templates" : ["AVLfl2d0", "AVLfl9d0"]
},
"templateSet5":{
"biome":{
"terrain" : "dirt",
"objectType" : "lake"
},
"templates" : ["AVLlk1d0", "AVLlk2d0", "AVLlk3d0"]
},
"templateSet7":{
"biome":{
"terrain" : "dirt",
"objectType" : "rock"
},
"templates" : ["AVLmd1d0", "AVLmd2d0"]
},
"templateSet8":{
"biome":{
"terrain" : "dirt",
"objectType" : "mountain"
},
"templates" : ["avlmtdr1", "avlmtdr2", "avlmtdr3", "avlmtdr4", "avlmtdr5", "avlmtdr6", "avlmtdr7", "avlmtdr8"]
},
"templateSet9":{
"biome":{
"terrain" : "dirt",
"objectType" : "tree"
},
"templates" : ["avlautr0", "avlautr1", "AVLAUTR2", "AVLAUTR3", "AVLAUTR4", "AVLAUTR5", "AVLautr6", "AVLautr7"]
},
"templateSet10":{
"biome":{
"terrain" : "dirt",
"objectType" : "rock"
},
"templates" : ["AVLoc1d0", "AVLoc2d0", "AVLoc3d0"]
},
"templateSet11":{
"biome":{
"terrain" : "dirt",
"objectType" : "tree"
},
"templates" : ["AVLPNTR0", "AVLPNTR1", "AVLPNTR2", "AVLPNTR3", "AVLPNTR4", "AVLPNTR5", "AVLpntr6", "AVLpntr7"]
},
"templateSet13":{
"biome":{
"terrain" : "dirt",
"objectType" : "rock"
},
"templates" : ["AvLRD01", "AvLRD02", "AvLRD04", "AVLrk3d0", "AVLrk5d0"]
},
"templateSet14":{
"biome":{
"terrain" : "dirt",
"objectType" : "plant"
},
"templates" : ["AVLsh1d0", "AVLsh2d0", "AVLsh3d0", "AVLsh4d0", "AVLsh5d0", "AVLsh6d0", "AVLsh7d0", "AVLsh8d0"]
},
"dirtStumps":{
"biome":{
"terrain" : "dirt",
"objectType" : "plant"
},
"templates" : ["AvLdlog", "AvLStm1", "AvLStm2", "AvLStm3"]
},
"templateSet16":{
"biome":{
"terrain" : "dirt",
"objectType" : "tree"
},
"templates" : ["AVLtr1d0", "AVLtr2d0", "AVLtr3d0"]
},
"templateSet17":{
"biome":{
"terrain" : "dirt",
"objectType" : "other"
},
"templates" : ["avlxdt00", "avlxdt01", "avlxdt02", "avlxdt03", "avlxdt04", "avlxdt05", "avlxdt06", "avlxdt07", "avlxdt08", "avlxdt09", "avlxdt10", "avlxdt11"]
},
"cactus":{
"biome":{
"terrain" : "sand",
"objectType" : "plant"
},
"templates" : ["AVLca010", "AVLca020", "AVLca030", "AVLca040", "AVLca050", "AVLca060", "AVLca070", "AVLca080", "AVLca090", "AVLca100", "AVLca110", "AVLca120", "AVLca130"]
},
"sandCraters":{
"biome":{
"terrain" : "sand",
"objectType" : "crater"
},
"templates" : ["AVLctds0", "AVLspit0"]
},
"templateSet32":{
"biome":{
"terrain" : "sand",
"objectType" : "mountain"
},
"templates" : ["AVLmtds1", "AVLmtds2", "AVLmtds3", "AVLmtds4", "AVLmtds5", "AVLmtds6"]
},
"templateSet34":{
"biome":{
"terrain" : "sand",
"objectType" : "rock"
},
"templates" : ["AVLdun10", "AVLdun20", "AVLdun30"]
},
"templateSet36":{
"biome":{
"terrain" : "sand",
"objectType" : "animal"
},
"templates" : ["AVLskul0"]
},
"sandPalms":{
"biome":{
"terrain" : "sand",
"objectType" : "tree"
},
"templates" : ["AVLplm10", "AVLplm20", "AVLplm30", "AVLplm40", "AVLplm50"]
},
"sandYucca":{
"biome":{
"terrain" : "sand",
"objectType" : "plant"
},
"templates" : ["AVLyuc10", "AVLyuc20", "AVLyuc30"]
},
"templateSet38":{
"biome":{
"terrain" : "sand",
"objectType" : "other"
},
"templates" : ["avlxds01", "avlxds02", "avlxds03", "avlxds04", "avlxds05", "avlxds06", "avlxds07", "avlxds08", "avlxds09", "avlxds10", "avlxds11", "avlxds12"]
},
"templateSet50":{
"biome":{
"terrain" : "grass",
"objectType" : "crater"
},
"templates" : ["AVLct1g0", "AVLct2g0", "AVLct3g0", "AVLct4g0", "AVLct5g0", "AVLct6g0", "AVLctrg0"]
},
"grassRedFlowers":{
"biome":{
"terrain" : "grass",
"objectType" : "plant"
},
"templates" : ["AVLf01g0", "AVLf02g0", "AVLf07g0"]
},
"grassPurpleFlowers":{
"biome":{
"terrain" : "grass",
"objectType" : "plant"
},
"templates" : ["AVLf03g0", "AVLf08g0", "AVLf12g0"]
},
"grassYellowFlowers":{
"biome":{
"terrain" : "grass",
"objectType" : "plant"
},
"templates" : ["AVLf04g0", "AVLf05g0", "AVLf09g0", "AVLf10g0", "AVLf11g0"]
},
"grassWhiteFlowers":{
"biome":{
"terrain" : "grass",
"objectType" : "plant"
},
"templates" : ["AVLf06g0"]
},
"templateSet53":{
"biome":{
"terrain" : "grass",
"objectType" : "lake"
},
"templates" : ["AVLlk1g0", "AVLlk2g0", "AVLlk3g0"]
},
"templateSet54":{
"biome":{
"terrain" : "grass",
"objectType" : "plant"
},
"templates" : ["AvLdlog"]
},
"templateSet55":{
"biome":{
"terrain" : "grass",
"objectType" : "rock"
},
"templates" : ["AVLmd1g0", "AVLmd2g0"]
},
"greyMountains":{
"biome":{
"terrain" : "grass",
"objectType" : "mountain"
},
"templates" : ["AVLmtgn0", "AVLmtgn1", "AVLmtgn2", "AVLmtgn3", "AVLmtgn4", "AVLmtgn5"]
},
"brownMountains":{
"biome":{
"terrain" : "grass",
"objectType" : "mountain"
},
"templates" : ["AVLmtgr1", "AVLmtgr2", "AVLmtgr3", "AVLmtgr4", "AVLmtgr5", "AVLmtgr6"]
},
"greenOakTrees":{
"biome":{
"terrain" : "grass",
"objectType" : "tree"
},
"templates" : ["AVLSPTR0", "AVLSPTR1", "AVLSPTR2", "AVLSPTR3", "AVLSPTR4", "AVLSPTR5", "AVLSPTR6", "AVLsptr7", "AVLsptr8"]
},
"autumnOakTrees":{
"biome":{
"terrain" : "grass",
"objectType" : "tree"
},
"templates" : ["avlautr0", "avlautr1", "AVLAUTR2", "AVLAUTR3", "AVLAUTR4", "AVLAUTR5", "AVLautr6", "AVLautr7"]
},
"templateSet58":{
"biome":{
"terrain" : "grass",
"objectType" : "rock"
},
"templates" : ["AVLoc1g0", "AVLoc2g0", "AVLoc3g0"]
},
"templateSet59":{
"biome":{
"terrain" : "grass",
"objectType" : "tree"
},
"templates" : ["AVLPNTR0", "AVLPNTR1", "AVLPNTR2", "AVLPNTR3", "AVLPNTR4", "AVLPNTR5", "AVLpntr6", "AVLpntr7"]
},
"templateSet61":{
"biome":{
"terrain" : "grass",
"objectType" : "rock"
},
"templates" : ["AvLRG01", "AvLRG02", "AvLRG03", "AvLRG04", "AvLRG05", "AvLRG06", "AvLRG07", "AvLRG08", "AvLRG09", "AvLRG10", "AvLRG11"]
},
"templateSet62":{
"biome":{
"terrain" : "grass",
"objectType" : "plant"
},
"templates" : ["AVLsh1g0", "AVLsh2g0", "AVLsh3g0", "AVLsh4g0", "AVLsh5g0", "AVLsh6g0"]
},
"templateSet63":{
"biome":{
"terrain" : "grass",
"objectType" : "plant"
},
"templates" : ["AvLStm1", "AvLStm2", "AvLStm3"]
},
"swampTreesOnGrass":{
"biome":{
"terrain" : "grass",
"faction" : "fortress",
"objectType" : "tree"
},
"templates" : ["AVLswmp0", "AVLswmp1", "AVLswmp2", "AVLswmp3", "AVLswmp4", "AVLswmp5", "AVLswmp6", "AVLswmp7", "AVLtr1d0", "AVLtr2d0", "AVLtr3d0", "AVLwlw10", "AVLwlw20", "AVLwlw30"]
},
"templateSet65":{
"biome":{
"terrain" : "grass",
"objectType" : "other"
},
"templates" : ["avlxgr01", "avlxgr02", "avlxgr03", "avlxgr04", "avlxgr05", "avlxgr06", "avlxgr07", "avlxgr08", "avlxgr09", "avlxgr10", "avlxgr11", "avlxgr12"]
},
"templateSet77":{
"biome":{
"terrain" : "snow",
"objectType" : "crater"
},
"templates" : ["AVLctsn0"]
},
"templateSet78":{
"biome":{
"terrain" : "snow",
"objectType" : "tree"
},
"templates" : ["AVLd1sn0", "AVLd2sn0", "AVLd3sn0", "AVLd4sn0", "AVLd5sn0", "AVLd6sn0", "AVLd7sn0", "AVLd8sn0", "AVLd9sn0", "AVLddsn0", "AVLddsn1", "AVLddsn2", "AVLddsn3", "AVLddsn4", "AVLddsn5", "AVLddsn6", "AVLddsn7"]
},
"templateSet79":{
"biome":{
"terrain" : "snow",
"objectType" : "lake"
},
"templates" : ["AVLflk10", "AVLflk20", "AVLflk30"]
},
"templateSet81":{
"biome":{
"terrain" : "snow",
"objectType" : "mountain"
},
"templates" : ["AVLmtsn1", "AVLmtsn2", "AVLmtsn3", "AVLmtsn4", "AVLmtsn5", "AVLmtsn6"]
},
"templateSet82":{
"biome":{
"terrain" : "snow",
"objectType" : "rock"
},
"templates" : ["AVLo1sn0", "AVLo2sn0", "AVLo3sn0"]
},
"templateSet83":{
"biome":{
"terrain" : "snow",
"objectType" : "tree"
},
"templates" : ["AVLSNTR0", "AVLSNTR1", "AVLSNTR2", "AVLSNTR3", "AVLSNTR4", "AVLSNTR5", "AVLsntr6", "AVLsntr7"]
},
"templateSet85":{
"biome":{
"terrain" : "snow",
"objectType" : "rock"
},
"templates" : ["AVLr1sn0", "AVLr2sn0", "AVLr3sn0", "AVLr4sn0", "AVLr5sn0", "AVLr6sn0", "AVLr7sn0", "AVLr8sn0"]
},
"templateSet86":{
"biome":{
"terrain" : "snow",
"objectType" : "plant"
},
"templates" : ["AVLs1sn0", "AVLs2sn0", "AVLs3sn0"]
},
"templateSet87":{
"biome":{
"terrain" : "snow",
"objectType" : "plant"
},
"templates" : ["AVLp1sn0", "AVLp2sn0"]
},
"templateSet99":{
"biome":{
"terrain" : "swamp",
"objectType" : "crater"
},
"templates" : ["AVLctrs0"]
},
"templateSet100":{
"biome":{
"terrain" : "swamp",
"objectType" : "tree"
},
"templates" : ["AVLdead0", "AVLdead1", "AVLdead2", "AVLdead3", "AVLdead4", "AVLdead5", "AVLdead6", "AVLdead7", "AVLdt1s0", "AVLdt2s0", "AVLdt3s0", "AVLswp60", "AVLswp70"]
},
"templateSet102":{
"biome":{
"terrain" : "swamp",
"objectType" : "lake"
},
"templates" : ["AVLlk1s0", "AVLlk2s0", "AVLlk3s0", "AVLswp50"]
},
"templateSet103":{
"biome":{
"terrain" : "swamp",
"objectType" : "plant"
},
"templates" : ["AVLman10", "AVLman20", "AVLman30", "AVLman40", "AVLman50"]
},
"templateSet104":{
"biome":{
"terrain" : "swamp",
"objectType" : "plant"
},
"templates" : ["AVLmoss0"]
},
"templateSet105":{
"biome":{
"terrain" : "swamp",
"objectType" : "mountain"
},
"templates" : ["AVLmtsw1", "AVLmtsw2", "AVLmtsw3", "AVLmtsw4", "AVLmtsw5", "AVLmtsw6"]
},
"swampTrees":{
"biome":{
"terrain" : "swamp",
"objectType" : "tree"
},
"templates" : ["AVLSPTR0", "AVLSPTR1", "AVLSPTR2", "AVLSPTR3", "AVLSPTR4", "AVLSPTR5", "AVLSPTR6", "AVLsptr7", "AVLsptr8"]
},
"templateSet108":{
"biome":{
"terrain" : "swamp",
"objectType" : "rock"
},
"templates" : ["AVLrk1s0", "AVLrk2s0", "AVLrk3s0", "AVLrk4s0"]
},
"templateSet109":{
"biome":{
"terrain" : "swamp",
"objectType" : "plant"
},
"templates" : ["AVLs01s0", "AVLs02s0", "AVLs03s0", "AVLs04s0", "AVLs05s0", "AVLs06s0", "AVLs07s0", "AVLs08s0", "AVLs09s0", "AVLs10s0", "AVLs11s0", "AVLswp10", "AVLswp20", "AVLswp30", "AVLswp40"]
},
"floodedPalms":{
"biome":{
"terrain" : "swamp",
"objectType" : "tree"
},
"templates" : ["AVLswmp0", "AVLswmp1", "AVLswmp2", "AVLswmp3", "AVLswmp4", "AVLswmp5", "AVLswmp6", "AVLswmp7"]
},
"swampTrees2":{
"biome":{
"terrain" : "swamp",
"objectType" : "tree"
},
"templates" : ["AVLtr1d0", "AVLtr2d0", "AVLtr3d0", "AVLwlw10", "AVLwlw20", "AVLwlw30"]
},
"swampPalms":{
"biome":{
"terrain" : "swamp",
"objectType" : "tree"
},
"templates" : ["avlswtr0", "avlswtr1", "avlswtr2", "avlswtr3", "avlswtr4", "avlswtr5", "avlswtr6", "avlswtr7", "avlswtr8", "avlswtr9"]
},
"swampSinglePalms":{
"biome":{
"terrain" : "swamp",
"objectType" : "plant"
},
"templates" : ["avlswt00", "avlswt01", "avlswt02", "avlswt03", "avlswt04", "avlswt05", "avlswt06", "avlswt07", "avlswt08", "avlswt09", "avlswt10", "avlswt11", "avlswt12", "avlswt13", "avlswt14", "avlswt15", "avlswt16", "avlswt17", "avlswt18", "avlswt19"]
},
"templateSet112":{
"biome":{
"terrain" : "swamp",
"objectType" : "other"
},
"templates" : ["avlxsw01", "avlxsw02", "avlxsw03", "avlxsw04", "avlxsw05", "avlxsw06", "avlxsw07", "avlxsw08", "avlxsw09", "avlxsw10", "avlxsw11"]
},
"templateSet124":{
"biome":{
"terrain" : "rough",
"objectType" : "plant"
},
"templates" : ["AVLca1r0", "AVLca2r0"]
},
"roughCraters":{
"biome":{
"terrain" : "rough",
"objectType" : "crater"
},
"templates" : ["AVLglly0", "AVLct1r0", "AVLct2r0", "AVLct3r0", "AVLct4r0", "AVLct5r0", "AVLct6r0", "AVLct7r0", "AVLct8r0", "AVLct9r0", "AVLctrr0"]
},
"templateSet129":{
"biome":{
"terrain" : "rough",
"objectType" : "rock"
},
"templates" : ["AVLmd1r0", "AVLmd2r0", "AVLmd3r0"]
},
"templateSet130":{
"biome":{
"terrain" : "rough",
"objectType" : "mountain"
},
"templates" : ["avlmtrf1", "avlmtrf2", "avlmtrf3", "avlmtrf4", "avlmtrf5", "avlmtrf6"]
},
"templateSet131":{
"biome":{
"terrain" : "rough",
"objectType" : "rock"
},
"templates" : ["AVLoc1r0", "AVLoc2r0", "AVLoc3r0", "AVLoc4r0"]
},
"templateSet133":{
"biome":{
"terrain" : "rough",
"objectType" : "rock"
},
"templates" : ["avlbuzr0", "AVLr02r0", "AVLr03r0", "AVLr04r0", "AVLr06r0", "AVLr07r0", "AVLr08r0", "AVLr09r0", "AVLr10r0", "AVLr11r0", "AVLr12r0", "AVLr13r0", "AVLr14r0", "AVLr15r0", "AvLRR01", "AvLRR05"]
},
"templateSet134":{
"biome":{
"terrain" : "rough",
"objectType" : "plant"
},
"templates" : ["AVLsh1r0", "AVLsh2r0", "AVLsh3r0", "avlsh4r0", "avlsh5r0", "avlsh6r0", "avlsh7r0", "avlsh8r0", "avlsh9r0"]
},
"templateSet135":{
"biome":{
"terrain" : "rough",
"objectType" : "animal"
},
"templates" : ["AVLskul0"]
},
"roughStumps":{
"biome":{
"terrain" : "rough",
"objectType" : "plant"
},
"templates" : ["AvLdlog", "AvLStm1", "AvLStm2", "AvLStm3"]
},
"roughSmallTree":{
"biome":{
"terrain" : "rough",
"objectType" : "plant"
},
"templates" : ["AVLroug0", "AVLroug1", "AVLroug2"]
},
"roughYucca":{
"biome":{
"terrain" : "rough",
"objectType" : "plant"
},
"templates" : ["AVLyuc10", "AVLyuc20", "AVLyuc30"]
},
"roughLake":{
"biome":{
"terrain" : "rough",
"objectType" : "lake"
},
"templates" : ["AVLlk1r"]
},
"templateSet139":{
"biome":{
"terrain" : "rough",
"objectType" : "other"
},
"templates" : ["AVLtRo00", "AVLtRo01", "AVLtRo02", "AVLtRo03", "AVLtRo04", "AVLtRo05", "AVLtRo06", "AVLtRo07", "AVLtRo08", "AVLtRo09", "AVLtRo10", "AVLtRo11", "AVLtRo12", "AVLtrRo0", "AVLtrRo1", "AVLtrRo2", "AVLtrRo3", "AVLtrRo4", "AVLtrRo5", "AVLtrRo6", "AVLtrRo7"]
},
"templateSet140":{
"biome":{
"terrain" : "rough",
"objectType" : "other"
},
"templates" : ["avlxro01", "avlxro02", "avlxro03", "avlxro04", "avlxro05", "avlxro06", "avlxro07", "avlxro08", "avlxro09", "avlxro10", "avlxro11", "avlxro12"]
},
"templateSet152":{
"biome":{
"terrain" : "subterra",
"objectType" : "crater"
},
"templates" : ["AVLct1u0", "AVLct2u0", "AVLct3u0", "AVLct4u0", "AVLct5u0"]
},
"templateSet153":{
"biome":{
"terrain" : "subterra",
"objectType" : "tree"
},
"templates" : ["AVLdead0", "AVLdead1", "AVLdead2", "AVLdead3", "AVLdead4", "AVLdead5", "AVLdead6", "AVLdead7"]
},
"templateSet155":{
"biome":{
"terrain" : "subterra",
"objectType" : "lake"
},
"templates" : ["AVLlk1u0", "AVLlk2u0", "AVLlk3u0"]
},
"templateSet156":{
"biome":{
"terrain" : "subterra",
"objectType" : "lake"
},
"templates" : ["AVLlv1u0", "AVLlv2u0", "AVLlv3u0"]
},
"templateSet157":{
"biome":{
"terrain" : "subterra",
"objectType" : "lake"
},
"templates" : ["AVLllk10", "AVLllk20"]
},
"templateSet158":{
"biome":{
"terrain" : "subterra",
"objectType" : "plant"
},
"templates" : ["AVLms010", "AVLms020", "AVLms030", "AVLms040", "AVLms050", "AVLms060", "AVLms070", "AVLms080", "AVLms090", "AVLms100", "AVLms110", "AVLms120"]
},
"templateSet159":{
"biome":{
"terrain" : "subterra",
"objectType" : "mountain"
},
"templates" : ["AVLmtsb0", "AVLmtsb1", "AVLmtsb2", "AVLmtsb3", "AVLmtsb4", "AVLmtsb5"]
},
"templateSet160":{
"biome":{
"terrain" : "subterra",
"objectType" : "rock"
},
"templates" : ["AVLoc1u0", "AVLoc2u0", "AVLoc3u0", "AVLoc4u0"]
},
"templateSet162":{
"biome":{
"terrain" : "subterra",
"objectType" : "rock"
},
"templates" : ["AVLr01u0", "AVLr02u0", "AVLr03u0", "AVLr04u0", "AVLr05u0", "AVLr06u0", "AVLr07u0", "AVLr08u0", "AVLr09u0", "AVLr10u0", "AVLr11u0", "AVLr12u0", "AVLr13u0", "AVLr14u0", "AVLr15u0", "AVLr16u0", "AVLstg10", "AVLstg20", "AVLstg30", "AVLstg40", "AVLstg50", "AVLstg60"]
},
"templateSet163":{
"biome":{
"terrain" : "subterra",
"objectType" : "other"
},
"templates" : ["avlxsu01", "avlxsu02", "avlxsu03", "avlxsu04", "avlxsu05", "avlxsu06", "avlxsu07", "avlxsu08", "avlxsu09", "avlxsu10", "avlxsu11", "avlxsu12"]
},
"lavaChasm":{
"biome":{
"terrain" : "lava",
"objectType" : "crater"
},
"templates" : ["AVLc10l0", "AVLc11l0", "AVLc12l0", "AVLc13l0", "AVLc14l0", "AVLct1l0", "AVLct2l0", "AVLct3l0", "AVLct4l0", "AVLct5l0", "AVLct6l0", "AVLct7l0", "AVLct8l0", "AVLct9l0", "AVLctrl0"]
},
"lavaDeadTree":{
"biome":{
"terrain" : "lava",
"objectType" : "tree"
},
"templates" : ["AVLdead0", "AVLdead1", "AVLdead2", "AVLdead3", "AVLdead4", "AVLdead5", "AVLdead6", "AVLdead7"]
},
"lavaLake":{
"biome":{
"terrain" : "lava",
"objectType" : "lake"
},
"templates" : ["AVLlav10", "AVLlav20", "AVLlav30", "AVLlav40", "AVLlav50", "AVLlav60", "AVLlav70", "AVLlav80", "AVLlav90", "AVLlv100", "AVLlv110", "AVLlv120", "AVLlv130", "AVLlv140", "AVLlv150", "AVLlv160", "AVLlv170", "AVLlv180", "AVLlv190", "AVLlv200", "AVLlv210", "AVLlv220", "AVLlv230", "AVLlv240", "AVLlv250", "AVLlv260"]
},
"templateSet180":{
"biome":{
"terrain" : "lava",
"objectType" : "mountain"
},
"templates" : ["AVLmtvo1", "AVLmtvo2", "AVLmtvo3", "AVLmtvo4", "AVLmtvo5", "AVLmtvo6"]
},
"volcanos":{
"biome":{
"terrain" : "lava",
"objectType" : "mountain"
},
"templates" : ["AVLvol10", "AVLvol20", "AVLvol30", "AVLvol40", "AVLvol50"]
},
"templateSet192":{
"biome":{
"terrain" : "water",
"objectType" : "tree"
},
"templates" : ["AVLklp10", "AVLklp20"]
},
"templateSet193":{
"biome":{
"terrain" : "water",
"objectType" : "rock"
},
"templates" : ["AVLrk1w0", "AVLrk2w0", "AVLrk3w0", "AVLrk4w0"]
},
"templateSet194":{
"biome":{
"terrain" : "water",
"objectType" : "mountain"
},
"templates" : ["AVLref10", "AVLref20", "AVLref30", "AVLref40", "AVLref50", "AVLref60"]
}
}

View File

@@ -67,6 +67,11 @@
"config/objects/witchHut.json"
],
"biomes" :
[
"config/biomes.json"
],
"artifacts" :
[
"config/artifacts.json"

67
config/schemas/biome.json Normal file
View File

@@ -0,0 +1,67 @@
{
"type" : "object",
"$schema" : "http://json-schema.org/draft-04/schema",
"title" : "VCMI map obstacle set format",
"description" : "Description of map object set, used only as sub-schema of object",
"required" : ["biome", "templates"],
"additionalProperties" : true, // may have type-dependant properties
"properties" : {
"biome" : {
"type" : "object",
"properties": {
"objectType" : {
"type" : "string",
"enmum": ["mountain", "tree", "lake", "crater", "rock", "plant", "structure", "animal", "other"],
"description" : "Type of the obstacle set"
},
"terrain" : {
"anyOf": [
{
"type" : "string",
"description" : "Terrain of the obstacle set"
},
{
"type" : "array",
"items" : { "type" : "string" },
"description" : "Terrains of the obstacle set"
}
]
},
"faction" : {
"anyOf": [
{
"type" : "string",
"description" : "Faction of the zone"
},
{
"type" : "array",
"items" : { "type" : "string" },
"description" : "Factions of the zone"
}
]
},
"alignment" : {
"anyOf": [
{
"type" : "string",
"enum" : ["good", "evil", "neutral"],
"description" : "Alignment of faction of the zone"
},
{
"type" : "array",
"items" : { "type" : "string" },
"description" : "Alignment of faction of the zone"
}
]
}
}
},
"templates" : {
"type" : "array",
"items" : { "type" : "string" },
"description" : "Object templates of the obstacle set"
}
}
}

View File

@@ -255,6 +255,11 @@
"description" : "List of configuration files for objects",
"items" : { "type" : "string", "format" : "textFile" }
},
"biomes" : {
"type" : "array",
"description" : "List of configuration files for biomes",
"items" : { "type" : "string", "format" : "textFile" }
},
"bonuses" : {
"type" : "array",
"description" : "List of configuration files for bonuses",

View File

@@ -73,6 +73,7 @@ Other:
- [Terrain](Entities_Format/Terrain_Format.md)
- [River](Entities_Format/River_Format.md)
- [Road](Entities_Format/Road_Format.md)
- [Biome](Entities_Format/Biome_Format.md)
- [Battlefield](Entities_Format/Battlefield_Format.md)
- [Battle Obstacle](Entities_Format/Battle_Obstacle_Format.md)

View File

@@ -121,6 +121,7 @@ set(lib_MAIN_SRCS
mapObjects/IObjectInterface.cpp
mapObjects/MiscObjects.cpp
mapObjects/ObjectTemplate.cpp
mapObjects/ObstacleSetHandler.cpp
mapping/CDrawRoadsOperation.cpp
mapping/CMap.cpp
@@ -482,6 +483,7 @@ set(lib_MAIN_HEADERS
mapObjects/MapObjects.h
mapObjects/MiscObjects.h
mapObjects/ObjectTemplate.h
mapObjects/ObstacleSetHandler.h
mapping/CDrawRoadsOperation.h
mapping/CMapDefines.h

View File

@@ -37,6 +37,7 @@
#include "rmg/CRmgTemplateStorage.h"
#include "mapObjectConstructors/CObjectClassesHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "mapObjects/ObstacleSetHandler.h"
#include "mapping/CMapEditManager.h"
#include "ScriptHandler.h"
#include "BattleFieldHandler.h"
@@ -223,6 +224,7 @@ void LibClasses::init(bool onlyEssential)
createHandler(arth, "Artifact", pomtime);
createHandler(creh, "Creature", pomtime);
createHandler(townh, "Town", pomtime);
createHandler(biomeHandler, "Obstacle set", pomtime);
createHandler(objh, "Object", pomtime);
createHandler(objtypeh, "Object types information", pomtime);
createHandler(spellh, "Spell", pomtime);

View File

@@ -23,6 +23,7 @@ class CSkillHandler;
class CBuildingHandler;
class CObjectHandler;
class CObjectClassesHandler;
class ObstacleSetHandler;
class CTownHandler;
class CGeneralTextHandler;
class CModHandler;
@@ -85,6 +86,7 @@ public:
std::shared_ptr<CCreatureHandler> creh;
std::shared_ptr<CSpellHandler> spellh;
std::shared_ptr<CSkillHandler> skillh;
// TODO: Remove ObjectHandler altogether?
std::shared_ptr<CObjectHandler> objh;
std::shared_ptr<CObjectClassesHandler> objtypeh;
std::shared_ptr<CTownHandler> townh;
@@ -99,6 +101,7 @@ public:
std::shared_ptr<BattleFieldHandler> battlefieldsHandler;
std::shared_ptr<ObstacleHandler> obstacleHandler;
std::shared_ptr<GameSettings> settingsHandler;
std::shared_ptr<ObstacleSetHandler> biomeHandler;
#if SCRIPTING_ENABLED
std::shared_ptr<scripting::ScriptHandler> scriptHandler;

View File

@@ -457,7 +457,47 @@ public:
WHIRLPOOL = 111,
WINDMILL = 112,
WITCH_HUT = 113,
BRUSH = 114, // TODO: How does it look like?
BUSH = 115,
CACTUS = 116,
CANYON = 117,
CRATER = 118,
DEAD_VEGETATION = 119,
FLOWERS = 120,
FROZEN_LAKE = 121,
HEDGE = 122,
HILL = 123,
HOLE = 124,
KELP = 125,
LAKE = 126,
LAVA_FLOW = 127,
LAVA_LAKE = 128,
MUSHROOMS = 129,
LOG = 130,
MANDRAKE = 131,
MOSS = 132,
MOUND = 133,
MOUNTAIN = 134,
OAK_TREES = 135,
OUTCROPPING = 136,
PINE_TREES = 137,
PLANT = 138,
RIVER_DELTA = 143,
ROCK = 147,
SAND_DUNE = 148,
SAND_PIT = 149,
SHRUB = 150,
SKULL = 151,
STALAGMITE = 152,
STUMP = 153,
TAR_PIT = 154,
TREES = 155,
VINE = 156,
VOLCANIC_VENT = 157,
VOLCANO = 158,
WILLOW_TREES = 159,
YUCCA_TREES = 160,
REEF = 161,
RANDOM_MONSTER_L5 = 162,
RANDOM_MONSTER_L6 = 163,
RANDOM_MONSTER_L7 = 164,

View File

@@ -13,7 +13,8 @@ VCMI_LIB_NAMESPACE_BEGIN
enum class EAlignment : int8_t
{
GOOD,
ANY = -1,
GOOD = 0,
EVIL,
NEUTRAL
};

View File

@@ -34,6 +34,7 @@
#include "../mapObjects/MiscObjects.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../mapObjects/CGTownInstance.h"
#include "../mapObjects/ObstacleSetHandler.h"
#include "../modding/IdentifierStorage.h"
#include "../modding/CModHandler.h"
#include "../modding/ModScope.h"
@@ -211,10 +212,28 @@ TObjectTypeHandler CObjectClassesHandler::loadSubObjectFromJson(const std::strin
createdObject->subtype = index;
createdObject->init(entry);
bool staticObject = createdObject->isStaticObject();
if (staticObject)
{
for (auto & templ : createdObject->getTemplates())
{
// Register templates for new objects from mods
VLC->biomeHandler->addTemplate(scope, templ->stringID, templ);
}
}
auto range = legacyTemplates.equal_range(std::make_pair(obj->id, index));
for (auto & templ : boost::make_iterator_range(range.first, range.second))
{
if (staticObject)
{
// Register legacy templates as "core"
// FIXME: Why does it clear stringID?
VLC->biomeHandler->addTemplate("core", templ.second->stringID, templ.second);
}
createdObject->addTemplate(templ.second);
}
legacyTemplates.erase(range.first, range.second);

View File

@@ -14,6 +14,7 @@
#include "../mapObjects/MiscObjects.h"
#include "../mapObjects/CGCreature.h"
#include "../mapObjects/ObstacleSetHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -33,6 +34,7 @@ class CObstacleConstructor : public CDefaultObjectTypeHandler<CGObjectInstance>
{
public:
bool isStaticObject() override;
};
class CreatureInstanceConstructor : public CDefaultObjectTypeHandler<CGCreature>

View File

@@ -0,0 +1,470 @@
/*
* ObstacleSetHandler.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "ObstacleSetHandler.h"
#include "../modding/IdentifierStorage.h"
#include "../constants/StringConstants.h"
#include "../TerrainHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
ObstacleSet::ObstacleSet():
type(INVALID),
allowedTerrains({TerrainId::NONE})
{
}
ObstacleSet::ObstacleSet(EObstacleType type, TerrainId terrain):
type(type),
allowedTerrains({terrain})
{
}
void ObstacleSet::addObstacle(std::shared_ptr<const ObjectTemplate> obstacle)
{
obstacles.push_back(obstacle);
}
void ObstacleSet::removeEmptyTemplates()
{
vstd::erase_if(obstacles, [](const std::shared_ptr<const ObjectTemplate> &tmpl)
{
if (tmpl->getBlockedOffsets().empty())
{
logMod->warn("Obstacle template %s blocks no tiles, removing it", tmpl->stringID);
return true;
}
return false;
});
}
ObstacleSetFilter::ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain = TerrainId::ANY_TERRAIN, FactionID faction = FactionID::ANY, EAlignment alignment = EAlignment::ANY):
allowedTypes(allowedTypes),
terrain(terrain),
faction(faction),
alignment(alignment)
{
}
ObstacleSetFilter::ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain = TerrainId::ANY_TERRAIN, FactionID faction = FactionID::ANY, EAlignment alignment = EAlignment::ANY):
allowedTypes({allowedType}),
terrain(terrain),
faction(faction),
alignment(alignment)
{
}
bool ObstacleSetFilter::filter(const ObstacleSet &set) const
{
if (terrain != TerrainId::ANY_TERRAIN && !vstd::contains(set.getTerrains(), terrain))
{
return false;
}
if (faction != FactionID::ANY)
{
auto factions = set.getFactions();
if (!factions.empty() && !vstd::contains(factions, faction))
{
return false;
}
}
// TODO: Also check specific factions
if (alignment != EAlignment::ANY)
{
auto alignments = set.getAlignments();
if (!alignments.empty() && !vstd::contains(alignments, alignment))
{
return false;
}
}
return true;
}
TerrainId ObstacleSetFilter::getTerrain() const
{
return terrain;
}
std::set<TerrainId> ObstacleSet::getTerrains() const
{
return allowedTerrains;
}
void ObstacleSet::setTerrain(TerrainId terrain)
{
this->allowedTerrains = {terrain};
}
void ObstacleSet::setTerrains(const std::set<TerrainId> & terrains)
{
this->allowedTerrains = terrains;
}
void ObstacleSet::addTerrain(TerrainId terrain)
{
this->allowedTerrains.insert(terrain);
}
std::set<FactionID> ObstacleSet::getFactions() const
{
return allowedFactions;
}
void ObstacleSet::addFaction(FactionID faction)
{
this->allowedFactions.insert(faction);
}
void ObstacleSet::addAlignment(EAlignment alignment)
{
this->allowedAlignments.insert(alignment);
}
std::set<EAlignment> ObstacleSet::getAlignments() const
{
return allowedAlignments;
}
ObstacleSet::EObstacleType ObstacleSet::getType() const
{
return type;
}
void ObstacleSet::setType(EObstacleType type)
{
this->type = type;
}
std::vector<std::shared_ptr<const ObjectTemplate>> ObstacleSet::getObstacles() const
{
return obstacles;
}
ObstacleSet::EObstacleType ObstacleSetHandler::convertObstacleClass(MapObjectID id)
{
switch (id)
{
case Obj::MOUNTAIN:
case Obj::VOLCANIC_VENT:
case Obj::VOLCANO:
case Obj::REEF:
return ObstacleSet::MOUNTAINS;
case Obj::OAK_TREES:
case Obj::PINE_TREES:
case Obj::TREES:
case Obj::DEAD_VEGETATION:
case Obj::HEDGE:
case Obj::KELP:
case Obj::WILLOW_TREES:
case Obj::YUCCA_TREES:
return ObstacleSet::TREES;
case Obj::FROZEN_LAKE:
case Obj::LAKE:
case Obj::LAVA_FLOW:
case Obj::LAVA_LAKE:
return ObstacleSet::LAKES;
case Obj::CANYON:
case Obj::CRATER:
case Obj::SAND_PIT:
case Obj::TAR_PIT:
return ObstacleSet::CRATERS;
case Obj::HILL:
case Obj::MOUND:
case Obj::OUTCROPPING:
case Obj::ROCK:
case Obj::SAND_DUNE:
case Obj::STALAGMITE:
return ObstacleSet::ROCKS;
case Obj::BUSH:
case Obj::CACTUS:
case Obj::FLOWERS:
case Obj::MUSHROOMS:
case Obj::LOG:
case Obj::MANDRAKE:
case Obj::MOSS:
case Obj::PLANT:
case Obj::SHRUB:
case Obj::STUMP:
case Obj::VINE:
return ObstacleSet::PLANTS;
case Obj::SKULL:
return ObstacleSet::ANIMALS;
default:
return ObstacleSet::OTHER;
}
}
ObstacleSet::EObstacleType ObstacleSet::typeFromString(const std::string &str)
{
static const std::map<std::string, EObstacleType> OBSTACLE_TYPE_NAMES =
{
{"mountain", MOUNTAINS},
{"tree", TREES},
{"lake", LAKES},
{"crater", CRATERS},
{"rock", ROCKS},
{"plant", PLANTS},
{"structure", STRUCTURES},
{"animal", ANIMALS},
{"other", OTHER}
};
if (OBSTACLE_TYPE_NAMES.find(str) != OBSTACLE_TYPE_NAMES.end())
{
return OBSTACLE_TYPE_NAMES.at(str);
}
// TODO: How to handle that?
throw std::runtime_error("Invalid obstacle type: " + str);
}
std::string ObstacleSet::toString() const
{
static const std::map<EObstacleType, std::string> OBSTACLE_TYPE_STRINGS =
{
{MOUNTAINS, "mountain"},
{TREES, "tree"},
{LAKES, "lake"},
{CRATERS, "crater"},
{ROCKS, "rock"},
{PLANTS, "plant"},
{STRUCTURES, "structure"},
{ANIMALS, "animal"},
{OTHER, "other"}
};
return OBSTACLE_TYPE_STRINGS.at(type);
}
std::vector<ObstacleSet::EObstacleType> ObstacleSetFilter::getAllowedTypes() const
{
return allowedTypes;
}
void ObstacleSetFilter::setType(ObstacleSet::EObstacleType type)
{
allowedTypes = {type};
}
void ObstacleSetFilter::setTypes(std::vector<ObstacleSet::EObstacleType> types)
{
this->allowedTypes = types;
}
std::vector<JsonNode> ObstacleSetHandler::loadLegacyData()
{
return {};
}
void ObstacleSetHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto os = loadFromJson(scope, data, name, biomes.size());
if(os)
{
addObstacleSet(os);
// TODO: Define some const array of object types ("biome" etc.)
VLC->identifiersHandler->registerObject(scope, "biome", name, biomes.back()->id);
}
else
{
logMod->error("Failed to load obstacle set: %s", name);
}
}
void ObstacleSetHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
//Unused
loadObject(scope, name, data);
}
std::shared_ptr<ObstacleSet> ObstacleSetHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name, size_t index)
{
auto os = std::make_shared<ObstacleSet>();
os->id = index;
auto biome = json["biome"].Struct();
os->setType(ObstacleSet::typeFromString(biome["objectType"].String()));
// TODO: Handle any (every) terrain option
if (biome["terrain"].isString())
{
auto terrainName = biome["terrain"].String();
VLC->identifiers()->requestIdentifier(scope, "terrain", terrainName, [os](si32 id)
{
os->setTerrain(TerrainId(id));
});
}
else if (biome["terrain"].isVector())
{
auto terrains = biome["terrain"].Vector();
for (const auto & terrain : terrains)
{
VLC->identifiers()->requestIdentifier(scope, "terrain", terrain.String(), [os](si32 id)
{
os->addTerrain(TerrainId(id));
});
}
}
else
{
logMod->error("No terrain specified for obstacle set %s", name);
}
auto handleFaction = [os, scope](const std::string & str)
{
VLC->identifiers()->requestIdentifier(scope, "faction", str, [os](si32 id)
{
os->addFaction(FactionID(id));
});
};
if (biome["faction"].isString())
{
auto factionName = biome["faction"].String();
handleFaction(factionName);
}
else if (biome["faction"].isVector())
{
auto factions = biome["faction"].Vector();
for (const auto & node : factions)
{
handleFaction(node.String());
}
}
// TODO: Move this parser to some utils
auto parseAlignment = [](const std::string & str) ->EAlignment
{
int alignment = vstd::find_pos(GameConstants::ALIGNMENT_NAMES, str);
if (alignment == -1)
{
logMod->error("Incorrect alignment: ", str);
return EAlignment::ANY;
}
else
{
return static_cast<EAlignment>(alignment);
}
};
if (biome["alignment"].isString())
{
os->addAlignment(parseAlignment(biome["alignment"].String()));
}
else if (biome["alignment"].isVector())
{
auto alignments = biome["alignment"].Vector();
for (const auto & node : alignments)
{
os->addAlignment(parseAlignment(node.String()));
}
}
auto templates = json["templates"].Vector();
for (const auto & node : templates)
{
logMod->trace("Registering obstacle template: %s in scope %s", node.String(), scope);
auto identifier = boost::algorithm::to_lower_copy(node.String());
auto jsonName = JsonNode(identifier);
VLC->identifiers()->requestIdentifier(node.getModScope(), "obstacleTemplate", identifier, [this, os](si32 id)
{
logMod->trace("Resolved obstacle id: %d", id);
os->addObstacle(obstacleTemplates[id]);
});
}
return os;
}
void ObstacleSetHandler::addTemplate(const std::string & scope, const std::string &name, std::shared_ptr<const ObjectTemplate> tmpl)
{
auto id = obstacleTemplates.size();
auto strippedName = boost::algorithm::to_lower_copy(name);
auto pos = strippedName.find(".def");
if(pos != std::string::npos)
strippedName.erase(pos, 4);
if (VLC->identifiersHandler->getIdentifier(scope, "obstacleTemplate", strippedName, true))
{
logMod->warn("Duplicate obstacle template: %s", strippedName);
return;
}
else
{
// Save by name
VLC->identifiersHandler->registerObject(scope, "obstacleTemplate", strippedName, id);
// Index by id
obstacleTemplates[id] = tmpl;
}
}
void ObstacleSetHandler::addObstacleSet(std::shared_ptr<ObstacleSet> os)
{
biomes.push_back(os);
}
void ObstacleSetHandler::afterLoadFinalization()
{
for (auto &os :biomes)
{
os->removeEmptyTemplates();
}
vstd::erase_if(biomes, [](const std::shared_ptr<ObstacleSet> &os)
{
if (os->getObstacles().empty())
{
logMod->warn("Obstacle set %d is empty, removing it", os->id);
return true;
}
return false;
});
// Populate map
for (auto &os : biomes)
{
obstacleSets[os->getType()].push_back(os);
}
}
TObstacleTypes ObstacleSetHandler::getObstacles( const ObstacleSetFilter &filter) const
{
TObstacleTypes result;
for (const auto &allowedType : filter.getAllowedTypes())
{
auto it = obstacleSets.find(allowedType);
if(it != obstacleSets.end())
{
for (const auto &os : it->second)
{
if (filter.filter(*os))
{
result.push_back(os);
}
}
}
}
return result;
}
VCMI_LIB_NAMESPACE_END

View File

@@ -0,0 +1,133 @@
/*
* ObstacleSetHandler.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../GameConstants.h"
#include "../constants/EntityIdentifiers.h"
#include "../IHandlerBase.h"
#include "../json/JsonNode.h"
#include "ObjectTemplate.h"
VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE ObstacleSet
{
public:
// TODO: Create string constants for these
enum EObstacleType
{
INVALID = -1,
MOUNTAINS = 0,
TREES,
LAKES, // Inluding dry or lava lakes
CRATERS, // Chasms, Canyons, etc.
ROCKS,
PLANTS, // Flowers, cacti, mushrooms, logs, shrubs, etc.
STRUCTURES, // Buildings, ruins, etc.
ANIMALS, // Living, or bones
OTHER // Crystals, shipwrecks, barrels, etc.
};
ObstacleSet();
explicit ObstacleSet(EObstacleType type, TerrainId terrain);
void addObstacle(std::shared_ptr<const ObjectTemplate> obstacle);
void removeEmptyTemplates();
std::vector<std::shared_ptr<const ObjectTemplate>> getObstacles() const;
EObstacleType getType() const;
void setType(EObstacleType type);
std::set<TerrainId> getTerrains() const;
void setTerrain(TerrainId terrain);
void setTerrains(const std::set<TerrainId> & terrains);
void addTerrain(TerrainId terrain);
std::set<EAlignment> getAlignments() const;
void addAlignment(EAlignment alignment);
std::set<FactionID> getFactions() const;
void addFaction(FactionID faction);
static EObstacleType typeFromString(const std::string &str);
std::string toString() const;
si32 id;
private:
EObstacleType type;
std::set<TerrainId> allowedTerrains; // Empty means all terrains
std::set<FactionID> allowedFactions; // Empty means all factions
std::set<EAlignment> allowedAlignments; // Empty means all alignments
std::vector<std::shared_ptr<const ObjectTemplate>> obstacles;
};
typedef std::vector<std::shared_ptr<ObstacleSet>> TObstacleTypes;
class DLL_LINKAGE ObstacleSetFilter
{
public:
ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain, FactionID faction, EAlignment alignment);
ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain, FactionID faction, EAlignment alignment);
bool filter(const ObstacleSet &set) const;
void setType(ObstacleSet::EObstacleType type);
void setTypes(std::vector<ObstacleSet::EObstacleType> types);
std::vector<ObstacleSet::EObstacleType> getAllowedTypes() const;
TerrainId getTerrain() const;
void setAlignment(EAlignment alignment);
private:
std::vector<ObstacleSet::EObstacleType> allowedTypes;
FactionID faction;
EAlignment alignment;
// TODO: Filter by faction, surface/underground, etc.
const TerrainId terrain;
};
// TODO: Instantiate ObstacleSetHandler
class DLL_LINKAGE ObstacleSetHandler : public IHandlerBase, boost::noncopyable
{
public:
ObstacleSetHandler() = default;
~ObstacleSetHandler() = default;
std::vector<JsonNode> loadLegacyData() override;
virtual void loadObject(std::string scope, std::string name, const JsonNode & data) override;
virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
std::shared_ptr<ObstacleSet> loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name, size_t index);
ObstacleSet::EObstacleType convertObstacleClass(MapObjectID id);
// TODO: Populate obstacleSets with all the obstacle sets from the game data
void addTemplate(const std::string & scope, const std::string &name, std::shared_ptr<const ObjectTemplate> tmpl);
void addObstacleSet(std::shared_ptr<ObstacleSet> set);
void afterLoadFinalization() override;
TObstacleTypes getObstacles(const ObstacleSetFilter &filter) const;
private:
std::vector< std::shared_ptr<ObstacleSet> > biomes;
// TODO: Serialize?
std::map<si32, std::shared_ptr<const ObjectTemplate>> obstacleTemplates;
// FIXME: Store pointers?
std::map<ObstacleSet::EObstacleType, std::vector<std::shared_ptr<ObstacleSet>>> obstacleSets;
};
VCMI_LIB_NAMESPACE_END

View File

@@ -15,6 +15,7 @@
#include "../mapObjectConstructors/CObjectClassesHandler.h"
#include "../mapObjects/CGObjectInstance.h"
#include "../mapObjects/ObjectTemplate.h"
#include "../mapObjects/ObstacleSetHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -36,6 +37,11 @@ void ObstacleProxy::collectPossibleObstacles(TerrainId terrain)
}
}
}
sortObstacles();
}
void ObstacleProxy::sortObstacles()
{
for(const auto & o : obstaclesBySize)
{
possibleObstacles.emplace_back(o);
@@ -46,6 +52,161 @@ void ObstacleProxy::collectPossibleObstacles(TerrainId terrain)
});
}
bool ObstacleProxy::prepareBiome(const ObstacleSetFilter & filter, CRandomGenerator & rand)
{
possibleObstacles.clear();
std::vector<std::shared_ptr<ObstacleSet>> obstacleSets;
size_t selectedSets = 0;
const size_t MINIMUM_SETS = 3; // Original Lava has only 4 types of sets
const size_t MAXIMUM_SETS = 9;
const size_t MIN_SMALL_SETS = 3;
const size_t MAX_SMALL_SETS = 5;
auto terrain = filter.getTerrain();
auto localFilter = filter;
localFilter.setType(ObstacleSet::EObstacleType::MOUNTAINS);
TObstacleTypes mountainSets = VLC->biomeHandler->getObstacles(localFilter);
if (!mountainSets.empty())
{
obstacleSets.push_back(*RandomGeneratorUtil::nextItem(mountainSets, rand));
selectedSets++;
logGlobal->info("Mountain set added");
}
else
{
logGlobal->warn("No mountain sets found for terrain %s", TerrainId::encode(terrain.getNum()));
// FIXME: Do we ever want to generate obstacles without any mountains?
}
localFilter.setType(ObstacleSet::EObstacleType::TREES);
TObstacleTypes treeSets = VLC->biomeHandler->getObstacles(localFilter);
// 1 or 2 tree sets
size_t treeSetsCount = std::min<size_t>(treeSets.size(), rand.nextInt(1, 2));
for (size_t i = 0; i < treeSetsCount; i++)
{
obstacleSets.push_back(*RandomGeneratorUtil::nextItem(treeSets, rand));
selectedSets++;
}
logGlobal->info("Added %d tree sets", treeSetsCount);
// Some obstacle types may be completely missing from water, but it's not a problem
localFilter.setTypes({ObstacleSet::EObstacleType::LAKES, ObstacleSet::EObstacleType::CRATERS});
TObstacleTypes largeSets = VLC->biomeHandler->getObstacles(localFilter);
// We probably don't want to have lakes and craters at the same time, choose one of them
if (!largeSets.empty())
{
obstacleSets.push_back(*RandomGeneratorUtil::nextItem(largeSets, rand));
selectedSets++;
// TODO: Convert to string
logGlobal->info("Added large set of type %s", obstacleSets.back()->getType());
}
localFilter.setType(ObstacleSet::EObstacleType::ROCKS);
TObstacleTypes rockSets = VLC->biomeHandler->getObstacles(localFilter);
size_t rockSetsCount = std::min<size_t>(rockSets.size(), rand.nextInt(1, 2));
for (size_t i = 0; i < rockSetsCount; i++)
{
obstacleSets.push_back(*RandomGeneratorUtil::nextItem(rockSets, rand));
selectedSets++;
}
logGlobal->info("Added %d rock sets", rockSetsCount);
localFilter.setType(ObstacleSet::EObstacleType::PLANTS);
TObstacleTypes plantSets = VLC->biomeHandler->getObstacles(localFilter);
// 1 or 2 sets (3 - rock sets)
size_t plantSetsCount = std::min<size_t>(plantSets.size(), rand.nextInt(1, std::max<size_t>(3 - rockSetsCount, 2)));
for (size_t i = 0; i < plantSetsCount; i++)
{
{
obstacleSets.push_back(*RandomGeneratorUtil::nextItem(plantSets, rand));
selectedSets++;
}
}
logGlobal->info("Added %d plant sets", plantSetsCount);
//3 to 5 of total small sets (rocks, plants, structures, animals and others)
//This gives total of 6 to 9 different sets
size_t maxSmallSets = std::min<size_t>(MAX_SMALL_SETS, std::max(MIN_SMALL_SETS, MAXIMUM_SETS - selectedSets));
size_t smallSets = rand.nextInt(MIN_SMALL_SETS, maxSmallSets);
localFilter.setTypes({ObstacleSet::EObstacleType::STRUCTURES, ObstacleSet::EObstacleType::ANIMALS});
TObstacleTypes smallObstacleSets = VLC->biomeHandler->getObstacles(localFilter);
RandomGeneratorUtil::randomShuffle(smallObstacleSets, rand);
localFilter.setType(ObstacleSet::EObstacleType::OTHER);
TObstacleTypes otherSets = VLC->biomeHandler->getObstacles(localFilter);
RandomGeneratorUtil::randomShuffle(otherSets, rand);
while (smallSets > 0)
{
if (!smallObstacleSets.empty())
{
obstacleSets.push_back(smallObstacleSets.back());
smallObstacleSets.pop_back();
selectedSets++;
smallSets--;
logGlobal->info("Added small set of type %s", obstacleSets.back()->getType());
}
else if(otherSets.empty())
{
logGlobal->warn("No other sets found for terrain %s", terrain.encode(terrain.getNum()));
break;
}
if (smallSets > 0)
{
// Fill with whatever's left
if (!otherSets.empty())
{
obstacleSets.push_back(otherSets.back());
otherSets.pop_back();
selectedSets++;
smallSets--;
logGlobal->info("Added set of other obstacles");
}
}
}
// Copy this set to our possible obstacles
if (selectedSets >= MINIMUM_SETS ||
(terrain == TerrainId::WATER && selectedSets > 0))
{
obstaclesBySize.clear();
for (const auto & os : obstacleSets)
{
for (const auto & temp : os->getObstacles())
{
if(temp->getBlockMapOffset().valid())
{
obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp);
}
}
}
sortObstacles();
return true;
}
else
{
return false; // Proceed with old method
}
}
void ObstacleProxy::addBlockedTile(const int3& tile)
{
blockedArea.add(tile);

View File

@@ -20,6 +20,7 @@ class CGObjectInstance;
class ObjectTemplate;
class CRandomGenerator;
class IGameCallback;
class ObstacleSetFilter;
class DLL_LINKAGE ObstacleProxy
{
@@ -29,6 +30,7 @@ public:
virtual ~ObstacleProxy() = default;
void collectPossibleObstacles(TerrainId terrain);
bool prepareBiome(const ObstacleSetFilter & filter, CRandomGenerator & rand);
void addBlockedTile(const int3 & tile);
@@ -52,6 +54,7 @@ public:
protected:
int getWeightedObjects(const int3& tile, CRandomGenerator& rand, IGameCallback * cb, std::list<rmg::Object>& allObjects, std::vector<std::pair<rmg::Object*, int3>>& weightedObjects);
void sortObstacles();
rmg::Area blockedArea;

View File

@@ -26,6 +26,7 @@
#include "../IHandlerBase.h"
#include "../Languages.h"
#include "../ObstacleHandler.h"
#include "../mapObjects/ObstacleSetHandler.h"
#include "../RiverHandler.h"
#include "../RoadHandler.h"
#include "../ScriptHandler.h"
@@ -207,7 +208,7 @@ void CContentHandler::init()
handlers.insert(std::make_pair("rivers", ContentTypeHandler(VLC->riverTypeHandler.get(), "river")));
handlers.insert(std::make_pair("roads", ContentTypeHandler(VLC->roadTypeHandler.get(), "road")));
handlers.insert(std::make_pair("obstacles", ContentTypeHandler(VLC->obstacleHandler.get(), "obstacle")));
//TODO: any other types of moddables?
handlers.insert(std::make_pair("biomes", ContentTypeHandler(VLC->biomeHandler.get(), "biome")));
}
bool CContentHandler::preloadModData(const std::string & modName, JsonNode modConfig, bool validate)

View File

@@ -25,6 +25,8 @@
#include "../../mapping/CMap.h"
#include "../../mapping/ObstacleProxy.h"
#include "../../mapObjects/CGObjectInstance.h"
#include "../../mapObjects/ObstacleSetHandler.h"
#include "../../CTownHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -34,7 +36,20 @@ void ObstaclePlacer::process()
if(!manager)
return;
collectPossibleObstacles(zone.getTerrainType());
auto faction = zone.getTownType().toFaction();
ObstacleSetFilter filter(ObstacleSet::EObstacleType::INVALID, zone.getTerrainType(), faction->getId(), faction->alignment);
if (!prepareBiome(filter, zone.getRand()))
{
logGlobal->warn("Failed to prepare biome, using all possible obstacles");
// Use all if we fail to create proper biome
collectPossibleObstacles(zone.getTerrainType());
}
else
{
logGlobal->info("Biome prepared successfully for zone %d", zone.getId());
}
{
auto area = zone.area();