diff --git a/bin/data/route_step.grf b/bin/data/route_step.grf
new file mode 100644
index 0000000000..4da31fa6fe
Binary files /dev/null and b/bin/data/route_step.grf differ
diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj
index 770a868c00..1b83b39684 100644
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -357,6 +357,7 @@
+
@@ -559,6 +560,9 @@
+
+
+
@@ -590,6 +594,7 @@
+
@@ -727,6 +732,7 @@
+
@@ -789,6 +795,7 @@
+
@@ -817,6 +824,7 @@
+
@@ -862,6 +870,7 @@
+
@@ -889,6 +898,7 @@
+
diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters
index 3400671e56..e8a80eb9d9 100644
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -300,6 +300,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -906,6 +909,15 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
Header Files
@@ -999,6 +1011,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -1410,6 +1425,9 @@
GUI Source Code
+
+ GUI Source Code
+
GUI Source Code
@@ -1596,6 +1614,9 @@
Widgets
+
+ Widgets
+
Widgets
@@ -1680,6 +1701,9 @@
Command handlers
+
+ Command handlers
+
Command handlers
@@ -1815,6 +1839,9 @@
Save/Load handlers
+
+ Save/Load handlers
+
Save/Load handlers
@@ -1896,6 +1923,9 @@
Tables
+
+ Tables
+
Tables
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index c73299cf9f..1a46dd1ea9 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -702,6 +702,10 @@
RelativePath=".\..\src\pbs.cpp"
>
+
+
@@ -1526,6 +1530,18 @@
RelativePath=".\..\src\pbs.h"
>
+
+
+
+
+
+
@@ -1650,6 +1666,10 @@
RelativePath=".\..\src\slope_type.h"
>
+
+
@@ -2210,6 +2230,10 @@
RelativePath=".\..\src\osk_gui.cpp"
>
+
+
@@ -2462,6 +2486,10 @@
RelativePath=".\..\src\widgets\osk_widget.h"
>
+
+
@@ -2578,6 +2606,10 @@
RelativePath=".\..\src\order_cmd.cpp"
>
+
+
@@ -2762,6 +2794,10 @@
RelativePath=".\..\src\saveload\order_sl.cpp"
>
+
+
@@ -2874,6 +2910,10 @@
RelativePath=".\..\src\table\control_codes.h"
>
+
+
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index 45b689d8df..30dad32c2e 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -699,6 +699,10 @@
RelativePath=".\..\src\pbs.cpp"
>
+
+
@@ -1523,6 +1527,18 @@
RelativePath=".\..\src\pbs.h"
>
+
+
+
+
+
+
@@ -1647,6 +1663,10 @@
RelativePath=".\..\src\slope_type.h"
>
+
+
@@ -2207,6 +2227,10 @@
RelativePath=".\..\src\osk_gui.cpp"
>
+
+
@@ -2459,6 +2483,10 @@
RelativePath=".\..\src\widgets\osk_widget.h"
>
+
+
@@ -2575,6 +2603,10 @@
RelativePath=".\..\src\order_cmd.cpp"
>
+
+
@@ -2759,6 +2791,10 @@
RelativePath=".\..\src\saveload\order_sl.cpp"
>
+
+
@@ -2871,6 +2907,10 @@
RelativePath=".\..\src\table\control_codes.h"
>
+
+
diff --git a/source.list b/source.list
index a579616764..ebb4ea31ef 100644
--- a/source.list
+++ b/source.list
@@ -66,6 +66,7 @@ network/network_udp.cpp
openttd.cpp
order_backup.cpp
pbs.cpp
+plans.cpp
progress.cpp
rail.cpp
rev.cpp
@@ -302,6 +303,9 @@ order_base.h
order_func.h
order_type.h
pbs.h
+plans_base.h
+plans_func.h
+plans_type.h
progress.h
querystring_gui.h
rail.h
@@ -333,6 +337,7 @@ signs_func.h
signs_type.h
slope_func.h
slope_type.h
+smallmap_colours.h
smallmap_gui.h
sortlist_type.h
sound_func.h
@@ -491,6 +496,7 @@ news_gui.cpp
object_gui.cpp
order_gui.cpp
osk_gui.cpp
+plans_gui.cpp
rail_gui.cpp
road_gui.cpp
roadveh_gui.cpp
@@ -555,6 +561,7 @@ widgets/news_widget.h
widgets/object_widget.h
widgets/order_widget.h
widgets/osk_widget.h
+widgets/plans_widget.h
widgets/rail_widget.h
widgets/road_widget.h
widgets/settings_widget.h
@@ -585,6 +592,7 @@ industry_cmd.cpp
misc_cmd.cpp
object_cmd.cpp
order_cmd.cpp
+plans_cmd.cpp
rail_cmd.cpp
road_cmd.cpp
roadveh_cmd.cpp
@@ -632,6 +640,7 @@ saveload/oldloader.cpp
saveload/oldloader.h
saveload/oldloader_sl.cpp
saveload/order_sl.cpp
+saveload/plans_sl.cpp
saveload/saveload.cpp
saveload/saveload.h
saveload/saveload_filter.h
@@ -661,6 +670,7 @@ table/build_industry.h
table/cargo_const.h
table/clear_land.h
table/control_codes.h
+table/darklight_colours.h
table/elrail_data.h
table/engines.h
table/genland.h
diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp
index 6437f236cd..434cc228fa 100644
--- a/src/airport_gui.cpp
+++ b/src/airport_gui.cpp
@@ -62,7 +62,7 @@ static void PlaceAirport(TileIndex tile)
uint32 p1 = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex();
p1 |= _selected_airport_layout << 8;
- CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_AIRPORT | CMD_MSG(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE), CcBuildAirport, "" };
+ CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_AIRPORT | CMD_MSG(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE), CcBuildAirport, 0, "" };
ShowSelectStationIfNeeded(cmdcont, TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE));
}
diff --git a/src/animated_tile.cpp b/src/animated_tile.cpp
index 78dda8b3b6..5874207316 100644
--- a/src/animated_tile.cpp
+++ b/src/animated_tile.cpp
@@ -37,7 +37,7 @@ void DeleteAnimatedTile(TileIndex tile)
*/
memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti));
_animated_tile_count--;
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
return;
}
}
@@ -50,7 +50,7 @@ void DeleteAnimatedTile(TileIndex tile)
*/
void AddAnimatedTile(TileIndex tile)
{
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) {
if (tile == *ti) return;
diff --git a/src/blitter/32bpp_anim.cpp b/src/blitter/32bpp_anim.cpp
index a3083e40b3..ad401dbffa 100644
--- a/src/blitter/32bpp_anim.cpp
+++ b/src/blitter/32bpp_anim.cpp
@@ -317,6 +317,50 @@ void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8 colour)
this->anim_buf[((uint32 *)video - (uint32 *)_screen.dst_ptr) + x + y * this->anim_buf_width] = colour | (DEFAULT_BRIGHTNESS << 8);
}
+void Blitter_32bppAnim::SetLine(void *video, int x, int y, uint8 *colours, uint width)
+{
+ Colour *dst = (Colour *)video + x + y * _screen.pitch;
+
+ if (_screen_disable_anim) {
+ do {
+ *dst = LookupColourInPalette(*colours);
+ dst++;
+ colours++;
+ } while (--width);
+ } else {
+ uint16 *dstanim = (uint16 *)(&this->anim_buf[(uint32 *)video - (uint32 *)_screen.dst_ptr + x + y * _screen.pitch]);
+ do {
+ *dstanim = *colours | (DEFAULT_BRIGHTNESS << 8);
+ *dst = LookupColourInPalette(*colours);
+ dst++;
+ dstanim++;
+ colours++;
+ } while (--width);
+ }
+}
+
+void Blitter_32bppAnim::SetLine32(void *video, int x, int y, uint32 *colours, uint width)
+{
+ Colour *dst = (Colour *)video + x + y * _screen.pitch;
+
+ if (_screen_disable_anim) {
+ do {
+ *dst = *colours;
+ dst++;
+ colours++;
+ } while (--width);
+ } else {
+ uint16 *dstanim = (uint16 *)(&this->anim_buf[(uint32 *)video - (uint32 *)_screen.dst_ptr + x + y * _screen.pitch]);
+ do {
+ *dstanim = 0;
+ *dst = *colours;
+ dst++;
+ dstanim++;
+ colours++;
+ } while (--width);
+ }
+}
+
void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colour)
{
if (_screen_disable_anim) {
diff --git a/src/blitter/32bpp_anim.hpp b/src/blitter/32bpp_anim.hpp
index e707c4437d..1e4a4ea4ae 100644
--- a/src/blitter/32bpp_anim.hpp
+++ b/src/blitter/32bpp_anim.hpp
@@ -32,6 +32,8 @@ public:
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal);
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
+ /* virtual */ void SetLine(void *video, int x, int y, uint8 *colours, uint width);
+ /* virtual */ void SetLine32(void *video, int x, int y, uint32 *colours, uint width);
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
diff --git a/src/blitter/32bpp_base.cpp b/src/blitter/32bpp_base.cpp
index 26dd2f037e..6b7d8ad4e3 100644
--- a/src/blitter/32bpp_base.cpp
+++ b/src/blitter/32bpp_base.cpp
@@ -24,6 +24,26 @@ void Blitter_32bppBase::SetPixel(void *video, int x, int y, uint8 colour)
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour);
}
+void Blitter_32bppBase::SetLine(void *video, int x, int y, uint8 *colours, uint width)
+{
+ Colour *dst = (Colour *)video + x + y * _screen.pitch;
+ do {
+ *dst = LookupColourInPalette(*colours);
+ dst++;
+ colours++;
+ } while (--width);
+}
+
+void Blitter_32bppBase::SetLine32(void *video, int x, int y, uint32 *colours, uint width)
+{
+ Colour *dst = (Colour *)video + x + y * _screen.pitch;
+ do {
+ *dst = *colours;
+ dst++;
+ colours++;
+ } while (--width);
+}
+
void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8 colour)
{
Colour colour32 = LookupColourInPalette(colour);
diff --git a/src/blitter/32bpp_base.hpp b/src/blitter/32bpp_base.hpp
index 26c3dee3fd..22bca227ad 100644
--- a/src/blitter/32bpp_base.hpp
+++ b/src/blitter/32bpp_base.hpp
@@ -23,6 +23,8 @@ public:
/* virtual */ uint8 GetScreenDepth() { return 32; }
/* virtual */ void *MoveTo(void *video, int x, int y);
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
+ /* virtual */ void SetLine(void *video, int x, int y, uint8 *colours, uint width);
+ /* virtual */ void SetLine32(void *video, int x, int y, uint32 *colours, uint width);
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp
index cc056f5b59..649b27312c 100644
--- a/src/blitter/32bpp_optimized.cpp
+++ b/src/blitter/32bpp_optimized.cpp
@@ -280,8 +280,8 @@ Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::Sprite *sprite, Alloc
zoom_max = ZOOM_LVL_NORMAL;
} else {
zoom_min = _settings_client.gui.zoom_min;
- zoom_max = _settings_client.gui.zoom_max;
- if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX;
+ zoom_max = (ZoomLevel) min(_settings_client.gui.zoom_max, ZOOM_LVL_DRAW_SPR);
+ if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_DRAW_SPR;
}
for (ZoomLevel z = zoom_min; z <= zoom_max; z++) {
diff --git a/src/blitter/8bpp_base.cpp b/src/blitter/8bpp_base.cpp
index eab6eaa0db..12150eb6af 100644
--- a/src/blitter/8bpp_base.cpp
+++ b/src/blitter/8bpp_base.cpp
@@ -35,6 +35,11 @@ void Blitter_8bppBase::SetPixel(void *video, int x, int y, uint8 colour)
*((uint8 *)video + x + y * _screen.pitch) = colour;
}
+void Blitter_8bppBase::SetLine(void *video, int x, int y, uint8 *colours, uint width)
+{
+ memcpy((uint8 *)video + x + y * _screen.pitch, colours, width * sizeof(uint8));
+}
+
void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8 colour)
{
do {
diff --git a/src/blitter/8bpp_base.hpp b/src/blitter/8bpp_base.hpp
index 2dff784992..a99f1180aa 100644
--- a/src/blitter/8bpp_base.hpp
+++ b/src/blitter/8bpp_base.hpp
@@ -21,6 +21,7 @@ public:
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal);
/* virtual */ void *MoveTo(void *video, int x, int y);
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
+ /* virtual */ void SetLine(void *video, int x, int y, uint8 *colours, uint width);
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
diff --git a/src/blitter/8bpp_optimized.cpp b/src/blitter/8bpp_optimized.cpp
index 0f07e7c7bb..90cec8805a 100644
--- a/src/blitter/8bpp_optimized.cpp
+++ b/src/blitter/8bpp_optimized.cpp
@@ -134,8 +134,8 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite *sprite, Alloca
zoom_max = ZOOM_LVL_NORMAL;
} else {
zoom_min = _settings_client.gui.zoom_min;
- zoom_max = _settings_client.gui.zoom_max;
- if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX;
+ zoom_max = (ZoomLevel) min(_settings_client.gui.zoom_max, ZOOM_LVL_DRAW_SPR);
+ if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_DRAW_SPR;
}
for (ZoomLevel i = zoom_min; i <= zoom_max; i++) {
diff --git a/src/blitter/base.hpp b/src/blitter/base.hpp
index a9403b339d..a699c5a2d0 100644
--- a/src/blitter/base.hpp
+++ b/src/blitter/base.hpp
@@ -100,6 +100,26 @@ public:
*/
virtual void SetPixel(void *video, int x, int y, uint8 colour) = 0;
+ /**
+ * Draw a sequence of pixels on the video-buffer.
+ * @param video The destination pointer (video-buffer).
+ * @param x The x position within video-buffer.
+ * @param y The y position within video-buffer.
+ * @param colours A 8bpp colour mapping buffer.
+ * @param width The length of the line.
+ */
+ virtual void SetLine(void *video, int x, int y, uint8 *colours, uint width) = 0;
+
+ /**
+ * Draw a sequence of pixels on the video-buffer (no LookupColourInPalette).
+ * @param video The destination pointer (video-buffer).
+ * @param x The x position within video-buffer.
+ * @param y The y position within video-buffer.
+ * @param colours A 32bpp colour buffer.
+ * @param width The length of the line.
+ */
+ virtual void SetLine32(void *video, int x, int y, uint32 *colours, uint width) { NOT_REACHED(); };
+
/**
* Make a single horizontal line in a single colour on the video-buffer.
* @param video The destination pointer (video-buffer).
diff --git a/src/blitter/null.hpp b/src/blitter/null.hpp
index a6fed2ebca..96863c0c3e 100644
--- a/src/blitter/null.hpp
+++ b/src/blitter/null.hpp
@@ -23,6 +23,7 @@ public:
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
/* virtual */ void *MoveTo(void *video, int x, int y) { return NULL; };
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour) {};
+ /* virtual */ void SetLine(void *video, int x, int y, uint8 *colours, uint width) {};
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour) {};
/* virtual */ void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) {};
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height) {};
diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp
index 2e9589aee2..a79b742cb3 100644
--- a/src/clear_cmd.cpp
+++ b/src/clear_cmd.cpp
@@ -46,20 +46,45 @@ static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags)
return price;
}
+SpriteID GetSpriteIDForClearLand(const Slope slope, byte set)
+{
+ return SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(slope) + set * 19;
+}
+
void DrawClearLandTile(const TileInfo *ti, byte set)
{
- DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE);
+ DrawGroundSprite(GetSpriteIDForClearLand(ti->tileh, set), PAL_NONE);
}
-void DrawHillyLandTile(const TileInfo *ti)
+SpriteID GetSpriteIDForHillyLand(const Slope slope, const uint rough_index)
{
- if (ti->tileh != SLOPE_FLAT) {
- DrawGroundSprite(SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
+ if (slope != SLOPE_FLAT) {
+ return SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(slope);
} else {
- DrawGroundSprite(_landscape_clear_sprites_rough[GB(ti->x ^ ti->y, 4, 3)], PAL_NONE);
+ return _landscape_clear_sprites_rough[rough_index];
}
}
+void DrawHillyLandTile(const TileInfo *ti)
+{
+ DrawGroundSprite(GetSpriteIDForHillyLand(ti->tileh, GB(ti->x ^ ti->y, 4, 3)), PAL_NONE);
+}
+
+SpriteID GetSpriteIDForRocks(const Slope slope, const uint tile_hash)
+{
+ return ((HasGrfMiscBit(GMB_SECOND_ROCKY_TILE_SET) && (tile_hash & 1)) ? SPR_FLAT_ROCKY_LAND_2 : SPR_FLAT_ROCKY_LAND_1) + SlopeToSpriteOffset(slope);
+}
+
+SpriteID GetSpriteIDForFields(const Slope slope, const uint field_type)
+{
+ return _clear_land_sprites_farmland[field_type] + SlopeToSpriteOffset(slope);
+}
+
+SpriteID GetSpriteIDForSnowDesert(const Slope slope, const uint density)
+{
+ return _clear_land_sprites_snow_desert[density] + SlopeToSpriteOffset(slope);
+}
+
static void DrawClearLandFence(const TileInfo *ti)
{
/* combine fences into one sprite object */
@@ -112,17 +137,17 @@ static void DrawTile_Clear(TileInfo *ti)
break;
case CLEAR_ROCKS:
- DrawGroundSprite((HasGrfMiscBit(GMB_SECOND_ROCKY_TILE_SET) && (TileHash(ti->x, ti->y) & 1) ? SPR_FLAT_ROCKY_LAND_2 : SPR_FLAT_ROCKY_LAND_1) + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
+ DrawGroundSprite(GetSpriteIDForRocks(ti->tileh, TileHash(ti->x, ti->y)), PAL_NONE);
break;
case CLEAR_FIELDS:
- DrawGroundSprite(_clear_land_sprites_farmland[GetFieldType(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
+ DrawGroundSprite(GetSpriteIDForFields(ti->tileh, GetFieldType(ti->tile)), PAL_NONE);
DrawClearLandFence(ti);
break;
case CLEAR_SNOW:
case CLEAR_DESERT:
- DrawGroundSprite(_clear_land_sprites_snow_desert[GetClearDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
+ DrawGroundSprite(GetSpriteIDForSnowDesert(ti->tileh, GetClearDensity(ti->tile)), PAL_NONE);
break;
}
@@ -171,7 +196,7 @@ static void UpdateFences(TileIndex tile)
dirty = true;
}
- if (dirty) MarkTileDirtyByTile(tile);
+ if (dirty) MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
@@ -253,7 +278,6 @@ static void TileLoop_Clear(TileIndex tile)
int z;
if (IsTileFlat(tile, &z) && z == 0) {
DoFloodTile(tile);
- MarkTileDirtyByTile(tile);
return;
}
}
@@ -307,7 +331,7 @@ static void TileLoop_Clear(TileIndex tile)
return;
}
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
void GenerateClearTile()
diff --git a/src/clear_func.h b/src/clear_func.h
index b128288d1b..c5bc85d2bd 100644
--- a/src/clear_func.h
+++ b/src/clear_func.h
@@ -17,4 +17,10 @@
void DrawHillyLandTile(const TileInfo *ti);
void DrawClearLandTile(const TileInfo *ti, byte set);
+SpriteID GetSpriteIDForClearLand(const Slope slope, byte set);
+SpriteID GetSpriteIDForHillyLand(const Slope slope, const uint rough_index);
+SpriteID GetSpriteIDForRocks(const Slope slope, const uint tile_hash);
+SpriteID GetSpriteIDForFields(const Slope slope, const uint field_type);
+SpriteID GetSpriteIDForSnowDesert(const Slope slope, const uint density);
+
#endif /* CLEAR_FUNC_H */
diff --git a/src/command.cpp b/src/command.cpp
index 8149cd9188..6575fc34aa 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -206,6 +206,12 @@ CommandProc CmdInsertSignalInstruction;
CommandProc CmdModifySignalInstruction;
CommandProc CmdRemoveSignalInstruction;
+CommandProc CmdAddPlan;
+CommandProc CmdAddPlanLine;
+CommandProc CmdRemovePlan;
+CommandProc CmdRemovePlanLine;
+CommandProc CmdChangePlanVisibility;
+
#define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type}
/**
@@ -370,6 +376,12 @@ static const Command _command_proc_table[] = {
DEF_CMD(CmdInsertSignalInstruction, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_INSERT_SIGNAL_INSTRUCTION
DEF_CMD(CmdModifySignalInstruction, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_MODIFY_SIGNAL_INSTRUCTION
DEF_CMD(CmdRemoveSignalInstruction, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SIGNAL_INSTRUCTION
+
+ DEF_CMD(CmdAddPlan, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN
+ DEF_CMD(CmdAddPlanLine, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ADD_PLAN_LINE
+ DEF_CMD(CmdRemovePlan, 0, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_PLAN
+ DEF_CMD(CmdRemovePlanLine, 0, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_PLAN_LINE
+ DEF_CMD(CmdChangePlanVisibility, 0, CMDT_OTHER_MANAGEMENT ), // CMD_CHANGE_PLAN_VISIBILITY
};
/*!
@@ -558,9 +570,10 @@ bool DoCommandP(const CommandContainer *container, bool my_cmd)
* @param callback A callback function to call after the command is finished
* @param text The text to pass
* @param my_cmd indicator if the command is from a company or server (to display error messages for a user)
+ * @param binary_length The quantity of binary data in text
* @return \c true if the command succeeded, else \c false.
*/
-bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd)
+bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, uint32 binary_length)
{
/* Cost estimation is generally only done when the
* local user presses shift while doing somthing.
@@ -590,7 +603,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
if (!(cmd & CMD_NETWORK_COMMAND) && GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = CLIENT_ID_SERVER;
#endif
- CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only);
+ CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only, binary_length);
if (res.Failed()) {
/* Only show the error when it's for us. */
StringID error_part1 = GB(cmd, 16, 16);
@@ -636,7 +649,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
* @param estimate_only whether to give only the estimate or also execute the command
* @return the command cost of this function.
*/
-CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only)
+CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, uint32 binary_length)
{
/* Prevent recursion; it gives a mess over the network */
assert(_docommand_recursive == 0);
@@ -715,7 +728,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
* send it to the command-queue and abort execution
*/
if (_networking && !_generating_world && !(cmd & CMD_NETWORK_COMMAND)) {
- NetworkSendCommand(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company);
+ NetworkSendCommand(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company, binary_length);
cur_company.Restore();
/* Don't return anything special here; no error, no costs.
diff --git a/src/command_func.h b/src/command_func.h
index c4cc51e3da..42a4ff8804 100644
--- a/src/command_func.h
+++ b/src/command_func.h
@@ -37,13 +37,13 @@ static const CommandCost CMD_ERROR = CommandCost(INVALID_STRING_ID);
CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = NULL);
CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags);
-bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true);
+bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true, uint32 binary_length = 0);
bool DoCommandP(const CommandContainer *container, bool my_cmd = true);
-CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only);
+CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only, uint32 binary_length);
#ifdef ENABLE_NETWORK
-void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company);
+void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company, uint32 binary_length);
#endif /* ENABLE_NETWORK */
extern Money _additional_cash_required;
@@ -102,6 +102,9 @@ CommandCallback CcPlaceSign;
CommandCallback CcTerraform;
CommandCallback CcGiveMoney;
+/* plans_gui.cpp */
+CommandCallback CcAddPlan;
+
/* rail_gui.cpp */
CommandCallback CcPlaySound1E;
CommandCallback CcRailDepot;
diff --git a/src/command_type.h b/src/command_type.h
index 30e48435f2..6736c29892 100644
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -337,6 +337,12 @@ enum Commands {
CMD_MODIFY_SIGNAL_INSTRUCTION, ///< modifies a signal instruction
CMD_REMOVE_SIGNAL_INSTRUCTION, ///< removes a signal instruction
+ CMD_ADD_PLAN,
+ CMD_ADD_PLAN_LINE,
+ CMD_REMOVE_PLAN,
+ CMD_REMOVE_PLAN_LINE,
+ CMD_CHANGE_PLAN_VISIBILITY,
+
CMD_END, ///< Must ALWAYS be on the end of this list!! (period)
};
@@ -474,6 +480,8 @@ struct Command {
*/
typedef void CommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2);
+#define MAX_CMD_TEXT_LENGTH 32000
+
/**
* Structure for buffering the build command when selecting a station to join.
*/
@@ -483,7 +491,8 @@ struct CommandContainer {
uint32 p2; ///< parameter p2.
uint32 cmd; ///< command being executed.
CommandCallback *callback; ///< any callback function executed upon successful completion of the command.
- char text[32 * MAX_CHAR_LENGTH]; ///< possible text sent for name changes etc, in bytes including '\0'.
+ uint32 binary_length; ///< in case text contains binary data, this describes its length.
+ char text[MAX_CMD_TEXT_LENGTH]; ///< possible text sent for name changes etc, in bytes including '\0'.
};
#endif /* COMMAND_TYPE_H */
diff --git a/src/console_gui.cpp b/src/console_gui.cpp
index ed46938cd5..6e807b3e25 100644
--- a/src/console_gui.cpp
+++ b/src/console_gui.cpp
@@ -374,7 +374,7 @@ struct IConsoleWindow : Window
this->Scroll(-wheel);
}
- virtual void OnFocusLost()
+ virtual void OnFocusLost(Window *newly_focused_window)
{
VideoDriver::GetInstance()->EditBoxLostFocus();
}
diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp
index f6699daeff..448a0f8963 100644
--- a/src/dock_gui.cpp
+++ b/src/dock_gui.cpp
@@ -196,7 +196,7 @@ struct BuildDocksToolbarWindow : Window {
uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join
/* tile is always the land tile, so need to evaluate _thd.pos */
- CommandContainer cmdcont = { tile, _ctrl_pressed, p2, CMD_BUILD_DOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_DOCK_HERE), CcBuildDocks, "" };
+ CommandContainer cmdcont = { tile, _ctrl_pressed, p2, CMD_BUILD_DOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_DOCK_HERE), CcBuildDocks, 0, "" };
/* Determine the watery part of the dock. */
DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile));
diff --git a/src/gfx.cpp b/src/gfx.cpp
index bc7f932441..0a2bd76f25 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -1191,6 +1191,9 @@ void ScreenSizeChanged()
_dirty_bytes_per_line = CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH);
_dirty_blocks = ReallocT(_dirty_blocks, _dirty_bytes_per_line * CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT));
+ extern uint32 *_vp_map_line;
+ _vp_map_line = ReallocT(_vp_map_line, _screen.width);
+
/* check the dirty rect */
if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height;
diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp
index e677fb3748..560f8282c4 100644
--- a/src/gfxinit.cpp
+++ b/src/gfxinit.cpp
@@ -19,6 +19,12 @@
#include "blitter/factory.hpp"
#include "video/video_driver.hpp"
#include "window_func.h"
+#include "zoom_func.h"
+#include "clear_map.h"
+#include "clear_func.h"
+#include "tree_map.h"
+#include "table/tree_land.h"
+#include "blitter/32bpp_base.hpp"
/* The type of set we're replacing */
#define SET_TYPE "graphics"
@@ -198,6 +204,9 @@ static void LoadSpriteTables()
LoadGrfFile("innerhighlight.grf", SPR_ZONING_INNER_HIGHLIGHT_BASE, i++);
+ /* Load route step graphics */
+ LoadGrfFile("route_step.grf", SPR_ROUTE_STEP_BASE, i++);
+
/* Initialize the unicode to sprite mapping table */
InitializeUnicodeGlyphMap();
@@ -313,6 +322,103 @@ void CheckBlitter()
ReInitAllWindows();
}
+static void UpdateRouteStepSpriteSize()
+{
+ extern uint _vp_route_step_width;
+ extern uint _vp_route_step_height_top;
+ extern uint _vp_route_step_height_middle;
+ extern uint _vp_route_step_height_bottom;
+ extern SubSprite _vp_route_step_subsprite;
+
+ Dimension d = GetSpriteSize(SPR_ROUTE_STEP_TOP);
+ _vp_route_step_width = d.width;
+ _vp_route_step_height_top = d.height;
+
+ d = GetSpriteSize(SPR_ROUTE_STEP_MIDDLE);
+ _vp_route_step_height_middle = d.height;
+ assert(_vp_route_step_width == d.width);
+
+ d = GetSpriteSize(SPR_ROUTE_STEP_BOTTOM);
+ _vp_route_step_height_bottom = d.height;
+ assert(_vp_route_step_width == d.width);
+
+ const int char_height = GetCharacterHeight(FS_SMALL) + 1;
+ _vp_route_step_subsprite.right = ScaleByZoom(_vp_route_step_width, ZOOM_LVL_GUI);
+ _vp_route_step_subsprite.bottom = ScaleByZoom(char_height, ZOOM_LVL_GUI);
+ _vp_route_step_subsprite.left = 0;
+ _vp_route_step_subsprite.top = 0;
+}
+
+/* multi can be density, field type, ... */
+static SpriteID GetSpriteIDForClearGround(const ClearGround cg, const Slope slope, const uint multi)
+{
+ switch (cg) {
+ case CLEAR_GRASS:
+ return GetSpriteIDForClearLand(slope, (byte) multi);
+ case CLEAR_ROUGH:
+ return GetSpriteIDForHillyLand(slope, multi);
+ case CLEAR_ROCKS:
+ return GetSpriteIDForRocks(slope, multi);
+ case CLEAR_FIELDS:
+ return GetSpriteIDForFields(slope, multi);
+ case CLEAR_SNOW:
+ case CLEAR_DESERT:
+ return GetSpriteIDForSnowDesert(slope, multi);
+ default: NOT_REACHED();
+ }
+}
+
+/** Once the sprites are loaded, we can determine main colours of ground/water/... */
+void GfxDetermineMainColours()
+{
+ /* Water. */
+ extern uint32 _vp_map_water_colour[5];
+ _vp_map_water_colour[0] = GetSpriteMainColour(SPR_FLAT_WATER_TILE, PAL_NONE);
+ if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32) {
+ _vp_map_water_colour[1] = Blitter_32bppBase::MakeTransparent(_vp_map_water_colour[0], 256, 192).data; // lighter
+ _vp_map_water_colour[2] = Blitter_32bppBase::MakeTransparent(_vp_map_water_colour[0], 192, 256).data; // darker
+ _vp_map_water_colour[3] = _vp_map_water_colour[2];
+ _vp_map_water_colour[4] = _vp_map_water_colour[1];
+ }
+
+ /* Clear ground. */
+ extern uint32 _vp_map_vegetation_clear_colours[16][6][8];
+ memset(_vp_map_vegetation_clear_colours, 0, sizeof(_vp_map_vegetation_clear_colours));
+ const struct {
+ byte min;
+ byte max;
+ } multi[6] = {
+ { 0, 3 }, // CLEAR_GRASS, density
+ { 0, 7 }, // CLEAR_ROUGH, "random" based on position
+ { 0, 1 }, // CLEAR_ROCKS, tile hash parity
+ { 0, 7 }, // CLEAR_FIELDS, some field types
+ { 0, 3 }, // CLEAR_SNOW, density
+ { 1, 3 }, // CLEAR_DESERT, density
+ };
+ for (uint s = 0; s <= SLOPE_ELEVATED; s++) {
+ for (uint cg = 0; cg < 6; cg++) {
+ for (uint m = multi[cg].min; m <= multi[cg].max; m++) {
+ _vp_map_vegetation_clear_colours[s][cg][m] = GetSpriteMainColour(GetSpriteIDForClearGround((ClearGround) cg, (Slope) s, m), PAL_NONE);
+ }
+ }
+ }
+
+ /* Trees. */
+ extern uint32 _vp_map_vegetation_tree_colours[5][MAX_TREE_COUNT_BY_LANDSCAPE];
+ const uint base = _tree_base_by_landscape[_settings_game.game_creation.landscape];
+ const uint count = _tree_count_by_landscape[_settings_game.game_creation.landscape];
+ for (uint tg = 0; tg < 5; tg++) {
+ for (uint i = base; i < base + count; i++) {
+ _vp_map_vegetation_tree_colours[tg][i - base] = GetSpriteMainColour(_tree_sprites[i].sprite, _tree_sprites[i].pal);
+ }
+ const int diff = MAX_TREE_COUNT_BY_LANDSCAPE - count;
+ if (diff > 0) {
+ for (uint i = count; i < MAX_TREE_COUNT_BY_LANDSCAPE; i++)
+ _vp_map_vegetation_tree_colours[tg][i] = _vp_map_vegetation_tree_colours[tg][i - count];
+ }
+ }
+}
+
/** Initialise and load all the sprites. */
void GfxLoadSprites()
{
@@ -323,7 +429,9 @@ void GfxLoadSprites()
GfxInitSpriteMem();
LoadSpriteTables();
GfxInitPalettes();
+ GfxDetermineMainColours();
+ UpdateRouteStepSpriteSize();
UpdateCursorSize();
}
diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp
index 84288a0e81..a66a6f1946 100644
--- a/src/hotkeys.cpp
+++ b/src/hotkeys.cpp
@@ -61,6 +61,8 @@ static const KeycodeNames _keycode_to_name[] = {
{"NUM_MINUS", WKC_NUM_MINUS},
{"=", WKC_EQUALS},
{"-", WKC_MINUS},
+ {"PAGE_UP", WKC_PAGEUP},
+ {"PAGE_DOWN", WKC_PAGEDOWN},
};
/**
diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp
index 5971964fd7..77c45410a7 100644
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -523,7 +523,7 @@ static void TransportIndustryGoods(TileIndex tile)
ResetIndustryConstructionStage(tile);
SetIndustryCompleted(tile);
SetIndustryGfx(tile, newgfx);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
}
@@ -556,7 +556,7 @@ static void AnimateTile_Industry(TileIndex tile)
}
SetAnimationFrame(tile, m);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
@@ -574,7 +574,7 @@ static void AnimateTile_Industry(TileIndex tile)
}
SetAnimationFrame(tile, m);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
@@ -588,7 +588,7 @@ static void AnimateTile_Industry(TileIndex tile)
}
SetAnimationFrame(tile, m);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
@@ -601,7 +601,7 @@ static void AnimateTile_Industry(TileIndex tile)
DeleteAnimatedTile(tile);
} else {
SetAnimationFrame(tile, m + 1);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
break;
@@ -627,7 +627,7 @@ static void AnimateTile_Industry(TileIndex tile)
}
SetAnimationFrame(tile, m);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
@@ -640,7 +640,7 @@ static void AnimateTile_Industry(TileIndex tile)
gfx = (gfx < 155) ? gfx + 1 : 148;
SetIndustryGfx(tile, gfx);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
@@ -659,7 +659,7 @@ static void AnimateTile_Industry(TileIndex tile)
} else {
SetAnimationFrame(tile, m);
SetIndustryGfx(tile, gfx);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
break;
@@ -685,7 +685,7 @@ static void AnimateTile_Industry(TileIndex tile)
byte m = (GetAnimationFrame(tile) + 1) | 0x40;
if (m > 0xC2) m = 0xC0;
SetAnimationFrame(tile, m);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
} else if (state >= 0x200 && state < 0x3A0) {
int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
if (state & i) return;
@@ -693,7 +693,7 @@ static void AnimateTile_Industry(TileIndex tile)
byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
if (m < 0x80) m = 0x82;
SetAnimationFrame(tile, m);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
}
@@ -723,7 +723,7 @@ static void MakeIndustryTileBigger(TileIndex tile)
StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
if (!IsIndustryCompleted(tile)) return;
@@ -818,7 +818,7 @@ static void TileLoop_Industry(TileIndex tile)
if (newgfx != INDUSTRYTILE_NOANIM) {
ResetIndustryConstructionStage(tile);
SetIndustryGfx(tile, newgfx);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
return;
}
@@ -1021,7 +1021,7 @@ static void PlantFarmField(TileIndex tile, IndustryID industry)
if (IsSuitableForFarmField(cur_tile, true)) {
MakeField(cur_tile, field_type, industry);
SetClearCounter(cur_tile, counter);
- MarkTileDirtyByTile(cur_tile);
+ MarkTileDirtyByTile(cur_tile, ZOOM_LVL_DRAW_MAP);
}
}
diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp
index c160142249..a5ad6ce2c2 100644
--- a/src/industry_gui.cpp
+++ b/src/industry_gui.cpp
@@ -2285,6 +2285,14 @@ struct IndustryCargoesWindow : public Window {
/* Only notify the smallmap window if it exists. In particular, do not
* bring it to the front to prevent messing up any nice layout of the user. */
InvalidateWindowClassesData(WC_SMALLMAP, 0);
+
+ /* Notify viewports too. */
+ Window *w;
+ FOR_ALL_WINDOWS_FROM_BACK(w) {
+ if (w->viewport != NULL)
+ if (w->viewport->zoom >= ZOOM_LVL_DRAW_MAP && w->viewport->map_type == VPMT_INDUSTRY)
+ w->InvalidateData();
+ }
}
/**
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 300692a3bc..0347d33038 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -403,6 +403,7 @@ STR_MAP_MENU_MAP_OF_WORLD :Map of world
STR_MAP_MENU_EXTRA_VIEW_PORT :Extra viewport
STR_MAP_MENU_LINGRAPH_LEGEND :Cargo Flow Legend
STR_MAP_MENU_SIGN_LIST :Sign list
+STR_MAP_MENU_PLAN_LIST :Plan list
############ range for town menu starts
STR_TOWN_MENU_TOWN_DIRECTORY :Town directory
@@ -1370,6 +1371,32 @@ STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Disabled
STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Double click
STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Single click (when focussed)
STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Single click (immediately)
+STR_CONFIG_SETTING_SHOW_VEHICLE_ROUTE_STEPS :Show the vehicle's route steps: {STRING2}
+
+STR_CONFIG_SETTING_VIEWPORT_MAP_SCAN_SURROUNDINGS :Scan surroundings (better for high zoom out levels): {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SLOPES :Show slopes: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_BRIDGES :Show bridges: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_TUNNELS :Show tunnels: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SCROLLING_VP :Show scrolling viewport: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SCROLLING_VP_NOTHING :No
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SCROLLING_VP_CONTOUR :Contour
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SCROLLING_VP_BLEND :Blend with some white (32bpp only)
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SCROLLING_VP_ALL :Blend + contour
+STR_CONFIG_SETTING_VIEWPORT_MAP_USE_OWNER_COLOUR_BRIDGE_TUNNEL :Use owner's colour for bridges and tunnels: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_DEFAULT_MODE :Default mode: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_DEFAULT_MODE_VEGETATION :Vegetation
+STR_CONFIG_SETTING_VIEWPORT_MAP_DEFAULT_MODE_OWNER :Owner
+STR_CONFIG_SETTING_VIEWPORT_MAP_DEFAULT_MODE_INDUSTRY :Industry
+STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK :Function of double-click: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_DO_NOTHING :Do nothing
+STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_ZOOM_MAIN :Zoom in directly to 1X
+STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_NEW_EXTRA :Open an extra viewport
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_VEHICLE_ROUTE :Show the vehicle's route: {STRING2}
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_VEHICLE_ROUTE_NO :No
+STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_VEHICLE_ROUTE_SIMPLE :Simple
+STR_CONFIG_SETTING_VIEWPORT_MAP_DRAW_ROUTE_DASH :Drawing style of vehicle's route: {STRING}
+STR_CONFIG_SETTING_VIEWPORT_MAP_DRAW_ROUTE_DASH_VALUE :dashed lines of {COMMA} pixel{P "" s}
+STR_CONFIG_SETTING_VIEWPORT_MAP_DRAW_ROUTE_DASH_DISABLED :plain lines
STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Right-click emulation: {STRING2}
STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Select the method to emulate right mouse-button clicks
@@ -1618,6 +1645,10 @@ STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normal
STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x
STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x
STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x
+STR_CONFIG_SETTING_ZOOM_LVL_OUT_16X :16x
+STR_CONFIG_SETTING_ZOOM_LVL_OUT_32X :32x
+STR_CONFIG_SETTING_ZOOM_LVL_OUT_64X :64x
+STR_CONFIG_SETTING_ZOOM_LVL_OUT_128X :128x
STR_CONFIG_SETTING_TOWN_GROWTH :Town growth speed: {STRING2}
STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Speed of town growth
STR_CONFIG_SETTING_TOWN_GROWTH_NONE :None
@@ -1717,6 +1748,7 @@ STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Industr
STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Cargo distribution
STR_CONFIG_SETTING_AI :{ORANGE}Competitors
STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players
+STR_CONFIG_SETTING_VIEWPORT_MAP_OPTIONS :{ORANGE}Map mode
STR_CONFIG_SETTING_PATHFINDER_OPF :Original
STR_CONFIG_SETTING_PATHFINDER_NPF :NPF
@@ -3626,6 +3658,14 @@ STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centre t
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}%
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure!
+# Industry tooltip
+STR_INDUSTRY_VIEW_TRANSPORTED_TOOLTIP :{BLACK}{STRING}
+STR_INDUSTRY_VIEW_TRANSPORTED_TOOLTIP_TOOLTIP :{BLACK}{STRING}{}{CARGO_LONG} ({COMMA}%)
+STR_INDUSTRY_VIEW_TRANSPORTED_TOOLTIP_TOOLTIP_TOOLTIP :{BLACK}{STRING}{}{CARGO_LONG} ({COMMA}%){}{BLACK}{CARGO_LONG} ({COMMA}%)
+
+# Town tooltip
+STR_TOWN_NAME_TOOLTIP :{BLACK}{TOWN}
+
############ range for requires starts
STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}
STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING}
@@ -4402,6 +4442,22 @@ STR_TEXTFILE_VIEW_README :{BLACK}View rea
STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog
STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence
+# Plans window
+STR_PLANS_CAPTION :{WHITE}Plans
+STR_PLANS_NEW_PLAN :{BLACK}New
+STR_PLANS_NEW_PLAN_TOOLTIP :{BLACK}Create a new plan
+STR_PLANS_ADD_LINES :{BLACK}Add lines
+STR_PLANS_ADDING_LINES :{BLACK}Adding...
+STR_PLANS_HIDE_ALL :{BLACK}Hide all
+STR_PLANS_HIDE_ALL_TOOLTIP :{BLACK}Set the visibility of all the plans and all their lines to false
+STR_PLANS_VISIBILITY_PRIVATE :{BLACK}Make private
+STR_PLANS_VISIBILITY_PUBLIC :{BLACK}Make public
+STR_PLANS_VISIBILITY_TOOLTIP :{BLACK}Toggle the visibility of a plan (private is yellow, public is blue). A public plan will be displayed in the plan window of the other companies but only its owner can add lines to it.
+STR_PLANS_DELETE :{BLACK}Delete
+STR_PLANS_DELETE_TOOLTIP :{BLACK}Delete the selected item in the list
+STR_PLANS_LIST_ITEM_PLAN :Plan #{NUM}: {NUM} line{P "" s} ({DATE_SHORT})
+STR_PLANS_LIST_ITEM_LINE : -- Line #{NUM}: {NUM} segment{P "" s}
+STR_PLANS_LIST_TOOLTIP :{BLACK}Double click any item in the list to (un)fold the related plan
# Vehicle loading indicators
STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}
@@ -4837,6 +4893,11 @@ STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Can't pl
STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Can't change sign name...
STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Can't delete sign...
+# Plan related errors
+STR_ERROR_TOO_MANY_PLANS :{WHITE}... too many plans
+STR_ERROR_TOO_MANY_NODES :{WHITE}... too many nodes in plan line
+STR_ERROR_NO_MORE_SPACE_FOR_LINES :{WHITE}No more space for lines
+
# Translatable comment for OpenTTD's desktop shortcut
STR_DESKTOP_SHORTCUT_COMMENT :A simulation game based on Transport Tycoon Deluxe
@@ -5261,6 +5322,12 @@ STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STR
STR_SAVEGAME_NAME_SPECTATOR :Spectator, {1:STRING1}
# Viewport strings
+STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP :{BROWN}{NUM} {STRING}
+STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_STATION :{BLACK}ST
+STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_WAYPOINT :{GRAY}WP
+STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_IMPLICIT :{GRAY}IM
+STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_DEPOT :{RED}DE
+
STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA})
STR_VIEWPORT_TOWN :{WHITE}{TOWN}
STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN}
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
index cdef1e6a6e..dad3b7d2c4 100644
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -231,6 +231,8 @@ enum {
GHK_CHAT_ALL,
GHK_CHAT_COMPANY,
GHK_CHAT_SERVER,
+ GHK_CHANGE_MAP_MODE_PREV,
+ GHK_CHANGE_MAP_MODE_NEXT,
};
struct MainWindow : Window
@@ -249,6 +251,7 @@ struct MainWindow : Window
NWidgetViewport *nvp = this->GetWidget(WID_M_VIEWPORT);
nvp->InitializeViewport(this, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
+ this->viewport->map_type = (ViewportMapType) _settings_client.gui.default_viewport_map_mode;
this->viewport->overlay = new LinkGraphOverlay(this, WID_M_VIEWPORT, 0, 0, 3);
this->refresh = LINKGRAPH_DELAY;
}
@@ -423,6 +426,25 @@ struct MainWindow : Window
break;
#endif
+ case GHK_CHANGE_MAP_MODE_PREV:
+ if (_focused_window && _focused_window->viewport && _focused_window->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
+ _focused_window->viewport->map_type = ChangeRenderMode(_focused_window->viewport, true);
+ _focused_window->SetDirty();
+ } else if (this->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
+ this->viewport->map_type = ChangeRenderMode(this->viewport, true);
+ this->SetDirty();
+ }
+ break;
+ case GHK_CHANGE_MAP_MODE_NEXT:
+ if (_focused_window && _focused_window->viewport && _focused_window->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
+ _focused_window->viewport->map_type = ChangeRenderMode(_focused_window->viewport, false);
+ _focused_window->SetDirty();
+ } else if (this->viewport->zoom >= ZOOM_LVL_DRAW_MAP) {
+ this->viewport->map_type = ChangeRenderMode(this->viewport, false);
+ this->SetDirty();
+ }
+ break;
+
default: return ES_NOT_HANDLED;
}
return ES_HANDLED;
@@ -439,7 +461,11 @@ struct MainWindow : Window
virtual void OnMouseWheel(int wheel)
{
- if (_settings_client.gui.scrollwheel_scrolling == 0) {
+ if (_ctrl_pressed) {
+ /* Cycle through the drawing modes */
+ this->viewport->map_type = ChangeRenderMode(this->viewport, wheel < 0);
+ this->SetDirty();
+ } else if (_settings_client.gui.scrollwheel_scrolling == 0) {
ZoomInOrOutToCursorWindow(wheel < 0, this);
}
}
@@ -465,6 +491,16 @@ struct MainWindow : Window
InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data, true);
}
+ virtual void OnMouseOver(Point pt, int widget)
+ {
+ if (pt.x != -1 && _game_mode != GM_MENU) {
+ /* Show tooltip with last month production or town name */
+ const Point p = GetTileBelowCursor();
+ const TileIndex tile = TileVirtXY(p.x, p.y);
+ if (tile < MapSize()) ShowTooltipForTile(this, tile);
+ }
+ }
+
static HotkeyList hotkeys;
};
@@ -517,6 +553,8 @@ static Hotkey global_hotkeys[] = {
Hotkey(_ghk_chat_company_keys, "chat_company", GHK_CHAT_COMPANY),
Hotkey(_ghk_chat_server_keys, "chat_server", GHK_CHAT_SERVER),
#endif
+ Hotkey(WKC_PAGEUP, "previous_map_mode", GHK_CHANGE_MAP_MODE_PREV),
+ Hotkey(WKC_PAGEDOWN, "next_map_mode", GHK_CHANGE_MAP_MODE_NEXT),
HOTKEY_LIST_END
};
HotkeyList MainWindow::hotkeys("global", global_hotkeys);
diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp
index 8794292b11..bb6d5d9be3 100644
--- a/src/misc_gui.cpp
+++ b/src/misc_gui.cpp
@@ -644,6 +644,7 @@ struct TooltipsWindow : public Window
byte paramcount; ///< Number of string parameters in #string_id.
uint64 params[5]; ///< The string parameters.
TooltipCloseCondition close_cond; ///< Condition for closing the window.
+ char buffer[DRAW_STRING_BUFFER]; ///< Text to draw
TooltipsWindow(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip) : Window(&_tool_tips_desc)
{
@@ -654,6 +655,7 @@ struct TooltipsWindow : public Window
memcpy(this->params, params, sizeof(this->params[0]) * paramcount);
this->paramcount = paramcount;
this->close_cond = close_tooltip;
+ if (this->paramcount == 0) GetString(this->buffer, str, lastof(this->buffer)); // Get the text while params are available
this->InitNested();
@@ -699,10 +701,14 @@ struct TooltipsWindow : public Window
GfxFillRect(r.left, r.top, r.right, r.bottom, PC_BLACK);
GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_LIGHT_YELLOW);
- for (uint arg = 0; arg < this->paramcount; arg++) {
- SetDParam(arg, this->params[arg]);
+ if (this->paramcount == 0) {
+ DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->buffer, TC_FROMSTRING, SA_CENTER);
+ } else {
+ for (uint arg = 0; arg < this->paramcount; arg++) {
+ SetDParam(arg, this->params[arg]);
+ }
+ DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->string_id, TC_FROMSTRING, SA_CENTER);
}
- DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->string_id, TC_FROMSTRING, SA_CENTER);
}
virtual void OnMouseLoop()
diff --git a/src/network/core/packet.cpp b/src/network/core/packet.cpp
index 7548132e0b..b3ebd422e2 100644
--- a/src/network/core/packet.cpp
+++ b/src/network/core/packet.cpp
@@ -15,6 +15,7 @@
#include "../../stdafx.h"
#include "../../string_func.h"
+#include "../../command_type.h"
#include "packet.h"
@@ -32,7 +33,7 @@ Packet::Packet(NetworkSocketHandler *cs)
this->next = NULL;
this->pos = 0; // We start reading from here
this->size = 0;
- this->buffer = MallocT(SEND_MTU);
+ this->buffer = MallocT(SHRT_MAX);
}
/**
@@ -47,7 +48,7 @@ Packet::Packet(PacketType type)
/* Skip the size so we can write that in before sending the packet */
this->pos = 0;
this->size = sizeof(PacketSize);
- this->buffer = MallocT(SEND_MTU);
+ this->buffer = MallocT(SHRT_MAX);
this->buffer[this->size++] = type;
}
@@ -99,7 +100,7 @@ void Packet::Send_bool(bool data)
*/
void Packet::Send_uint8(uint8 data)
{
- assert(this->size < SEND_MTU - sizeof(data));
+ assert(this->size < SHRT_MAX - sizeof(data));
this->buffer[this->size++] = data;
}
@@ -109,7 +110,7 @@ void Packet::Send_uint8(uint8 data)
*/
void Packet::Send_uint16(uint16 data)
{
- assert(this->size < SEND_MTU - sizeof(data));
+ assert(this->size < SHRT_MAX - sizeof(data));
this->buffer[this->size++] = GB(data, 0, 8);
this->buffer[this->size++] = GB(data, 8, 8);
}
@@ -120,7 +121,7 @@ void Packet::Send_uint16(uint16 data)
*/
void Packet::Send_uint32(uint32 data)
{
- assert(this->size < SEND_MTU - sizeof(data));
+ assert(this->size < SHRT_MAX - sizeof(data));
this->buffer[this->size++] = GB(data, 0, 8);
this->buffer[this->size++] = GB(data, 8, 8);
this->buffer[this->size++] = GB(data, 16, 8);
@@ -133,7 +134,7 @@ void Packet::Send_uint32(uint32 data)
*/
void Packet::Send_uint64(uint64 data)
{
- assert(this->size < SEND_MTU - sizeof(data));
+ assert(this->size < SHRT_MAX - sizeof(data));
this->buffer[this->size++] = GB(data, 0, 8);
this->buffer[this->size++] = GB(data, 8, 8);
this->buffer[this->size++] = GB(data, 16, 8);
@@ -153,10 +154,22 @@ void Packet::Send_string(const char *data)
{
assert(data != NULL);
/* The <= *is* valid due to the fact that we are comparing sizes and not the index. */
- assert(this->size + strlen(data) + 1 <= SEND_MTU);
+ assert(this->size + strlen(data) + 1 <= SHRT_MAX);
while ((this->buffer[this->size++] = *data++) != '\0') {}
}
+/**
+ * Sends a binary data over the network.
+ * @param data The data to send
+ */
+void Packet::Send_binary(const char *data, const size_t size)
+{
+ assert(data != NULL);
+ assert(size < MAX_CMD_TEXT_LENGTH);
+ memcpy(&this->buffer[this->size], data, size);
+ this->size += (PacketSize) size;
+}
+
/*
* Receiving commands
@@ -311,4 +324,18 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set
str_validate(bufp, last, settings);
}
+/**
+ * Reads binary data.
+ * @param buffer The buffer to put the data into.
+ * @param size The size of the buffer.
+ */
+void Packet::Recv_binary(char *buffer, size_t size)
+{
+ /* Don't allow reading from a closed socket */
+ if (cs->HasClientQuit()) return;
+
+ memcpy(buffer, &this->buffer[this->pos], size);
+ this->pos += (PacketSize) size;
+}
+
#endif /* ENABLE_NETWORK */
diff --git a/src/network/core/packet.h b/src/network/core/packet.h
index 7f344d0179..b27e590d55 100644
--- a/src/network/core/packet.h
+++ b/src/network/core/packet.h
@@ -52,7 +52,7 @@ struct Packet {
PacketSize size;
/** The current read/write position in the packet */
PacketSize pos;
- /** The buffer of this packet, of basically variable length up to SEND_MTU. */
+ /** The buffer of this packet, of basically variable length up to SHRT_MAX. */
byte *buffer;
private:
@@ -73,6 +73,7 @@ public:
void Send_uint32(uint32 data);
void Send_uint64(uint64 data);
void Send_string(const char *data);
+ void Send_binary(const char *data, const size_t size);
/* Reading/receiving of packets */
void ReadRawPacketSize();
@@ -85,6 +86,7 @@ public:
uint32 Recv_uint32();
uint64 Recv_uint64();
void Recv_string(char *buffer, size_t size, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
+ void Recv_binary(char *buffer, size_t size);
};
#endif /* ENABLE_NETWORK */
diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp
index d4d294146e..a78d2bf621 100644
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -862,7 +862,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
* the server will give us a client-id and let us in */
_network_join_status = NETWORK_JOIN_STATUS_REGISTERING;
ShowJoinStatusWindow();
- NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company);
+ NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company, 0);
}
} else {
/* take control over an existing company */
diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp
index 6e5458fd86..72babbc772 100644
--- a/src/network/network_command.cpp
+++ b/src/network/network_command.cpp
@@ -51,6 +51,7 @@ static CommandCallback * const _callback_table[] = {
/* 0x19 */ CcStartStopVehicle,
/* 0x1A */ CcGame,
/* 0x1B */ CcAddVehicleNewGroup,
+ /* 0x1C */ CcAddPlan,
};
/**
@@ -136,8 +137,9 @@ static CommandQueue _local_execution_queue;
* @param callback A callback function to call after the command is finished
* @param text The text to pass
* @param company The company that wants to send the command
+ * @param binary_length The quantity of binary data in text
*/
-void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company)
+void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company, uint32 binary_length)
{
assert((cmd & CMD_FLAGS_MASK) == 0);
@@ -149,7 +151,12 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comman
c.cmd = cmd;
c.callback = callback;
- strecpy(c.text, (text != NULL) ? text : "", lastof(c.text));
+ c.binary_length = binary_length;
+ if (binary_length == 0) {
+ strecpy(c.text, (text != NULL) ? text : "", lastof(c.text));
+ } else {
+ memcpy(c.text, text, binary_length);
+ }
if (_network_server) {
/* If we are the server, we queue the command in our 'special' queue.
@@ -310,7 +317,13 @@ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *c
cp->p1 = p->Recv_uint32();
cp->p2 = p->Recv_uint32();
cp->tile = p->Recv_uint32();
- p->Recv_string(cp->text, lengthof(cp->text), (!_network_server && GetCommandFlags(cp->cmd) & CMD_STR_CTRL) != 0 ? SVS_ALLOW_CONTROL_CODE | SVS_REPLACE_WITH_QUESTION_MARK : SVS_REPLACE_WITH_QUESTION_MARK);
+ cp->binary_length = p->Recv_uint32();
+ if (cp->binary_length == 0) {
+ p->Recv_string(cp->text, lengthof(cp->text), (!_network_server && GetCommandFlags(cp->cmd) & CMD_STR_CTRL) != 0 ? SVS_ALLOW_CONTROL_CODE | SVS_REPLACE_WITH_QUESTION_MARK : SVS_REPLACE_WITH_QUESTION_MARK);
+ } else {
+ if ((p->pos + (PacketSize) cp->binary_length + /* callback index */ 1) > p->size) return "invalid binary data length";
+ p->Recv_binary(cp->text, cp->binary_length);
+ }
byte callback = p->Recv_uint8();
if (callback >= lengthof(_callback_table)) return "invalid callback";
@@ -331,7 +344,12 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp)
p->Send_uint32(cp->p1);
p->Send_uint32(cp->p2);
p->Send_uint32(cp->tile);
- p->Send_string(cp->text);
+ p->Send_uint32(cp->binary_length);
+ if (cp->binary_length == 0) {
+ p->Send_string(cp->text);
+ } else {
+ p->Send_binary(cp->text, cp->binary_length);
+ }
byte callback = 0;
while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) {
diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp
index 6a33c73d89..7e59261762 100644
--- a/src/network/network_server.cpp
+++ b/src/network/network_server.cpp
@@ -2192,7 +2192,7 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
/* ci is NULL when replaying, or for AIs. In neither case there is a client. */
ci->client_playas = c->index;
NetworkUpdateClientInfo(ci->client_id);
- NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, c->index);
+ NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, c->index, 0);
}
/* Announce new company on network. */
diff --git a/src/newgrf_animation_base.h b/src/newgrf_animation_base.h
index 7b94031fbd..3ccbe93700 100644
--- a/src/newgrf_animation_base.h
+++ b/src/newgrf_animation_base.h
@@ -102,7 +102,7 @@ struct AnimationBase {
}
SetAnimationFrame(tile, frame);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
/**
diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp
index 2d7c666607..fb5d366719 100644
--- a/src/newgrf_house.cpp
+++ b/src/newgrf_house.cpp
@@ -755,7 +755,7 @@ bool NewHouseTileLoop(TileIndex tile)
}
SetHouseProcessingTime(tile, hs->processing_time);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
return true;
}
@@ -790,7 +790,7 @@ static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_rando
case HOUSE_TRIGGER_TILE_LOOP_TOP:
if (!first) {
/* The top tile is marked dirty by the usual TileLoop */
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
break;
}
/* Random value of first tile already set. */
diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp
index 90a17550d0..ba92b1c05a 100644
--- a/src/newgrf_industrytiles.cpp
+++ b/src/newgrf_industrytiles.cpp
@@ -336,7 +336,7 @@ static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, I
random_bits &= ~object.reseed[VSG_SCOPE_SELF];
random_bits |= new_random_bits & object.reseed[VSG_SCOPE_SELF];
SetIndustryRandomBits(tile, random_bits);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
reseed_industry |= object.reseed[VSG_SCOPE_PARENT];
}
diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp
index cd5dad7b47..37db2f8416 100644
--- a/src/newgrf_station.cpp
+++ b/src/newgrf_station.cpp
@@ -1030,7 +1030,7 @@ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigg
random_bits |= Random() & reseed;
SetStationTileRandomBits(tile, random_bits);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
}
diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp
index b5b9921525..130caf505a 100644
--- a/src/object_cmd.cpp
+++ b/src/object_cmd.cpp
@@ -124,7 +124,7 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u
DirtyCompanyInfrastructureWindows(owner);
}
MakeObject(t, owner, o->index, wc, Random());
- MarkTileDirtyByTile(t);
+ MarkTileDirtyByTile(t, ZOOM_LVL_DRAW_MAP);
}
Object::IncTypeCount(type);
@@ -140,7 +140,7 @@ static void IncreaseAnimationStage(TileIndex tile)
TileArea ta = Object::GetByTile(tile)->location;
TILE_AREA_LOOP(t, ta) {
SetAnimationFrame(t, GetAnimationFrame(t) + 1);
- MarkTileDirtyByTile(t);
+ MarkTileDirtyByTile(t, ZOOM_LVL_DRAW_MAP);
}
}
diff --git a/src/openttd.cpp b/src/openttd.cpp
index 577da2aa28..057700f09b 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -65,6 +65,7 @@
#include "gfx_layout.h"
#include "viewport_sprite_sorter.h"
#include "programmable_signals.h"
+#include "smallmap_gui.h"
#include "linkgraph/linkgraphschedule.h"
#include "tracerestrict.h"
@@ -1192,6 +1193,8 @@ void SwitchToMode(SwitchMode new_mode)
default: NOT_REACHED();
}
+
+ SmallMapWindow::RebuildColourIndexIfNecessary();
}
diff --git a/src/order_backup.cpp b/src/order_backup.cpp
index 597ad13bba..de0517cf71 100644
--- a/src/order_backup.cpp
+++ b/src/order_backup.cpp
@@ -210,7 +210,7 @@ CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1,
/* We need to circumvent the "prevention" from this command being executed
* while the game is paused, so use the internal method. Nor do we want
* this command to get its cost estimated when shift is pressed. */
- DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false);
+ DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false, 0);
} else {
/* The command came from the game logic, i.e. the clearing of a tile.
* In that case we have no need to actually sync this, just do it. */
diff --git a/src/order_gui.cpp b/src/order_gui.cpp
index e686aef725..741ea24b51 100644
--- a/src/order_gui.cpp
+++ b/src/order_gui.cpp
@@ -624,6 +624,8 @@ private:
order.SetDepotActionType(ODATFB_NEAREST_DEPOT);
DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER));
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
}
/**
@@ -709,6 +711,8 @@ private:
/* When networking, move one order lower */
int selected = this->selected_order + (int)_networking;
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
if (DoCommandP(this->vehicle->tile, this->vehicle->index, this->OrderGetSel(), CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER))) {
this->selected_order = selected >= this->vehicle->GetNumOrders() ? -1 : selected;
this->UpdateButtonState();
@@ -802,6 +806,13 @@ public:
this->OnInvalidateData(VIWD_MODIFY_ORDERS);
}
+ ~OrdersWindow()
+ {
+ if (!FocusWindowById(WC_VEHICLE_VIEW, this->window_number)) {
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
{
switch (widget) {
@@ -1176,6 +1187,8 @@ public:
order.MakeConditional(order_id);
DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER));
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
}
ResetObjectToPlace();
break;
@@ -1234,7 +1247,7 @@ public:
} else {
const Order *o = this->vehicle->GetOrder(this->OrderGetSel());
ShowDropDownMenu(this, _order_non_stop_drowdown, o->GetNonStopType(), WID_O_NON_STOP, 0,
- o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12));
+ o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12), 0, DDSF_LOST_FOCUS);
}
break;
@@ -1254,7 +1267,7 @@ public:
case OPOS_SHARE: sel = 3; break;
default: NOT_REACHED();
}
- ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, sel, WID_O_GOTO, 0, 0);
+ ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, sel, WID_O_GOTO, 0, 0, 0, DDSF_LOST_FOCUS);
}
break;
@@ -1262,7 +1275,7 @@ public:
if (this->GetWidget(widget)->ButtonHit(pt)) {
this->OrderClick_FullLoad(-1);
} else {
- ShowDropDownMenu(this, _order_full_load_drowdown, this->vehicle->GetOrder(this->OrderGetSel())->GetLoadType(), WID_O_FULL_LOAD, 0, 2);
+ ShowDropDownMenu(this, _order_full_load_drowdown, this->vehicle->GetOrder(this->OrderGetSel())->GetLoadType(), WID_O_FULL_LOAD, 0, 2, 0, DDSF_LOST_FOCUS);
}
break;
@@ -1270,7 +1283,7 @@ public:
if (this->GetWidget(widget)->ButtonHit(pt)) {
this->OrderClick_Unload(-1);
} else {
- ShowDropDownMenu(this, _order_unload_drowdown, this->vehicle->GetOrder(this->OrderGetSel())->GetUnloadType(), WID_O_UNLOAD, 0, 8);
+ ShowDropDownMenu(this, _order_unload_drowdown, this->vehicle->GetOrder(this->OrderGetSel())->GetUnloadType(), WID_O_UNLOAD, 0, 8, 0, DDSF_LOST_FOCUS);
}
break;
@@ -1282,7 +1295,7 @@ public:
if (this->GetWidget(widget)->ButtonHit(pt)) {
this->OrderClick_Service(-1);
} else {
- ShowDropDownMenu(this, _order_depot_action_dropdown, DepotActionStringIndex(this->vehicle->GetOrder(this->OrderGetSel())), WID_O_SERVICE, 0, 0);
+ ShowDropDownMenu(this, _order_depot_action_dropdown, DepotActionStringIndex(this->vehicle->GetOrder(this->OrderGetSel())), WID_O_SERVICE, 0, 0, 0, DDSF_LOST_FOCUS);
}
break;
@@ -1290,7 +1303,7 @@ public:
if (this->GetWidget(widget)->ButtonHit(pt)) {
this->OrderClick_Refit(0, true);
} else {
- ShowDropDownMenu(this, _order_refit_action_dropdown, 0, WID_O_REFIT_DROPDOWN, 0, 0);
+ ShowDropDownMenu(this, _order_refit_action_dropdown, 0, WID_O_REFIT_DROPDOWN, 0, 0, 0, DDSF_LOST_FOCUS);
}
break;
@@ -1309,7 +1322,7 @@ public:
case WID_O_COND_COMPARATOR: {
const Order *o = this->vehicle->GetOrder(this->OrderGetSel());
- ShowDropDownMenu(this, _order_conditional_condition, o->GetConditionComparator(), WID_O_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0);
+ ShowDropDownMenu(this, _order_conditional_condition, o->GetConditionComparator(), WID_O_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0, 0, DDSF_LOST_FOCUS);
break;
}
@@ -1455,6 +1468,8 @@ public:
if (cmd.IsType(OT_NOTHING)) return;
if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) {
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
/* With quick goto the Go To button stays active */
if (!_settings_client.gui.quick_goto) ResetObjectToPlace();
}
@@ -1517,6 +1532,27 @@ public:
this->vscroll->SetCapacityFromWidget(this, WID_O_ORDER_LIST);
}
+ virtual void OnFocus(Window *previously_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, previously_focused_window)) {
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
+ virtual void OnFocusLost(Window *newly_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, newly_focused_window)) {
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
+ const Vehicle *GetVehicle()
+ {
+ return this->vehicle;
+ }
+
static HotkeyList hotkeys;
};
diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp
index 974e465f43..0ebc393def 100644
--- a/src/osk_gui.cpp
+++ b/src/osk_gui.cpp
@@ -206,7 +206,7 @@ struct OskWindow : public Window {
this->parent->SetWidgetDirty(this->text_btn);
}
- virtual void OnFocusLost()
+ virtual void OnFocusLost(Window *newly_focused_window)
{
VideoDriver::GetInstance()->EditBoxLostFocus();
delete this;
diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp
index bb705e5f4a..6a5a717584 100644
--- a/src/pathfinder/npf/npf.cpp
+++ b/src/pathfinder/npf/npf.cpp
@@ -281,14 +281,14 @@ static void NPFMarkTile(TileIndex tile)
/* DEBUG: mark visited tiles by mowing the grass under them ;-) */
if (!IsRailDepot(tile)) {
SetRailGroundType(tile, RAIL_GROUND_BARREN);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
case MP_ROAD:
if (!IsRoadDepot(tile)) {
SetRoadside(tile, ROADSIDE_BARREN);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp
index 081bfdc645..a36cc8ea21 100644
--- a/src/pathfinder/yapf/yapf_rail.cpp
+++ b/src/pathfinder/yapf/yapf_rail.cpp
@@ -78,7 +78,7 @@ private:
do {
if (HasStationReservation(tile)) return false;
SetRailStationReservation(tile, true);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
tile = TILE_ADD(tile, diff);
} while (IsCompatibleTrainStationTile(tile, start) && tile != m_origin_tile);
diff --git a/src/pbs.cpp b/src/pbs.cpp
index 139ded7f34..efc8840bd9 100644
--- a/src/pbs.cpp
+++ b/src/pbs.cpp
@@ -66,7 +66,7 @@ void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool
do {
SetRailStationReservation(tile, b);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
tile = TILE_ADD(tile, diff);
} while (IsCompatibleTrainStationTile(tile, start));
}
@@ -86,9 +86,9 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
if (_settings_client.gui.show_track_reservation) {
/* show the reserved rail if needed */
if (IsBridgeTile(tile)) {
- MarkBridgeDirty(tile);
+ MarkBridgeDirty(tile, ZOOM_LVL_DRAW_MAP);
} else {
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
@@ -98,7 +98,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
if (IsRailDepot(tile)) {
if (!HasDepotReservation(tile)) {
SetDepotReservation(tile, true);
- MarkTileDirtyByTile(tile); // some GRFs change their appearance when tile is reserved
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); // some GRFs change their appearance when tile is reserved
return true;
}
}
@@ -116,7 +116,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
if (HasStationRail(tile) && !HasStationReservation(tile)) {
SetRailStationReservation(tile, true);
if (trigger_stations && IsRailStation(tile)) TriggerStationRandomisation(NULL, tile, SRT_PATH_RESERVATION);
- MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); // some GRFs need redraw after reserving track
return true;
}
break;
@@ -145,9 +145,9 @@ void UnreserveRailTrack(TileIndex tile, Track t)
if (_settings_client.gui.show_track_reservation) {
if (IsBridgeTile(tile)) {
- MarkBridgeDirty(tile);
+ MarkBridgeDirty(tile, ZOOM_LVL_DRAW_MAP);
} else {
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
@@ -155,7 +155,7 @@ void UnreserveRailTrack(TileIndex tile, Track t)
case MP_RAILWAY:
if (IsRailDepot(tile)) {
SetDepotReservation(tile, false);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
break;
}
if (IsPlainRail(tile)) UnreserveTrack(tile, t);
@@ -171,7 +171,7 @@ void UnreserveRailTrack(TileIndex tile, Track t)
case MP_STATION:
if (HasStationRail(tile)) {
SetRailStationReservation(tile, false);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
diff --git a/src/plans.cpp b/src/plans.cpp
new file mode 100644
index 0000000000..a98c09a437
--- /dev/null
+++ b/src/plans.cpp
@@ -0,0 +1,21 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file plans.cpp Handling of plans. */
+
+#include "stdafx.h"
+#include "plans_base.h"
+#include "core/pool_func.hpp"
+
+/** Initialize the plan-pool */
+PlanPool _plan_pool("Plan");
+INSTANTIATE_POOL_METHODS(Plan)
+
+Plan *_current_plan = NULL;
+Plan *_new_plan = NULL;
diff --git a/src/plans_base.h b/src/plans_base.h
new file mode 100644
index 0000000000..ca31a5ca13
--- /dev/null
+++ b/src/plans_base.h
@@ -0,0 +1,237 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file plans_base.h Base class for plans. */
+
+#ifndef PLANS_BASE_H
+#define PLANS_BASE_H
+
+#include "plans_func.h"
+#include "core/pool_type.hpp"
+#include "company_type.h"
+#include "company_func.h"
+#include "command_func.h"
+#include "map_func.h"
+#include "date_func.h"
+#include "viewport_func.h"
+#include "core/endian_func.hpp"
+#include
+
+typedef Pool PlanPool;
+typedef std::vector TileVector;
+typedef std::vector PlanLineVector;
+extern PlanPool _plan_pool;
+
+struct PlanLine {
+ bool visible;
+ bool focused;
+ TileVector tiles;
+
+ PlanLine()
+ {
+ this->visible = true;
+ this->focused = false;
+ }
+
+ ~PlanLine()
+ {
+ this->Clear();
+ }
+
+ void Clear()
+ {
+ this->tiles.clear();
+ }
+
+ bool AppendTile(TileIndex tile)
+ {
+ const uint cnt = (uint) this->tiles.size();
+
+ if (cnt > 0) {
+ const TileIndex last_tile = this->tiles[cnt - 1];
+ if (last_tile == tile) return false;
+ MarkTileLineDirty(last_tile, tile);
+
+ if (cnt > 1) {
+ const TileIndex t0 = this->tiles[cnt - 2];
+ const int x0 = (int) TileX(t0);
+ const int y0 = (int) TileY(t0);
+ const TileIndex t1 = this->tiles[cnt - 1];
+ const int x1 = (int) TileX(t1);
+ const int y1 = (int) TileY(t1);
+ const int x2 = (int) TileX(tile);
+ const int y2 = (int) TileY(tile);
+
+ if ((y1 - y0) * (x2 - x1) == (y2 - y1) * (x1 - x0)) { // Same direction.
+ if (abs(x2 - x1) <= abs(x2 - x0) && abs(y2 - y1) <= abs(y2 - y0)) { // Tile i+1 is between i and i+2.
+ /* The new tile is in the continuity, just update the last tile. */
+ this->tiles[cnt - 1] = tile;
+ MarkTileLineDirty(t1, tile);
+ return true;
+ }
+ }
+ }
+ }
+
+ if (this->tiles.size() * sizeof(TileIndex) >= MAX_CMD_TEXT_LENGTH) return false;
+
+ this->tiles.push_back(tile);
+ return true;
+ }
+
+ void SetFocus(bool focused)
+ {
+ if (this->focused != focused) this->MarkDirty();
+ this->focused = focused;
+ }
+
+ bool ToggleVisibility()
+ {
+ this->SetVisibility(!this->visible);
+ return this->visible;
+ }
+
+ void SetVisibility(bool visible)
+ {
+ if (this->visible != visible) this->MarkDirty();
+ this->visible = visible;
+ }
+
+ void MarkDirty()
+ {
+ const uint sz = (uint) this->tiles.size();
+ for (uint i = 1; i < sz; i++) {
+ MarkTileLineDirty(this->tiles[i-1], this->tiles[i]);
+ }
+ }
+
+ TileIndex *Export(uint *buffer_length)
+ {
+ const uint cnt = (uint) this->tiles.size();
+ const uint datalen = sizeof(TileIndex) * cnt;
+ TileIndex *buffer = (TileIndex *) malloc(datalen);
+ if (buffer) {
+ for (uint i = 0; i < cnt; i++) {
+ buffer[i] = TO_LE32(this->tiles[i]);
+ }
+ if (buffer_length) *buffer_length = datalen;
+ }
+ return buffer;
+ }
+
+ void Import(const TileIndex* data, const uint data_length)
+ {
+ for (uint i = data_length; i != 0; i--, data++) {
+ this->tiles.push_back(FROM_LE32(*data));
+ }
+ }
+};
+
+struct Plan : PlanPool::PoolItem<&_plan_pool> {
+ OwnerByte owner;
+ PlanLineVector lines;
+ PlanLine *temp_line;
+ bool visible;
+ bool visible_by_all;
+ bool show_lines;
+ Date creation_date;
+
+ Plan(Owner owner = INVALID_OWNER)
+ {
+ this->owner = owner;
+ this->creation_date = _date;
+ this->visible = false;
+ this->visible_by_all = false;
+ this->show_lines = false;
+ this->temp_line = new PlanLine();
+ }
+
+ ~Plan()
+ {
+ for (PlanLineVector::iterator it = lines.begin(); it != lines.end(); it++) {
+ delete (*it);
+ }
+ this->lines.clear();
+ delete temp_line;
+ }
+
+ void SetFocus(bool focused)
+ {
+ for (PlanLineVector::iterator it = lines.begin(); it != lines.end(); it++) {
+ (*it)->SetFocus(focused);
+ }
+ }
+
+ void SetVisibility(bool visible, bool do_lines = true)
+ {
+ this->visible = visible;
+
+ if (!do_lines) return;
+ for (PlanLineVector::iterator it = lines.begin(); it != lines.end(); it++) {
+ (*it)->SetVisibility(visible);
+ }
+ }
+
+ bool ToggleVisibility()
+ {
+ this->SetVisibility(!this->visible);
+ return this->visible;
+ }
+
+ PlanLine *NewLine()
+ {
+ PlanLine *pl = new PlanLine();
+ if (pl) this->lines.push_back(pl);
+ return pl;
+ }
+
+ bool StoreTempTile(TileIndex tile)
+ {
+ return this->temp_line->AppendTile(tile);
+ }
+
+ bool ValidateNewLine()
+ {
+ bool ret = false;
+ if (this->temp_line->tiles.size() > 1) {
+ uint buffer_length = 0;
+ const TileIndex *buffer = this->temp_line->Export(&buffer_length);
+ if (buffer) {
+ _current_plan->SetVisibility(true, false);
+ ret = DoCommandP(0, _current_plan->index, (uint32) this->temp_line->tiles.size(), CMD_ADD_PLAN_LINE, NULL, (const char *) buffer, true, buffer_length);
+ free(buffer);
+ }
+ _current_plan->temp_line->MarkDirty();
+ this->temp_line->Clear();
+ }
+ return ret;
+ }
+
+ bool IsListable()
+ {
+ return (this->owner == _local_company || this->visible_by_all);
+ }
+
+ bool IsVisible()
+ {
+ if (!this->IsListable()) return false;
+ return this->visible;
+ }
+
+ bool ToggleVisibilityByAll()
+ {
+ if (_current_plan->owner == _local_company) DoCommandP(0, _current_plan->index, !this->visible_by_all, CMD_CHANGE_PLAN_VISIBILITY);
+ return this->visible_by_all;
+ }
+};
+
+#define FOR_ALL_PLANS_FROM(var, start) FOR_ALL_ITEMS_FROM(Plan, plan_index, var, start)
+#define FOR_ALL_PLANS(var) FOR_ALL_PLANS_FROM(var, 0)
+
+#endif /* PLANS_BASE_H */
diff --git a/src/plans_cmd.cpp b/src/plans_cmd.cpp
new file mode 100644
index 0000000000..1cc585e410
--- /dev/null
+++ b/src/plans_cmd.cpp
@@ -0,0 +1,140 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file plans_cmd.cpp Handling of plan related commands. */
+
+#include "stdafx.h"
+#include "command_func.h"
+#include "plans_base.h"
+#include "plans_func.h"
+#include "window_func.h"
+#include "company_func.h"
+#include "window_gui.h"
+#include "table/strings.h"
+
+/**
+ * Create a new plan.
+ * @param tile unused
+ * @param flags type of operation
+ * @param p1 owner of the plan
+ * @param p2 unused
+ * @param text unused
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdAddPlan(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (!Plan::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_PLANS);
+ if (flags & DC_EXEC) {
+ Owner o = (Owner) p1;
+ _new_plan = new Plan(o);
+ if (o == _local_company) {
+ _new_plan->SetVisibility(true);
+ Window *w = FindWindowById(WC_PLANS, 0);
+ if (w) w->InvalidateData(INVALID_PLAN, false);
+ }
+ }
+ return CommandCost();
+}
+
+/**
+ * Create a new line in a plan.
+ * @param tile unused
+ * @param flags type of operation
+ * @param p1 plan id
+ * @param p2 number of nodes
+ * @param text list of tile indexes that compose the line, encoded in base64
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdAddPlanLine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (flags & DC_EXEC) {
+ Plan *p = Plan::Get(p1);
+ PlanLine *pl = p->NewLine();
+ if (!pl) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_LINES);
+ if (p2 > (MAX_CMD_TEXT_LENGTH / sizeof(TileIndex))) return_cmd_error(STR_ERROR_TOO_MANY_NODES);
+ pl->Import((const TileIndex *) text, p2);
+ if (p->IsListable()) {
+ pl->SetVisibility(p->visible);
+ if (p->visible) pl->MarkDirty();
+ Window *w = FindWindowById(WC_PLANS, 0);
+ if (w) w->InvalidateData(INVALID_PLAN, false);
+ }
+ }
+ return CommandCost();
+}
+
+/**
+ * Edit the visibility of a plan.
+ * @param tile unused
+ * @param flags type of operation
+ * @param p1 plan id
+ * @param p2 visibility
+ * @param text unused
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdChangePlanVisibility(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (flags & DC_EXEC) {
+ Plan *p = Plan::Get(p1);
+ p->visible_by_all = p2 != 0;
+ Window *w = FindWindowById(WC_PLANS, 0);
+ if (w) w->InvalidateData(INVALID_PLAN, false);
+ }
+ return CommandCost();
+}
+
+/**
+ * Delete a plan.
+ * @param tile unused
+ * @param flags type of operation
+ * @param p1 plan id
+ * @param p2 unused
+ * @param text unused
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdRemovePlan(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (flags & DC_EXEC) {
+ Plan *p = Plan::Get(p1);
+ if (p->IsListable()) {
+ p->SetVisibility(false);
+ Window *w = FindWindowById(WC_PLANS, 0);
+ if (w) w->InvalidateData(p->index, false);
+ }
+ if (p == _current_plan) _current_plan = NULL;
+ delete p;
+ }
+ return CommandCost();
+}
+
+/**
+ * Remove a line from a plan.
+ * @param tile unused
+ * @param flags type of operation
+ * @param p1 plan id
+ * @param p2 line id
+ * @param text unused
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdRemovePlanLine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (flags & DC_EXEC) {
+ Plan *p = Plan::Get(p1);
+ PlanLineVector::iterator it = p->lines.begin();
+ std::advance(it, p2);
+ (*it)->SetVisibility(false);
+ delete *it;
+ p->lines.erase(it);
+ if (p->IsListable()) {
+ Window *w = FindWindowById(WC_PLANS, 0);
+ if (w) w->InvalidateData(p->index, false);
+ }
+ }
+ return CommandCost();
+}
diff --git a/src/plans_func.h b/src/plans_func.h
new file mode 100644
index 0000000000..d158c2bf15
--- /dev/null
+++ b/src/plans_func.h
@@ -0,0 +1,22 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file plans_func.h Functions related to plans. */
+
+#ifndef PLANS_FUNC_H
+#define PLANS_FUNC_H
+
+#include "plans_type.h"
+
+void ShowPlansWindow();
+
+extern Plan *_new_plan;
+extern Plan *_current_plan;
+
+#endif /* PLANS_FUNC_H */
diff --git a/src/plans_gui.cpp b/src/plans_gui.cpp
new file mode 100644
index 0000000000..8139e49d24
--- /dev/null
+++ b/src/plans_gui.cpp
@@ -0,0 +1,366 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file plans_gui.cpp The GUI for planning. */
+
+#include "stdafx.h"
+#include "plans_func.h"
+#include "plans_base.h"
+#include "command_func.h"
+#include "company_func.h"
+#include "company_gui.h"
+#include "settings_gui.h"
+#include "window_gui.h"
+#include "window_func.h"
+#include "viewport_func.h"
+#include "gfx_func.h"
+#include "tilehighlight_func.h"
+#include "strings_func.h"
+#include "core/pool_func.hpp"
+#include "widgets/plans_widget.h"
+#include "table/strings.h"
+#include "table/sprites.h"
+
+static const NWidgetPart _nested_plans_widgets[] = {
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+ NWidget(WWT_CAPTION, COLOUR_GREY, WID_PLN_CAPTION), SetDataTip(STR_PLANS_CAPTION, STR_NULL),
+ NWidget(WWT_SHADEBOX, COLOUR_GREY),
+ NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
+ NWidget(WWT_STICKYBOX, COLOUR_GREY),
+ EndContainer(),
+
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_PANEL, COLOUR_GREY),
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_INSET, COLOUR_GREY, WID_PLN_LIST), SetFill(1, 1), SetPadding(2, 1, 2, 2), SetResize(1, 0), SetScrollbar(WID_PLN_SCROLLBAR), SetDataTip(STR_NULL, STR_PLANS_LIST_TOOLTIP),
+ EndContainer(),
+ EndContainer(),
+ EndContainer(),
+ NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_PLN_SCROLLBAR),
+ EndContainer(),
+
+ NWidget(WWT_PANEL, COLOUR_GREY),
+ NWidget(NWID_HORIZONTAL),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_PLN_NEW), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_PLANS_NEW_PLAN, STR_NULL),
+ NWidget(WWT_TEXTBTN_2, COLOUR_GREY, WID_PLN_ADD_LINES), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_PLANS_ADD_LINES, STR_PLANS_ADDING_LINES),
+ NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_PLN_VISIBILITY), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_PLANS_VISIBILITY_PUBLIC, STR_PLANS_VISIBILITY_TOOLTIP),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_PLN_HIDE_ALL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_PLANS_HIDE_ALL, STR_NULL),
+ NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_PLN_DELETE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_PLANS_DELETE, STR_PLANS_DELETE_TOOLTIP),
+ NWidget(WWT_RESIZEBOX, COLOUR_GREY),
+ EndContainer(),
+ EndContainer(),
+};
+
+static WindowDesc _plans_desc(
+ WDP_AUTO, "plans", 300, 100,
+ WC_PLANS, WC_NONE,
+ WDF_CONSTRUCTION,
+ _nested_plans_widgets, lengthof(_nested_plans_widgets)
+);
+
+struct PlansWindow : Window {
+ typedef struct {
+ bool is_plan;
+ int plan_id;
+ int line_id;
+ } ListItem;
+
+ Scrollbar *vscroll;
+ int text_offset;
+ std::vector list; ///< The translation table linking panel indices to their related PlanID.
+ int selected; ///< What item is currently selected in the panel.
+
+ PlansWindow(WindowDesc *desc) : Window(desc)
+ {
+ this->CreateNestedTree();
+ this->vscroll = this->GetScrollbar(WID_PLN_SCROLLBAR);
+ this->FinishInitNested();
+
+ Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON);
+ this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2 + SETTING_BUTTON_WIDTH;
+
+ this->selected = INT_MAX;
+ RebuildList();
+ }
+
+ ~PlansWindow()
+ {
+ this->list.clear();
+ _current_plan = NULL;
+ }
+
+ virtual void OnClick(Point pt, int widget, int click_count)
+ {
+ switch (widget) {
+ case WID_PLN_NEW:
+ DoCommandP(0, _local_company, 0, CMD_ADD_PLAN, CcAddPlan);
+ break;
+ case WID_PLN_ADD_LINES:
+ if (_current_plan) HandlePlacePushButton(this, widget, SPR_CURSOR_MOUSE, HT_POINT);
+ break;
+ case WID_PLN_DELETE:
+ if (this->selected != INT_MAX) {
+ if (this->list[this->selected].is_plan) {
+ DoCommandP(0, this->list[this->selected].plan_id, 0, CMD_REMOVE_PLAN);
+ } else {
+ DoCommandP(0, this->list[this->selected].plan_id, this->list[this->selected].line_id, CMD_REMOVE_PLAN_LINE);
+ }
+ }
+ break;
+ case WID_PLN_HIDE_ALL: {
+ Plan *p;
+ FOR_ALL_PLANS(p) {
+ if (p->IsListable()) p->SetVisibility(false);
+ }
+ this->SetWidgetDirty(WID_PLN_LIST);
+ break;
+ }
+ case WID_PLN_VISIBILITY:
+ if (_current_plan) _current_plan->ToggleVisibilityByAll();
+ break;
+ case WID_PLN_LIST: {
+ int new_selected = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_PLN_LIST, WD_FRAMERECT_TOP);
+ if (this->selected != INT_MAX) {
+ _current_plan->SetFocus(false);
+ }
+ if (new_selected != INT_MAX) {
+ if (this->list[new_selected].is_plan) {
+ _current_plan = Plan::Get(this->list[new_selected].plan_id);
+ _current_plan->SetFocus(true);
+ if (pt.x >= 22 && pt.x < 41) _current_plan->ToggleVisibility();
+ } else {
+ _current_plan = Plan::Get(this->list[new_selected].plan_id);
+ PlanLine *pl = _current_plan->lines[this->list[new_selected].line_id];
+ pl->SetFocus(true);
+ if (pt.x >= 22 && pt.x < 41) {
+ if (pl->ToggleVisibility()) _current_plan->SetVisibility(true, false);
+ }
+ }
+ if (click_count > 1 && (pt.x < 22 || pt.x >= 41)) {
+ _current_plan->show_lines = !_current_plan->show_lines;
+ this->InvalidateData(INVALID_PLAN);
+ }
+ } else {
+ if (_current_plan) {
+ _current_plan->SetFocus(false);
+ _current_plan = NULL;
+ }
+ }
+ this->selected = new_selected;
+ this->SetDirty();
+ break;
+ }
+ default: break;
+ }
+ }
+
+ virtual void OnPaint()
+ {
+ this->SetWidgetDisabledState(WID_PLN_HIDE_ALL, this->vscroll->GetCount() == 0);
+ if (_current_plan) {
+ this->SetWidgetsDisabledState(_current_plan->owner != _local_company, WID_PLN_ADD_LINES, WID_PLN_VISIBILITY, WID_PLN_DELETE, WIDGET_LIST_END);
+ this->GetWidget(WID_PLN_VISIBILITY)->widget_data = _current_plan->visible_by_all ? STR_PLANS_VISIBILITY_PRIVATE : STR_PLANS_VISIBILITY_PUBLIC;
+ } else {
+ this->SetWidgetsDisabledState(true, WID_PLN_ADD_LINES, WID_PLN_VISIBILITY, WID_PLN_DELETE, WIDGET_LIST_END);
+ }
+ this->DrawWidgets();
+ }
+
+ virtual void DrawWidget(const Rect &r, int widget) const
+ {
+ switch (widget) {
+ case WID_PLN_LIST: {
+ uint y = r.top + WD_FRAMERECT_TOP; // Offset from top of widget.
+ if (this->vscroll->GetCount() == 0) {
+ DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_STATION_LIST_NONE);
+ return;
+ }
+
+ bool rtl = _current_text_dir == TD_RTL;
+ uint icon_left = 4 + (rtl ? r.right - this->text_offset : r.left);
+ uint btn_left = (rtl ? icon_left - SETTING_BUTTON_WIDTH + 4 : icon_left + SETTING_BUTTON_WIDTH - 4);
+ uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : this->text_offset);
+ uint text_right = r.right - (rtl ? this->text_offset : WD_FRAMERECT_RIGHT);
+
+ for (uint16 i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < this->vscroll->GetCount(); i++) {
+ Plan *p = Plan::Get(list[i].plan_id);
+
+ if (i == this->selected) GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_GREY);
+
+ if (list[i].is_plan) {
+ DrawCompanyIcon(p->owner, icon_left, y + (FONT_HEIGHT_NORMAL - 10) / 2 + 1);
+ DrawBoolButton(btn_left, y + (FONT_HEIGHT_NORMAL - 10) / 2, p->visible, true);
+ SetDParam(0, list[i].plan_id + 1);
+ SetDParam(1, p->lines.size());
+ SetDParam(2, p->creation_date);
+ DrawString(text_left, text_right, y, STR_PLANS_LIST_ITEM_PLAN, p->visible_by_all ? TC_LIGHT_BLUE : TC_YELLOW);
+ } else {
+ PlanLine *pl = p->lines[list[i].line_id];
+ DrawBoolButton(btn_left, y + (FONT_HEIGHT_NORMAL - 10) / 2, pl->visible, true);
+ SetDParam(0, list[i].line_id + 1);
+ SetDParam(1, pl->tiles.size() - 1);
+ DrawString(text_left, text_right, y, STR_PLANS_LIST_ITEM_LINE, TC_WHITE);
+ }
+ y += this->resize.step_height;
+ }
+ break;
+ }
+ }
+ }
+
+ virtual void OnResize()
+ {
+ this->vscroll->SetCapacityFromWidget(this, WID_PLN_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
+ }
+
+ virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+ {
+ switch (widget) {
+ case WID_PLN_LIST:
+ resize->height = FONT_HEIGHT_NORMAL;
+ size->height = resize->height * 5 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
+ break;
+ }
+ }
+
+ /** The drawing of a line starts. */
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ /* A player can't add lines to a public plan of another company. */
+ if (_current_plan && _current_plan->owner == _local_company) VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_DRAW_PLANLINE);
+ }
+
+ /** The drawing of a line is in progress. */
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ const Point p = GetTileBelowCursor();
+ const TileIndex tile = TileVirtXY(p.x, p.y);
+ if (_current_plan && tile < MapSize()) {
+ _current_plan->StoreTempTile(tile);
+ _thd.selstart = _thd.selend;
+ }
+ }
+
+ /** The drawing of a line ends up normally. */
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (_current_plan) _current_plan->ValidateNewLine();
+ }
+
+ /** The drawing of a line is aborted. */
+ virtual void OnPlaceObjectAbort()
+ {
+ if (_current_plan) {
+ _current_plan->temp_line->MarkDirty();
+ _current_plan->temp_line->Clear();
+ }
+
+ this->RaiseWidget(WID_PLN_ADD_LINES);
+ this->SetWidgetDirty(WID_PLN_ADD_LINES);
+ }
+
+ void RebuildList()
+ {
+ int old_focused_plan_id = this->selected == INT_MAX ? INT_MAX : this->list[this->selected].plan_id;
+
+ int sbcnt = 0;
+ this->list.clear();
+ Plan *p;
+ FOR_ALL_PLANS(p) {
+ if (!p->IsListable()) continue;
+
+ ListItem li;
+ li.is_plan = true;
+ li.plan_id = p->index;
+ this->list.push_back(li);
+ if (old_focused_plan_id == p->index) this->selected = sbcnt;
+ sbcnt++;
+
+ if (p->show_lines) {
+ const int sz = (int) p->lines.size();
+ sbcnt += sz;
+ li.is_plan = false;
+ for (int i = 0; i < sz; i++) {
+ li.line_id = i;
+ this->list.push_back(li);
+ }
+ }
+ }
+
+ if (this->selected == INT_MAX) ResetObjectToPlace();
+
+ this->vscroll->SetCount(sbcnt);
+ }
+
+ virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
+ {
+ if (data != INVALID_PLAN && this->selected != INT_MAX) {
+ if (this->list[this->selected].plan_id == data) {
+ /* Invalidate the selection if the selected plan has been modified or deleted. */
+ this->selected = INT_MAX;
+
+ /* Cancel drawing associated to the deleted plan. */
+ ResetObjectToPlace();
+ }
+ }
+
+ RebuildList();
+ }
+
+ void SelectPlan(PlanID plan_index)
+ {
+ if (this->selected != INT_MAX) {
+ if (plan_index == this->list[this->selected].plan_id) return;
+ Plan::Get(this->list[this->selected].plan_id)->SetFocus(false);
+ }
+
+ if (plan_index == INVALID_PLAN) {
+ this->selected = INT_MAX;
+ return;
+ }
+ Plan::Get(plan_index)->SetFocus(true);
+
+ for (size_t i = 0; i < this->list.size(); i++) {
+ if (this->list[i].is_plan && this->list[i].plan_id == plan_index) {
+ this->selected = (int) i;
+ return;
+ }
+ }
+ }
+};
+
+/** Show the window to manage plans. */
+void ShowPlansWindow()
+{
+ if (BringWindowToFrontById(WC_PLANS, 0) != NULL) return;
+ new PlansWindow(&_plans_desc);
+}
+
+/**
+ * Only the creator of a plan executes this function.
+ * The other players should not be bothered with these changes.
+ */
+void CcAddPlan(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
+{
+ if (result.Failed()) return;
+
+ _current_plan = _new_plan;
+ _current_plan->SetVisibility(true);
+
+ Window *w = FindWindowById(WC_PLANS, 0);
+ if (w) {
+ w->InvalidateData(INVALID_PLAN, false);
+ ((PlansWindow *) w)->SelectPlan(_current_plan->index);
+ if (!w->IsWidgetLowered(WID_PLN_ADD_LINES)) {
+ w->SetWidgetDisabledState(WID_PLN_ADD_LINES, false);
+ HandlePlacePushButton(w, WID_PLN_ADD_LINES, SPR_CURSOR_MOUSE, HT_POINT);
+ }
+ }
+}
diff --git a/src/plans_type.h b/src/plans_type.h
new file mode 100644
index 0000000000..5947fc39e4
--- /dev/null
+++ b/src/plans_type.h
@@ -0,0 +1,25 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file plans_type.h Types related to planning. */
+
+#ifndef PLANS_TYPE_H
+#define PLANS_TYPE_H
+
+#include "stdafx.h"
+#include "core/smallvec_type.hpp"
+#include "tile_type.h"
+
+typedef uint16 PlanID;
+struct PlanLine;
+struct Plan;
+
+static const PlanID INVALID_PLAN = 0xFFFF; ///< Sentinel for an invalid plan.
+
+#endif /* PLANS_TYPE_H */
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
index 70957ca19e..6cf8db4680 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -1195,7 +1195,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) && EnsureNoVehicleOnGround(tile).Succeeded() ? UINT_MAX : 0) & mask));
}
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
AddTrackToSignalBuffer(tile, track, _current_company);
YapfNotifyTrackLayoutChange(tile, track);
if (v != NULL) {
@@ -1559,7 +1559,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1
YapfNotifyTrackLayoutChange(tile, track);
if (v != NULL) TryPathReserve(v, false);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
return CommandCost(EXPENSES_CONSTRUCTION, cost);
@@ -1702,7 +1702,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
SetRailType(tile, totype);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
/* update power of train on this tile */
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
}
@@ -1786,10 +1786,10 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
YapfNotifyTrackLayoutChange(endtile, track);
if (IsBridge(tile)) {
- MarkBridgeDirty(tile);
+ MarkBridgeDirty(tile, ZOOM_LVL_DRAW_MAP);
} else {
- MarkTileDirtyByTile(tile);
- MarkTileDirtyByTile(endtile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
+ MarkTileDirtyByTile(endtile, ZOOM_LVL_DRAW_MAP);
}
}
diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp
index d45313c5f0..64a985a441 100644
--- a/src/rail_gui.cpp
+++ b/src/rail_gui.cpp
@@ -203,7 +203,7 @@ static void PlaceRail_Station(TileIndex tile)
int h = _settings_client.gui.station_platlength;
if (!_railstation.orientation) Swap(w, h);
- CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" };
+ CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, 0, "" };
ShowSelectStationIfNeeded(cmdcont, TileArea(tile, w, h));
}
}
@@ -753,7 +753,7 @@ struct BuildRailToolbarWindow : Window {
uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24;
uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16;
- CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, "" };
+ CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, 0, "" };
ShowSelectWaypointIfNeeded(cmdcont, ta);
}
}
@@ -910,7 +910,7 @@ static void HandleStationPlacement(TileIndex start, TileIndex end)
uint32 p1 = _cur_railtype | _railstation.orientation << 4 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24;
uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16;
- CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" };
+ CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, 0, "" };
ShowSelectStationIfNeeded(cmdcont, ta);
}
diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp
index eb06e7af65..3668596be2 100644
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -1534,7 +1534,7 @@ static void TileLoop_Road(TileIndex tile)
TileY(tile) * TILE_SIZE + 7,
0,
EV_BULLDOZER);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
return;
}
}
@@ -1559,7 +1559,7 @@ static void TileLoop_Road(TileIndex tile)
cur_rs = ROADSIDE_BARREN;
}
SetRoadside(tile, cur_rs);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
} else if (IncreaseRoadWorksCounter(tile)) {
TerminateRoadWorks(tile);
@@ -1574,7 +1574,7 @@ static void TileLoop_Road(TileIndex tile)
}
}
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
diff --git a/src/road_gui.cpp b/src/road_gui.cpp
index b158482ef3..fc16123248 100644
--- a/src/road_gui.cpp
+++ b/src/road_gui.cpp
@@ -233,7 +233,7 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u
p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7.
TileArea ta(start_tile, end_tile);
- CommandContainer cmdcont = { ta.tile, ta.w | ta.h << 8, p2, cmd, CcRoadStop, "" };
+ CommandContainer cmdcont = { ta.tile, ta.w | ta.h << 8, p2, cmd, CcRoadStop, 0, "" };
ShowSelectStationIfNeeded(cmdcont, ta);
}
diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp
index 0f6dc84d15..9ba1fa5705 100644
--- a/src/saveload/extended_ver_sl.cpp
+++ b/src/saveload/extended_ver_sl.cpp
@@ -57,6 +57,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", NULL, NULL, NULL },
{ XSLFI_AUTO_TIMETABLE, XSCF_NULL, 1, 1, "auto_timetables", NULL, NULL, NULL },
{ XSLFI_VEHICLE_REPAIR_COST, XSCF_NULL, 1, 1, "vehicle_repair_cost", NULL, NULL, NULL },
+ { XSLFI_ENH_VIEWPORT_PLANS, XSCF_IGNORABLE_ALL, 1, 1, "enh_viewport_plans", NULL, NULL, "PLAN,PLLN" },
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
};
diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h
index d4ded50cca..68779d3cea 100644
--- a/src/saveload/extended_ver_sl.h
+++ b/src/saveload/extended_ver_sl.h
@@ -32,6 +32,7 @@ enum SlXvFeatureIndex {
XSLFI_TT_WAIT_IN_DEPOT, ///< Timetabling waiting time in depot patch
XSLFI_AUTO_TIMETABLE, ///< Auto timetables and separation patch
XSLFI_VEHICLE_REPAIR_COST, ///< Vehicle repair costs patch
+ XSLFI_ENH_VIEWPORT_PLANS, ///< Enhanced viewport patch: plans
XSLFI_SIZE, ///< Total count of features, including null feature
};
@@ -86,6 +87,8 @@ enum SlxiSubChunkFlags {
XSCF_IGNORABLE_VERSION = 1 << 1, ///< the loader is free to ignore this without aborting the load if the version is greater than the maximum that can be loaded
XSCF_EXTRA_DATA_PRESENT = 1 << 2, ///< extra data field is present, extra data in some sub-chunk/feature specific format, not used for anything yet
XSCF_CHUNK_ID_LIST_PRESENT = 1 << 3, ///< chunk ID list field is present, list of chunks which this sub-chunk/feature adds to the save game, this can be used to discard the chunks if the feature is unknown
+
+ XSCF_IGNORABLE_ALL = XSCF_IGNORABLE_UNKNOWN | XSCF_IGNORABLE_VERSION, ///< all "ignorable" flags
};
DECLARE_ENUM_AS_BIT_SET(SlxiSubChunkFlags)
diff --git a/src/saveload/plans_sl.cpp b/src/saveload/plans_sl.cpp
new file mode 100644
index 0000000000..7e39d9239c
--- /dev/null
+++ b/src/saveload/plans_sl.cpp
@@ -0,0 +1,87 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file plans_sl.cpp Code handling saving and loading of plans data. */
+
+#include "../stdafx.h"
+#include "../plans_base.h"
+#include "../fios.h"
+
+#include "saveload.h"
+
+/** Description of a plan within the savegame. */
+static const SaveLoad _plan_desc[] = {
+ SLE_VAR(Plan, owner, SLE_UINT8),
+ SLE_VAR(Plan, visible, SLE_BOOL),
+ SLE_VAR(Plan, visible_by_all, SLE_BOOL),
+ SLE_VAR(Plan, creation_date, SLE_INT32),
+ SLE_END()
+};
+
+/** Save all plans. */
+static void Save_PLAN()
+{
+ Plan *p;
+ FOR_ALL_PLANS(p) {
+ SlSetArrayIndex(p->index);
+ SlObject(p, _plan_desc);
+ }
+}
+
+/** Load all plans. */
+static void Load_PLAN()
+{
+ int index;
+ while ((index = SlIterateArray()) != -1) {
+ Plan *p = new (index) Plan();
+ SlObject(p, _plan_desc);
+ }
+}
+
+/** Save all plan lines. */
+static void Save_PLANLINE()
+{
+ Plan *p;
+ FOR_ALL_PLANS(p) {
+ for (size_t i = 0; i < p->lines.size(); i++) {
+ SlSetArrayIndex((uint) p->index << 16 | (uint) i);
+ PlanLine *pl = p->lines[i];
+ size_t plsz = pl->tiles.size();
+ SlSetLength(plsz * sizeof(TileIndex));
+ SlArray(&pl->tiles[0], plsz, SLE_UINT32);
+ }
+ }
+}
+
+/** Load all plan lines. */
+static void Load_PLANLINE()
+{
+ int index;
+ while ((index = SlIterateArray()) != -1) {
+ Plan *p = Plan::Get((uint) index >> 16);
+ uint line_index = index & 0xFFFF;
+ if (p->lines.size() <= line_index) p->lines.resize(line_index + 1);
+ PlanLine *pl = new PlanLine();
+ p->lines[line_index] = pl;
+ size_t plsz = SlGetFieldLength() / sizeof(TileIndex);
+ pl->tiles.resize(plsz);
+ SlArray(&pl->tiles[0], plsz, SLE_UINT32);
+ }
+
+ Plan *p;
+ FOR_ALL_PLANS(p) {
+ p->SetVisibility(false);
+ }
+}
+
+/** Chunk handlers related to plans. */
+extern const ChunkHandler _plan_chunk_handlers[] = {
+ { 'PLAN', Save_PLAN, Load_PLAN, NULL, NULL, CH_ARRAY},
+ { 'PLLN', Save_PLANLINE, Load_PLANLINE, NULL, NULL, CH_ARRAY | CH_LAST},
+};
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 1b3bb0fbd2..26381b16f9 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -456,6 +456,7 @@ extern const ChunkHandler _object_chunk_handlers[];
extern const ChunkHandler _persistent_storage_chunk_handlers[];
extern const ChunkHandler _trace_restrict_chunk_handlers[];
extern const ChunkHandler _signal_chunk_handlers[];
+extern const ChunkHandler _plan_chunk_handlers[];
/** Array of all chunks in a savegame, \c NULL terminated. */
static const ChunkHandler * const _chunk_handlers[] = {
@@ -495,6 +496,7 @@ static const ChunkHandler * const _chunk_handlers[] = {
_persistent_storage_chunk_handlers,
_trace_restrict_chunk_handlers,
_signal_chunk_handlers,
+ _plan_chunk_handlers,
NULL,
};
diff --git a/src/script/api/script_object.cpp b/src/script/api/script_object.cpp
index 49dba6bb73..14ef59d8a0 100644
--- a/src/script/api/script_object.cpp
+++ b/src/script/api/script_object.cpp
@@ -307,7 +307,7 @@ ScriptObject::ActiveInstance::~ActiveInstance()
#endif
/* Try to perform the command. */
- CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : NULL, text, false, estimate_only);
+ CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : NULL, text, false, estimate_only, 0);
/* We failed; set the error and bail out */
if (res.Failed()) {
diff --git a/src/settings.cpp b/src/settings.cpp
index 203dccbea0..bc2fb2ad45 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -1999,7 +1999,7 @@ void SyncCompanySettings()
const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save);
uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv);
uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv);
- if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company);
+ if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company, 0);
}
}
#endif /* ENABLE_NETWORK */
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
index 25b6aeacc8..1ae77508c9 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -1256,7 +1256,6 @@ uint SettingsContainer::GetMaxHelpHeight(int maxw)
return biggest;
}
-
/**
* Draw a row in the settings panel.
*
@@ -1478,6 +1477,9 @@ static SettingsContainer &GetSettingsTree()
graphics->Add(new SettingEntry("gui.zoom_max"));
graphics->Add(new SettingEntry("gui.smallmap_land_colour"));
graphics->Add(new SettingEntry("gui.graph_line_thickness"));
+ graphics->Add(new SettingEntry("gui.show_vehicle_route_steps"));
+ graphics->Add(new SettingEntry("gui.show_vehicle_route"));
+ graphics->Add(new SettingEntry("gui.dash_level_of_route_lines"));
}
SettingsPage *sound = main->Add(new SettingsPage(STR_CONFIG_SETTING_SOUND));
@@ -1505,6 +1507,18 @@ static SettingsContainer &GetSettingsTree()
SettingsPage *viewports = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_VIEWPORTS));
{
+ SettingsPage *viewport_map = interface->Add(new SettingsPage(STR_CONFIG_SETTING_VIEWPORT_MAP_OPTIONS));
+ {
+ viewport_map->Add(new SettingEntry("gui.default_viewport_map_mode"));
+ viewport_map->Add(new SettingEntry("gui.action_when_viewport_map_is_dblclicked"));
+ viewport_map->Add(new SettingEntry("gui.viewport_map_scan_surroundings"));
+ viewport_map->Add(new SettingEntry("gui.show_scrolling_viewport_on_map"));
+ viewport_map->Add(new SettingEntry("gui.show_slopes_on_viewport_map"));
+ viewport_map->Add(new SettingEntry("gui.show_bridges_on_map"));
+ viewport_map->Add(new SettingEntry("gui.show_tunnels_on_map"));
+ viewport_map->Add(new SettingEntry("gui.use_owner_colour_for_tunnelbridge"));
+ }
+
viewports->Add(new SettingEntry("gui.auto_scrolling"));
viewports->Add(new SettingEntry("gui.reverse_scroll"));
viewports->Add(new SettingEntry("gui.smooth_scroll"));
diff --git a/src/settings_type.h b/src/settings_type.h
index 07b5869fa2..2707662d51 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -111,6 +111,16 @@ struct GUISettings {
uint8 right_mouse_btn_emulation; ///< should we emulate right mouse clicking?
uint8 scrollwheel_scrolling; ///< scrolling using the scroll wheel?
uint8 scrollwheel_multiplier; ///< how much 'wheel' per incoming event from the OS?
+ bool viewport_map_scan_surroundings; ///< look for the most important tile in surroundings
+ bool show_slopes_on_viewport_map; ///< use slope orientation to render the ground
+ uint32 default_viewport_map_mode; ///< the mode to use by default when a viewport is in map mode, 0=owner, 1=industry, 2=vegetation
+ uint32 action_when_viewport_map_is_dblclicked; ///< what to do when a doubleclick occurs on the viewport map
+ uint32 show_scrolling_viewport_on_map; ///< when a no map viewport is scrolled, its location is marked on the other map viewports
+ bool show_bridges_on_map; ///< bridges are rendered on a viewport in map mode
+ bool show_tunnels_on_map; ///< tunnels are rendered on a viewport in map mode
+ uint32 show_vehicle_route; ///< show a vehicle's route when its orders/timetable window is focused
+ uint32 dash_level_of_route_lines; ///< the dash level passed to GfxDrawLine() (plain if 0)
+ bool use_owner_colour_for_tunnelbridge;///< bridges and tunnels are rendered with their owner's colour
bool timetable_arrival_departure; ///< show arrivals and departures in vehicle timetables
uint8 max_departures; ///< maximum number of departures to show per station
uint16 max_departure_time; ///< maximum time in advance to show departures
@@ -157,6 +167,7 @@ struct GUISettings {
byte missing_strings_threshold; ///< the number of missing strings before showing the warning
uint8 graph_line_thickness; ///< the thickness of the lines in the various graph guis
uint8 osk_activation; ///< Mouse gesture to trigger the OSK.
+ bool show_vehicle_route_steps; ///< when a window related to a specific vehicle is focused, show route steps
uint16 console_backlog_timeout; ///< the minimum amount of time items should be in the console backlog before they will be removed in ~3 seconds granularity.
uint16 console_backlog_length; ///< the minimum amount of items in the console backlog before items will be removed.
diff --git a/src/signal.cpp b/src/signal.cpp
index e2657c286a..be087ccd42 100644
--- a/src/signal.cpp
+++ b/src/signal.cpp
@@ -524,7 +524,7 @@ static void UpdateSignalsAroundSegment(SigInfo info)
MarkDependencidesForUpdate(SignalReference(tile, track));
}
SetSignalStateByTrackdir(tile, trackdir, newstate);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
diff --git a/src/smallmap_colours.h b/src/smallmap_colours.h
new file mode 100644
index 0000000000..f4eea04b06
--- /dev/null
+++ b/src/smallmap_colours.h
@@ -0,0 +1,106 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/** @file smallmap_colours.h Colours used by smallmap. */
+
+#ifndef SMALLMAP_COLOURS_H
+#define SMALLMAP_COLOURS_H
+
+#include "core/endian_func.hpp"
+
+static const uint8 PC_ROUGH_LAND = 0x52; ///< Dark green palette colour for rough land.
+static const uint8 PC_GRASS_LAND = 0x54; ///< Dark green palette colour for grass land.
+static const uint8 PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land.
+static const uint8 PC_FIELDS = 0x25; ///< Light brown palette colour for fields.
+static const uint8 PC_TREES = 0x57; ///< Green palette colour for trees.
+static const uint8 PC_WATER = 0xCA; ///< Dark blue palette colour for water.
+
+#define MKCOLOUR(x) TO_LE32X(x)
+
+#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x))
+#define MKCOLOUR_X0X0(x) (MKCOLOUR(0x01000100) * (uint)(x))
+#define MKCOLOUR_0X0X(x) (MKCOLOUR(0x00010001) * (uint)(x))
+#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x))
+#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x))
+
+#define MKCOLOUR_XYXY(x, y) (MKCOLOUR_X0X0(x) | MKCOLOUR_0X0X(y))
+#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
+
+#define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00)
+#define MKCOLOUR_0FF0 MKCOLOUR_0XX0(0xFF)
+#define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF)
+#define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF)
+
+#include "table/heightmap_colours.h"
+#include "table/darklight_colours.h"
+
+/** Colour scheme of the smallmap. */
+struct SmallMapColourScheme {
+ uint32 *height_colours; ///< Cached colours for each level in a map.
+ const uint32 *height_colours_base; ///< Base table for determining the colours
+ size_t colour_count; ///< The number of colours.
+ uint32 default_colour; ///< Default colour of the land.
+};
+
+extern SmallMapColourScheme _heightmap_schemes[];
+
+struct AndOr {
+ uint32 mor;
+ uint32 mand;
+};
+
+static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
+{
+ return (colour & mask->mand) | mask->mor;
+}
+
+/** Colour masks for "Contour" and "Routes" modes. */
+static const AndOr _smallmap_contours_andor[] = {
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR
+ {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, // MP_RAILWAY
+ {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD
+ {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES
+ {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000}, // MP_STATION
+ {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID
+ {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
+ {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT
+ {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F},
+};
+
+/** Colour masks for "Vehicles", "Industry", and "Vegetation" modes. */
+static const AndOr _smallmap_vehicles_andor[] = {
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR
+ {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_RAILWAY
+ {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD
+ {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES
+ {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_STATION
+ {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID
+ {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY
+ {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
+ {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT
+ {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
+};
+
+static const uint32 _vegetation_clear_bits[] = {
+ MKCOLOUR_XXXX(PC_GRASS_LAND), ///< full grass
+ MKCOLOUR_XXXX(PC_ROUGH_LAND), ///< rough land
+ MKCOLOUR_XXXX(PC_GREY), ///< rocks
+ MKCOLOUR_XXXX(PC_FIELDS), ///< fields
+ MKCOLOUR_XXXX(PC_LIGHT_BLUE), ///< snow
+ MKCOLOUR_XXXX(PC_ORANGE), ///< desert
+ MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused
+ MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused
+};
+
+#endif /* SMALLMAP_COLOURS_H */
diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp
index 2d316caf92..970b991165 100644
--- a/src/smallmap_gui.cpp
+++ b/src/smallmap_gui.cpp
@@ -25,6 +25,7 @@
#include "company_base.h"
#include "screenshot.h"
+#include "smallmap_colours.h"
#include "smallmap_gui.h"
#include "table/strings.h"
@@ -40,15 +41,6 @@ static int _smallmap_cargo_count; ///< Number of cargos in the link stats leg
/** Link stat colours shown in legenda. */
static uint8 _linkstat_colours_in_legenda[] = {0, 1, 3, 5, 7, 9, 11};
-static const int NUM_NO_COMPANY_ENTRIES = 4; ///< Number of entries in the owner legend that are not companies.
-
-static const uint8 PC_ROUGH_LAND = 0x52; ///< Dark green palette colour for rough land.
-static const uint8 PC_GRASS_LAND = 0x54; ///< Dark green palette colour for grass land.
-static const uint8 PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land.
-static const uint8 PC_FIELDS = 0x25; ///< Light brown palette colour for fields.
-static const uint8 PC_TREES = 0x57; ///< Green palette colour for trees.
-static const uint8 PC_WATER = 0xCA; ///< Dark blue palette colour for water.
-
/** Macro for ordinary entry of LegendAndColour */
#define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false}
@@ -136,7 +128,7 @@ static const LegendAndColour _legend_vegetation[] = {
MKEND()
};
-static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
+LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER),
MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS),
@@ -158,17 +150,17 @@ static LegendAndColour _legend_linkstats[NUM_CARGO + lengthof(_linkstat_colours_
* Allow room for all industries, plus a terminator entry
* This is required in order to have the industry slots all filled up
*/
-static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1];
+LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1];
/** For connecting industry type to position in industries list(small map legend) */
-static uint _industry_to_list_pos[NUM_INDUSTRYTYPES];
+uint _industry_to_list_pos[NUM_INDUSTRYTYPES];
/** Show heightmap in industry and owner mode of smallmap window. */
-static bool _smallmap_show_heightmap = false;
+bool _smallmap_show_heightmap = false;
/** Highlight a specific industry type */
static IndustryType _smallmap_industry_highlight = INVALID_INDUSTRYTYPE;
/** State of highlight blinking */
static bool _smallmap_industry_highlight_state;
/** For connecting company ID to position in owner list (small map legend) */
-static uint _company_to_list_pos[MAX_COMPANIES];
+uint _company_to_list_pos[MAX_COMPANIES];
/**
* Fills an array for the industries legends.
@@ -244,35 +236,9 @@ static const LegendAndColour * const _legend_table[] = {
_legend_land_owners,
};
-#define MKCOLOUR(x) TO_LE32X(x)
-
-#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x))
-#define MKCOLOUR_X0X0(x) (MKCOLOUR(0x01000100) * (uint)(x))
-#define MKCOLOUR_0X0X(x) (MKCOLOUR(0x00010001) * (uint)(x))
-#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x))
-#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x))
-
-#define MKCOLOUR_XYXY(x, y) (MKCOLOUR_X0X0(x) | MKCOLOUR_0X0X(y))
-#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
-
-#define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00)
-#define MKCOLOUR_0FF0 MKCOLOUR_0XX0(0xFF)
-#define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF)
-#define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF)
-
-#include "table/heightmap_colours.h"
-
-/** Colour scheme of the smallmap. */
-struct SmallMapColourScheme {
- uint32 *height_colours; ///< Cached colours for each level in a map.
- const uint32 *height_colours_base; ///< Base table for determining the colours
- size_t colour_count; ///< The number of colours.
- uint32 default_colour; ///< Default colour of the land.
-};
-
/** Available colour schemes for height maps. */
-static SmallMapColourScheme _heightmap_schemes[] = {
- {NULL, _green_map_heights, lengthof(_green_map_heights), MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme.
+SmallMapColourScheme _heightmap_schemes[] = {
+ {NULL, _green_map_heights, lengthof(_green_map_heights), MKCOLOUR_XXXX(0x5B)}, ///< Green colour scheme.
{NULL, _dark_green_map_heights, lengthof(_dark_green_map_heights), MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme.
{NULL, _violet_map_heights, lengthof(_violet_map_heights), MKCOLOUR_XXXX(0x82)}, ///< Violet colour scheme.
};
@@ -354,66 +320,6 @@ void BuildOwnerLegend()
_smallmap_company_count = i;
}
-struct AndOr {
- uint32 mor;
- uint32 mand;
-};
-
-static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
-{
- return (colour & mask->mand) | mask->mor;
-}
-
-
-/** Colour masks for "Contour" and "Routes" modes. */
-static const AndOr _smallmap_contours_andor[] = {
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR
- {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, // MP_RAILWAY
- {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD
- {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES
- {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000}, // MP_STATION
- {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID
- {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
- {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT
- {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F},
-};
-
-/** Colour masks for "Vehicles", "Industry", and "Vegetation" modes. */
-static const AndOr _smallmap_vehicles_andor[] = {
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR
- {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_RAILWAY
- {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD
- {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES
- {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_STATION
- {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID
- {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY
- {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
- {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT
- {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
-};
-
-/** Mapping of tile type to importance of the tile (higher number means more interesting to show). */
-static const byte _tiletype_importance[] = {
- 2, // MP_CLEAR
- 8, // MP_RAILWAY
- 7, // MP_ROAD
- 5, // MP_HOUSE
- 2, // MP_TREES
- 9, // MP_STATION
- 2, // MP_WATER
- 1, // MP_VOID
- 6, // MP_INDUSTRY
- 8, // MP_TUNNELBRIDGE
- 2, // MP_OBJECT
- 0,
-};
-
-
static inline TileType GetEffectiveTileType(TileIndex tile)
{
TileType t = GetTileType(tile);
@@ -525,17 +431,6 @@ static inline uint32 GetSmallMapLinkStatsPixels(TileIndex tile, TileType t)
return _smallmap_show_heightmap ? GetSmallMapContoursPixels(tile, t) : GetSmallMapRoutesPixels(tile, t);
}
-static const uint32 _vegetation_clear_bits[] = {
- MKCOLOUR_XXXX(PC_GRASS_LAND), ///< full grass
- MKCOLOUR_XXXX(PC_ROUGH_LAND), ///< rough land
- MKCOLOUR_XXXX(PC_GREY), ///< rocks
- MKCOLOUR_XXXX(PC_FIELDS), ///< fields
- MKCOLOUR_XXXX(PC_LIGHT_BLUE), ///< snow
- MKCOLOUR_XXXX(PC_ORANGE), ///< desert
- MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused
- MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused
-};
-
/**
* Return the colour a tile would be displayed with in the smallmap in mode "Vegetation".
*
@@ -595,6 +490,16 @@ static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t)
return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour);
}
+static void NotifyAllViewports(ViewportMapType map_type)
+{
+ Window *w;
+ FOR_ALL_WINDOWS_FROM_BACK(w) {
+ if (w->viewport != NULL)
+ if (w->viewport->zoom >= ZOOM_LVL_DRAW_MAP && w->viewport->map_type == map_type)
+ w->InvalidateData();
+ }
+}
+
/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleTypeByte. */
static const byte _vehicle_type_colours[6] = {
PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED
@@ -1443,6 +1348,7 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
/* If click on industries label, find right industry type and enable/disable it. */
if (click_pos < _smallmap_industry_count) {
this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count);
+ NotifyAllViewports(VPMT_INDUSTRY);
}
} else if (this->map_type == SMT_LINKSTATS) {
if (click_pos < _smallmap_cargo_count) {
@@ -1452,6 +1358,7 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
} else if (this->map_type == SMT_OWNER) {
if (click_pos < _smallmap_company_count) {
this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES);
+ NotifyAllViewports(VPMT_OWNER);
}
}
this->SetDirty();
@@ -1465,9 +1372,11 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
switch (this->map_type) {
case SMT_INDUSTRY:
tbl = _legend_from_industries;
+ NotifyAllViewports(VPMT_INDUSTRY);
break;
case SMT_OWNER:
tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]);
+ NotifyAllViewports(VPMT_OWNER);
break;
case SMT_LINKSTATS:
tbl = _legend_linkstats;
@@ -1486,6 +1395,7 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap.
_smallmap_show_heightmap = !_smallmap_show_heightmap;
this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap);
+ NotifyAllViewports(VPMT_INDUSTRY);
this->SetDirty();
break;
@@ -1536,7 +1446,7 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
{
if (widget != WID_SM_MAP || _scrolling_viewport) return false;
- _scrolling_viewport = true;
+ _scrolling_viewport = this;
return true;
}
diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h
index 8e54531019..9589ca3aea 100644
--- a/src/smallmap_gui.h
+++ b/src/smallmap_gui.h
@@ -20,9 +20,34 @@
#include "linkgraph/linkgraph_gui.h"
#include "widgets/smallmap_widget.h"
+static const int NUM_NO_COMPANY_ENTRIES = 4; ///< Number of entries in the owner legend that are not companies.
+
+/** Mapping of tile type to importance of the tile (higher number means more interesting to show). */
+static const byte _tiletype_importance[] = {
+ 2, // MP_CLEAR
+ 8, // MP_RAILWAY
+ 7, // MP_ROAD
+ 5, // MP_HOUSE
+ 2, // MP_TREES
+ 9, // MP_STATION
+ 2, // MP_WATER
+ 1, // MP_VOID
+ 6, // MP_INDUSTRY
+ 8, // MP_TUNNELBRIDGE
+ 2, // MP_OBJECT
+ 0,
+};
+
/* set up the cargos to be displayed in the smallmap's route legend */
void BuildLinkStatsLegend();
+struct TunnelBridgeToMap {
+ TileIndex from_tile;
+ TileIndex to_tile;
+ uint8 colour;
+};
+typedef SmallVector TunnelBridgeToMapVector;
+
void BuildIndustriesLegend();
void ShowSmallMap();
void BuildLandLegend();
@@ -147,7 +172,6 @@ protected:
return Company::IsValidID(_local_company) ? 1U << _local_company : 0xffffffff;
}
- void RebuildColourIndexIfNecessary();
uint GetNumberRowsLegend(uint columns) const;
void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0);
void SwitchMapType(SmallMapType map_type);
@@ -175,6 +199,8 @@ public:
SmallMapWindow(WindowDesc *desc, int window_number);
virtual ~SmallMapWindow() { delete this->overlay; }
+ static void RebuildColourIndexIfNecessary();
+
void SmallMapCenterOnCurrentPos();
Point GetStationMiddle(const Station *st) const;
diff --git a/src/sound.cpp b/src/sound.cpp
index 79dd988bfa..8c23dd2e87 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -189,7 +189,7 @@ static void StartSound(SoundID sound_id, float pan, uint volume)
}
-static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
+static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87, 10, 1, 1, 1};
assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
static const byte _sound_base_vol[] = {
diff --git a/src/spritecache.cpp b/src/spritecache.cpp
index 908e7599ab..e9ab6b7538 100644
--- a/src/spritecache.cpp
+++ b/src/spritecache.cpp
@@ -853,6 +853,102 @@ void *GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator)
}
}
+/**
+ * Reads a sprite and finds its most representative colour.
+ * @param sprite Sprite to read.
+ * @param palette_id Palette for remapping colours.
+ * @return if blitter supports 32bpp, average Colour.data else a palette index.
+ */
+uint32 GetSpriteMainColour(SpriteID sprite_id, PaletteID palette_id)
+{
+ if (!SpriteExists(sprite_id)) return 0;
+
+ SpriteCache *sc = GetSpriteCache(sprite_id);
+ if (sc->type != ST_NORMAL) return 0;
+
+ const byte * const remap = (palette_id == PAL_NONE ? NULL : GetNonSprite(GB(palette_id, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1);
+
+ uint8 file_slot = sc->file_slot;
+ size_t file_pos = sc->file_pos;
+
+ SpriteLoader::Sprite sprites[ZOOM_LVL_COUNT];
+ SpriteLoader::Sprite *sprite = &sprites[ZOOM_LVL_SHIFT];
+ sprites[ZOOM_LVL_NORMAL].type = ST_NORMAL;
+ SpriteLoaderGrf sprite_loader(sc->container_ver);
+ uint8 sprite_avail;
+ const uint8 screen_depth = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
+
+ /* Try to read the 32bpp sprite first. */
+ if (screen_depth == 32) {
+ sprite_avail = sprite_loader.LoadSprite(sprites, file_slot, file_pos, ST_NORMAL, true);
+ if (sprite_avail & ZOOM_LVL_BASE) {
+ /* Return the average colour. */
+ uint32 r = 0, g = 0, b = 0, cnt = 0;
+ SpriteLoader::CommonPixel *pixel = sprite->data;
+ for (uint x = sprite->width * sprite->height; x != 0; x--) {
+ if (pixel->a) {
+ if (remap && pixel->m) {
+ const Colour c = _cur_palette.palette[remap[pixel->m]];
+ if (c.a) {
+ r += c.r;
+ g += c.g;
+ b += c.b;
+ cnt++;
+ }
+ } else {
+ r += pixel->r;
+ g += pixel->g;
+ b += pixel->b;
+ cnt++;
+ }
+ }
+ pixel++;
+ }
+ return cnt ? Colour(r / cnt, g / cnt, b / cnt).data : 0;
+ }
+ }
+
+ /* No 32bpp, try 8bpp. */
+ sprite_avail = sprite_loader.LoadSprite(sprites, file_slot, file_pos, ST_NORMAL, false);
+ if (sprite_avail & ZOOM_LVL_BASE) {
+ SpriteLoader::CommonPixel *pixel = sprite->data;
+ if (screen_depth == 32) {
+ /* Return the average colour. */
+ uint32 r = 0, g = 0, b = 0, cnt = 0;
+ for (uint x = sprite->width * sprite->height; x != 0; x--) {
+ if (pixel->a) {
+ const uint col_index = remap ? remap[pixel->m] : pixel->m;
+ const Colour c = _cur_palette.palette[col_index];
+ r += c.r;
+ g += c.g;
+ b += c.b;
+ cnt++;
+ }
+ pixel++;
+ }
+ return cnt ? Colour(r / cnt, g / cnt, b / cnt).data : 0;
+ } else {
+ /* Return the most used indexed colour. */
+ int cnt[256];
+ memset(cnt, 0, sizeof(cnt));
+ for (uint x = sprite->width * sprite->height; x != 0; x--) {
+ cnt[remap ? remap[pixel->m] : pixel->m]++;
+ pixel++;
+ }
+ int cnt_max = -1;
+ uint32 rk = 0;
+ for (uint x = 1; x < lengthof(cnt); x++) {
+ if (cnt[x] > cnt_max) {
+ rk = x;
+ cnt_max = cnt[x];
+ }
+ }
+ return rk;
+ }
+ }
+
+ return 0;
+}
static void GfxInitSpriteCache()
{
diff --git a/src/spritecache.h b/src/spritecache.h
index 803bdb32c2..c631e9d5fa 100644
--- a/src/spritecache.h
+++ b/src/spritecache.h
@@ -57,4 +57,6 @@ bool LoadNextSprite(int load_index, byte file_index, uint file_sprite_id, byte c
bool SkipSpriteData(byte type, uint16 num);
void DupSprite(SpriteID old_spr, SpriteID new_spr);
+uint32 GetSpriteMainColour(SpriteID sprite_id, PaletteID palette_id);
+
#endif /* SPRITECACHE_H */
diff --git a/src/station.cpp b/src/station.cpp
index 9b5dcfb4ca..7e1f639459 100644
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -222,7 +222,7 @@ void Station::MarkTilesDirty(bool cargo_change) const
for (h = 0; h < train_station.h; h++) {
for (w = 0; w < train_station.w; w++) {
if (this->TileBelongsToRailStation(tile)) {
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
tile += TileDiffXY(1, 0);
}
diff --git a/src/stdafx.h b/src/stdafx.h
index 13bc9685d2..b21ef4c24b 100644
--- a/src/stdafx.h
+++ b/src/stdafx.h
@@ -525,4 +525,19 @@ static inline void free(const void *ptr)
#define OVERRIDE
#endif
+/**
+ * Using _mm_prefetch() with gcc implies the compile flag -msse.
+ * This is not the case with __builtin_prefetch() so the latter can be used in normal .cpp files.
+ */
+#if defined(_MSC_VER)
+ #define INCLUDE_FOR_PREFETCH_NTA
+ #define PREFETCH_NTA(address) _mm_prefetch((const char *) (address), _MM_HINT_NTA);
+#elif defined(__GNUC__)
+ #define INCLUDE_FOR_PREFETCH_NTA "stdafx.h"
+ #define PREFETCH_NTA(address) __builtin_prefetch((const void *) (address), 0, 0);
+#else
+ #define INCLUDE_FOR_PREFETCH_NTA "stdafx.h"
+ #define PREFETCH_NTA(address)
+#endif
+
#endif /* STDAFX_H */
diff --git a/src/table/darklight_colours.h b/src/table/darklight_colours.h
new file mode 100644
index 0000000000..09d315e3b1
--- /dev/null
+++ b/src/table/darklight_colours.h
@@ -0,0 +1,52 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD 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, version 2.
+ * OpenTTD 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 OpenTTD. If not, see .
+ */
+
+/**
+ * @file darklight_colours.h The colour tables to lighten and darken.
+ */
+
+static const byte _lighten_colour[] = {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, // 0
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x0F, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x0F, // 1
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x0F, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 2
+ 0x31, 0x0F, 0x33, 0x34, 0x45, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x0F, 0x3D, 0x3E, 0x3F, 0x40, // 3
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x0F, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x0F, // 4
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x0F, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x0F, // 5
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x0F, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x0F, // 6
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x0F, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x0F, // 7
+ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x0F, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x0F, // 8
+ 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x0F, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, // 9
+ 0xA1, 0x0F, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0x0F, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, // A
+ 0xB1, 0x0F, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x0F, // B
+ 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0x0F, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0x0F, 0xCF, 0xD0, // C
+ 0xD1, 0x0F, 0x0F, 0xD2, 0xD3, 0xD4, 0xD5, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x0F, // D
+ 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0x0F, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0x0F, 0xE3, // E
+ 0xE8, 0xF2, 0xF3, 0xCE, 0x44, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0x0F, 0xFC, 0xFD, 0xFF, // F
+};
+
+static const byte _darken_colour[] = {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0
+ 0x02, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x02, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, // 1
+ 0x02, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x02, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, // 2
+ 0x2F, 0x30, 0x42, 0x32, 0x33, 0x02, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x02, 0x3C, 0x3D, 0x3E, // 3
+ 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x01, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, // 4
+ 0x02, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x02, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, // 5
+ 0x02, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x02, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, // 6
+ 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0xEF, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, // 7
+ 0x02, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x02, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, // 8
+ 0x02, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x02, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, // 9
+ 0x9F, 0xA0, 0xB4, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0x02, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, // A
+ 0xAF, 0xB0, 0x02, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, // B
+ 0x3F, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0x02, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xF3, 0xCE, // C
+ 0xCF, 0xD0, 0xD3, 0xD4, 0xD5, 0xD6, 0xDF, 0x02, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, // D
+ 0xE1, 0xE2, 0x02, 0xEF, 0xE3, 0xE4, 0xE5, 0xE6, 0xB8, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0x02, // E
+ 0xB5, 0x02, 0xF1, 0xF2, 0x43, 0x02, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFE, 0xF5, 0x0F // F
+};
diff --git a/src/table/settings.ini b/src/table/settings.ini
index f6fe58bb89..3d82046855 100644
--- a/src/table/settings.ini
+++ b/src/table/settings.ini
@@ -2868,6 +2868,104 @@ strhelp = STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT
strval = STR_JUST_COMMA
cat = SC_BASIC
+[SDTC_BOOL]
+var = gui.viewport_map_scan_surroundings
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = true
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_SCAN_SURROUNDINGS
+proc = RedrawScreen
+
+[SDTC_BOOL]
+var = gui.show_slopes_on_viewport_map
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = true
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SLOPES
+proc = RedrawScreen
+
+[SDTC_BOOL]
+var = gui.show_bridges_on_map
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = true
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_BRIDGES
+proc = RedrawScreen
+
+[SDTC_BOOL]
+var = gui.show_tunnels_on_map
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = true
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_TUNNELS
+proc = RedrawScreen
+
+[SDTC_VAR]
+var = gui.show_vehicle_route
+type = SLE_UINT32
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def = 0
+min = 0
+max = 1
+interval = 1
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_VEHICLE_ROUTE
+strval = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_VEHICLE_ROUTE_NO
+proc = RedrawScreen
+
+[SDTC_VAR]
+var = gui.dash_level_of_route_lines
+type = SLE_UINT32
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_0ISDISABLED
+def = 0
+min = 0
+max = 10
+interval = 1
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_DRAW_ROUTE_DASH
+strval = STR_CONFIG_SETTING_VIEWPORT_MAP_DRAW_ROUTE_DASH_VALUE
+proc = RedrawScreen
+cat = SC_EXPERT
+
+[SDTC_BOOL]
+var = gui.use_owner_colour_for_tunnelbridge
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = false
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_USE_OWNER_COLOUR_BRIDGE_TUNNEL
+proc = RedrawScreen
+
+[SDTC_VAR]
+var = gui.show_scrolling_viewport_on_map
+type = SLE_UINT32
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def = 3
+min = 0
+max = 3
+interval = 1
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SCROLLING_VP
+strval = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_SCROLLING_VP_NOTHING
+
+[SDTC_VAR]
+var = gui.default_viewport_map_mode
+type = SLE_UINT32
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def = 0
+min = 0
+max = 2
+interval = 1
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_DEFAULT_MODE
+strval = STR_CONFIG_SETTING_VIEWPORT_MAP_DEFAULT_MODE_VEGETATION
+
+[SDTC_VAR]
+var = gui.action_when_viewport_map_is_dblclicked
+type = SLE_UINT32
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+guiflags = SGF_MULTISTRING
+def = 1
+min = 0
+max = 2
+interval = 1
+str = STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK
+strval = STR_CONFIG_SETTING_VIEWPORT_MAP_ACTION_DBLCLICK_DO_NOTHING
+
[SDTC_BOOL]
var = gui.pause_on_newgame
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
@@ -3402,6 +3500,13 @@ strhelp = STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT
strval = STR_JUST_COMMA
proc = RedrawScreen
+[SDTC_BOOL]
+var = gui.show_vehicle_route_steps
+flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
+def = true
+str = STR_CONFIG_SETTING_SHOW_VEHICLE_ROUTE_STEPS
+proc = RedrawScreen
+
; For the dedicated build we'll enable dates in logs by default.
[SDTC_BOOL]
ifdef = DEDICATED
diff --git a/src/table/sprites.h b/src/table/sprites.h
index b7957aa385..529b24635c 100644
--- a/src/table/sprites.h
+++ b/src/table/sprites.h
@@ -163,7 +163,15 @@ static const SpriteID SPR_WINDOW_DEFSIZE = SPR_OPENTTD_BASE + 168;
static const SpriteID SPR_IMG_CARGOFLOW = SPR_OPENTTD_BASE + 174;
-static const SpriteID SPR_SIGNALS_BASE = SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT;
+/** Sprites for the route step marker. */
+static const SpriteID SPR_ROUTE_STEP_BASE = SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT;
+static const SpriteID SPR_ROUTE_STEP_TOP = SPR_ROUTE_STEP_BASE + 0;
+static const SpriteID SPR_ROUTE_STEP_MIDDLE = SPR_ROUTE_STEP_BASE + 1;
+static const SpriteID SPR_ROUTE_STEP_BOTTOM = SPR_ROUTE_STEP_BASE + 2;
+static const SpriteID SPR_ROUTE_STEP_BOTTOM_SHADOW = SPR_ROUTE_STEP_BASE + 3;
+static const SpriteID ROUTE_STEP_SPRITE_COUNT = 4;
+
+static const SpriteID SPR_SIGNALS_BASE = SPR_ROUTE_STEP_BASE + ROUTE_STEP_SPRITE_COUNT;
static const uint16 PRESIGNAL_SPRITE_COUNT = 48;
static const uint16 PRESIGNAL_AND_SEMAPHORE_SPRITE_COUNT = 112;
static const uint16 PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT = 240;
diff --git a/src/table/tree_land.h b/src/table/tree_land.h
index 64757267ec..28cb75ecd6 100644
--- a/src/table/tree_land.h
+++ b/src/table/tree_land.h
@@ -12,8 +12,11 @@
#ifndef TREE_LAND_H
#define TREE_LAND_H
+#include "../sprite.h"
+
static const byte _tree_base_by_landscape[4] = {0, 12, 20, 32};
static const byte _tree_count_by_landscape[4] = {12, 8, 12, 9};
+#define MAX_TREE_COUNT_BY_LANDSCAPE 12
struct TreePos {
uint8 x;
@@ -227,4 +230,18 @@ static const PalSpriteID _tree_layout_sprite[164 + (79 - 48 + 1)][4] = {
{ { 0x716, PAL_NONE }, { 0x701, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x716, PAL_NONE } }, // 31
};
+/** Tree Sprites with their palettes */
+static const PalSpriteID _tree_sprites[] = {
+ { 1621, PAL_NONE }, { 1587, PAL_NONE }, { 1656, PAL_NONE }, { 1579, PAL_NONE },
+ { 1607, PAL_NONE }, { 1593, PAL_NONE }, { 1614, PAL_NONE }, { 1586, PAL_NONE },
+ { 1663, PAL_NONE }, { 1677, PAL_NONE }, { 1691, PAL_NONE }, { 1705, PAL_NONE },
+ { 1711, PAL_NONE }, { 1746, PAL_NONE }, { 1753, PAL_NONE }, { 1732, PAL_NONE },
+ { 1739, PAL_NONE }, { 1718, PAL_NONE }, { 1725, PAL_NONE }, { 1760, PAL_NONE },
+ { 1838, PAL_NONE }, { 1844, PAL_NONE }, { 1866, PAL_NONE }, { 1871, PAL_NONE },
+ { 1899, PAL_NONE }, { 1935, PAL_NONE }, { 1928, PAL_NONE }, { 1915, PAL_NONE },
+ { 1887, PAL_NONE }, { 1908, PAL_NONE }, { 1824, PAL_NONE }, { 1943, PAL_NONE },
+ { 1950, PAL_NONE }, { 1957, PALETTE_TO_GREEN }, { 1964, PALETTE_TO_RED }, { 1971, PAL_NONE },
+ { 1978, PAL_NONE }, { 1985, PALETTE_TO_RED, }, { 1992, PALETTE_TO_PALE_GREEN }, { 1999, PALETTE_TO_YELLOW }, { 2006, PALETTE_TO_RED }
+};
+
#endif /* TREE_LAND_H */
diff --git a/src/tilearea_type.h b/src/tilearea_type.h
index 45bfb3d4c0..ba3a08f1ad 100644
--- a/src/tilearea_type.h
+++ b/src/tilearea_type.h
@@ -12,6 +12,8 @@
#ifndef TILEAREA_TYPE_H
#define TILEAREA_TYPE_H
+#include "stdafx.h"
+#include INCLUDE_FOR_PREFETCH_NTA
#include "map_func.h"
/** Represents the covered area of e.g. a rail station */
@@ -184,6 +186,65 @@ public:
}
};
+/** Iterator to iterate over a tile area (rectangle) of the map.
+ * It prefetches tiles once per row.
+ */
+class OrthogonalPrefetchTileIterator {
+private:
+ TileIndex tile; ///< The current tile we are at.
+ int w; ///< The width of the iterated area.
+ int x; ///< The current 'x' position in the rectangle.
+ int y; ///< The current 'y' position in the rectangle.
+
+public:
+ /**
+ * Construct the iterator.
+ * @param ta Area, i.e. begin point and width/height of to-be-iterated area.
+ */
+ OrthogonalPrefetchTileIterator(const TileArea &ta) : tile(ta.w == 0 || ta.h == 0 ? INVALID_TILE : ta.tile), w(ta.w), x(ta.w), y(ta.h)
+ {
+ PREFETCH_NTA(&_m[ta.tile]);
+ }
+
+ /** Some compilers really like this. */
+ virtual ~OrthogonalPrefetchTileIterator()
+ {
+ }
+
+ /**
+ * Get the tile we are currently at.
+ * @return The tile we are at, or INVALID_TILE when we're done.
+ */
+ inline operator TileIndex () const
+ {
+ return this->tile;
+ }
+
+ /**
+ * Move ourselves to the next tile in the rectangle on the map.
+ */
+ inline OrthogonalPrefetchTileIterator& operator ++()
+ {
+ assert(this->tile != INVALID_TILE);
+
+ if (--this->x > 0) {
+ this->tile++;
+ } else if (--this->y > 0) {
+ this->x = this->w;
+ this->tile += TileDiffXY(1, 1) - this->w;
+ PREFETCH_NTA(&_m[tile]);
+ } else {
+ this->tile = INVALID_TILE;
+ }
+ return *this;
+ }
+
+ virtual OrthogonalPrefetchTileIterator *Clone() const
+ {
+ return new OrthogonalPrefetchTileIterator(*this);
+ }
+};
+
/** Iterator to iterate over a diagonal area of the map. */
class DiagonalTileIterator : public TileIterator {
private:
@@ -230,5 +291,6 @@ public:
* @param ta The tile area to search over.
*/
#define TILE_AREA_LOOP(var, ta) for (OrthogonalTileIterator var(ta); var != INVALID_TILE; ++var)
+#define TILE_AREA_LOOP_WITH_PREFETCH(var, ta) for (OrthogonalPrefetchTileIterator var(ta); var != INVALID_TILE; ++var)
#endif /* TILEAREA_TYPE_H */
diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp
index c266134ab9..a3b6f17bf9 100644
--- a/src/timetable_gui.cpp
+++ b/src/timetable_gui.cpp
@@ -24,6 +24,7 @@
#include "date_gui.h"
#include "vehicle_gui.h"
#include "settings_type.h"
+#include "viewport_func.h"
#include "widgets/timetable_widget.h"
@@ -179,6 +180,13 @@ struct TimetableWindow : Window {
this->owner = this->vehicle->owner;
}
+ ~TimetableWindow()
+ {
+ if (!FocusWindowById(WC_VEHICLE_VIEW, this->window_number)) {
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
/**
* Build the arrival-departure list for a given vehicle
* @param v the vehicle to make the list for
@@ -716,6 +724,27 @@ struct TimetableWindow : Window {
// this->GetWidget(TTV_AUTO_SELECTION)->SetDisplayedPlane(!_settings_game.order.timetable_automated ? 0 : 1);
this->GetWidget(WID_VT_EXPECTED_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : 1);
}
+
+ virtual void OnFocus(Window *previously_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, previously_focused_window)) {
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
+ virtual void OnFocusLost(Window *newly_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, newly_focused_window)) {
+ MarkAllRoutePathsDirty(this->vehicle);
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
+ const Vehicle *GetVehicle()
+ {
+ return this->vehicle;
+ }
};
static const NWidgetPart _nested_timetable_widgets[] = {
diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp
index be4c644b8a..49a2cffff5 100644
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -46,6 +46,7 @@
#include "game/game.hpp"
#include "goal_base.h"
#include "story_base.h"
+#include "plans_func.h"
#include "toolbar_gui.h"
#include "zoning.h"
@@ -455,6 +456,7 @@ enum MapMenuEntries {
MME_SHOW_SIGNLISTS,
MME_SHOW_TOWNDIRECTORY,
MME_SHOW_INDUSTRYDIRECTORY,
+ MME_SHOW_PLANS,
};
static CallBackFunction ToolbarMapClick(Window *w)
@@ -464,6 +466,7 @@ static CallBackFunction ToolbarMapClick(Window *w)
*list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false);
*list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false);
*list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false);
+ *list->Append() = new DropDownListStringItem(STR_MAP_MENU_PLAN_LIST, MME_SHOW_PLANS, false);
PopupMainToolbMenu(w, WID_TN_SMALL_MAP, list, 0);
return CBF_NONE;
}
@@ -495,6 +498,7 @@ static CallBackFunction MenuClickMap(int index)
case MME_SHOW_SIGNLISTS: ShowSignList(); break;
case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break;
+ case MME_SHOW_PLANS: ShowPlansWindow(); break;
}
return CBF_NONE;
}
@@ -613,7 +617,7 @@ static CallBackFunction MenuClickCompany(int index)
if (_network_server) {
DoCommandP(0, 0, _network_own_client_id, CMD_COMPANY_CTRL);
} else {
- NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company);
+ NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company, 0);
}
return CBF_NONE;
@@ -1656,6 +1660,7 @@ enum MainToolbarHotkeys {
MTHK_EXTRA_VIEWPORT,
MTHK_CLIENT_LIST,
MTHK_SIGN_LIST,
+ MTHK_PLAN_LIST,
};
/** Main toolbar. */
@@ -1751,6 +1756,7 @@ struct MainToolbarWindow : Window {
case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
#endif
case MTHK_SIGN_LIST: ShowSignList(); break;
+ case MTHK_PLAN_LIST: ShowPlansWindow(); break;
default: return ES_NOT_HANDLED;
}
return ES_HANDLED;
@@ -1856,6 +1862,7 @@ static Hotkey maintoolbar_hotkeys[] = {
Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
#endif
Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
+ Hotkey('P', "plan_list", MTHK_PLAN_LIST),
HOTKEY_LIST_END
};
HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 66b833156f..1c869d2f6b 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -414,7 +414,7 @@ static void AnimateTile_Town(TileIndex tile)
DeleteAnimatedTile(tile);
}
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
/**
@@ -525,7 +525,7 @@ static void MakeSingleHouseBigger(TileIndex tile)
ChangePopulation(Town::GetByTile(tile), HouseSpec::Get(GetHouseType(tile))->population);
ResetHouseAge(tile);
}
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
/**
diff --git a/src/town_gui.cpp b/src/town_gui.cpp
index 68f8eab962..572df33851 100644
--- a/src/town_gui.cpp
+++ b/src/town_gui.cpp
@@ -1863,6 +1863,7 @@ void PlaceProc_House(TileIndex tile)
InteractiveRandom(), // p2 - random bits for the house
CMD_BUILD_HOUSE | CMD_MSG(STR_ERROR_CAN_T_BUILD_HOUSE_HERE),
CcPlaySound1E,
+ 0,
""
};
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index ca74a8b2ee..bb85d0327b 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -1750,7 +1750,7 @@ static void UpdateLevelCrossingTile(TileIndex tile, bool sound, bool force_state
if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
}
SetCrossingBarred(tile, new_state);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
@@ -2275,7 +2275,7 @@ static bool CheckTrainStayInDepot(Train *v)
}
SetDepotReservation(v->tile, true);
- if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile);
+ if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile, ZOOM_LVL_DRAW_MAP);
VehicleServiceInDepot(v);
SetWindowClassesDirty(WC_TRAINS_LIST);
@@ -2355,10 +2355,10 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_
if (_settings_client.gui.show_track_reservation) {
if (IsBridge(tile)) {
- MarkBridgeDirty(tile);
+ MarkBridgeDirty(tile, ZOOM_LVL_DRAW_MAP);
} else {
- MarkTileDirtyByTile(tile);
- MarkTileDirtyByTile(end);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
+ MarkTileDirtyByTile(end, ZOOM_LVL_DRAW_MAP);
}
}
}
@@ -2425,7 +2425,7 @@ void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_t
} else {
/* Turn the signal back to red. */
SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_RED);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
} else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
break;
@@ -2700,7 +2700,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
if (res_dest.okay) {
/* Got a valid reservation that ends at a safe target, quick exit. */
if (got_reservation != NULL) *got_reservation = true;
- if (changed_signal) MarkTileDirtyByTile(tile);
+ if (changed_signal) MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir()));
return best_track;
}
@@ -2759,7 +2759,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
best_track = FindFirstTrack(res);
TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir()));
if (got_reservation != NULL) *got_reservation = true;
- if (changed_signal) MarkTileDirtyByTile(tile);
+ if (changed_signal) MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
} else {
FreeTrainTrackReservation(v);
if (mark_stuck) MarkTrainAsStuck(v);
@@ -2807,7 +2807,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir,
TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir()));
- if (changed_signal) MarkTileDirtyByTile(tile);
+ if (changed_signal) MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
return best_track;
}
@@ -2860,7 +2860,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
/* If we are in a depot, tentatively reserve the depot. */
if (v->track == TRACK_BIT_DEPOT) {
SetDepotReservation(v->tile, true);
- if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile);
+ if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile, ZOOM_LVL_DRAW_MAP);
}
DiagDirection exitdir = TrackdirToExitdir(origin.trackdir);
diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp
index 4fcda82d81..e52528a243 100644
--- a/src/tree_cmd.cpp
+++ b/src/tree_cmd.cpp
@@ -363,7 +363,7 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (flags & DC_EXEC) {
AddTreeCount(tile, 1);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
if (c != NULL) c->tree_limit -= 1 << 16;
}
/* 2x as expensive to add more trees to an existing tile */
@@ -429,7 +429,7 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
/* Plant full grown trees in scenario editor */
PlantTreesOnTile(tile, treetype, 0, _game_mode == GM_EDITOR ? 3 : 0);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
if (c != NULL) c->tree_limit -= 1 << 16;
/* When planting rainforest-trees, set tropiczone to rainforest in editor. */
@@ -581,7 +581,7 @@ static void TileLoopTreesDesert(TileIndex tile)
case TROPICZONE_DESERT:
if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) {
SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
break;
@@ -630,7 +630,7 @@ static void TileLoopTreesAlps(TileIndex tile)
return;
}
}
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
static void TileLoop_Trees(TileIndex tile)
@@ -653,7 +653,7 @@ static void TileLoop_Trees(TileIndex tile)
uint density = GetTreeDensity(tile);
if (density < 3) {
SetTreeGroundDensity(tile, TREE_GROUND_GRASS, density + 1);
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
}
if (GetTreeCounter(tile) < 15) {
@@ -746,7 +746,7 @@ static void TileLoop_Trees(TileIndex tile)
break;
}
- MarkTileDirtyByTile(tile);
+ MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
}
void OnTick_Trees()
diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp
index f21eeaef2e..0fc12cf781 100644
--- a/src/tree_gui.cpp
+++ b/src/tree_gui.cpp
@@ -29,21 +29,6 @@
void PlaceTreesRandomly();
-/** Tree Sprites with their palettes */
-const PalSpriteID tree_sprites[] = {
- { 1621, PAL_NONE }, { 1587, PAL_NONE }, { 1656, PAL_NONE }, { 1579, PAL_NONE },
- { 1607, PAL_NONE }, { 1593, PAL_NONE }, { 1614, PAL_NONE }, { 1586, PAL_NONE },
- { 1663, PAL_NONE }, { 1677, PAL_NONE }, { 1691, PAL_NONE }, { 1705, PAL_NONE },
- { 1711, PAL_NONE }, { 1746, PAL_NONE }, { 1753, PAL_NONE }, { 1732, PAL_NONE },
- { 1739, PAL_NONE }, { 1718, PAL_NONE }, { 1725, PAL_NONE }, { 1760, PAL_NONE },
- { 1838, PAL_NONE }, { 1844, PAL_NONE }, { 1866, PAL_NONE }, { 1871, PAL_NONE },
- { 1899, PAL_NONE }, { 1935, PAL_NONE }, { 1928, PAL_NONE }, { 1915, PAL_NONE },
- { 1887, PAL_NONE }, { 1908, PAL_NONE }, { 1824, PAL_NONE }, { 1943, PAL_NONE },
- { 1950, PAL_NONE }, { 1957, PALETTE_TO_GREEN }, { 1964, PALETTE_TO_RED }, { 1971, PAL_NONE },
- { 1978, PAL_NONE }, { 1985, PALETTE_TO_RED, }, { 1992, PALETTE_TO_PALE_GREEN }, { 1999, PALETTE_TO_YELLOW }, { 2006, PALETTE_TO_RED }
-};
-
-
/**
* The build trees window.
*/
@@ -75,8 +60,8 @@ public:
offset.y = 0;
for (int i = this->base; i < this->base + this->count; i++) {
- if (i >= (int)lengthof(tree_sprites)) return size;
- this_size = GetSpriteSize(tree_sprites[i].sprite, &offset);
+ if (i >= (int)lengthof(_tree_sprites)) return size;
+ this_size = GetSpriteSize(_tree_sprites[i].sprite, &offset);
size.width = max(size.width, 2 * max(this_size.width, -offset.x));
size.height = max(size.height, max(this_size.height, -offset.y));
}
@@ -108,7 +93,7 @@ public:
int i = this->base + widget - WID_BT_TYPE_11;
/* Trees "grow" in the centre on the bottom line of the buttons */
- DrawSprite(tree_sprites[i].sprite, tree_sprites[i].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - 7);
+ DrawSprite(_tree_sprites[i].sprite, _tree_sprites[i].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - 7);
}
virtual void OnClick(Point pt, int widget, int click_count)
diff --git a/src/tunnelbridge.h b/src/tunnelbridge.h
index 0a2c2293d5..fbeb298688 100644
--- a/src/tunnelbridge.h
+++ b/src/tunnelbridge.h
@@ -14,8 +14,8 @@
#include "map_func.h"
-void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height);
-void MarkBridgeDirty(TileIndex tile);
+void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
+void MarkBridgeDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
/**
* Calculates the length of a tunnel or a bridge (without end tiles)
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index f963222f5a..e94711fb4a 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -62,22 +62,22 @@ static const int BRIDGE_Z_START = 3;
* @param direction Direction from \a begin to \a end.
* @param bridge_height Bridge height level.
*/
-void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
+void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height, const ZoomLevel mark_dirty_if_zoomlevel_is_below)
{
TileIndexDiff delta = TileOffsByDiagDir(direction);
for (TileIndex t = begin; t != end; t += delta) {
- MarkTileDirtyByTile(t, bridge_height - TileHeight(t));
+ MarkTileDirtyByTile(t, mark_dirty_if_zoomlevel_is_below, bridge_height - TileHeight(t));
}
- MarkTileDirtyByTile(end);
+ MarkTileDirtyByTile(end, mark_dirty_if_zoomlevel_is_below);
}
/**
* Mark bridge tiles dirty.
* @param tile Bridge head.
*/
-void MarkBridgeDirty(TileIndex tile)
+void MarkBridgeDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below)
{
- MarkBridgeDirty(tile, GetOtherTunnelBridgeEnd(tile), GetTunnelBridgeDirection(tile), GetBridgeHeight(tile));
+ MarkBridgeDirty(tile, GetOtherTunnelBridgeEnd(tile), GetTunnelBridgeDirection(tile), GetBridgeHeight(tile), mark_dirty_if_zoomlevel_is_below);
}
/** Reset the data been eventually changed by the grf loaded. */
@@ -949,7 +949,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
if (height < minz) SetRoadside(c, ROADSIDE_PAVED);
}
ClearBridgeMiddle(c);
- MarkTileDirtyByTile(c, height - TileHeight(c));
+ MarkTileDirtyByTile(c, ZOOM_LVL_DRAW_MAP, height - TileHeight(c));
}
if (rail) {
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index 1ce56b7b16..c234d8128f 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -52,6 +52,7 @@
#include "gamelog.h"
#include "linkgraph/linkgraph.h"
#include "linkgraph/refresh.h"
+#include "blitter/factory.hpp"
#include "table/strings.h"
@@ -1158,6 +1159,62 @@ void ViewportAddVehicles(DrawPixelInfo *dpi)
}
}
+void ViewportMapDrawVehicles(DrawPixelInfo *dpi)
+{
+ /* The bounding rectangle */
+ const int l = dpi->left;
+ const int r = dpi->left + dpi->width;
+ const int t = dpi->top;
+ const int b = dpi->top + dpi->height;
+
+ /* The hash area to scan */
+ int xl, xu, yl, yu;
+
+ if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
+ xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
+ xu = GB(r, 7 + ZOOM_LVL_SHIFT, 6);
+ } else {
+ /* scan whole hash row */
+ xl = 0;
+ xu = 0x3F;
+ }
+
+ if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
+ yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
+ yu = GB(b, 6 + ZOOM_LVL_SHIFT, 6) << 6;
+ } else {
+ /* scan whole column */
+ yl = 0;
+ yu = 0x3F << 6;
+ }
+
+ const int w = UnScaleByZoom(dpi->width, dpi->zoom);
+ const int h = UnScaleByZoom(dpi->height, dpi->zoom);
+ Blitter *blitter = BlitterFactory::GetCurrentBlitter();
+ for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
+ for (int x = xl;; x = (x + 1) & 0x3F) {
+ const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
+
+ while (v != NULL) {
+ if (!(v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) && (v->type != VEH_EFFECT)) {
+ Point pt = RemapCoords(v->x_pos, v->y_pos, v->z_pos);
+ const int pixel_x = UnScaleByZoomLower(pt.x - dpi->left, dpi->zoom);
+ if (IsInsideMM(pixel_x, 0, w)) {
+ const int pixel_y = UnScaleByZoomLower(pt.y - dpi->top, dpi->zoom);
+ if (IsInsideMM(pixel_y, 0, h))
+ blitter->SetPixel(dpi->dst_ptr, pixel_x, pixel_y, PC_WHITE);
+ }
+ }
+ v = v->hash_viewport_next;
+ }
+
+ if (x == xu) break;
+ }
+
+ if (y == yu) break;
+ }
+}
+
/**
* Find the vehicle close to the clicked coordinates.
* @param vp Viewport clicked in.
@@ -1620,7 +1677,7 @@ void VehicleEnterDepot(Vehicle *v)
SetWindowClassesDirty(WC_TRAINS_LIST);
/* Clear path reservation */
SetDepotReservation(t->tile, false);
- if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
+ if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile, ZOOM_LVL_DRAW_MAP);
UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
t->wait_counter = 0;
@@ -1774,7 +1831,9 @@ void Vehicle::UpdateViewport(bool dirty)
min(old_coord.left, this->coord.left),
min(old_coord.top, this->coord.top),
max(old_coord.right, this->coord.right),
- max(old_coord.bottom, this->coord.bottom));
+ max(old_coord.bottom, this->coord.bottom),
+ this->type != VEH_EFFECT ? ZOOM_LVL_END : ZOOM_LVL_DRAW_MAP
+ );
}
}
}
diff --git a/src/vehicle_func.h b/src/vehicle_func.h
index 9eb6b91219..a06449d62b 100644
--- a/src/vehicle_func.h
+++ b/src/vehicle_func.h
@@ -58,6 +58,7 @@ void ResetVehicleColourMap();
byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type);
void ViewportAddVehicles(DrawPixelInfo *dpi);
+void ViewportMapDrawVehicles(DrawPixelInfo *dpi);
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical);
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore = NULL);
diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp
index 9df4badc16..19009c77ee 100644
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -631,6 +631,32 @@ struct RefitWindow : public Window {
this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0);
}
+ ~RefitWindow()
+ {
+ if (this->window_number != INVALID_VEHICLE) {
+ if (!FocusWindowById(WC_VEHICLE_VIEW, this->window_number)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+ }
+
+ virtual void OnFocus(Window *previously_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, previously_focused_window)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
+ virtual void OnFocusLost(Window *newly_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, newly_focused_window)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
virtual void OnInit()
{
if (this->cargo != NULL) {
@@ -1640,7 +1666,7 @@ public:
case WID_VL_SORT_BY_PULLDOWN:// Select sorting criteria dropdown menu
ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_VL_SORT_BY_PULLDOWN, 0,
- (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10));
+ (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10), 0, DDSF_LOST_FOCUS);
return;
case WID_VL_LIST: { // Matrix to show vehicles
@@ -1901,6 +1927,16 @@ struct VehicleDetailsWindow : Window {
this->tab = TDW_TAB_CARGO;
}
+ ~VehicleDetailsWindow()
+ {
+ if (this->window_number != INVALID_VEHICLE) {
+ if (!FocusWindowById(WC_VEHICLE_VIEW, this->window_number)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+ }
+
/**
* Some data on this window has become invalid.
* @param data Information about the changed data.
@@ -2218,7 +2254,7 @@ struct VehicleDetailsWindow : Window {
case WID_VD_SERVICE_INTERVAL_DROPDOWN: {
const Vehicle *v = Vehicle::Get(this->window_number);
- ShowDropDownMenu(this, _service_interval_dropdown, v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0);
+ ShowDropDownMenu(this, _service_interval_dropdown, v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0, 0, DDSF_LOST_FOCUS);
break;
}
@@ -2268,6 +2304,22 @@ struct VehicleDetailsWindow : Window {
this->vscroll->SetCapacityFromWidget(this, WID_VD_MATRIX);
}
}
+
+ virtual void OnFocus(Window *previously_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, previously_focused_window)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
+ virtual void OnFocusLost(Window *newly_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, newly_focused_window)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
};
/** Vehicle details window descriptor. */
@@ -2547,12 +2599,30 @@ public:
~VehicleViewWindow()
{
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
DeleteWindowById(WC_VEHICLE_ORDERS, this->window_number, false);
DeleteWindowById(WC_VEHICLE_REFIT, this->window_number, false);
DeleteWindowById(WC_VEHICLE_DETAILS, this->window_number, false);
DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number, false);
}
+ virtual void OnFocus(Window *previously_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, previously_focused_window)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
+ virtual void OnFocusLost(Window *newly_focused_window)
+ {
+ if (HasFocusedVehicleChanged(this->window_number, newly_focused_window)) {
+ if (this->window_number != INVALID_VEHICLE) MarkAllRoutePathsDirty(Vehicle::Get(this->window_number));
+ MarkAllRouteStepsDirty(this);
+ }
+ }
+
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
{
const Vehicle *v = Vehicle::Get(this->window_number);
diff --git a/src/vehicle_gui.h b/src/vehicle_gui.h
index 83e098dcd9..3b17a05bc1 100644
--- a/src/vehicle_gui.h
+++ b/src/vehicle_gui.h
@@ -18,6 +18,7 @@
#include "station_type.h"
#include "engine_type.h"
#include "company_type.h"
+#include "widgets/dropdown_func.h"
void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit = false);
@@ -101,4 +102,33 @@ Vehicle *CheckClickOnVehicle(const struct ViewPort *vp, int x, int y);
void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip);
+/**
+ * Tell if the focused window concerns the specified vehicle.
+ * @param vid Vehicle id to check.
+ * @param ref_window The window to check against.
+ * @return True if the focused window is about specified vehicle.
+ */
+static inline bool HasFocusedVehicleChanged(const VehicleID vid, Window *ref_window)
+{
+ if (ref_window) {
+ WindowClass wc = ref_window->window_class;
+ WindowNumber wn = ref_window->window_number;
+
+ if (wc == WC_DROPDOWN_MENU) GetParentWindowInfo(ref_window, wc, wn);
+
+ switch (wc) {
+ default:
+ break;
+ case WC_VEHICLE_DETAILS:
+ case WC_VEHICLE_REFIT:
+ case WC_VEHICLE_ORDERS:
+ case WC_VEHICLE_TIMETABLE:
+ case WC_VEHICLE_VIEW:
+ return ((uint32) wn != vid);
+ }
+ }
+
+ return true;
+}
+
#endif /* VEHICLE_GUI_H */
diff --git a/src/viewport.cpp b/src/viewport.cpp
index 9d69f06bfa..79b1374d51 100644
--- a/src/viewport.cpp
+++ b/src/viewport.cpp
@@ -63,6 +63,13 @@
*/
#include "stdafx.h"
+#include "clear_map.h"
+#include "tree_map.h"
+#include "industry.h"
+#include "smallmap_gui.h"
+#include "smallmap_colours.h"
+#include "table/tree_land.h"
+#include "blitter/32bpp_base.hpp"
#include "landscape.h"
#include "viewport_func.h"
#include "station_base.h"
@@ -70,6 +77,8 @@
#include "town.h"
#include "signs_base.h"
#include "signs_func.h"
+#include "plans_base.h"
+#include "plans_func.h"
#include "vehicle_base.h"
#include "vehicle_gui.h"
#include "blitter/factory.hpp"
@@ -85,6 +94,9 @@
#include "linkgraph/linkgraph_gui.h"
#include "viewport_sprite_sorter.h"
#include "bridge_map.h"
+#include "depot_base.h"
+#include "tunnelbridge_map.h"
+#include "gui.h"
#include