Discussion in 'General Modification' started by marc1967, Jul 22, 2015.

Remove all ads!
  1. marc1967

    marc1967 Established Member

    Jan 19, 2014
    Likes Received:
    Have you ever noticed the file terrain.bmp in data\rules? It looks like this:


    Well it actually does something wonderful. The terrain value of an encounter will be based on how the color of that map matches up with where the encounter occurs on World Map:


    The terrain value (based on the color) is passed to the function encounter_exist() in random_encounters.py. The value of setup.terrain will be based on this color. Here are the eight different values that can be sent.

    Yellow: terrain == 0 (TERRAIN_SCRUB) (0)
    Dark yellow: terrain == 1 (TERRAIN_SCRUB & TERRAIN_F_ROAD) (0 + 1)
    Green: terrain == 2 (TERRAIN_FOREST) (2)
    Dark Green: terrain == 3 (TERRAIN_FOREST & TERRAIN_F_ROAD) (2 + 1)
    Red: terrain == 4 (TERRAIN_SWAMP) (4)
    Dark red: terrain == 5 (TERRAIN_SWAMP & TERRAIN_F_ROAD) (4 + 1)
    Blue: terrain == 6 (TERRAIN_RIVERSIDE) (6)
    Dark Blue: terrain == 7 (TERRAIN_RIVERSIDE & TERRAIN_F_ROAD ) (6 + 1)

    (If anyone wants the specifics of how to edit the file, or the exact values of the colors, I can elaborate. In brief, it's a BMP file, but it uses "Indexed Color Mode" instead of RGB, which can be a bit tricky but not a big deal really. Also, there were two colors that didn't actually appear on the original terrain.bmp (Dark Green(3) and Dark Blue(7)), but I found them hidden away in the Color Table of the file, and I painted them on and they worked. So all eight colors are available!)

    The exiting part is that terrain.bmp can be easilly edited to change the colors. Here is an example of the current World Map redone with more varied terrain colors:

    terrain new.jpg terrain+worldmap new.jpg

    This version of terrain.bmp will give Scrub(1) encounters along much of the road, but shifts to Forest(3) as it skirts Decklo Grove and Gnarley Forest, then to Swamp (4,5) near Nulb and Welkwood Bog, and finally it ocassioanly uses Riverside(7) as it touches rivers here and there. I think it would be cool to use one of the other colors to make Hill encounters near the Kron Hills area in the NW part of the map.

    Also, the potential to use the colors in terrain.bmp to layout areas on the World Map based on danger level could make for a more fun and realistic travelling. So safe roads, more dangerous off-road, really scary near the Temple, Welkwood Bog, etc. How else do you explain Micky never getting eaten by Vodyani as he travels the road between Hommlet and Nulb every night. :)


    In the Co8 mods, this functionality was removed and replaced with a simple random number generated from 1 to 8, which then uses one of the 8 random maps. This was done because the original system was always coming up with Riverside terrain. But the reason for this was Not becasue the system that uses terrain.bmp was broken. There were 2 peripheral factors that made it look broken:

    1) A small programming error (detailed below) was making all the terrain that should have been Scrub come up as Riverside instead.

    2) This one is not a bug, but the way the map colors are laid out, you get the Scrub terrain over 90% of the time (which defaults to Riverside beacause of #1 above), with Forest ocassionally, and Swamp so rarely that some were wondering why they made the maps and didn't even us them in this thread: http://www.co8.org/forum/showthread.php?t=2206&highlight=Random+Encouter&page=3

    These two things made it look like the whole thing didn't work at all, but it does.


    OK, so the cool thing about the eight different colors is you don't have to use them for different terrains. Once a value from 0 to 7 is passed into the random encounter processing, you can us it to indiacte anything about that zone. It could be dangerous hills, safe roads, a snowy mountain pass, etc.

    Here is a simple example of what could be done by ignoring the terrain association, and just reusing the colors as you wish:

    Yellow (0) = Well travelled road, minimal dangerous encounters, but interesting ones with NPCs, caravans, travelling mechants, patrols, tiny villages, etc.

    Dark Yellow (1) = Secondary road, possible dangerous encounter or fun friendly encounter as above.

    Green (2) = Off-road area, likely dangerous encounter.

    Dark Green (3) = Dangerous off-road area, high probability for a dangerous encounter, possible powerful high level encounter. Genrate the actual terrain randomly, but with no road.

    Red (4) = Swampy area, likely dangerous encounter.

    Dark Red (5) = Faerie Forest area, sylvan encounters.

    Blue (6) = Riverside area. Use riverside map, and place characters deep in the water with low hight creatures so they can't see who they are attacking. =P

    Dark Blue (7) = Snowy Mountain Pass.​


    The reason things didn't work right is that a tiny function called get_map_from_terrain() is incorrectly coded from random_encounter.py. It's a shame they went through all the trouble to make this cool system only to screw it all up with a few lines of code that actually use it. But the fix I have below should allow encounters to happen by terrain as they were originally intened. Here are the two errors in get_map_from_terrain():

    1) The first error explains why the Riverside encounter was coming up so often in the original game, and yet the Scrub never did at all. The problem is that TERRAIN_SCRUB has a value of "0", and they use a Bitwise-And to try to test it's value. So every time you were to have a Scrub encounter, the line "if (terrain & TERRAIN_SCRUB):" would fail since 0 & 0 is always 0. The encounter would then default to everyone's favorite Riverside. So no Scrub would ever appear.

    2) Ironically, if you actually DID get a Riverside encounter then you would actually go to a Forest instead, argg. Since the value of TERRAIN_RIVERSIDE is 6, it will pass the test for forest in the line of code "elif (terrain & TERRAIN_FOREST):" since 2 & 6 = 2. TERRAIN_RIVERSIDE should have been set internally to 8, and not 6.

    Here are the constants, and the faulty function:
    def get_map_from_terrain( terrain ):
    	if (terrain & TERRAIN_SCRUB):		# this check will never pass since TERRAIN_SCRUB = 0.
    		map = 5070
    	elif (terrain & TERRAIN_FOREST):	# this check will pass for TERRAIN_FOREST(2), but also TERRAIN_RIVERSIDE(6).
    		map = 5071
    	elif (terrain & TERRAIN_SWAMP):
    		map = 5072
    		map = 5073
    	if (terrain & TERRAIN_F_ROAD):
    		map = map + 4
    	return map

    This code change will allow the game to process the colors properly from terrain.bmp as originally intended.

    def get_map_from_terrain( terrain ):
    	t = terrain
    	if (terrain & TERRAIN_F_ROAD):
    		t = terrain - 1
    	if (t == TERRAIN_SCRUB):
    		map = 5070
    	elif (t == TERRAIN_FOREST):
    		map = 5071
    	elif (t == TERRAIN_SWAMP):
    		map = 5072
    		map = 5073
    	if (terrain & TERRAIN_F_ROAD):
    		map = map + 4
    	return map
    This fix won't actually make the game better by itself if you still use the original terrain.bmp, since the way they painted that version you will get Scrub almost all the time anyways. However, if you lay out a new terrain.bmp as I did above, they will work together wonderfully.
  2. Daryk

    Daryk Veteran Member

    Jan 14, 2012
    Likes Received:
    Brillliant! Your fix should definitely go in the next update. I always wondered why I kept seeing the river map when I wasn't anywhere near a river.
  3. Shiningted

    Shiningted I want my goat back Global Moderator

    Oct 23, 2004
    Likes Received:
    Brilliant Marc! Truly awesome discovery! :clap:
  4. Gaear

    Gaear Bastard Maestro Administrator

    Apr 27, 2004
    Likes Received:
    But I want the river road! ;)
  5. Sitra Achara

    Sitra Achara Senior Member

    Sep 1, 2003
    Likes Received:
    As far as I can tell this is further bugged in the sense that the X,Y coordinates the game uses to access the BMP are resolution-dependent. This would mean that for anything but the "intended resolution" (probably 800x600), it won't work well.
    Additionally, it causes crashes sometimes due to accessing the array out of bounds, especially in the northern section of the map.
    anatoliy likes this.
Our Host!