polyline update applied

--HG--
branch : novattd150
This commit is contained in:
Pavel Stupnikov
2015-03-16 12:56:24 +03:00
9 changed files with 357 additions and 180 deletions

View File

@@ -110,7 +110,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
InitializeEconomy();
ResetObjectToPlace();
ClearRailPlacementEndpoints();
ResetRailPlacementSnapping();
GamelogReset();
GamelogStartAction(GLAT_START);

View File

@@ -417,6 +417,8 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
Track track = Extract<Track, 0, 3>(p2);
CommandCost cost(EXPENSES_CONSTRUCTION);
_rail_track_endtile = INVALID_TILE;
if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
Slope tileh = GetTileSlope(tile);
@@ -433,7 +435,10 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
ret = CheckTrackCombination(tile, trackbit, flags);
if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track);
if (ret.Failed()) return ret;
if (ret.Failed()) {
if (ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) _rail_track_endtile = tile;
return ret;
}
ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
if (ret.Failed()) return ret;
@@ -522,6 +527,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
}
if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
_rail_track_endtile = tile;
return_cmd_error(STR_ERROR_ALREADY_BUILT);
}
/* FALL THROUGH */
@@ -580,6 +586,8 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
CommandCost cost(EXPENSES_CONSTRUCTION);
bool crossing = false;
_rail_track_endtile = INVALID_TILE;
if (!ValParamTrackOrientation(track)) return CMD_ERROR;
TrackBits trackbit = TrackToTrackBits(track);
@@ -840,6 +848,8 @@ static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint3
bool remove = HasBit(p2, 7);
RailType railtype = Extract<RailType, 0, 4>(p2);
_rail_track_endtile = INVALID_TILE;
if ((!remove && !ValParamRailtype(railtype)) || !ValParamTrackOrientation(track)) return CMD_ERROR;
if (p1 >= MapSize()) return CMD_ERROR;
TileIndex end_tile = p1;
@@ -851,10 +861,12 @@ static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint3
bool had_success = false;
CommandCost last_error = CMD_ERROR;
for (;;) {
TileIndex last_endtile = _rail_track_endtile;
CommandCost ret = DoCommand(tile, remove ? 0 : railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
if (ret.Failed()) {
last_error = ret;
if (_rail_track_endtile == INVALID_TILE) _rail_track_endtile = last_endtile;
if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
if (HasBit(p2, 8)) return last_error;
break;

View File

@@ -57,6 +57,9 @@ extern TileIndex _rail_track_endtile; // rail_cmd.cpp
/* Map the setting: default_signal_type to the corresponding signal type */
static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY};
static const int HOTKEY_POLYRAIL = 0x1000;
static const int HOTKEY_NEW_POLYRAIL = 0x1001;
struct RailStationGUISettings {
Axis orientation; ///< Currently selected rail station orientation
@@ -93,13 +96,20 @@ void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32
if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile);
}
static bool GenericPlaceRail(TileIndex tile, Track track)
static CommandContainer GenericPlaceRailCmd(TileIndex tile, Track track)
{
return DoCommandP(tile, _cur_railtype, track,
_remove_button_clicked ?
CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK),
CcPlaySound1E);
CommandContainer ret = {
tile, // tile
_cur_railtype, // p1
track, // p2
_remove_button_clicked ?
CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), // cmd
CcPlaySound1E, // callback
"" // text
};
return ret;
}
/**
@@ -352,13 +362,20 @@ static void BuildRailClick_Remove(Window *w)
}
}
static bool DoRailroadTrack(TileIndex start_tile, TileIndex end_tile, Track track)
static CommandContainer DoRailroadTrackCmd(TileIndex start_tile, TileIndex end_tile, Track track)
{
return DoCommandP(start_tile, end_tile, _cur_railtype | (track << 4),
_remove_button_clicked ?
CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK),
CcPlaySound1E);
CommandContainer ret = {
start_tile, // tile
end_tile, // p1
_cur_railtype | (track << 4), // p2
_remove_button_clicked ?
CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), // cmd
CcPlaySound1E, // callback
"" // text
};
return ret;
}
static void HandleAutodirPlacement()
@@ -367,8 +384,21 @@ static void HandleAutodirPlacement()
TileIndex start_tile = TileVirtXY(_thd.selstart.x, _thd.selstart.y);
TileIndex end_tile = TileVirtXY(_thd.selend.x, _thd.selend.y);
if ((_thd.drawstyle & HT_RAIL ? GenericPlaceRail(end_tile, track) : DoRailroadTrack(start_tile, end_tile, track))
&& !_shift_pressed) {
CommandContainer cmd = (_thd.drawstyle & HT_RAIL) ?
GenericPlaceRailCmd(end_tile, track) : // one tile case
DoRailroadTrackCmd(start_tile, end_tile, track); // multitile selection
/* When overbuilding existing tracks in polyline mode we just want to move the
* snap point without altering the user with the "already built" error. Don't
* execute the command right away, firstly check if tracks are being overbuilt. */
if (!(_thd.place_mode & HT_POLY) || _shift_pressed ||
DoCommand(&cmd, DC_AUTO | DC_NO_WATER).GetErrorMessage() != STR_ERROR_ALREADY_BUILT) {
/* place tracks */
if (!DoCommandP(&cmd)) return;
}
/* save new snap points for the polyline tool */
if (!_shift_pressed && _rail_track_endtile != INVALID_TILE) {
StoreRailPlacementEndpoints(start_tile, _rail_track_endtile, track, true);
}
}
@@ -632,10 +662,39 @@ struct BuildRailToolbarWindow : Window {
this->last_user_action = widget;
break;
case WID_RAT_POLYRAIL:
HandlePlacePushButton(this, WID_RAT_POLYRAIL, GetRailTypeInfo(railtype)->cursor.autorail, HT_RAIL | HT_POLY);
this->last_user_action = widget;
case WID_RAT_POLYRAIL: {
bool was_snap = CurrentlySnappingRailPlacement();
bool was_open = this->IsWidgetLowered(WID_RAT_POLYRAIL);
bool do_snap;
bool do_open;
/* "polyrail" hotkey - activate polyline tool in snapping mode, close the tool if snapping mode is already active
* "new_polyrail" hotkey - activate polyline tool in non-snapping (new line) mode, close the tool if non-snapping mode is already active
* button ctrl-clicking - switch between snapping and non-snapping modes, open the tool in non-snapping mode if it is closed
* button clicking - open the tool in non-snapping mode, close the tool if it is opened */
if (this->last_user_action == HOTKEY_POLYRAIL) {
do_snap = true;
do_open = !was_open || !was_snap;
} else if (this->last_user_action == HOTKEY_NEW_POLYRAIL) {
do_snap = false;
do_open = !was_open || was_snap;
} else if (_ctrl_pressed) {
do_snap = !was_open || !was_snap;
do_open = true;
} else {
do_snap = false;
do_open = !was_open;
}
/* close the tool explicitly so it can be re-opened in different snapping mode */
if (was_open) ResetObjectToPlace();
/* open the tool in desired mode */
if (do_open && HandlePlacePushButton(this, WID_RAT_POLYRAIL, GetRailTypeInfo(railtype)->cursor.autorail, do_snap ? (HT_RAIL | HT_POLY) : (HT_RAIL | HT_NEW_POLY))) {
/* if we are re-opening the tool but we couldn't switch the snapping
* then close the tool instead of appearing to be doing nothing */
if (was_open && do_snap != CurrentlySnappingRailPlacement()) ResetObjectToPlace();
}
this->last_user_action = WID_RAT_POLYRAIL;
break;
}
case WID_RAT_DEMOLISH:
HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
@@ -701,7 +760,15 @@ struct BuildRailToolbarWindow : Window {
virtual EventState OnHotkey(int hotkey)
{
MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection
return Window::OnHotkey(hotkey);
if (hotkey == HOTKEY_POLYRAIL || hotkey == HOTKEY_NEW_POLYRAIL) {
/* Indicate to the OnClick that the action comes from a hotkey rather
* then from a click and that the CTRL state should be ignored. */
this->last_user_action = hotkey;
hotkey = WID_RAT_POLYRAIL;
}
return this->Window::OnHotkey(hotkey);
}
virtual void OnPlaceObject(Point pt, TileIndex tile)
@@ -877,7 +944,8 @@ static EventState RailToolbarGlobalHotkeys(int hotkey)
}
const uint16 _railtoolbar_autorail_keys[] = {'5', 'A' | WKC_GLOBAL_HOTKEY, 0};
const uint16 _railtoolbar_polyrail_keys[] = {'5' | WKC_CTRL, 'A' | WKC_GLOBAL_HOTKEY | WKC_CTRL, 0};
const uint16 _railtoolbar_polyrail_keys[] = {'5' | WKC_CTRL, 'A' | WKC_CTRL | WKC_GLOBAL_HOTKEY, 0};
const uint16 _railtoolbar_new_poly_keys[] = {'5' | WKC_CTRL | WKC_SHIFT, 'A' | WKC_CTRL | WKC_SHIFT | WKC_GLOBAL_HOTKEY, 0};
static Hotkey railtoolbar_hotkeys[] = {
Hotkey('1', "build_ns", WID_RAT_BUILD_NS),
@@ -885,7 +953,8 @@ static Hotkey railtoolbar_hotkeys[] = {
Hotkey('3', "build_ew", WID_RAT_BUILD_EW),
Hotkey('4', "build_y", WID_RAT_BUILD_Y),
Hotkey(_railtoolbar_autorail_keys, "autorail", WID_RAT_AUTORAIL),
Hotkey(_railtoolbar_polyrail_keys, "polyrail", WID_RAT_POLYRAIL),
Hotkey(_railtoolbar_polyrail_keys, "polyrail", HOTKEY_POLYRAIL),
Hotkey(_railtoolbar_new_poly_keys, "new_polyrail", HOTKEY_NEW_POLYRAIL),
Hotkey('6', "demolish", WID_RAT_DEMOLISH),
Hotkey('7', "depot", WID_RAT_BUILD_DEPOT),
Hotkey('8', "waypoint", WID_RAT_BUILD_WAYPOINT),
@@ -1819,7 +1888,6 @@ struct BuildRailDepotWindow : public PickerWindowBase {
case WID_BRAD_DEPOT_SE:
case WID_BRAD_DEPOT_SW:
case WID_BRAD_DEPOT_NW:
case WID_BRAD_DEPOT_AUTO:
this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
_build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE);
this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
@@ -1857,9 +1925,6 @@ static const NWidgetPart _nested_build_depot_widgets[] = {
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_AUTO), SetMinimalSize(134, 12), SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_BUILD_DEPOT_TRAIN_ORIENTATION_AUTO_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 3),
EndContainer(),
};
@@ -1980,7 +2045,7 @@ static void ShowBuildWaypointPicker(Window *parent)
*/
void InitializeRailGui()
{
_build_depot_direction = (DiagDirection)(DIAGDIR_NW + 1);
_build_depot_direction = DIAGDIR_NW;
}
/**

View File

@@ -1,4 +1,4 @@
/* $Id: rev.cpp.in 26482 2014-04-23 20:13:33Z rubidium $ */
/* $Id: rev.cpp.in 26440 2014-04-01 18:33:16Z frosch $ */
/*
* This file is part of OpenTTD.
@@ -39,7 +39,7 @@ bool IsReleasedVersion()
* norev000 is for non-releases that are made on systems without
* subversion or sources that are not a checkout of subversion.
*/
const char _openttd_revision[] = "1.5.0-beta2";
const char _openttd_revision[] = "1.4.0";
/**
* The text version of OpenTTD's build date.
@@ -72,11 +72,11 @@ const byte _openttd_revision_modified = 0;
* final release will always have a lower version number than the released
* version, thus making comparisons on specific revisions easy.
*/
const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 0 << 20 | 0 << 19 | (27170 & ((1 << 19) - 1));
const uint32 _openttd_newgrf_version = 1 << 28 | 4 << 24 | 0 << 20 | 1 << 19 | (26440 & ((1 << 19) - 1));
#ifdef __MORPHOS__
/**
* Variable used by MorphOS to show the version.
*/
extern const char morphos_versions_tag[] = "$VER: OpenTTD 1.5.0-beta2 (16.03.15) OpenTTD Team [MorphOS, PowerPC]";
extern const char morphos_versions_tag[] = "$VER: OpenTTD 1.4.0 (02.04.14) OpenTTD Team [MorphOS, PowerPC]";
#endif

View File

@@ -904,6 +904,7 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_EW, "WID_RAT_BUILD_EW");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_Y, "WID_RAT_BUILD_Y");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_AUTORAIL, "WID_RAT_AUTORAIL");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_POLYRAIL, "WID_RAT_POLYRAIL");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_DEMOLISH, "WID_RAT_DEMOLISH");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_DEPOT, "WID_RAT_BUILD_DEPOT");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_WAYPOINT, "WID_RAT_BUILD_WAYPOINT");

View File

@@ -1982,6 +1982,7 @@ public:
WID_RAT_BUILD_EW = ::WID_RAT_BUILD_EW, ///< Build rail along the game view X axis.
WID_RAT_BUILD_Y = ::WID_RAT_BUILD_Y, ///< Build rail along the game grid Y axis.
WID_RAT_AUTORAIL = ::WID_RAT_AUTORAIL, ///< Autorail tool.
WID_RAT_POLYRAIL = ::WID_RAT_POLYRAIL, ///< Polyline rail tool.
WID_RAT_DEMOLISH = ::WID_RAT_DEMOLISH, ///< Destroy something with dynamite!
WID_RAT_BUILD_DEPOT = ::WID_RAT_BUILD_DEPOT, ///< Build a depot.
WID_RAT_BUILD_WAYPOINT = ::WID_RAT_BUILD_WAYPOINT, ///< Build a waypoint.

View File

@@ -32,7 +32,8 @@ void VpSetPlaceSizingLimit(int limit);
void UpdateTileSelection();
void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track start_track, bool bidirectional = true);
void ClearRailPlacementEndpoints();
void ResetRailPlacementSnapping();
bool CurrentlySnappingRailPlacement();
extern TileHighlightData _thd;

View File

@@ -29,6 +29,7 @@ enum HighLightStyle {
HT_VEHICLE = 0x100, ///< vehicle is accepted as target as well (bitmask)
HT_DIAGONAL = 0x200, ///< Also allow 'diagonal rectangles'. Only usable in combination with #HT_RECT or #HT_POINT.
HT_POLY = 0x400, ///< polyline mode; connect highlighted track with previous one
HT_NEW_POLY = 0xC00, ///< start completly new polyline; implies #HT_POLY
HT_DRAG_MASK = 0x0F8, ///< Mask for the tile drag-type modes.
/* lower bits (used with HT_LINE and HT_RAIL):
@@ -63,7 +64,7 @@ struct TileHighlightData {
Point selend; ///< The location where the drag currently ends.
Point selstart2; ///< The location where the second segment of a polyline track starts.
Point selend2; ///< The location where the second segment of a polyline track ends.
HighLightStyle dir2; ///< Direction of the second segment of a polyline track, HT_DIR_END if second segment is not selected.
HighLightStyle dir2; ///< Direction of the second segment of a polyline track, HT_DIR_END if second segment is not selected. HT_LINE drawstyle.
byte sizelimit; ///< Whether the selection is limited in length, and what the maximum length is.
HighLightStyle drawstyle; ///< Lower bits 0-3 are reserved for detailed highlight information.

View File

@@ -152,6 +152,12 @@ typedef SmallVector<StringSpriteToDraw, 4> StringSpriteToDrawVector;
typedef SmallVector<ParentSpriteToDraw, 64> ParentSpriteToDrawVector;
typedef SmallVector<ChildScreenSpriteToDraw, 16> ChildScreenSpriteToDrawVector;
enum RailSnapMode {
RSM_NO_SNAP,
RSM_SNAP_TO_TILE,
RSM_SNAP_TO_RAIL,
};
/**
* Snapping point for a track.
*
@@ -199,14 +205,22 @@ static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right,
static ViewportDrawer _vd;
TileHighlightData _thd;
static LineSnapPoints _rail_snap_points; ///< Set of points where a rail track will be snapped to (polyline tool).
static LineSnapPoint _current_snap_lock; ///< Start point and direction at which selected track is locked on currently (while dragging in polyline mode).
static TileInfo *_cur_ti;
bool _draw_bounding_boxes = false;
bool _draw_dirty_blocks = false;
uint _dirty_block_colour = 0;
static VpSpriteSorter _vp_sprite_sorter = NULL;
static RailSnapMode _rail_snap_mode = RSM_NO_SNAP; ///< Type of rail track snapping (polyline tool).
static LineSnapPoints _tile_snap_points; ///< Tile to which a rail track will be snapped to (polyline tool).
static LineSnapPoints _rail_snap_points; ///< Set of points where a rail track will be snapped to (polyline tool).
static LineSnapPoint _current_snap_lock; ///< Start point and direction at which selected track is locked on currently (while dragging in polyline mode).
static RailSnapMode GetRailSnapMode();
static void SetRailSnapMode(RailSnapMode mode);
static TileIndex GetRailSnapTile();
static void SetRailSnapTile(TileIndex tile);
static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z)
{
Point p = RemapCoords(x, y, z);
@@ -1052,27 +1066,27 @@ static void DrawTileSelection(const TileInfo *ti)
/* Draw a blue rect. */
DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE);
}
}
}
break;
case HT_POINT:
if (IsInsideSelectedRectangle(ti->x, ti->y)) {
/* Figure out the Z coordinate for the single dot. */
int z = 0;
FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
if (ti->tileh & SLOPE_N) {
z += TILE_HEIGHT;
if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT;
}
if (IsHalftileSlope(ti->tileh)) {
Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT;
if (halftile_corner != CORNER_S) {
foundation_part = FOUNDATION_PART_HALFTILE;
if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT;
/* Figure out the Z coordinate for the single dot. */
int z = 0;
FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
if (ti->tileh & SLOPE_N) {
z += TILE_HEIGHT;
if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT;
}
}
DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part);
if (IsHalftileSlope(ti->tileh)) {
Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh);
if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT;
if (halftile_corner != CORNER_S) {
foundation_part = FOUNDATION_PART_HALFTILE;
if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT;
}
}
DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part);
}
break;
@@ -1087,12 +1101,13 @@ static void DrawTileSelection(const TileInfo *ti)
HighLightStyle type = GetPartOfAutoLine(ti->x, ti->y, _thd.selstart, _thd.selend, _thd.drawstyle & HT_DIR_MASK);
if (type < HT_DIR_END) {
DrawAutorailSelection(ti, type);
} else if ((_thd.drawstyle & HT_POLY) && _thd.dir2 < HT_DIR_END) {
} else if (_thd.dir2 < HT_DIR_END) {
/* FIXME mb missing condition (_thd.drawstyle & HT_POLY) */
type = GetPartOfAutoLine(ti->x, ti->y, _thd.selstart2, _thd.selend2, _thd.dir2);
if (type < HT_DIR_END) DrawAutorailSelection(ti, type, PALETTE_SEL_TILE_BLUE);
}
}
break;
}
}
}
}
@@ -1277,9 +1292,8 @@ static void ViewportAddTownNames(DrawPixelInfo *dpi)
const Town *t;
FOR_ALL_TOWNS(t) {
ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign,
//_settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN,
//STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK,
t->Label(), t->SmallLabel(), STR_VIEWPORT_TOWN_TINY_BLACK,
_settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN,
STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK,
t->index, t->cache.population);
}
}
@@ -2098,8 +2112,7 @@ static bool CheckClickOnTown(const ViewPort *vp, int x, int y)
const Town *t;
FOR_ALL_TOWNS(t) {
if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) {
if(_ctrl_pressed) TownExecuteAction(t, 4); //build statue
else ShowTownViewWindow(t->index);
ShowTownViewWindow(t->index);
return true;
}
}
@@ -2194,15 +2207,21 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click)
if (v != NULL && VehicleClicked(v)) return true;
}
/* Double-clicking finishes current polyline and starts new one. */
if (double_click && _settings_client.gui.polyrail_double_click && (_thd.place_mode & HT_POLY)) {
ClearRailPlacementEndpoints();
SetTileSelectSize(1, 1);
return true;
}
/* Vehicle placement mode already handled above. */
if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
if (_thd.place_mode & HT_POLY) {
/* In polyline mode double-clicking on a single white line, finishes current polyline.
* If however the user double-clicks on a line that has a white and a blue section,
* both lines (white and blue) will be constructed consecutively. */
static bool stop_snap_on_double_click = false;
/* FIXME _settings_client.gui.polyrail_double_click */
if (double_click && stop_snap_on_double_click) {
SetRailSnapMode(RSM_NO_SNAP);
return true;
}
stop_snap_on_double_click = !(_thd.drawstyle & HT_LINE) || (_thd.dir2 == HT_DIR_END);
}
PlaceObject();
return true;
}
@@ -2218,7 +2237,7 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click)
v = v->First();
if (_ctrl_pressed && v->owner == _local_company) {
if (_settings_client.gui.enable_ctrl_click_start_stop)
StartStopVehicle(v, true);
StartStopVehicle(v, true);
} else {
ShowVehicleViewWindow(v);
}
@@ -2440,9 +2459,6 @@ void UpdateTileSelection()
_thd.new_size.x += TILE_SIZE;
_thd.new_size.y += TILE_SIZE;
}
if (_thd.place_mode & HT_POLY) {
CalcNewPolylineOutersize();
}
new_drawstyle = _thd.next_drawstyle;
}
} else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
@@ -2463,7 +2479,16 @@ void UpdateTileSelection()
case HT_LINE:
/* HT_POLY */
if (_thd.place_mode & HT_POLY) {
if (_rail_snap_points.Length() > 0) {
RailSnapMode snap_mode = GetRailSnapMode();
if (snap_mode == RSM_NO_SNAP ||
(snap_mode == RSM_SNAP_TO_TILE && GetRailSnapTile() == TileVirtXY(pt.x, pt.y))) {
new_drawstyle = GetAutorailHT(pt.x, pt.y);
_thd.new_offs.x = 0;
_thd.new_offs.y = 0;
_thd.new_outersize.x = 0;
_thd.new_outersize.y = 0;
_thd.dir2 = HT_DIR_END;
} else {
new_drawstyle = CalcPolyrailDrawstyle(pt, false);
if (new_drawstyle != HT_NONE) {
x1 = _thd.selstart.x & ~TILE_UNIT_MASK;
@@ -2476,21 +2501,15 @@ void UpdateTileSelection()
_thd.new_pos.y = y1;
_thd.new_size.x = x2 - x1 + TILE_SIZE;
_thd.new_size.y = y2 - y1 + TILE_SIZE;
CalcNewPolylineOutersize();
}
break;
}
_thd.new_offs.x = 0;
_thd.new_offs.y = 0;
_thd.new_outersize.x = 0;
_thd.new_outersize.y = 0;
_thd.dir2 = HT_DIR_END;
break;
}
/* HT_RAIL */
if (_thd.place_mode & HT_RAIL) {
/* Draw one highlighted tile in any direction */
new_drawstyle = GetAutorailHT(pt.x, pt.y);
break;
/* Draw one highlighted tile in any direction */
new_drawstyle = GetAutorailHT(pt.x, pt.y);
break;
}
/* HT_LINE */
switch (_thd.place_mode & HT_DIR_MASK) {
@@ -2523,6 +2542,8 @@ void UpdateTileSelection()
}
}
if (new_drawstyle & HT_LINE) CalcNewPolylineOutersize();
/* redraw selection */
if (_thd.drawstyle != new_drawstyle ||
_thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y ||
@@ -2588,6 +2609,10 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag
_thd.place_mode = HT_SPECIAL | others;
_thd.next_drawstyle = _thd.drawstyle | others;
_current_snap_lock.x = -1;
if ((_thd.place_mode & HT_POLY) != 0 && GetRailSnapMode() == RSM_NO_SNAP) {
SetRailSnapMode(RSM_SNAP_TO_TILE);
SetRailSnapTile(tile);
}
} else {
_thd.place_mode = HT_SPECIAL | others;
_thd.next_drawstyle = HT_POINT | others;
@@ -2968,26 +2993,34 @@ static inline uint SqrDist(const Point &a, const Point &b)
static LineSnapPoint *FindBestPolyline(const Point &pt, LineSnapPoint *snap_points, uint num_points, Polyline *ret)
{
while (num_points > 0) {
/* run a single bubble sort loop to find the closest snap point (push it to the and of the array) */
uint prev_dist = SqrDist(snap_points[0], pt);
for (uint i = 1; i < num_points; i++) {
uint next_dist = SqrDist(snap_points[i], pt);
if (prev_dist < next_dist) {
Swap(snap_points[i], snap_points[i - 1]);
} else {
prev_dist = next_dist;
}
/* Find the best polyline (a pair of two lines - the white one and the blue
* one) led from any of saved snap points to the mouse cursor. */
LineSnapPoint *best_snap_point = NULL; // the best polyline we found so far is led from this snap point
for (int i = 0; i < (int)num_points; i++) {
/* try to fit a polyline */
Polyline polyline;
if (!FindPolyline(pt, snap_points[i], &polyline)) continue; // skip non-matching snap points
/* check whether we've found a better polyline */
if (best_snap_point != NULL) {
/* firstly choose shorter polyline (the one with smaller amount of
* track pieces composing booth the white and the blue line) */
uint cur_len = polyline.first_len + polyline.second_len;
uint best_len = ret->first_len + ret->second_len;
if (cur_len > best_len) continue;
/* secondly choose that polyline which has longer first (white) line */
if (cur_len == best_len && polyline.first_len < ret->first_len) continue;
/* finally check euclidean distance to snap points and choose the
* one which is closer */
if (cur_len == best_len && polyline.first_len == ret->first_len && SqrDist(pt, snap_points[i]) >= SqrDist(pt, *best_snap_point)) continue;
}
/* try to fit a line */
if (FindPolyline(pt, snap_points[num_points - 1], ret)) return &snap_points[num_points - 1];
/* repeat procedure for the rest of snap points */
--num_points;
/* save the found polyline */
*ret = polyline;
best_snap_point = &snap_points[i];
}
return NULL;
return best_snap_point;
}
/** while dragging */
@@ -3178,6 +3211,7 @@ static void CalcRaildirsDrawstyle(int x, int y, int method)
_thd.selend.x = x;
_thd.selend.y = y;
_thd.dir2 = HT_DIR_END;
_thd.next_drawstyle = b;
ShowLengthMeasurement(b, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
@@ -3185,33 +3219,37 @@ static void CalcRaildirsDrawstyle(int x, int y, int method)
static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging)
{
RailSnapMode snap_mode = GetRailSnapMode();
/* are we only within one tile? */
if (snap_mode == RSM_SNAP_TO_TILE && GetRailSnapTile() == TileVirtXY(pt.x, pt.y)) {
_thd.selend.x = pt.x;
_thd.selend.y = pt.y;
return GetAutorailHT(pt.x, pt.y);
}
/* find the best track */
Polyline line;
HighLightStyle ret = HT_LINE | HT_POLY;
bool lock_snapping = dragging && snap_mode == RSM_SNAP_TO_RAIL;
if (!lock_snapping) _current_snap_lock.x = -1;
if (!dragging) {
_current_snap_lock.x = -1;
if (FindBestPolyline(pt, _rail_snap_points.Begin(), _rail_snap_points.Length(), &line) == NULL) ret = HT_NONE; // no match
} else if (_current_snap_lock.x != -1) {
if (FindBestPolyline(pt, &_current_snap_lock, 1, &line) == NULL) ret = HT_NONE; // no match
const LineSnapPoint *snap_point;
if (_current_snap_lock.x != -1) {
snap_point = FindBestPolyline(pt, &_current_snap_lock, 1, &line);
} else if (snap_mode == RSM_SNAP_TO_TILE) {
snap_point = FindBestPolyline(pt, _tile_snap_points.Begin(), _tile_snap_points.Length(), &line);
} else {
const LineSnapPoint *snap_point = FindBestPolyline(pt, _rail_snap_points.Begin(), _rail_snap_points.Length(), &line);
if (snap_point == NULL) {
ret = HT_NONE; // no match
} else {
_current_snap_lock = *snap_point;
_current_snap_lock.dirs &= (1 << line.first_dir) | (1 << ReverseDir(line.first_dir)); // lock direction
}
}
assert(snap_mode == RSM_SNAP_TO_RAIL);
snap_point = FindBestPolyline(pt, _rail_snap_points.Begin(), _rail_snap_points.Length(), &line);
}
if (ret == HT_NONE) {
_thd.selstart.x = -1;
_thd.selend.x = -1;
_thd.selstart2.x = -1;
_thd.selend2.x = -1;
_thd.dir2 = HT_DIR_END;
return ret;
if (snap_point == NULL) return HT_NONE; // no match
if (lock_snapping && _current_snap_lock.x == -1) {
/* lock down the snap point */
_current_snap_lock = *snap_point;
_current_snap_lock.dirs &= (1 << line.first_dir) | (1 << ReverseDir(line.first_dir));
}
TileIndexDiffC first_dir = TileIndexDiffCByDir(line.first_dir);
@@ -3228,7 +3266,6 @@ static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging)
Trackdir seldir = PointDirToTrackdir(_thd.selstart, line.first_dir);
_thd.selstart.x &= ~TILE_UNIT_MASK;
_thd.selstart.y &= ~TILE_UNIT_MASK;
ret |= (HighLightStyle)TrackdirToTrack(seldir);
if (line.second_len != 0) {
TileIndexDiffC second_dir = TileIndexDiffCByDir(line.second_dir);
@@ -3246,6 +3283,7 @@ static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging)
_thd.dir2 = HT_DIR_END;
}
HighLightStyle ret = HT_LINE | (HighLightStyle)TrackdirToTrack(seldir);
ShowLengthMeasurement(ret, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), TCC_HOVER, true);
return ret;
}
@@ -3267,7 +3305,7 @@ void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method)
return;
}
if ((_thd.place_mode & HT_POLY) && _rail_snap_points.Length() > 0) {
if ((_thd.place_mode & HT_POLY) && GetRailSnapMode() != RSM_NO_SNAP) {
Point pt = { x, y };
_thd.next_drawstyle = CalcPolyrailDrawstyle(pt, true);
return;
@@ -3325,11 +3363,11 @@ calc_heightdiff_single_direction:;
x = sx + Clamp(x - sx, -limit, limit);
y = sy + Clamp(y - sy, -limit, limit);
}
/* With current code passing a HT_LINE style to calculate the height
* difference is enough. However if/when a point-tool is created
* with this method, function should be called with new_style (below)
* instead of HT_LINE | style case HT_POINT is handled specially
* new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */
/* With current code passing a HT_LINE style to calculate the height
* difference is enough. However if/when a point-tool is created
* with this method, function should be called with new_style (below)
* instead of HT_LINE | style case HT_POINT is handled specially
* new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */
ShowLengthMeasurement(HT_LINE | style, TileVirtXY(sx, sy), TileVirtXY(x, y));
break;
@@ -3409,6 +3447,7 @@ calc_heightdiff_single_direction:;
_thd.selend.x = x;
_thd.selend.y = y;
_thd.dir2 = HT_DIR_END;
}
/**
@@ -3426,11 +3465,10 @@ EventState VpHandlePlaceSizingDrag()
return ES_HANDLED;
}
/* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */
if (_left_button_down) {
w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
return ES_HANDLED;
}
/* While dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ).
* Do it even if the button is no longer pressed to make sure that OnPlaceDrag was called at least once. */
w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor());
if (_left_button_down) return ES_HANDLED;
/* mouse button released..
* keep the selected tool, but reset it to the original mode. */
@@ -3447,8 +3485,12 @@ EventState VpHandlePlaceSizingDrag()
}
SetTileSelectSize(1, 1);
w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
if (_thd.place_mode & HT_POLY) {
if (GetRailSnapMode() == RSM_SNAP_TO_TILE) SetRailSnapMode(RSM_NO_SNAP);
if (_thd.drawstyle == HT_NONE) return ES_HANDLED;
}
w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y));
return ES_HANDLED;
}
@@ -3495,6 +3537,10 @@ void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowC
VpStartPreSizing();
}
if (mode & HT_POLY) {
SetRailSnapMode((mode & HT_NEW_POLY) == HT_NEW_POLY ? RSM_NO_SNAP : RSM_SNAP_TO_RAIL);
}
if ((icon & ANIMCURSOR_FLAG) != 0) {
SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]);
} else {
@@ -3508,6 +3554,44 @@ void ResetObjectToPlace()
SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
}
Point GetViewportStationMiddle(const ViewPort *vp, const Station *st)
{
int x = TileX(st->xy) * TILE_SIZE;
int y = TileY(st->xy) * TILE_SIZE;
int z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1));
Point p = RemapCoords(x, y, z);
p.x = UnScaleByZoom(p.x - vp->virtual_left, vp->zoom) + vp->left;
p.y = UnScaleByZoom(p.y - vp->virtual_top, vp->zoom) + vp->top;
return p;
}
/** Helper class for getting the best sprite sorter. */
struct ViewportSSCSS {
VpSorterChecker fct_checker; ///< The check function.
VpSpriteSorter fct_sorter; ///< The sorting function.
};
/** List of sorters ordered from best to worst. */
static ViewportSSCSS _vp_sprite_sorters[] = {
#ifdef WITH_SSE
{ &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 },
#endif
{ &ViewportSortParentSpritesChecker, &ViewportSortParentSprites }
};
/** Choose the "best" sprite sorter and set _vp_sprite_sorter. */
void InitializeSpriteSorter()
{
for (uint i = 0; i < lengthof(_vp_sprite_sorters); i++) {
if (_vp_sprite_sorters[i].fct_checker()) {
_vp_sprite_sorter = _vp_sprite_sorters[i].fct_sorter;
break;
}
}
assert(_vp_sprite_sorter != NULL);
}
static LineSnapPoint LineSnapPointAtRailTrackEndpoint(TileIndex tile, DiagDirection exit_dir, bool bidirectional)
{
LineSnapPoint ret;
@@ -3554,57 +3638,69 @@ void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track
LineSnapPoint snap_end = LineSnapPointAtRailTrackEndpoint(end_tile, TrackdirToExitdir(exit_trackdir_at_end), bidirectional_exit);
/* Find if we already had these coordinates before. */
LineSnapPoint *snap;
bool had_start = false;
bool had_end = false;
for (snap = _rail_snap_points.Begin(); snap != _rail_snap_points.End(); snap++) {
/* Coordinates found - remove the snap point as it was already used. */
if (snap->x == snap_start.x && snap->y == snap_start.y) snap_start.dirs = 0;
if (snap->x == snap_end.x && snap->y == snap_end.y) snap_end.dirs = 0;
had_start |= (snap->x == snap_start.x && snap->y == snap_start.y);
had_end |= (snap->x == snap_end.x && snap->y == snap_end.y);
}
/* Create new snap point set. */
_rail_snap_points.Clear();
if (snap_start.dirs != 0) *_rail_snap_points.Append() = snap_start;
if (snap_end.dirs != 0) *_rail_snap_points.Append() = snap_end;
}
}
void ClearRailPlacementEndpoints()
{
_rail_snap_points.Clear();
}
Point GetViewportStationMiddle(const ViewPort *vp, const Station *st)
{
int x = TileX(st->xy) * TILE_SIZE;
int y = TileY(st->xy) * TILE_SIZE;
int z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1));
Point p = RemapCoords(x, y, z);
p.x = UnScaleByZoom(p.x - vp->virtual_left, vp->zoom) + vp->left;
p.y = UnScaleByZoom(p.y - vp->virtual_top, vp->zoom) + vp->top;
return p;
}
/** Helper class for getting the best sprite sorter. */
struct ViewportSSCSS {
VpSorterChecker fct_checker; ///< The check function.
VpSpriteSorter fct_sorter; ///< The sorting function.
};
/** List of sorters ordered from best to worst. */
static ViewportSSCSS _vp_sprite_sorters[] = {
#ifdef WITH_SSE
{ &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 },
#endif
{ &ViewportSortParentSpritesChecker, &ViewportSortParentSprites }
};
/** Choose the "best" sprite sorter and set _vp_sprite_sorter. */
void InitializeSpriteSorter()
{
for (uint i = 0; i < lengthof(_vp_sprite_sorters); i++) {
if (_vp_sprite_sorters[i].fct_checker()) {
_vp_sprite_sorter = _vp_sprite_sorters[i].fct_sorter;
break;
if (had_start && had_end) {
/* just stop snaping, don't forget snap points */
SetRailSnapMode(RSM_NO_SNAP);
} else {
/* include only new points */
_rail_snap_points.Clear();
if (!had_start) *_rail_snap_points.Append() = snap_start;
if (!had_end) *_rail_snap_points.Append() = snap_end;
SetRailSnapMode(RSM_SNAP_TO_RAIL);
}
}
assert(_vp_sprite_sorter != NULL);
}
bool CurrentlySnappingRailPlacement()
{
return (_thd.place_mode & HT_POLY) && GetRailSnapMode() == RSM_SNAP_TO_RAIL;
}
static RailSnapMode GetRailSnapMode()
{
if (_rail_snap_mode == RSM_SNAP_TO_TILE && _tile_snap_points.Length() == 0) return RSM_NO_SNAP;
if (_rail_snap_mode == RSM_SNAP_TO_RAIL && _rail_snap_points.Length() == 0) return RSM_NO_SNAP;
return _rail_snap_mode;
}
static void SetRailSnapMode(RailSnapMode mode)
{
_rail_snap_mode = mode;
if ((_thd.place_mode & HT_POLY) && (GetRailSnapMode() == RSM_NO_SNAP)) {
SetTileSelectSize(1, 1);
}
}
static TileIndex GetRailSnapTile()
{
if (_tile_snap_points.Length() == 0) return INVALID_TILE;
return TileVirtXY(_tile_snap_points[DIAGDIR_NE].x, _tile_snap_points[DIAGDIR_NE].y);
}
static void SetRailSnapTile(TileIndex tile)
{
_tile_snap_points.Clear();
if (tile == INVALID_TILE) return;
for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
LineSnapPoint *point = _tile_snap_points.Append();
*point = LineSnapPointAtRailTrackEndpoint(tile, dir, false);
point->dirs = ROR<uint8>(point->dirs, DIRDIFF_REVERSE);
}
}
void ResetRailPlacementSnapping()
{
_rail_snap_mode = RSM_NO_SNAP;
_tile_snap_points.Clear();
_rail_snap_points.Clear();
_current_snap_lock.x = -1;
}