← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/busy_roads_for_buildings into lp:widelands

 

SirVer has proposed merging lp:~widelands-dev/widelands/busy_roads_for_buildings into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #992598 in widelands: "Improve road visibility for the color-blind"
  https://bugs.launchpad.net/widelands/+bug/992598
  Bug #1328637 in widelands: "Road textures are hard to see in some worlds"
  https://bugs.launchpad.net/widelands/+bug/1328637

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/busy_roads_for_buildings/+merge/249013

- Implement drawing of per-tribe roads and textures. Each tribe can have multiple normal or busy roads and they will be used at random when roads are drawn.
- Small buildings will now use normal roads for the road towards them, all others use busy roads.

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/busy_roads_for_buildings into lp:widelands.
=== modified file 'src/economy/flag.cc'
--- src/economy/flag.cc	2014-11-30 18:49:38 +0000
+++ src/economy/flag.cc	2015-02-08 18:18:34 +0000
@@ -203,7 +203,9 @@
 
 	const Map & map = egbase.map();
 	egbase.set_road
-		(map.get_fcoords(map.tl_n(m_position)), Road_SouthEast, Road_Normal);
+		(map.get_fcoords(map.tl_n(m_position)),
+		 RoadType::kSouthEast,
+		 m_building->get_size() == BaseImmovable::SMALL? RoadType::kNormal : RoadType::kBusy);
 
 	building.set_economy(get_economy());
 }
@@ -219,7 +221,7 @@
 
 	const Map & map = egbase.map();
 	egbase.set_road
-		(map.get_fcoords(map.tl_n(m_position)), Road_SouthEast, Road_None);
+		(map.get_fcoords(map.tl_n(m_position)), RoadType::kSouthEast, RoadType::kNone);
 
 	m_building = nullptr;
 }

=== modified file 'src/economy/road.cc'
--- src/economy/road.cc	2014-11-30 18:49:38 +0000
+++ src/economy/road.cc	2015-02-08 18:18:34 +0000
@@ -99,7 +99,7 @@
 	Player & owner          = start.owner();
 	Road & road             = *new Road();
 	road.set_owner(&owner);
-	road.m_type             = Road_Normal;
+	road.m_type             = RoadType::kNormal;
 	road.m_flags[FlagStart] = &start;
 	road.m_flags[FlagEnd]   = &end;
 	// m_flagidx is set when attach_road() is called, i.e. in init()
@@ -224,7 +224,7 @@
 			Direction const rdir = 2 * (dir - WALK_E);
 
 			if (rdir <= 4)
-				egbase.set_road(curf, rdir, Road_None);
+				egbase.set_road(curf, rdir, RoadType::kNone);
 		}
 
 		// mark the road that leads away from this field
@@ -233,7 +233,7 @@
 			Direction const rdir = 2 * (dir - WALK_E);
 
 			if (rdir <= 4)
-				egbase.set_road(curf, rdir, Road_None);
+				egbase.set_road(curf, rdir, RoadType::kNone);
 
 			map.get_neighbour(curf, dir, &curf);
 		}
@@ -293,7 +293,7 @@
 			} else if
 				(!slot.carrier_request &&
 				 (slot.carrier_type == 1 ||
-				  m_type == Road_Busy)) {
+				  m_type == RoadType::kBusy)) {
 				_request_carrier(slot);
 			}
 		}
@@ -584,7 +584,7 @@
 			(!slot.carrier.get(game) &&
 			 !slot.carrier_request &&
 			 (slot.carrier_type == 1 ||
-			  m_type == Road_Busy)) {
+			  m_type == RoadType::kBusy)) {
 			_request_carrier(slot);
 		}
 	}
@@ -632,7 +632,7 @@
 								// ie: cancelling current task
 								m_carrier_slots[1].carrier = nullptr;
 								m_carrier_slots[1].carrier_request = nullptr;
-								m_type = Road_Normal;
+								m_type = RoadType::kNormal;
 								_mark_map(game);
 							}
 						}
@@ -648,7 +648,7 @@
 	if (100 < tdelta) {
 		m_busyness_last_update = gametime;
 		if (500 < (m_busyness += 10)) {
-			m_type = Road_Busy;
+			m_type = RoadType::kBusy;
 			_mark_map(game);
 			for (CarrierSlot& slot : m_carrier_slots) {
 				if

=== modified file 'src/graphic/CMakeLists.txt'
=== modified file 'src/graphic/game_renderer.cc'
--- src/graphic/game_renderer.cc	2014-11-28 08:13:14 +0000
+++ src/graphic/game_renderer.cc	2015-02-08 18:18:34 +0000
@@ -209,6 +209,13 @@
 
 			f.brightness = field_brightness(fcoords, gametime, map, player);
 
+			PlayerNumber owner_number = fcoords.field->get_owned_by();
+			if (owner_number > 0) {
+				f.road_textures = &egbase.player(owner_number).tribe().road_textures();
+			} else {
+				f.road_textures = nullptr;
+			}
+
 			f.roads = field_roads(fcoords, map, player);
 		}
 	}

=== modified file 'src/graphic/gl/fields_to_draw.h'
--- src/graphic/gl/fields_to_draw.h	2014-11-08 18:06:17 +0000
+++ src/graphic/gl/fields_to_draw.h	2015-02-08 18:18:34 +0000
@@ -20,11 +20,14 @@
 #ifndef WL_GRAPHIC_GL_FIELDS_TO_DRAW_H
 #define WL_GRAPHIC_GL_FIELDS_TO_DRAW_H
 
+#include <cstddef>
+#include <string>
 #include <vector>
-#include <cstddef>
 
 #include <stdint.h>
 
+#include "logic/road_textures.h"
+
 // Helper struct that contains the data needed for drawing all fields. All
 // methods are inlined for performance reasons.
 class FieldsToDraw {
@@ -37,6 +40,7 @@
 		float brightness;            // brightness of the pixel
 		uint8_t ter_r, ter_d;        // Texture index of the right and down triangle.
 		uint8_t roads;  // Bitmask of roads to render, see logic/roadtype.h.
+		const RoadTextures* road_textures; // Road Textures to use for drawing.
 	};
 
 	FieldsToDraw(int minfx, int maxfx, int minfy, int maxfy)

=== modified file 'src/graphic/gl/road_program.cc'
--- src/graphic/gl/road_program.cc	2015-01-20 18:54:50 +0000
+++ src/graphic/gl/road_program.cc	2015-02-08 18:18:34 +0000
@@ -19,6 +19,7 @@
 
 #include "graphic/gl/road_program.h"
 
+#include <cassert>
 #include <cmath>
 
 #include "base/log.h"
@@ -37,17 +38,14 @@
 // Attributes.
 attribute vec2 attr_position;
 attribute vec2 attr_texture_position;
-attribute float attr_texture_mix;
 attribute float attr_brightness;
 
 // Outputs.
 varying vec2 out_texture_position;
-varying float out_texture_mix;
 varying float out_brightness;
 
 void main() {
 	out_texture_position = attr_texture_position;
-	out_texture_mix = attr_texture_mix;
 	out_brightness = attr_brightness;
 	gl_Position = vec4(attr_position, 0., 1.);
 }
@@ -58,16 +56,12 @@
 
 // Inputs.
 varying vec2 out_texture_position;
-varying float out_texture_mix;
 varying float out_brightness;
 
-uniform sampler2D u_normal_road_texture;
-uniform sampler2D u_busy_road_texture;
+uniform sampler2D u_texture;
 
 void main() {
-	vec4 normal_road_color = texture2D(u_normal_road_texture, out_texture_position);
-	vec4 busy_road_color = texture2D(u_busy_road_texture, out_texture_position);
-	vec4 color = mix(normal_road_color, busy_road_color, out_texture_mix);
+	vec4 color = texture2D(u_texture, out_texture_position);
 	color.rgb *= out_brightness;
 	gl_FragColor = color;
 }
@@ -81,14 +75,9 @@
 	attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
 	attr_texture_position_ =
 		glGetAttribLocation(gl_program_.object(), "attr_texture_position");
-	attr_texture_mix_ = glGetAttribLocation(gl_program_.object(), "attr_texture_mix");
 	attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
 
-	u_normal_road_texture_ = glGetUniformLocation(gl_program_.object(), "u_normal_road_texture");
-	u_busy_road_texture_ = glGetUniformLocation(gl_program_.object(), "u_busy_road_texture");
-
-	normal_road_texture_ = load_image("world/pics/roadt_normal.png");
-	busy_road_texture_ = load_image("world/pics/roadt_busy.png");
+	u_texture_ = glGetUniformLocation(gl_program_.object(), "u_texture");
 }
 
 RoadProgram::~RoadProgram() {
@@ -97,16 +86,15 @@
 void RoadProgram::add_road(const Surface& surface,
                            const FieldsToDraw::Field& start,
                            const FieldsToDraw::Field& end,
-                           const Widelands::RoadType road_type) {
+                           const Widelands::RoadType road_type,
+                           const Direction direction,
+                           int* gl_texture) {
 	// The thickness of the road in pixels on screen.
 	static constexpr float kRoadThicknessInPixels = 5.;
 
 	// The overshot of the road in either direction in percent.
 	static constexpr float kRoadElongationInPercent = .1;
 
-	// A tiny value we use instead 0, to make sure that we always sample inside of the texture.
-	constexpr float kEpsilon = 1e-6;
-
 	const float delta_x = end.pixel_x - start.pixel_x;
 	const float delta_y = end.pixel_y - start.pixel_y;
 	const float vector_length = std::hypot(delta_x, delta_y);
@@ -119,35 +107,43 @@
 	const float road_thickness_x = (-delta_y / vector_length) * kRoadThicknessInPixels;
 	const float road_thickness_y = (delta_x / vector_length) * kRoadThicknessInPixels;
 
-	const float texture_mix = road_type == Widelands::Road_Normal ? 0. : 1.;
+	const Texture& texture =
+	   road_type == Widelands::RoadType::kNormal ?
+	      start.road_textures->get_normal_texture(start.fx, start.fy, direction) :
+	      start.road_textures->get_busy_texture(start.fx, start.fy, direction);
+	if (*gl_texture == -1) {
+		*gl_texture = texture.get_gl_texture();
+	}
+	// We assume that all road textures are in the same OpenGL texture, i.e. in
+	// one texture atlas.
+	assert(*gl_texture == texture.get_gl_texture());
+
+	const auto& texture_rect = texture.texture_coordinates();
 
 	vertices_.emplace_back(PerVertexData{
 	   start.pixel_x - road_overshoot_x + road_thickness_x,
 	   start.pixel_y - road_overshoot_y + road_thickness_y,
-	   kEpsilon,
-	   kEpsilon,
+	   texture_rect.x,
+	   texture_rect.y,
 	   start.brightness,
-	   texture_mix,
 	});
 	surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
 
 	vertices_.emplace_back(PerVertexData{
 	   start.pixel_x - road_overshoot_x - road_thickness_x,
 	   start.pixel_y - road_overshoot_y - road_thickness_y,
-	   kEpsilon,
-	   1.f - kEpsilon,
+	   texture_rect.x,
+		texture_rect.y + texture_rect.h,
 	   start.brightness,
-	   texture_mix,
 	});
 	surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
 
 	vertices_.emplace_back(PerVertexData{
 	   end.pixel_x + road_overshoot_x + road_thickness_x,
 	   end.pixel_y + road_overshoot_y + road_thickness_y,
-	   1.f - kEpsilon,
-	   kEpsilon,
+	   texture_rect.x + texture_rect.w,
+	   texture_rect.y,
 	   end.brightness,
-	   texture_mix,
 	});
 	surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
 
@@ -161,10 +157,9 @@
 	vertices_.emplace_back(PerVertexData{
 	   end.pixel_x + road_overshoot_x - road_thickness_x,
 	   end.pixel_y + road_overshoot_y - road_thickness_y,
-	   1.f - kEpsilon,
-	   1.f - kEpsilon,
+	   texture_rect.x + texture_rect.w,
+	   texture_rect.y + texture_rect.h,
 	   end.brightness,
-	   texture_mix,
 	});
 	surface.pixel_to_gl(&vertices_.back().gl_x, &vertices_.back().gl_y);
 }
@@ -172,6 +167,7 @@
 void RoadProgram::draw(const Surface& surface, const FieldsToDraw& fields_to_draw) {
 	vertices_.clear();
 
+	int gl_texture = -1;
 	for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
 		const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
 
@@ -179,9 +175,9 @@
 		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
 		if (rn_index != -1) {
 			const Widelands::RoadType road =
-			   static_cast<Widelands::RoadType>(field.roads & Widelands::Road_Mask);
-			if (road != Widelands::Road_None) {
-				add_road(surface, field, fields_to_draw.at(rn_index), road);
+				static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
+			if (road != Widelands::RoadType::kNone) {
+				add_road(surface, field, fields_to_draw.at(rn_index), road, kEast, &gl_texture);
 			}
 		}
 
@@ -189,9 +185,9 @@
 		const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
 		if (brn_index != -1) {
 			const Widelands::RoadType road =
-			   static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::Road_Mask);
-			if (road != Widelands::Road_None) {
-				add_road(surface, field, fields_to_draw.at(brn_index), road);
+				static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
+			if (road != Widelands::RoadType::kNone) {
+				add_road(surface, field, fields_to_draw.at(brn_index), road, kSouthEast, &gl_texture);
 			}
 		}
 
@@ -200,9 +196,9 @@
 		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
 		if (bln_index != -1) {
 			const Widelands::RoadType road =
-			   static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::Road_Mask);
-			if (road != Widelands::Road_None) {
-				add_road(surface, field, fields_to_draw.at(bln_index), road);
+				static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
+			if (road != Widelands::RoadType::kNone) {
+				add_road(surface, field, fields_to_draw.at(bln_index), road, kSouthWest, &gl_texture);
 			}
 		}
 	}
@@ -212,7 +208,6 @@
 	glEnableVertexAttribArray(attr_position_);
 	glEnableVertexAttribArray(attr_texture_position_);
 	glEnableVertexAttribArray(attr_brightness_);
-	glEnableVertexAttribArray(attr_texture_mix_);
 
 	glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
 	glBufferData(
@@ -229,25 +224,18 @@
 	set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, gl_x));
 	set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
 	set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
-	set_attrib_pointer(attr_texture_mix_, 1, offsetof(PerVertexData, texture_mix));
 
 	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
 	// Bind the textures.
 	glActiveTexture(GL_TEXTURE0);
-	glBindTexture(GL_TEXTURE_2D, normal_road_texture_->get_gl_texture());
-	glUniform1i(u_normal_road_texture_, 0);
+	glBindTexture(GL_TEXTURE_2D, gl_texture);
 
-	glActiveTexture(GL_TEXTURE1);
-	glBindTexture(GL_TEXTURE_2D, busy_road_texture_->get_gl_texture());
-	glUniform1i(u_busy_road_texture_, 1);
+	glUniform1i(u_texture_, 0);
 
 	glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
 
 	glDisableVertexAttribArray(attr_position_);
 	glDisableVertexAttribArray(attr_texture_position_);
 	glDisableVertexAttribArray(attr_brightness_);
-	glDisableVertexAttribArray(attr_texture_mix_);
-
-	glActiveTexture(GL_TEXTURE0);
 }

=== modified file 'src/graphic/gl/road_program.h'
--- src/graphic/gl/road_program.h	2014-11-24 07:10:03 +0000
+++ src/graphic/gl/road_program.h	2015-02-08 18:18:34 +0000
@@ -48,21 +48,18 @@
 		float texture_x;
 		float texture_y;
 		float brightness;
-
-		// This is a hack: we want to draw busy and normal roads in the same
-		// run, but since samplers (apparently?) cannot be passed through
-		// attribute arrays, we instead sample twice (busy and normal) and mix
-		// them together with 'texture_mix' which is either 1 or 0.
-		float texture_mix;
 	};
-	static_assert(sizeof(PerVertexData) == 24, "Wrong padding.");
+	static_assert(sizeof(PerVertexData) == 20, "Wrong padding.");
 
 	// Adds a road from 'start' to 'end' to be rendered in this frame using the
 	// correct texture for 'road_type'.
+	enum Direction {kEast, kSouthEast, kSouthWest};
 	void add_road(const Surface& surface,
 	              const FieldsToDraw::Field& start,
 	              const FieldsToDraw::Field& end,
-	              const Widelands::RoadType road_type);
+	              const Widelands::RoadType road_type,
+	              const Direction direction,
+					  int* gl_texture);
 
 	// The buffer that will contain 'vertices_' for rendering.
 	Gl::Buffer gl_array_buffer_;
@@ -74,19 +71,13 @@
 	GLint attr_position_;
 	GLint attr_texture_position_;
 	GLint attr_brightness_;
-	GLint attr_texture_mix_;
 
 	// Uniforms.
-	GLint u_normal_road_texture_;
-	GLint u_busy_road_texture_;
+	GLint u_texture_;
 
 	// All vertices that get rendered this frame.
 	std::vector<PerVertexData> vertices_;
 
-	// The road textures.
-	std::unique_ptr<Texture> normal_road_texture_;
-	std::unique_ptr<Texture> busy_road_texture_;
-
 	DISALLOW_COPY_AND_ASSIGN(RoadProgram);
 };
 

=== modified file 'src/logic/CMakeLists.txt'
--- src/logic/CMakeLists.txt	2015-01-31 16:03:59 +0000
+++ src/logic/CMakeLists.txt	2015-02-08 18:18:34 +0000
@@ -167,6 +167,8 @@
     replay.h
     requirements.cc
     requirements.h
+    road_textures.cc
+    road_textures.h
     roadtype.h
     save_handler.cc
     save_handler.h

=== modified file 'src/logic/bob.h'
--- src/logic/bob.h	2014-09-19 12:54:54 +0000
+++ src/logic/bob.h	2015-02-08 18:18:34 +0000
@@ -35,7 +35,7 @@
 class Map;
 struct Route;
 struct Transfer;
-struct TribeDescr;
+class TribeDescr;
 
 
 /**

=== modified file 'src/logic/buildcost.h'
--- src/logic/buildcost.h	2014-09-10 10:18:46 +0000
+++ src/logic/buildcost.h	2015-02-08 18:18:34 +0000
@@ -30,7 +30,7 @@
 
 namespace Widelands {
 
-struct TribeDescr;
+class TribeDescr;
 
 struct Buildcost : std::map<WareIndex, uint8_t> {
 	void parse(const TribeDescr & tribe, Section & buildcost_s);

=== modified file 'src/logic/building.h'
--- src/logic/building.h	2014-09-29 12:37:07 +0000
+++ src/logic/building.h	2015-02-08 18:18:34 +0000
@@ -47,7 +47,7 @@
 
 struct Flag;
 struct Message;
-struct TribeDescr;
+class TribeDescr;
 class WaresQueue;
 
 class Building;

=== modified file 'src/logic/editor_game_base.cc'
--- src/logic/editor_game_base.cc	2015-01-31 16:03:59 +0000
+++ src/logic/editor_game_base.cc	2015-02-08 18:18:34 +0000
@@ -32,6 +32,9 @@
 #include "graphic/color.h"
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
+#include "graphic/image_io.h"
+#include "graphic/texture_atlas.h"
+#include "io/filesystem/layered_filesystem.h"
 #include "logic/battle.h"
 #include "logic/building.h"
 #include "logic/constants.h"
@@ -282,7 +285,34 @@
 		tribe_descr->load_graphics();
 	}
 
-	// TODO(unknown): load player graphics? (maybe)
+	// Construct and hold on to the texture atlas that contains all road images.
+	TextureAtlas ta;
+
+	// These will be deleted at the end of the method.
+	std::vector<std::unique_ptr<Texture>> individual_textures_;
+	for (auto* tribe : tribes_) {
+		for (const std::string& texture_path : tribe->normal_road_paths()) {
+			individual_textures_.emplace_back(load_image(texture_path, g_fs));
+			ta.add(*individual_textures_.back());
+		}
+		for (const std::string& texture_path : tribe->busy_road_paths()) {
+			individual_textures_.emplace_back(load_image(texture_path, g_fs));
+			ta.add(*individual_textures_.back());
+		}
+	}
+
+	std::vector<std::unique_ptr<Texture>> textures;
+	road_texture_ = ta.pack(&textures);
+
+	size_t next_texture_to_move = 0;
+	for (auto* tribe : tribes_) {
+		for (size_t i = 0; i < tribe->normal_road_paths().size(); ++i) {
+			tribe->add_normal_road_texture(std::move(textures.at(next_texture_to_move++)));
+		}
+		for (size_t i = 0; i < tribe->busy_road_paths().size(); ++i) {
+			tribe->add_busy_road_texture(std::move(textures.at(next_texture_to_move++)));
+		}
+	}
 }
 
 /**
@@ -516,12 +546,12 @@
 	assert(&first_field <= f.field);
 	assert                (f.field < &first_field + m.max_index());
 	assert
-		(direction == Road_SouthWest ||
-		 direction == Road_SouthEast ||
-		 direction == Road_East);
+		(direction == RoadType::kSouthWest ||
+		 direction == RoadType::kSouthEast ||
+		 direction == RoadType::kEast);
 	assert
-		(roadtype == Road_None || roadtype == Road_Normal ||
-		 roadtype == Road_Busy || roadtype == Road_Water);
+		(roadtype == RoadType::kNone || roadtype == RoadType::kNormal ||
+		 roadtype == RoadType::kBusy || roadtype == RoadType::kWater);
 
 	if (f.field->get_road(direction) == roadtype)
 		return;
@@ -530,17 +560,17 @@
 	FCoords neighbour;
 	uint8_t mask = 0;
 	switch (direction) {
-	case Road_SouthWest:
+	case RoadType::kSouthWest:
 		neighbour = m.bl_n(f);
-		mask = Road_Mask << Road_SouthWest;
+		mask = RoadType::kMask << RoadType::kSouthWest;
 		break;
-	case Road_SouthEast:
+	case RoadType::kSouthEast:
 		neighbour = m.br_n(f);
-		mask = Road_Mask << Road_SouthEast;
+		mask = RoadType::kMask << RoadType::kSouthEast;
 		break;
-	case Road_East:
+	case RoadType::kEast:
 		neighbour = m. r_n(f);
-		mask = Road_Mask << Road_East;
+		mask = RoadType::kMask << RoadType::kEast;
 		break;
 	default:
 		assert(false);

=== modified file 'src/logic/editor_game_base.h'
--- src/logic/editor_game_base.h	2015-01-31 16:03:59 +0000
+++ src/logic/editor_game_base.h	2015-02-08 18:18:34 +0000
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "graphic/texture.h"
 #include "logic/bob.h"
 #include "logic/building.h"
 #include "logic/map.h"
@@ -49,7 +50,7 @@
 struct ObjectManager;
 class Player;
 struct PlayerImmovable;
-struct TribeDescr;
+class TribeDescr;
 struct Flag;
 struct AttackController;
 
@@ -262,9 +263,10 @@
 	uint32_t lasttrackserial_;
 	std::map<uint32_t, void*> trackpointers_;
 
+	std::unique_ptr<Texture> road_texture_;
 
-		DISALLOW_COPY_AND_ASSIGN(EditorGameBase);
-	};
+	DISALLOW_COPY_AND_ASSIGN(EditorGameBase);
+};
 
 #define iterate_players_existing(p, nr_players, egbase, player)                                    \
 	iterate_player_numbers(                                                                         \

=== modified file 'src/logic/field.h'
--- src/logic/field.h	2014-12-01 21:47:22 +0000
+++ src/logic/field.h	2015-02-08 18:18:34 +0000
@@ -198,10 +198,10 @@
 
 	int32_t get_roads() const {return roads;}
 	int32_t get_road(int32_t const dir) const {
-		return (roads >> dir) & Road_Mask;
+		return (roads >> dir) & RoadType::kMask;
 	}
 	void set_road(int32_t const dir, int32_t const type) {
-		roads &= ~(Road_Mask << dir);
+		roads &= ~(RoadType::kMask << dir);
 		roads |= type << dir;
 	}
 

=== modified file 'src/logic/immovable.h'
--- src/logic/immovable.h	2014-09-14 11:31:58 +0000
+++ src/logic/immovable.h	2015-02-08 18:18:34 +0000
@@ -44,7 +44,7 @@
 class World;
 struct Flag;
 struct PlayerImmovable;
-struct TribeDescr;
+class TribeDescr;
 
 struct NoteImmovable {
 	CAN_BE_SEND_AS_NOTE(NoteId::Immovable)

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2015-01-31 16:03:59 +0000
+++ src/logic/player.cc	2015-02-08 18:18:34 +0000
@@ -1054,8 +1054,8 @@
 		Field & tr_field = m_fields[tr.field - &first_map_field];
 		if (tr_field.vision <= 1) {
 			tr_field.terrains.d = tr.field->terrain_d();
-			tr_field.roads &= ~(Road_Mask << Road_SouthWest);
-			tr_field.roads |= Road_Mask << Road_SouthWest & tr.field->get_roads();
+			tr_field.roads &= ~(RoadType::kMask << RoadType::kSouthWest);
+			tr_field.roads |= RoadType::kMask << RoadType::kSouthWest & tr.field->get_roads();
 		}
 	}
 	{ //  discover both triangles and the SE edge of the top left  neighbour
@@ -1063,8 +1063,8 @@
 		Field & tl_field = m_fields[tl.field - &first_map_field];
 		if (tl_field.vision <= 1) {
 			tl_field.terrains = tl.field->get_terrains();
-			tl_field.roads &= ~(Road_Mask << Road_SouthEast);
-			tl_field.roads |= Road_Mask << Road_SouthEast & tl.field->get_roads();
+			tl_field.roads &= ~(RoadType::kMask << RoadType::kSouthEast);
+			tl_field.roads |= RoadType::kMask << RoadType::kSouthEast & tl.field->get_roads();
 		}
 	}
 	{ //  discover the R triangle and the  E edge of the     left  neighbour
@@ -1072,8 +1072,8 @@
 		Field & l_field = m_fields[l.field - &first_map_field];
 		if (l_field.vision <= 1) {
 			l_field.terrains.r = l.field->terrain_r();
-			l_field.roads &= ~(Road_Mask << Road_East);
-			l_field.roads |= Road_Mask << Road_East & l.field->get_roads();
+			l_field.roads &= ~(RoadType::kMask << RoadType::kEast);
+			l_field.roads |= RoadType::kMask << RoadType::kEast & l.field->get_roads();
 		}
 	}
 }

=== modified file 'src/logic/player.h'
--- src/logic/player.h	2014-12-28 16:45:37 +0000
+++ src/logic/player.h	2015-02-08 18:18:34 +0000
@@ -42,7 +42,7 @@
 class Soldier;
 class TrainingSite;
 struct Flag;
-struct TribeDescr;
+class TribeDescr;
 struct Road;
 struct AttackController;
 
@@ -246,14 +246,14 @@
 		/// east, as far as this player knows.
 		/// Only valid when this player has seen this node or the node to the
 		/// east.
-		uint8_t road_e() const {return roads & Road_Mask;}
+		uint8_t road_e() const {return roads & RoadType::kMask;}
 
 		/// Whether there is a road between this node and the node to the
 		/// southeast, as far as this player knows.
 		/// Only valid when this player has seen this node or the node to the
 		/// southeast.
 		uint8_t road_se() const {
-			return roads >> Road_SouthEast & Road_Mask;
+			return roads >> RoadType::kSouthEast & RoadType::kMask;
 		}
 
 		/// Whether there is a road between this node and the node to the
@@ -261,7 +261,7 @@
 		/// Only valid when this player has seen this node or the node to the
 		/// southwest.
 		uint8_t road_sw() const {
-			return roads >> Road_SouthWest & Road_Mask;
+			return roads >> RoadType::kSouthWest & RoadType::kMask;
 		}
 
 		/**

=== modified file 'src/logic/production_program.h'
--- src/logic/production_program.h	2014-11-28 16:40:55 +0000
+++ src/logic/production_program.h	2015-02-08 18:18:34 +0000
@@ -43,7 +43,7 @@
 struct ImmovableDescr;
 struct ProductionSiteDescr;
 class ProductionSite;
-struct TribeDescr;
+class TribeDescr;
 class Worker;
 class World;
 

=== added file 'src/logic/road_textures.cc'
--- src/logic/road_textures.cc	1970-01-01 00:00:00 +0000
+++ src/logic/road_textures.cc	2015-02-08 18:18:34 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006-2015 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "logic/road_textures.h"
+
+#include <memory>
+
+const Texture& RoadTextures::get_normal_texture(int x, int y, int direction) const {
+	return *normal_textures_.at((x + y + direction) % normal_textures_.size());
+}
+
+const Texture& RoadTextures::get_busy_texture(int x, int y, int direction) const {
+	return *busy_textures_.at((x + y + direction) % busy_textures_.size());
+}
+
+void RoadTextures::add_normal_road_texture(std::unique_ptr<Texture> texture) {
+	normal_textures_.emplace_back(std::move(texture));
+}
+
+void RoadTextures::add_busy_road_texture(std::unique_ptr<Texture> texture) {
+	busy_textures_.emplace_back(std::move(texture));
+}

=== added file 'src/logic/road_textures.h'
--- src/logic/road_textures.h	1970-01-01 00:00:00 +0000
+++ src/logic/road_textures.h	2015-02-08 18:18:34 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006-2015 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_LOGIC_ROAD_TEXTURES_H
+#define WL_LOGIC_ROAD_TEXTURES_H
+
+#include <memory>
+#include <vector>
+
+#include "graphic/texture.h"
+
+// Simple container to give access of the road textures of a tribe.
+class RoadTextures {
+public:
+	// Returns the road texture that should be used for the Cooordinate x, y and
+	// the road going into direction 'direction' (which can be any number).
+	const Texture& get_normal_texture(int x, int y, int direction) const;
+	const Texture& get_busy_texture(int x, int y, int direction) const;
+
+	// Adds a new road texture.
+	void add_normal_road_texture(std::unique_ptr<Texture> texture);
+	void add_busy_road_texture(std::unique_ptr<Texture> texture);
+
+private:
+	std::vector<std::unique_ptr<Texture>> normal_textures_;
+	std::vector<std::unique_ptr<Texture>> busy_textures_;
+};
+
+#endif  // end of include guard: WL_LOGIC_ROAD_TEXTURES_H

=== modified file 'src/logic/roadtype.h'
--- src/logic/roadtype.h	2014-11-01 20:40:39 +0000
+++ src/logic/roadtype.h	2015-02-08 18:18:34 +0000
@@ -30,15 +30,15 @@
 // the drawing code to keep around what kind of road it should draw. I guess
 // that is the reason why it was combined in the first place. Still it is ugly.
 enum RoadType {
-	Road_None = 0,
-	Road_Normal = 1,
-	Road_Busy = 2,
-	Road_Water = 3,
-	Road_Mask = 3,
+	kNone = 0,
+	kNormal = 1,
+	kBusy = 2,
+	kWater = 3,
+	kMask = 3,
 
-	Road_East      = 0, //  shift values
-	Road_SouthEast = 2,
-	Road_SouthWest = 4,
+	kEast      = 0, //  shift values
+	kSouthEast = 2,
+	kSouthWest = 4,
 };
 
 }

=== modified file 'src/logic/tribe.cc'
--- src/logic/tribe.cc	2015-01-31 16:03:59 +0000
+++ src/logic/tribe.cc	2015-02-08 18:18:34 +0000
@@ -28,10 +28,12 @@
 
 #include "base/i18n.h"
 #include "base/macros.h"
+#include "base/wexception.h"
 #include "graphic/graphic.h"
 #include "helper.h"
 #include "io/fileread.h"
 #include "io/filesystem/disk_filesystem.h"
+#include "io/filesystem/filesystem.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/carrier.h"
 #include "logic/constructionsite.h"
@@ -235,6 +237,33 @@
 				PARSE_ORDER_INFORMATION(worker);
 			}
 
+			{
+				Section road_s = root_conf.get_safe_section("roads");
+				const auto load_roads = [&road_s, this](
+				   const std::string& prefix, std::vector<std::string>* images) {
+					for (int i = 0; i < 99; ++i) {
+						const char* img =
+						   road_s.get_string((boost::format("%s_%02i") % prefix % i).str().c_str(), nullptr);
+						if (img == nullptr) {
+							break;
+						}
+						if (!g_fs->file_exists(img)) {
+							throw new GameDataError("File %s for roadtype %s in tribe %s does not exist",
+							                        img,
+							                        prefix.c_str(),
+							                        m_name.c_str());
+						}
+						images->emplace_back(img);
+					}
+					if (images->empty()) {
+						throw new GameDataError(
+						   "No %s roads defined in tribe %s.", prefix.c_str(), m_name.c_str());
+					}
+				};
+				load_roads("normal", &m_normal_road_paths);
+				load_roads("busy", &m_busy_road_paths);
+			}
+
 			m_frontier_animation_id =
 			   g_gr->animations().load(path, root_conf.get_safe_section("frontier"));
 			m_flag_animation_id =
@@ -292,6 +321,27 @@
 		m_buildings.get(i)->load_graphics();
 }
 
+const std::vector<std::string>& TribeDescr::normal_road_paths() const {
+	return m_normal_road_paths;
+}
+
+const std::vector<std::string>& TribeDescr::busy_road_paths() const {
+	return m_busy_road_paths;
+}
+
+
+void TribeDescr::add_normal_road_texture(std::unique_ptr<Texture> texture) {
+	m_road_textures.add_normal_road_texture(std::move(texture));
+}
+
+void TribeDescr::add_busy_road_texture(std::unique_ptr<Texture> texture) {
+	m_road_textures.add_busy_road_texture(std::move(texture));
+}
+
+const RoadTextures& TribeDescr::road_textures() const {
+	return m_road_textures;
+}
+
 
 /*
  * does this tribe exist?

=== modified file 'src/logic/tribe.h'
--- src/logic/tribe.h	2014-09-14 11:31:58 +0000
+++ src/logic/tribe.h	2015-02-08 18:18:34 +0000
@@ -21,14 +21,18 @@
 #define WL_LOGIC_TRIBE_H
 
 #include <map>
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
 #include "graphic/animation.h"
+#include "graphic/texture.h"
 #include "logic/bob.h"
 #include "logic/building.h"
 #include "logic/description_maintainer.h"
 #include "logic/immovable.h"
+#include "logic/road_textures.h"
+#include "logic/roadtype.h"
 #include "logic/tribe_basic_info.h"
 #include "logic/ware_descr.h"
 #include "logic/worker.h"
@@ -52,7 +56,8 @@
 buildings it can build and the associated graphics.
 Two players can choose the same tribe.
 */
-struct TribeDescr {
+class TribeDescr {
+public:
 	TribeDescr(const std::string & name, EditorGameBase &);
 
 	//  Static function to check for tribes.
@@ -62,7 +67,20 @@
 	static std::vector<TribeBasicInfo> get_all_tribe_infos();
 
 
-	const std::string & name() const {return m_name;}
+	const std::string& name() const {return m_name;}
+
+	// A vector of all texture images that can be used for drawing a
+	// (normal|busy) road. The images are guaranteed to exist.
+	const std::vector<std::string>& normal_road_paths() const;
+	const std::vector<std::string>& busy_road_paths() const;
+
+	// Add the corresponding texture (which probably resides in a
+	// texture atlas) for roads.
+	void add_normal_road_texture(std::unique_ptr<Texture> texture);
+	void add_busy_road_texture(std::unique_ptr<Texture> texture);
+
+	// The road textures used for drawing roads.
+	const RoadTextures& road_textures() const;
 
 	WareIndex get_nrworkers() const {return m_workers.get_nitems();}
 	WorkerDescr const * get_worker_descr(const WareIndex& index) const {
@@ -174,6 +192,11 @@
 
 private:
 	const std::string m_name;
+
+	std::vector<std::string> m_normal_road_paths;
+	std::vector<std::string> m_busy_road_paths;
+	RoadTextures m_road_textures;
+
 	uint32_t m_frontier_animation_id;
 	uint32_t m_flag_animation_id;
 	uint32_t m_bob_vision_range;

=== modified file 'src/logic/ware_descr.h'
--- src/logic/ware_descr.h	2014-09-10 08:55:04 +0000
+++ src/logic/ware_descr.h	2015-02-08 18:18:34 +0000
@@ -39,7 +39,7 @@
 
 namespace Widelands {
 
-struct TribeDescr;
+class TribeDescr;
 
 /**
  * Wares can be stored in warehouses. They can be transferred across an

=== modified file 'src/logic/warehouse.h'
--- src/logic/warehouse.h	2014-09-19 12:54:54 +0000
+++ src/logic/warehouse.h	2015-02-08 18:18:34 +0000
@@ -38,7 +38,7 @@
 class Request;
 struct Requirements;
 class Soldier;
-struct TribeDescr;
+class TribeDescr;
 class WareInstance;
 struct WareList;
 

=== modified file 'src/logic/worker_descr.h'
--- src/logic/worker_descr.h	2014-09-19 12:54:54 +0000
+++ src/logic/worker_descr.h	2015-02-08 18:18:34 +0000
@@ -37,7 +37,7 @@
 
 class WorkerDescr : public BobDescr
 {
-	friend struct TribeDescr;
+	friend class TribeDescr;
 	friend class Warehouse;
 	friend struct WorkerProgram;
 

=== modified file 'src/map_io/map_players_view_packet.cc'
--- src/map_io/map_players_view_packet.cc	2014-10-27 10:14:10 +0000
+++ src/map_io/map_players_view_packet.cc	2015-02-08 18:18:34 +0000
@@ -485,11 +485,11 @@
 					{ //  edges
 						uint8_t mask = 0;
 						if (f_vision | bl_vision)
-							mask  = Road_Mask << Road_SouthWest;
+							mask  = RoadType::kMask << RoadType::kSouthWest;
 						if (f_vision | br_vision)
-							mask |= Road_Mask << Road_SouthEast;
+							mask |= RoadType::kMask << RoadType::kSouthEast;
 						if (f_vision |  r_vision)
-							mask |= Road_Mask << Road_East;
+							mask |= RoadType::kMask << RoadType::kEast;
 						f_player_field.roads = f.field->get_roads() & mask;
 					}
 
@@ -816,17 +816,17 @@
 				{ //  edges
 					uint8_t mask = 0;
 					if (f_seen | bl_seen) {
-						mask  = Road_Mask << Road_SouthWest;
+						mask  = RoadType::kMask << RoadType::kSouthWest;
 					} else if (f_everseen | bl_everseen) {
 						//  The player has seen the SouthWest edge but does not see
 						//  it now. Load his information about this edge from file.
 						if (road_file_version < 2) {
-							try {roads  = legacy_road_bitbuffer.get() << Road_SouthWest;}
+							try {roads  = legacy_road_bitbuffer.get() << RoadType::kSouthWest;}
 							catch (const FileRead::FileBoundaryExceeded &) {
 								throw GameDataError
 									("MapPlayersViewPacket::read: player %u: in "
 									"\"%s\": node (%i, %i): unexpected end of file while "
-									"reading Road_SouthWest",
+									"reading RoadType::kSouthWest",
 									plnum, roads_filename, f.x, f.y);
 							}
 						} else {
@@ -834,17 +834,17 @@
 						}
 					}
 					if (f_seen | br_seen) {
-						mask |= Road_Mask << Road_SouthEast;
+						mask |= RoadType::kMask << RoadType::kSouthEast;
 					} else if (f_everseen | br_everseen) {
 						//  The player has seen the SouthEast edge but does not see
 						//  it now. Load his information about this edge from file.
 						if (road_file_version < 2) {
-							try {roads |= legacy_road_bitbuffer.get() << Road_SouthEast;}
+							try {roads |= legacy_road_bitbuffer.get() << RoadType::kSouthEast;}
 							catch (const FileRead::FileBoundaryExceeded &) {
 								throw GameDataError
 									("MapPlayersViewPacket::read: player %u: in "
 										"\"%s\": node (%i, %i): unexpected end of file while "
-										"reading Road_SouthEast",
+										"reading RoadType::kSouthEast",
 										plnum, roads_filename, f.x, f.y);
 							}
 						} else {
@@ -852,17 +852,17 @@
 						}
 					}
 					if (f_seen |  r_seen) {
-						mask |= Road_Mask << Road_East;
+						mask |= RoadType::kMask << RoadType::kEast;
 					} else if (f_everseen |  r_everseen) {
 						//  The player has seen the      East edge but does not see
 						//  it now. Load his information about this edge from file.
 						if (road_file_version < 2) {
-							try {roads |= legacy_road_bitbuffer.get() << Road_East;}
+							try {roads |= legacy_road_bitbuffer.get() << RoadType::kEast;}
 							catch (const FileRead::FileBoundaryExceeded &) {
 								throw GameDataError
 									("MapPlayersViewPacket::read: player %u: in "
 										"\"%s\": node (%i, %i): unexpected end of file while "
-										"reading Road_East",
+										"reading RoadType::kEast",
 										plnum, roads_filename, f.x, f.y);
 							}
 						} else {

=== modified file 'src/scripting/lua_game.h'
--- src/scripting/lua_game.h	2015-01-31 16:03:59 +0000
+++ src/scripting/lua_game.h	2015-02-08 18:18:34 +0000
@@ -27,7 +27,7 @@
 #include "scripting/luna.h"
 
 namespace Widelands {
-	struct TribeDescr;
+	class TribeDescr;
 	class Objective;
 	struct Message;
 }

=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc	2015-01-31 16:03:59 +0000
+++ src/scripting/lua_map.cc	2015-02-08 18:18:34 +0000
@@ -220,7 +220,7 @@
 	WorkersMap valid_workers;
 	valid_workers.insert(WorkerAmount(r.owner().tribe().worker_index("carrier"), 1));
 
-	if (r.get_roadtype() == Road_Busy)
+	if (r.get_roadtype() == RoadType::kBusy)
 		valid_workers.insert(WorkerAmount(r.owner().tribe().carrier2(), 1));
 
 	return valid_workers;
@@ -2531,9 +2531,9 @@
 */
 int LuaRoad::get_road_type(lua_State * L) {
 	switch (get(L, get_egbase(L))->get_roadtype()) {
-		case Road_Normal:
+		case RoadType::kNormal:
 			lua_pushstring(L, "normal"); break;
-		case Road_Busy:
+		case RoadType::kBusy:
 			lua_pushstring(L, "busy"); break;
 		default:
 		   report_error(L, "Unknown Roadtype! This is a bug in widelands!");

=== modified file 'src/wui/encyclopedia_window.h'
--- src/wui/encyclopedia_window.h	2014-09-20 09:37:47 +0000
+++ src/wui/encyclopedia_window.h	2015-02-08 18:18:34 +0000
@@ -29,7 +29,7 @@
 
 namespace Widelands {
 struct WareDescr;
-struct TribeDescr;
+class TribeDescr;
 }
 
 class InteractivePlayer;

=== modified file 'src/wui/interactive_base.cc'
--- src/wui/interactive_base.cc	2015-01-31 16:03:59 +0000
+++ src/wui/interactive_base.cc	2015-02-08 18:18:34 +0000
@@ -767,7 +767,7 @@
 		int32_t const shift = 2 * (dir - Widelands::WALK_E);
 
 		uint8_t set_to = overlay_manager.get_road_overlay(c);
-		set_to |=  Widelands::Road_Normal << shift;
+		set_to |=  Widelands::RoadType::kNormal << shift;
 		overlay_manager.register_road_overlay(c, set_to, m_jobid);
 	}
 

=== modified file 'src/wui/waresdisplay.h'
--- src/wui/waresdisplay.h	2014-09-14 11:31:58 +0000
+++ src/wui/waresdisplay.h	2015-02-08 18:18:34 +0000
@@ -32,7 +32,7 @@
 namespace UI {struct Textarea;}
 
 namespace Widelands {
-struct TribeDescr;
+class TribeDescr;
 struct WareList;
 }
 

=== modified file 'tribes/atlanteans/conf'
--- tribes/atlanteans/conf	2014-08-26 17:25:00 +0000
+++ tribes/atlanteans/conf	2015-02-08 18:18:34 +0000
@@ -8,12 +8,18 @@
 uiposition=100
 carrier2=horse
 icon=pics/icon.png
+
 # Wares and workers positions in wares window. Columns are separated by ;,
 # Entries in the columns separated by ,
 wares_order=stone, log, planks, spideryarn, spidercloth; fish, smoked_fish, meat, smoked_meat, water, corn, cornflour, blackroot, blackrootflour, bread; quartz, diamond, coal, ironore, iron, goldore, gold; pick, saw, shovel, hammer, milking_tongs, fishing_net, bucket, hunting_bow, hook_pole, scythe, bread_paddle, fire_tongs; light_trident, long_trident, steel_trident, double_trident, heavy_double_trident,steel_shield, advanced_shield, tabard, goldyarn, golden_tabard
 
 workers_order=carrier, horse, horsebreeder; stonecutter, woodcutter, sawyer, forester, builder, spiderbreeder, weaver, shipwright; fisher, fish_breeder, hunter, smoker, farmer, blackroot_farmer, miller, baker; geologist, miner, charcoal_burner, smelter; toolsmith; soldier, trainer, weaponsmith, armorsmith, scout
 
+# Image file paths for this tribe's road textures
+[roads]
+busy_00=tribes/atlanteans/pics/roadt_busy.png
+normal_00=tribes/atlanteans/pics/roadt_normal.png
+
 # Some blue fires would be fine, but just an idea
 [frontier]
 pics=pics/frontier_??.png

=== added file 'tribes/atlanteans/pics/roadt_busy.png'
Binary files tribes/atlanteans/pics/roadt_busy.png	1970-01-01 00:00:00 +0000 and tribes/atlanteans/pics/roadt_busy.png	2015-02-08 18:18:34 +0000 differ
=== added file 'tribes/atlanteans/pics/roadt_normal.png'
Binary files tribes/atlanteans/pics/roadt_normal.png	1970-01-01 00:00:00 +0000 and tribes/atlanteans/pics/roadt_normal.png	2015-02-08 18:18:34 +0000 differ
=== modified file 'tribes/barbarians/conf'
--- tribes/barbarians/conf	2014-08-26 17:25:00 +0000
+++ tribes/barbarians/conf	2015-02-08 18:18:34 +0000
@@ -8,12 +8,17 @@
 uiposition=10
 carrier2=ox
 icon=pics/icon.png
+
 # Wares and workers positions in wares window. Columns are separated by ;,
 # Entries in the columns separated by ,
 wares_order= raw_stone,log, blackwood, grout, thatchreed, cloth; fish, meat, water, wheat, pittabread, beer, strongbeer, ration, snack, meal; coal, ironore, iron, goldore, gold; pick, felling_ax, shovel, hammer, fishing_rod, hunting_spear, scythe, bread_paddle, kitchen_tools, fire_tongs; ax, sharpax, broadax, bronzeax, battleax, warriorsax, helm , mask , warhelm
 
 workers_order=carrier, ox, cattlebreeder; stonemason, lumberjack, ranger, builder, lime-burner, gardener, weaver, shipwright; fisher , hunter , gamekeeper, farmer, baker, brewer, master-brewer, innkeeper; geologist,miner, chief-miner, master-miner, charcoal_burner, smelter; blacksmith, master-blacksmith; soldier, trainer, helmsmith, scout
 
+# Image file paths for this tribe's road textures
+[roads]
+busy_00=tribes/barbarians/pics/roadt_busy.png
+normal_00=tribes/barbarians/pics/roadt_normal.png
 
 [frontier]
 pics=pics/frontier_??.png

=== added file 'tribes/barbarians/pics/roadt_busy.png'
Binary files tribes/barbarians/pics/roadt_busy.png	1970-01-01 00:00:00 +0000 and tribes/barbarians/pics/roadt_busy.png	2015-02-08 18:18:34 +0000 differ
=== added file 'tribes/barbarians/pics/roadt_normal.png'
Binary files tribes/barbarians/pics/roadt_normal.png	1970-01-01 00:00:00 +0000 and tribes/barbarians/pics/roadt_normal.png	2015-02-08 18:18:34 +0000 differ
=== modified file 'tribes/empire/conf'
--- tribes/empire/conf	2014-08-26 17:25:00 +0000
+++ tribes/empire/conf	2015-02-08 18:18:34 +0000
@@ -8,12 +8,20 @@
 uiposition=20
 carrier2=donkey
 icon=pics/icon.png
+
 # Wares and workers positions in wares window. Columns are separated by ;,
 # Entries in the columns separated by ,
 wares_order=stone, log, wood, wool,cloth;   fish,meat, water, wheat, flour, bread, beer, grape, wine, ration, meal;  marble, marblecolumn, coal, ironore, iron, goldore, gold;    pick, ax, saw, shovel, hammer, fishing_rod, hunting_spear, scythe, bread_paddle, basket, kitchen_tools, fire_tongs;   wood_lance, lance, advanced_lance, heavy_lance, war_lance, helm, armor, chain_armor, plate_armor
 
 workers_order=carrier, donkey, donkeybreeder;   stonemason, carpenter, lumberjack, forester, builder, shepherd, weaver, shipwright; fisher, hunter, farmer, miller, baker, brewer, pig-breeder, vinefarmer, innkeeper; geologist, miner, master-miner, charcoal_burner, smelter; toolsmith; soldier, trainer, weaponsmith, armorsmith, scout
 
+# Image file paths for this tribe's road textures
+[roads]
+busy_00=tribes/empire/pics/roadt_busy.png
+normal_00=tribes/empire/pics/roadt_normal_00.png
+normal_01=tribes/empire/pics/roadt_normal_01.png
+normal_02=tribes/empire/pics/roadt_normal_02.png
+
 # No idea for the frontier. Maybe some javelins?
 [frontier]
 pics=pics/frontier_??.png

=== added file 'tribes/empire/pics/roadt_busy.png'
Binary files tribes/empire/pics/roadt_busy.png	1970-01-01 00:00:00 +0000 and tribes/empire/pics/roadt_busy.png	2015-02-08 18:18:34 +0000 differ
=== added file 'tribes/empire/pics/roadt_normal_00.png'
Binary files tribes/empire/pics/roadt_normal_00.png	1970-01-01 00:00:00 +0000 and tribes/empire/pics/roadt_normal_00.png	2015-02-08 18:18:34 +0000 differ
=== added file 'tribes/empire/pics/roadt_normal_01.png'
Binary files tribes/empire/pics/roadt_normal_01.png	1970-01-01 00:00:00 +0000 and tribes/empire/pics/roadt_normal_01.png	2015-02-08 18:18:34 +0000 differ
=== added file 'tribes/empire/pics/roadt_normal_02.png'
Binary files tribes/empire/pics/roadt_normal_02.png	1970-01-01 00:00:00 +0000 and tribes/empire/pics/roadt_normal_02.png	2015-02-08 18:18:34 +0000 differ
=== removed file 'world/pics/roadt_busy.png'
Binary files world/pics/roadt_busy.png	2014-04-26 10:53:52 +0000 and world/pics/roadt_busy.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'world/pics/roadt_normal.png'
Binary files world/pics/roadt_normal.png	2015-01-13 20:54:09 +0000 and world/pics/roadt_normal.png	1970-01-01 00:00:00 +0000 differ

References