mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- Fixed all unit test failures and a few more bugs - Simplified view generation algorithm
This commit is contained in:
		| @@ -1,467 +1,213 @@ | ||||
| // Defines terrain view patterns. | ||||
|  | ||||
| // The following properties are mandatory: | ||||
| // data:		the 3x3 pattern | ||||
| // mapping:		maps the pattern to a range of terrain view images/frames of the .DEF, e.g. 10-15 | ||||
| //				for patterns which represent two transitions a comma can be used to distinct between dirt and sand | ||||
| //				e.g. 10-15, 25-35 whereas the first value is always dirt and the second sand | ||||
|  | ||||
| // The following properties are optional: | ||||
| // flipMode:	should the same be flipped or different images be used(see rock) or is flip not supported at all; allowed values: sameImage | diffImages; default is: sameImage | ||||
| // id:			the identifier for the pattern if it's referenced by other patterns | ||||
| // minPoints:	the minimum points to reach to validate the pattern successfully | ||||
|  | ||||
| // The following table shows the rules for the 3x3 pattern of all terrain types:  | ||||
| // I) normal(e.g. grass, lava, ...): | ||||
| // N:		Native type | ||||
| // D:		Dirt border | ||||
| // S:		Sand border | ||||
| // T:		Sand OR dirt border(all Ts in the pattern are replaced by dirt OR sand) | ||||
| // ?:		T or N | ||||
| // ?:		D,S or N | ||||
| // II) dirt: | ||||
| // N:		Native type | ||||
| // D:		Dirt border | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
| // III) sand: | ||||
| // N:		Native type | ||||
| // S:		Sand border | ||||
| // IV) water: | ||||
| // N:		Native type | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
| // V) rock: | ||||
| // No rules | ||||
| // IV) water, rock: | ||||
| // N:		Native type | ||||
| // S:		Sand border | ||||
| // ?:		Any border | ||||
|  | ||||
| // Some additional info: | ||||
| // Rules can be combined with comma. e.g. T, N which would be the same meaning of ?. It's most useful in combination with pattern chaining. | ||||
| // Chaining of patterns is supported. To reference a another pattern you simply add the <Ref Id> to the relevant field of the pattern. | ||||
| // Rules can be given points: <[Rule OR Ref Id]-Points> With the property minPoints simple conditions can be built. | ||||
|  | ||||
| { | ||||
| 	"normal" : | ||||
| 	[ | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"id" : "s1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T,N-1", "T,N-2", "T,N-3", | ||||
| 				"T,N-2", "N", "N", | ||||
| 				"T", "N", "N" | ||||
| 			], | ||||
| 			"maxPoints" : 3, | ||||
| 			"mapping" : "0-3, 20-23" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D-1,S-2,N", "N", "N", | ||||
| 				"T,D-2", "N", "N", | ||||
| 				"D-1,S-2,N", "N", "N" | ||||
| 			], | ||||
| 			"maxPoints" : 4, | ||||
| 			"mapping" : "4-7, 24-27" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D-1,S-2,N", "T,D-2", "D-1,S-2,N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"maxPoints" : 4, | ||||
| 			"mapping" : "8-11, 28-31" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "s3-1", | ||||
| 				"N", "s2-1", "T" | ||||
| 			], | ||||
| 			"mapping" : "12-15, 32-35", | ||||
| 			"minPoints" : 2 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "T", "?", | ||||
| 				"T", "N", "s6-1,m1-1,m2-1,N", | ||||
| 				"?", "s6-1,m1-1,m2-1,N", "N" | ||||
| 			], | ||||
| 			"mapping" : "16-17, 36-37", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s6", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "s5-1,N", | ||||
| 				"N", "s5-1,N", "T" | ||||
| 			], | ||||
| 			"mapping" : "18-19, 38-39", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		// Mixed transitions | ||||
| 		{ | ||||
| 			"id" : "m1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"T", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "T" | ||||
| 			], | ||||
| 			"mapping" : "40, 42" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "41" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D,N", | ||||
| 				"N", "N", "D", | ||||
| 				"S", "D,N", "D,N" | ||||
| 			], | ||||
| 			"mapping" : "43" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "S", | ||||
| 				"N", "N", "D", | ||||
| 				"D,N", "D", "D,N" | ||||
| 			], | ||||
| 			"mapping" : "44" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "45" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m6", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"D,N", "D", "S" | ||||
| 			], | ||||
| 			"mapping" : "46" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m7", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "?", | ||||
| 				"N", "N", "S", | ||||
| 				"D-1,N", "D-1,N", "?" | ||||
| 			], | ||||
| 			"minPoints" : 1, | ||||
| 			"mapping" : "47" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "m8", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "D", | ||||
| 				"N", "N", "D", | ||||
| 				"?", "S", "?" | ||||
| 			], | ||||
| 			"mapping" : "48" | ||||
| 		}, | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"id" : "n1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "49-72" | ||||
| 		} | ||||
| 	], | ||||
| 	"dirt" : | ||||
| 	[ | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"id" : "s1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "S", | ||||
| 				"S", "N", "N", | ||||
| 				"S", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "0-3" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "D", "D", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "D", "D" | ||||
| 			], | ||||
| 			"mapping" : "4-7" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"D", "N", "D", | ||||
| 				"D", "N", "D" | ||||
| 			], | ||||
| 			"mapping" : "8-11" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "D", "D", | ||||
| 				"D", "N", "?", | ||||
| 				"D", "?", "S" | ||||
| 			], | ||||
| 			"mapping" : "12-15" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "D", | ||||
| 				"S", "N", "s6-1,D", | ||||
| 				"D", "s6-1,D", "D" | ||||
| 			], | ||||
| 			"mapping" : "16-17", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s6", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "D", "D", | ||||
| 				"D", "N", "s5-1,D", | ||||
| 				"D", "s5-1,D", "S" | ||||
| 			], | ||||
| 			"mapping" : "18-19", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		// Mixed transition | ||||
| 		{ | ||||
| 			"id" : "m1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "D", "D", | ||||
| 				"D", "N", "D", | ||||
| 				"D", "D", "S" | ||||
| 			], | ||||
| 			"mapping" : "20" | ||||
| 		}, | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"id" : "n1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"D", "D", "D", | ||||
| 				"D", "N", "D", | ||||
| 				"D", "D", "D" | ||||
| 			], | ||||
| 			"mapping" : "21-44" | ||||
| 		} | ||||
| 	], | ||||
| 	"sand" : | ||||
| 	[ | ||||
| 		{ | ||||
| 			"id" : "n1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "?", "?", | ||||
| 				"?", "N", "?", | ||||
| 				"?", "?", "?" | ||||
| 			], | ||||
| 			"mapping" : "0-23" | ||||
| 		} | ||||
| 	], | ||||
| 	"water" : | ||||
| 	[ | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"id" : "s1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "S", | ||||
| 				"S", "N", "N", | ||||
| 				"S", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "0-3" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "N", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "4-7" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "8-11" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "12-15" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "N,S-1", | ||||
| 				"S", "N", "N", | ||||
| 				"N,S-1", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "16-17", | ||||
| 			"maxPoints" : 1 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s6", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "s5-1,N", | ||||
| 				"N", "s5-1,N", "S" | ||||
| 			], | ||||
| 			"mapping" : "18-19", | ||||
| 			"minPoints" : 1 | ||||
| 		}, | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"id" : "n1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "20-32" | ||||
| 		} | ||||
| 	], | ||||
| 	"rock" : | ||||
| 	[ | ||||
| 		// No transition | ||||
| 		{ | ||||
| 			"id" : "n1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "0-7" | ||||
| 		}, | ||||
| 		// Standard transitions | ||||
| 		{ | ||||
| 			"id" : "s1", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "8-15", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s2", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "N", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"?", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "16-19", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s3", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"?", "S", "?", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "20-23", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s4", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "S" | ||||
| 			], | ||||
| 			"mapping" : "24-31", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s5", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"S", "S", "N", | ||||
| 				"S", "N", "N", | ||||
| 				"N", "N", "N" | ||||
| 			], | ||||
| 			"mapping" : "32-39", | ||||
| 			"flipMode" : "diffImages" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"id" : "s6", | ||||
| 			"data" : | ||||
| 			[ | ||||
| 				"N", "N", "N", | ||||
| 				"N", "N", "s5-1,N", | ||||
| 				"N", "s5-1,N", "S" | ||||
| 			], | ||||
| 			"mapping" : "40-47", | ||||
| 			"flipMode" : "diffImages", | ||||
| 			"minPoints" : 1 | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| // The order of the patterns is important, do not change! | ||||
| [ | ||||
| 	// Extended mixed transitions | ||||
| 	{ | ||||
| 		"id" : "x1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T", "N", "N", | ||||
| 			"N", "N", "T", | ||||
| 			"N", "T", "T" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "73,74", "dirt" : "45" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "x2", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"D", "D", "N", | ||||
| 			"D", "N", "N", | ||||
| 			"N", "N", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "75" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "x3", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"S", "S", "N", | ||||
| 			"S", "N", "N", | ||||
| 			"N", "N", "D" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "76" } | ||||
| 	}, | ||||
| 	// No transition | ||||
| 	{ | ||||
| 		"id" : "n1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "49-72", "dirt" : "21-44", "sand" : "0-23", "water" : "20-32", "rock": "0-7" } | ||||
| 	}, | ||||
| 	// Mixed transitions | ||||
| 	{ | ||||
| 		"id" : "m1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "T" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "40, 42", "dirt" : "20" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m2", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"D", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "41" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m3", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "D,N", | ||||
| 			"N", "N", "D", | ||||
| 			"S", "D,N", "D,N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "43" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m4", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "S", | ||||
| 			"N", "N", "D", | ||||
| 			"D,N", "D", "D,N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "44" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m5", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "D", | ||||
| 			"N", "N", "D", | ||||
| 			"N", "N", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "45" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m6", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N", | ||||
| 			"D,N", "D", "S" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "46" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m7", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "?", | ||||
| 			"N", "N", "S", | ||||
| 			"D-1,N", "D-1,N", "?" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "47" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "m8", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "D-1,N", | ||||
| 			"N", "N", "D-1,N", | ||||
| 			"?", "S", "?" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "48" } | ||||
| 	}, | ||||
| 	// Standard transitions | ||||
| 	{ | ||||
| 		"id" : "s1", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T,N-1", "T,N-2", "T,N-3", | ||||
| 			"T,N-2", "N", "N", | ||||
| 			"T", "N", "N" | ||||
| 		], | ||||
| 		"maxPoints" : 3, | ||||
| 		"mapping" : { "normal" : "0-3, 20-23", "dirt" : "0-3", "water" : "0-3", "rock": "4D:8-15" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s2", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"?", "N", "N", | ||||
| 			"T", "N", "N", | ||||
| 			"?", "N", "N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "4-7, 24-27", "dirt" : "4-7", "water" : "4-7", "rock": "2D:16-19" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s3", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"?", "T", "?", | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "N" | ||||
| 		], | ||||
| 		"mapping" : { "normal" : "8-11, 28-31", "dirt" : "8-11", "water" : "8-11", "rock": "2D:20-23" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s4", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "s3-1,m7-1,m8-1", | ||||
| 			"N", "s2-1,m7-1,m8-1", "T" | ||||
| 		], | ||||
| 		"minPoints" : 2, | ||||
| 		"mapping" : { "normal" : "12-15, 32-35", "dirt" : "12-15", "water" : "12-15", "rock": "4D:24-31" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s5", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"T", "T", "?", | ||||
| 			"T", "N", "s6-1,m1-1,m2-1,N", | ||||
| 			"?", "s6-1,m1-1,m2-1,N", "N" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "16-17, 36-37", "dirt" : "16-17", "water" : "16-17", "rock": "4D:32-39" } | ||||
| 	}, | ||||
| 	{ | ||||
| 		"id" : "s6", | ||||
| 		"data" : | ||||
| 		[ | ||||
| 			"N", "N", "N", | ||||
| 			"N", "N", "s5-1,N", | ||||
| 			"N", "s5-1,N", "T" | ||||
| 		], | ||||
| 		"minPoints" : 1, | ||||
| 		"mapping" : { "normal" : "18-19, 38-39", "dirt" : "18-19", "water" : "18-19", "rock": "4D:40-47" } | ||||
| 	} | ||||
| ] | ||||
|   | ||||
| @@ -213,8 +213,7 @@ CMapUndoManager & CMapEditManager::getUndoManager() | ||||
| 	return undoManager; | ||||
| } | ||||
|  | ||||
| const std::string TerrainViewPattern::FLIP_MODE_SAME_IMAGE = "sameImage"; | ||||
| const std::string TerrainViewPattern::FLIP_MODE_DIFF_IMAGES = "diffImages"; | ||||
| const std::string TerrainViewPattern::FLIP_MODE_DIFF_IMAGES = "D"; | ||||
|  | ||||
| const std::string TerrainViewPattern::RULE_DIRT = "D"; | ||||
| const std::string TerrainViewPattern::RULE_SAND = "S"; | ||||
| @@ -222,10 +221,9 @@ const std::string TerrainViewPattern::RULE_TRANSITION = "T"; | ||||
| const std::string TerrainViewPattern::RULE_NATIVE = "N"; | ||||
| const std::string TerrainViewPattern::RULE_ANY = "?"; | ||||
|  | ||||
| TerrainViewPattern::TerrainViewPattern() : minPoints(0), flipMode(FLIP_MODE_SAME_IMAGE), | ||||
| 	terGroup(ETerrainGroup::NORMAL) | ||||
| TerrainViewPattern::TerrainViewPattern() : diffImages(false), rotationTypesCount(0), minPoints(0), terGroup(ETerrainGroup::NORMAL) | ||||
| { | ||||
|  | ||||
| 	maxPoints = std::numeric_limits<int>::max(); | ||||
| } | ||||
|  | ||||
| TerrainViewPattern::WeightedRule::WeightedRule() : points(0) | ||||
| @@ -252,67 +250,70 @@ CTerrainViewPatternConfig & CTerrainViewPatternConfig::get() | ||||
| CTerrainViewPatternConfig::CTerrainViewPatternConfig() | ||||
| { | ||||
| 	const JsonNode config(ResourceID("config/terrainViewPatterns.json")); | ||||
| 	const auto & groupMap = config.Struct(); | ||||
| 	BOOST_FOREACH(const auto & groupPair, groupMap) | ||||
| 	const auto & patternsVec = config.Vector(); | ||||
| 	BOOST_FOREACH(const auto & ptrnNode, patternsVec) | ||||
| 	{ | ||||
| 		auto terGroup = getTerrainGroup(groupPair.first); | ||||
| 		BOOST_FOREACH(const JsonNode & ptrnNode, groupPair.second.Vector()) | ||||
| 		TerrainViewPattern pattern; | ||||
|  | ||||
| 		// Read pattern data | ||||
| 		const JsonVector & data = ptrnNode["data"].Vector(); | ||||
| 		assert(data.size() == 9); | ||||
| 		for(int i = 0; i < data.size(); ++i) | ||||
| 		{ | ||||
| 			TerrainViewPattern pattern; | ||||
|  | ||||
| 			// Read pattern data | ||||
| 			const JsonVector & data = ptrnNode["data"].Vector(); | ||||
| 			if(data.size() != 9) | ||||
| 			std::string cell = data[i].String(); | ||||
| 			boost::algorithm::erase_all(cell, " "); | ||||
| 			std::vector<std::string> rules; | ||||
| 			boost::split(rules, cell, boost::is_any_of(",")); | ||||
| 			BOOST_FOREACH(std::string ruleStr, rules) | ||||
| 			{ | ||||
| 				throw std::runtime_error("Size of pattern's data vector has to be 9."); | ||||
| 			} | ||||
| 			for(int i = 0; i < data.size(); ++i) | ||||
| 			{ | ||||
| 				std::string cell = data[i].String(); | ||||
| 				boost::algorithm::erase_all(cell, " "); | ||||
| 				std::vector<std::string> rules; | ||||
| 				boost::split(rules, cell, boost::is_any_of(",")); | ||||
| 				BOOST_FOREACH(std::string ruleStr, rules) | ||||
| 				std::vector<std::string> ruleParts; | ||||
| 				boost::split(ruleParts, ruleStr, boost::is_any_of("-")); | ||||
| 				TerrainViewPattern::WeightedRule rule; | ||||
| 				rule.name = ruleParts[0]; | ||||
| 				assert(!rule.name.empty()); | ||||
| 				if(ruleParts.size() > 1) | ||||
| 				{ | ||||
| 					std::vector<std::string> ruleParts; | ||||
| 					boost::split(ruleParts, ruleStr, boost::is_any_of("-")); | ||||
| 					TerrainViewPattern::WeightedRule rule; | ||||
| 					rule.name = ruleParts[0]; | ||||
| 					if(ruleParts.size() > 1) | ||||
| 					{ | ||||
| 						rule.points = boost::lexical_cast<int>(ruleParts[1]); | ||||
| 					} | ||||
| 					pattern.data[i].push_back(rule); | ||||
| 					rule.points = boost::lexical_cast<int>(ruleParts[1]); | ||||
| 				} | ||||
| 				pattern.data[i].push_back(rule); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 			// Read mapping | ||||
| 			std::string mappingStr = ptrnNode["mapping"].String(); | ||||
| 		// Read various properties | ||||
| 		pattern.id = ptrnNode["id"].String(); | ||||
| 		assert(!pattern.id.empty()); | ||||
| 		pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float()); | ||||
| 		pattern.maxPoints = static_cast<int>(ptrnNode["maxPoints"].Float()); | ||||
| 		if(pattern.maxPoints == 0) pattern.maxPoints = std::numeric_limits<int>::max(); | ||||
|  | ||||
| 		// Read mapping | ||||
| 		const auto & mappingStruct = ptrnNode["mapping"].Struct(); | ||||
| 		BOOST_FOREACH(const auto & mappingPair, mappingStruct) | ||||
| 		{ | ||||
| 			TerrainViewPattern terGroupPattern = pattern; | ||||
| 			auto mappingStr = mappingPair.second.String(); | ||||
| 			boost::algorithm::erase_all(mappingStr, " "); | ||||
| 			auto colonIndex = mappingStr.find_first_of(":"); | ||||
| 			const auto & flipMode = mappingStr.substr(0, colonIndex); | ||||
| 			terGroupPattern.diffImages = TerrainViewPattern::FLIP_MODE_DIFF_IMAGES == &(flipMode[flipMode.length() - 1]); | ||||
| 			if(terGroupPattern.diffImages) | ||||
| 			{ | ||||
| 				terGroupPattern.rotationTypesCount = boost::lexical_cast<int>(flipMode.substr(0, flipMode.length() - 1)); | ||||
| 				assert(terGroupPattern.rotationTypesCount == 2 || terGroupPattern.rotationTypesCount == 4); | ||||
| 			} | ||||
| 			mappingStr = mappingStr.substr(colonIndex + 1); | ||||
| 			std::vector<std::string> mappings; | ||||
| 			boost::split(mappings, mappingStr, boost::is_any_of(",")); | ||||
| 			BOOST_FOREACH(std::string mapping, mappings) | ||||
| 			{ | ||||
| 				std::vector<std::string> range; | ||||
| 				boost::split(range, mapping, boost::is_any_of("-")); | ||||
| 				pattern.mapping.push_back(std::make_pair(boost::lexical_cast<int>(range[0]), | ||||
| 				terGroupPattern.mapping.push_back(std::make_pair(boost::lexical_cast<int>(range[0]), | ||||
| 					boost::lexical_cast<int>(range.size() > 1 ? range[1] : range[0]))); | ||||
| 			} | ||||
|  | ||||
| 			// Read optional attributes | ||||
| 			pattern.id = ptrnNode["id"].String(); | ||||
| 			assert(!pattern.id.empty()); | ||||
| 			pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float()); | ||||
| 			pattern.maxPoints = static_cast<int>(ptrnNode["maxPoints"].Float()); | ||||
| 			if(pattern.maxPoints == 0) pattern.maxPoints = std::numeric_limits<int>::max(); | ||||
| 			pattern.flipMode = ptrnNode["flipMode"].String(); | ||||
| 			if(pattern.flipMode.empty()) | ||||
| 			{ | ||||
| 				pattern.flipMode = TerrainViewPattern::FLIP_MODE_SAME_IMAGE; | ||||
| 			} | ||||
|  | ||||
| 			pattern.terGroup = terGroup; | ||||
| 			patterns[terGroup].push_back(pattern); | ||||
| 			const auto & terGroup = getTerrainGroup(mappingPair.first); | ||||
| 			terGroupPattern.terGroup = terGroup; | ||||
| 			patterns[terGroup].push_back(terGroupPattern); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -332,23 +333,22 @@ ETerrainGroup::ETerrainGroup CTerrainViewPatternConfig::getTerrainGroup(const st | ||||
| 	return it->second; | ||||
| } | ||||
|  | ||||
|  | ||||
| const std::vector<TerrainViewPattern> & CTerrainViewPatternConfig::getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const | ||||
| { | ||||
| 	return patterns.find(terGroup)->second; | ||||
| } | ||||
|  | ||||
| const TerrainViewPattern & CTerrainViewPatternConfig::getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const | ||||
| boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const | ||||
| { | ||||
| 	const std::vector<TerrainViewPattern> & groupPatterns = getPatternsForGroup(terGroup); | ||||
| 	BOOST_FOREACH(const TerrainViewPattern & pattern, groupPatterns) | ||||
| 	{ | ||||
| 		if(id == pattern.id) | ||||
| 		{ | ||||
| 			return pattern; | ||||
| 			return boost::optional<const TerrainViewPattern &>(pattern); | ||||
| 		} | ||||
| 	} | ||||
| 	throw std::runtime_error("Pattern with ID not found: " + id); | ||||
| 	return boost::optional<const TerrainViewPattern &>(); | ||||
| } | ||||
|  | ||||
| CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, const MapRect & rect, ETerrainType terType, CRandomGenerator * gen) | ||||
| @@ -413,7 +413,7 @@ void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect) | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			//assert(bestPattern != -1); | ||||
| 			assert(bestPattern != -1); | ||||
| 			if(bestPattern == -1) | ||||
| 			{ | ||||
| 				// This shouldn't be the case | ||||
| @@ -435,15 +435,16 @@ void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect) | ||||
|  | ||||
| 			// Set terrain view | ||||
| 			auto & tile = map->getTile(int3(x, y, rect.z)); | ||||
| 			if(pattern.flipMode == TerrainViewPattern::FLIP_MODE_SAME_IMAGE) | ||||
| 			if(!pattern.diffImages) | ||||
| 			{ | ||||
| 				tile.terView = gen->getInteger(mapping.first, mapping.second); | ||||
| 				tile.extTileFlags = valRslt.flip; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				const int framesPerRot = 2; | ||||
| 				int firstFrame = mapping.first + valRslt.flip * framesPerRot; | ||||
| 				const int framesPerRot = (mapping.second - mapping.first + 1) / pattern.rotationTypesCount; | ||||
| 				int flip = (pattern.rotationTypesCount == 2 && valRslt.flip == 2) ? 1 : valRslt.flip; | ||||
| 				int firstFrame = mapping.first + flip * framesPerRot; | ||||
| 				tile.terView = gen->getInteger(firstFrame, firstFrame + framesPerRot - 1); | ||||
| 				tile.extTileFlags =	0; | ||||
| 			} | ||||
| @@ -522,12 +523,12 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 			TerrainViewPattern::WeightedRule rule = pattern.data[i][j]; | ||||
| 			if(!rule.isStandardRule()) | ||||
| 			{ | ||||
| 				if(recDepth == 0) | ||||
| 				if(recDepth == 0 && map->isInTheMap(currentPos)) | ||||
| 				{ | ||||
| 					if(map->isInTheMap(currentPos) && terType == centerTerType) | ||||
| 					const auto & patternForRule = CTerrainViewPatternConfig::get().getPatternById(getTerrainGroup(terType), rule.name); | ||||
| 					if(patternForRule) | ||||
| 					{ | ||||
| 						const auto & patternForRule = CTerrainViewPatternConfig::get().getPatternById(pattern.terGroup, rule.name); | ||||
| 						auto rslt = validateTerrainView(currentPos, patternForRule, 1); | ||||
| 						auto rslt = validateTerrainView(currentPos, *patternForRule, 1); | ||||
| 						if(rslt.result) topPoints = std::max(topPoints, rule.points); | ||||
| 					} | ||||
| 					continue; | ||||
| @@ -538,7 +539,6 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			bool nativeTestOk = (rule.name == TerrainViewPattern::RULE_NATIVE || rule.name == TerrainViewPattern::RULE_ANY) && !isAlien; | ||||
| 			auto applyValidationRslt = [&](bool rslt) | ||||
| 			{ | ||||
| 				if(rslt) | ||||
| @@ -550,11 +550,9 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 			// Validate cell with the ruleset of the pattern | ||||
| 			if(pattern.terGroup == ETerrainGroup::NORMAL) | ||||
| 			{ | ||||
| 				bool dirtTestOk = (rule.name == TerrainViewPattern::RULE_DIRT | ||||
| 						|| rule.name == TerrainViewPattern::RULE_TRANSITION || rule.name == TerrainViewPattern::RULE_ANY) | ||||
| 				bool dirtTestOk = (rule.name == TerrainViewPattern::RULE_DIRT || rule.name == TerrainViewPattern::RULE_TRANSITION) | ||||
| 						&& isAlien && !isSandType(terType); | ||||
| 				bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION | ||||
| 						|| rule.name == TerrainViewPattern::RULE_ANY) | ||||
| 				bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION) | ||||
| 						&& isSandType(terType); | ||||
|  | ||||
| 				if(transitionReplacement.empty() && rule.name == TerrainViewPattern::RULE_TRANSITION | ||||
| @@ -569,30 +567,26 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					applyValidationRslt(dirtTestOk || sandTestOk || nativeTestOk); | ||||
| 					bool nativeTestOk = rule.name == TerrainViewPattern::RULE_NATIVE && !isAlien; | ||||
| 					applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || dirtTestOk || sandTestOk || nativeTestOk); | ||||
| 				} | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::DIRT) | ||||
| 			{ | ||||
| 				bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && isSandType(terType); | ||||
| 				bool dirtTestOk = rule.name == TerrainViewPattern::RULE_DIRT && !isSandType(terType) && !nativeTestOk; | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || dirtTestOk || nativeTestOk); | ||||
| 				bool nativeTestOk = rule.name == TerrainViewPattern::RULE_NATIVE && !isSandType(terType); | ||||
| 				bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION) | ||||
| 						&& isSandType(terType); | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::SAND) | ||||
| 			{ | ||||
| 				bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && isAlien; | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); | ||||
| 				applyValidationRslt(true); | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::WATER) | ||||
| 			else if(pattern.terGroup == ETerrainGroup::WATER || pattern.terGroup == ETerrainGroup::ROCK) | ||||
| 			{ | ||||
| 				bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && terType != ETerrainType::DIRT | ||||
| 						&& terType != ETerrainType::WATER; | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); | ||||
| 			} | ||||
| 			else if(pattern.terGroup == ETerrainGroup::ROCK) | ||||
| 			{ | ||||
| 				bool sandTestOk = rule.name == TerrainViewPattern::RULE_SAND && terType != ETerrainType::DIRT | ||||
| 						&& terType != ETerrainType::ROCK; | ||||
| 				bool nativeTestOk = rule.name == TerrainViewPattern::RULE_NATIVE && !isAlien; | ||||
| 				bool sandTestOk = (rule.name == TerrainViewPattern::RULE_SAND || rule.name == TerrainViewPattern::RULE_TRANSITION) | ||||
| 						&& isAlien; | ||||
| 				applyValidationRslt(rule.name == TerrainViewPattern::RULE_ANY || sandTestOk || nativeTestOk); | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -134,35 +134,25 @@ struct DLL_LINKAGE TerrainViewPattern | ||||
| 	struct WeightedRule | ||||
| 	{ | ||||
| 		WeightedRule(); | ||||
|  | ||||
| 		/// Gets true if this rule is a standard rule which means that it has a value of one of the RULE_* constants. | ||||
| 		bool isStandardRule() const; | ||||
|  | ||||
| 		/// The name of the rule. Can be any value of the RULE_* constants or a ID of a another pattern. | ||||
| 		std::string name; | ||||
|  | ||||
| 		/// Optional. A rule can have points. Patterns may have a minimum count of points to reach to be successful. | ||||
| 		int points; | ||||
| 	}; | ||||
|  | ||||
| 	/// Constant for the flip mode same image. Pattern will be flipped and the same image will be used(which is given in the mapping). | ||||
| 	static const std::string FLIP_MODE_SAME_IMAGE; | ||||
|  | ||||
| 	/// Constant for the flip mode different images. Pattern will be flipped and different images will be used(mapping area is divided into 4 parts) | ||||
| 	static const std::string FLIP_MODE_DIFF_IMAGES; | ||||
|  | ||||
| 	/// Constant for the rule dirt, meaning a dirty border is required. | ||||
| 	static const std::string RULE_DIRT; | ||||
|  | ||||
| 	/// Constant for the rule sand, meaning a sandy border is required. | ||||
| 	static const std::string RULE_SAND; | ||||
|  | ||||
| 	/// Constant for the rule transition, meaning a dirty OR sandy border is required. | ||||
| 	static const std::string RULE_TRANSITION; | ||||
|  | ||||
| 	/// Constant for the rule native, meaning a native type is required. | ||||
| 	static const std::string RULE_NATIVE; | ||||
|  | ||||
| 	/// Constant for the rule any, meaning a native type, dirty OR sandy border is required. | ||||
| 	static const std::string RULE_ANY; | ||||
|  | ||||
| @@ -189,13 +179,16 @@ struct DLL_LINKAGE TerrainViewPattern | ||||
| 	/// std::vector -> size=1: typical, size=2: if this pattern should map to two different types of borders | ||||
| 	/// std::pair   -> 1st value: lower range, 2nd value: upper range | ||||
| 	std::vector<std::pair<int, int> > mapping; | ||||
| 	/// If diffImages is true, different images/frames are used to place a rotated terrain view. If it's false | ||||
| 	/// the same frame will be used and rotated. | ||||
| 	bool diffImages; | ||||
| 	/// The rotationTypesCount is only used if diffImages is true and holds the number how many rotation types(horizontal, etc...) | ||||
| 	/// are supported. | ||||
| 	int rotationTypesCount; | ||||
|  | ||||
| 	/// The minimum and maximum points to reach to validate the pattern successfully. | ||||
| 	int minPoints, maxPoints; | ||||
|  | ||||
| 	/// Describes if flipping is required and which mapping should be used. | ||||
| 	std::string flipMode; | ||||
|  | ||||
| 	ETerrainGroup::ETerrainGroup terGroup; | ||||
| }; | ||||
|  | ||||
| @@ -206,7 +199,7 @@ public: | ||||
| 	static CTerrainViewPatternConfig & get(); | ||||
|  | ||||
| 	const std::vector<TerrainViewPattern> & getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; | ||||
| 	const TerrainViewPattern & getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; | ||||
| 	boost::optional<const TerrainViewPattern &> getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; | ||||
| 	ETerrainGroup::ETerrainGroup getTerrainGroup(const std::string & terGroup) const; | ||||
|  | ||||
| private: | ||||
|   | ||||
| @@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain) | ||||
|  | ||||
| 			// Get mapping range | ||||
| 			const auto & pattern = CTerrainViewPatternConfig::get().getPatternById(terGroup, id); | ||||
| 			const auto & mapping = pattern.mapping; | ||||
| 			const auto & mapping = (*pattern).mapping; | ||||
|  | ||||
| 			const auto & positionsNode = node["pos"].Vector(); | ||||
| 			BOOST_FOREACH(const auto & posNode, positionsNode) | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -38,7 +38,7 @@ | ||||
| 			"pattern" : "normal.m3" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 5,34,0 ] ], | ||||
| 			"pos" : [ [ 5,34,0 ], [ 26,23,0 ] ], | ||||
| 			"pattern" : "normal.m4" | ||||
| 		}, | ||||
| 		{ | ||||
| @@ -61,9 +61,17 @@ | ||||
| 			"pos" : [ [ 7,23,0 ] ], | ||||
| 			"pattern" : "normal.n1" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 14,6,0 ] ], | ||||
| 			"pattern" : "normal.x1" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 26,22,0 ] ], | ||||
| 			"pattern" : "normal.x2" | ||||
| 		}, | ||||
| 		// Dirt type | ||||
| 		{ | ||||
| 			"pos" : [ [ 22,26,0 ], [ 27,35,0 ] ], | ||||
| 			"pos" : [ [ 22,26,0 ] ], | ||||
| 			"pattern" : "dirt.s1" | ||||
| 		}, | ||||
| 		{ | ||||
| @@ -79,7 +87,7 @@ | ||||
| 			"pattern" : "dirt.s4" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 26,28,1 ] ], | ||||
| 			"pos" : [ [ 26,28,1 ], [ 27,35,0 ] ], | ||||
| 			"pattern" : "dirt.s5" | ||||
| 		}, | ||||
| 		{ | ||||
| @@ -94,6 +102,10 @@ | ||||
| 			"pos" : [ [ 20,27,1 ] ], | ||||
| 			"pattern" : "dirt.n1" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 11,24,1 ] ], | ||||
| 			"pattern" : "dirt.x1" | ||||
| 		}, | ||||
| 		// Sand type | ||||
| 		{ | ||||
| 			"pos" : [ [ 22,27,1 ] ], | ||||
| @@ -134,7 +146,7 @@ | ||||
| 			"pattern" : "rock.n1" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 11,21,1 ] ], | ||||
| 			"pos" : [ [ 11,21,1 ], [ 10,22,1 ] ], | ||||
| 			"pattern" : "rock.s1" | ||||
| 		}, | ||||
| 		{ | ||||
| @@ -150,7 +162,7 @@ | ||||
| 			"pattern" : "rock.s4" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"pos" : [ [ 10,22,1 ] ], | ||||
| 			"pos" : [ [ 12,24,1 ] ], | ||||
| 			"pattern" : "rock.s5" | ||||
| 		}, | ||||
| 		{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user