Mercurial > hg > openttd
changeset 6012:542153c1c803 draft
(svn r8735) -Feature: drive-through road stops made possible by the hard work of mart3p.
author | rubidium <rubidium@openttd.org> |
---|---|
date | Wed, 14 Feb 2007 16:37:16 +0000 |
parents | 21d301b3bd81 |
children | 69b46559a66b |
files | bin/data/roadstops.grf src/command.cpp src/command.h src/gfxinit.cpp src/lang/english.txt src/lang/hungarian.txt src/npf.cpp src/pathfind.cpp src/road_gui.cpp src/road_map.cpp src/roadveh_cmd.cpp src/saveload.cpp src/settings.cpp src/settings_gui.cpp src/station.cpp src/station.h src/station_cmd.cpp src/station_map.h src/table/sprites.h src/table/station_land.h src/variables.h src/vehicle.cpp src/vehicle.h src/yapf/follow_track.hpp src/yapf/yapf_road.cpp src/yapf/yapf_settings.h |
diffstat | 26 files changed, 373 insertions(+), 61 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1a243ef6e358f4d7d379a95ebcdc7be499e0c38f GIT binary patch literal 2403 zc$|fnYm6Ib6^7558GFXxH}?3pcDhZ{@outA(_~4u2{hnklPFE5Goz%UrE0l|ic7Pi z*$p7Y2@F5#9eeTaX4Bn>3WT6tQ6z%6m3xE)a;qSXFG#KgVt!C*_{Awgsw&kWimK)F z1_|+tkt~fr%l0|%`@F9`fvIvD-r0V0`}i~*h4;Y;I1Mg*2%dxm@L?6c4&Q}e!f)YK zcn$svLjY7UgJamhiq-2j(BvITCM@3TFHsUDVsbrU#j4s+hC#(zp}RFJ7;82v)*2m5 z)|-uh2b5;lP_H+Fx)n6y-SRpNsiZv9tOv2lh8%{B2Sf2>B3aiN14d_%QI;mT&Sl`1 zr6gFBCUsqxK{riI3{j=~QaXZ;2`28x%V~r(COE3Bu4fQ3sB$UQ?GMs?S=GC(pl6`? zSgv(Cy?&;treiJ9R5M{WR*}V}M4*{r_xF%8M#{XsJ-ZjC;5~2#9)qW#22HpD--Mg+ zQ}`9U3?VE-J!mw?ni?=>RxB}nBh~FyECjwL4TsSlz1uNI)2&IJ&M@9D_j}eLn+&@> zeaPr!oR!iFnQBiLQ!eq?Ol4#_?50uGLqirD-AbnnRMP=7nHle5Y9?UJU<j3n$0bQM zqSKO^8H^_XAU%dw0aJxBcx!vOePjv_!VEkBRj_wv|01l5$$tR9hCciW2;PLZLB>XI z$I0CPIH@HWXG5!E#yZn9vE9fmD;}3vaxkt~7GqHsmG)j?5E?AViP=(eIEh0l<am%9 z4Jb2N6LzAZN0TX(Icf}<PPzDVI?6g~99bHTbX-?t?Di>7_h5!LR7-)8L+xzFG!+;* zgj%|8WCpra*C-{0-7rOau}ArY48kWG-;JqU3EtTL`}XXFaOx1u!o%=sxC+<d+k)Mm z*!6GlPq8V(94@6RR+F2RMo<x7By4J>h81C7Bd{o&?3jE_wc<S);b>6j3J9<GdNQ2Q zgvUW$m!!CWL$PO_3PSKg0+VcA3n!C-&V~Z8Qi7|g;WP1ml{NBAtT8yK=n7*r#T$7p zc9BsiMa2|yhUrWruSdnyNUUTU`H*thy|rJcuwM!C=}u^qA@h1Ztjn1?kDo^?QZ>`8 z^K_lF2vc{N@UQKEY&$a|wx`9)pArUdz<1y`@CUK5jN|xjJcW<o1^g1O;&Zr#-@{+v z%h<zZa2>~Sy%sRX6Cn0`t6;OCHz*}_aD1D!$9bbzu}m`qj^k6Qy-#lxO@8ud7JSF` zx26+IMT_U?gd|=)j1HX{JUS>VzU|v|M0OmT7Dx-rlI=%_=tle;eKnkx#Az#X60YO9 zURb76Xt!r*tX-y$(%HesW!I|>rX@q7pG7ay8*~tB@e3jv@pANZdrsm>3jSPZAD2?v zV3nTaQqi)4T_SA>7R@B3qG`6ul$G=hjipd`R>~EoKOW_hE9K7&c{(;!zET$HWU+x3 zaVo`zcvNCzt0J{_wM{A5O($N#)c9@@`M0(|a#X}-4j$Tx%~e=~=i$e28~!LN@EtJl z9z2Azcpg82pT{M<f#1R(3T2lR-*3u(r|0`E$?5ce*YEkx8oFV(-|IM?p66W$FYHko z-DnSUy$!HjuM>LhiKOdof^Sjr=2XJjgsL5lweLlrrle{$9E%>79FL}C+qUB|(J1st z!m=usONIDdyz2YT&~i^6HF<Pgo}aJMeX8&KmgiVeA#cym3s0)HQ?;3Ead!i0iYDXt z%hjq!`=#r0bTlzPZ&z)~%I>uUouG#Xdu66Nba-$;T`DauYN;w!V~Z~r7cXDAa(OYq z?f8MrYJTDJm8+xc%A%AJ6*e(J6*8pDm%^;lT9{a*BiM?wXvJB1v9&-MY|&xKG`F(q zYW~>7f;bvi7B4OrNmnl|UR)|2yZEXAdJm8g|M3~owzF^+9u-K}U<JMbKY~{T)UONi zvsl4n=n3g-*u<~ki}(|4<5F2jKj!<rj^8RceotuMan^FKvm<=J8@ksG-;2uVijen0 zZzJu|bev}0&<i`BYi;U-N_>PWnrks{Q@6drTr?pw&l55CqhdHgdGXc)i95L_IGqy6 zTZ8-4wVLO6-VHvAiW5H=?UUxKaZwp1h4#?C_`O)A`_)ZuamRP!v*bv%8Wr)`xFER> zJwY~|Q*9Xq#_M#i<U90Xa_Ezi22>oOd>5{bVnV0ryyki-*kSr^T#1j!zFngW$rS9+ zJudMt(`Oaa_B}eF>|nl2vX-bphH$%pd|<>gaUnFmc1Y6j=0Vw#6ZA1<iJRt~9{G#t zku(3VN1nnjU`t58h2O_pcpLk;JnrojNo$v=5TT_rTrCaqy2n^e(MF73D~7v8{Rth5 z$q}O0^Dj*?Pberci*ICaS#god;#X|bXrHH9tlc`4+%#-kQ2&9rEY;2prj@F|elSN* z;5nKJr)8mII7eq*dQf(3SGZJePb;F5#9?$fT1`A_IIb;>xJ2vm&v89^A)Fgn(wgyl zKAwv%$jag(y(WpjC1WC8Pt$ERDeYiQWyLg`x%fcQWAI<J>xJ4X2(<T6Mxagl9kdT) eE7EtcW>RZ$OIKIn4$`F&($asBR*qeSo$KFb?hRD{
--- a/src/command.cpp +++ b/src/command.cpp @@ -45,6 +45,7 @@ DEF_COMMAND(CmdRemoveTrainWaypoint); DEF_COMMAND(CmdBuildRoadStop); +DEF_COMMAND(CmdRemoveRoadStop); DEF_COMMAND(CmdBuildLongRoad); DEF_COMMAND(CmdRemoveLongRoad); @@ -188,7 +189,7 @@ {NULL, 0}, /* 19 */ {NULL, 0}, /* 20 */ {CmdBuildRoadStop, 0}, /* 21 */ - {NULL, 0}, /* 22 */ + {CmdRemoveRoadStop, 0}, /* 22 */ {CmdBuildLongRoad, 0}, /* 23 */ {CmdRemoveLongRoad, 0}, /* 24 */ {CmdBuildRoad, 0}, /* 25 */
--- a/src/command.h +++ b/src/command.h @@ -27,6 +27,7 @@ CMD_REMOVE_TRAIN_WAYPOINT = 18, CMD_BUILD_ROAD_STOP = 21, + CMD_REMOVE_ROAD_STOP = 22, CMD_BUILD_LONG_ROAD = 23, CMD_REMOVE_LONG_ROAD = 24, CMD_BUILD_ROAD = 25,
--- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -387,6 +387,9 @@ assert(load_index == SPR_AIRPORTX_BASE); load_index += LoadGrfFile("airports.grf", load_index, i++); + assert(load_index == SPR_ROADSTOP_BASE); + load_index += LoadGrfFile("roadstops.grf", load_index, i++); + /* Initialize the unicode to sprite mapping table */ InitializeUnicodeGlyphMap();
--- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1041,6 +1041,7 @@ STR_CONFIG_PATCHES_NONUNIFORM_STATIONS :{LTBLUE}Nonuniform stations: {ORANGE}{STRING1} STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL :{LTBLUE}New global pathfinding (NPF, overrides NTP): {ORANGE}{STRING1} STR_CONFIG_PATCHES_FREIGHT_TRAINS :{LTBLUE}Weight multiplier for freight to simulate heavy trains: {ORANGE}{STRING} +STR_CONFIG_PATCHES_STOP_ON_TOWN_ROAD :{LTBLUE}Allow drive-through road stops on town owned roads: {ORANGE}{STRING} STR_CONFIG_PATCHES_SMALL_AIRPORTS :{LTBLUE}Always allow small airports: {ORANGE}{STRING1} @@ -1584,6 +1585,8 @@ STR_1816_TREE_LINED_ROAD :Tree-lined road STR_1817_ROAD_VEHICLE_DEPOT :Road vehicle depot STR_1818_ROAD_RAIL_LEVEL_CROSSING :Road/rail level crossing +STR_CAN_T_REMOVE_BUS_STATION :{WHITE}Can't remove bus station... +STR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Can't remove lorry station... ##id 0x2000 STR_2000_TOWNS :{WHITE}Towns
--- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -1107,6 +1107,7 @@ STR_CONFIG_PATCHES_NONUNIFORM_STATIONS :{LTBLUE}Különböző vágánytípusok engedélyezése egy állomáson: {ORANGE}{STRING} STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL :{LTBLUE}Új útvonalkereső (NPF, felülbírálja az NTP-t): {ORANGE}{STRING} STR_CONFIG_PATCHES_FREIGHT_TRAINS :{LTBLUE}Tömegszorzó tehervonatoknak (szimulációs célból): {ORANGE}{STRING} +STR_CONFIG_PATCHES_STOP_ON_TOWN_ROAD :{LTBLUE}Áthajtható állomások engedélyezése városi utakra: {ORANGE}{STRING} STR_CONFIG_PATCHES_SMALL_AIRPORTS :{LTBLUE}Mindig engedélyezze a kis repülőtereket: {ORANGE}{STRING} @@ -1650,6 +1651,8 @@ STR_1816_TREE_LINED_ROAD :Fával szegélyezett út STR_1817_ROAD_VEHICLE_DEPOT :Garázs STR_1818_ROAD_RAIL_LEVEL_CROSSING :Út/vasút kereszteződés +STR_CAN_T_REMOVE_BUS_STATION :{WHITE}Nem távolíthatod el ezt a buszmegállót... +STR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Nem távolíthatod el ezt a teherautó megállót... ##id 0x2000 STR_2000_TOWNS :{WHITE}Városok
--- a/src/npf.cpp +++ b/src/npf.cpp @@ -279,6 +279,12 @@ if (IsLevelCrossing(tile)) cost += _patches.npf_crossing_penalty; break; + case MP_STATION: + cost = NPF_TILE_LENGTH; + /* Increase the cost for drive-through road stops */ + if (IsDriveThroughStopTile(tile)) cost += _patches.npf_road_drive_through_penalty; + break; + default: break; } @@ -453,7 +459,7 @@ if (IsTileType(tile, MP_RAILWAY) || /* Rail tile (also rail depot) */ IsRailwayStationTile(tile) || /* Rail station tile */ IsTileDepotType(tile, TRANSPORT_ROAD) || /* Road depot tile */ - IsRoadStopTile(tile) || /* Road station tile */ + IsStandardRoadStopTile(tile) || /* Road station tile (but not drive-through stops) */ IsTileDepotType(tile, TRANSPORT_WATER)) { /* Water depot tile */ return IsTileOwner(tile, owner); /* You need to own these tiles entirely to use them */ } @@ -529,8 +535,8 @@ } else if (IsBridgeTile(src_tile) && GetBridgeRampDirection(src_tile) == src_exitdir) { dst_tile = GetOtherBridgeEnd(src_tile); override_dst_check = true; - } else if (type != TRANSPORT_WATER && (IsRoadStopTile(src_tile) || IsTileDepotType(src_tile, type))) { - /* This is a road station or a train or road depot. We can enter and exit + } else if (type != TRANSPORT_WATER && (IsStandardRoadStopTile(src_tile) || IsTileDepotType(src_tile, type))) { + /* This is a road station (non drive-through) or a train or road depot. We can enter and exit * those from one side only. Trackdirs don't support that (yet), so we'll * do this here. */ @@ -599,7 +605,7 @@ } /* Determine available tracks */ - if (type != TRANSPORT_WATER && (IsRoadStopTile(dst_tile) || IsTileDepotType(dst_tile, type))){ + if (type != TRANSPORT_WATER && (IsStandardRoadStopTile(dst_tile) || IsTileDepotType(dst_tile, type))){ /* Road stations and road and train depots return 0 on GTTS, so we have to do this by hand... */ DiagDirection exitdir; if (IsRoadStopTile(dst_tile)) {
--- a/src/pathfind.cpp +++ b/src/pathfind.cpp @@ -296,7 +296,7 @@ if (tpf->tracktype == TRANSPORT_ROAD) { // road stops and depots now have a track (r4419) // don't enter road stop from the back - if (IsRoadStopTile(tile) && ReverseDiagDir(GetRoadStopDir(tile)) != direction) return; + if (IsStandardRoadStopTile(tile) && ReverseDiagDir(GetRoadStopDir(tile)) != direction) return; // don't enter road depot from the back if (IsTileDepotType(tile, TRANSPORT_ROAD) && ReverseDiagDir(GetRoadDepotDirection(tile)) != direction) return; }
--- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -16,6 +16,7 @@ #include "sound.h" #include "command.h" #include "variables.h" +#include "station_map.h" //needed for catchments #include "station.h" @@ -83,7 +84,7 @@ if (success) { SndPlayTileFx(SND_1F_SPLAT, tile); ResetObjectToPlace(); - BuildRoadOutsideStation(tile, (DiagDirection)p1); + if (!HASBIT(p2, 1)) BuildRoadOutsideStation(tile, (DiagDirection)p1); } } @@ -92,14 +93,45 @@ DoCommandP(tile, _road_depot_orientation, 0, CcRoadDepot, CMD_BUILD_ROAD_DEPOT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1807_CAN_T_BUILD_ROAD_VEHICLE)); } +static void PlaceRoadStop(TileIndex tile, uint32 p2, uint32 cmd) +{ + uint32 p1 = _road_station_picker_orientation; + + if (p1 >= DIAGDIR_END) { + SETBIT(p2, 1); // It's a drive-through stop + p1 -= DIAGDIR_END; // Adjust picker result to actual direction + + /* Only allow building over a road if its a straight road, + * facing the right direction and it belongs to the player */ + if ((IsTileType(tile, MP_STREET) && + GetRoadTileType(tile) == ROAD_TILE_NORMAL && + (IsTileOwner(tile, _current_player) || (_patches.road_stop_on_town_road && IsTileOwner(tile, OWNER_TOWN))) && + !(GetRoadBits(tile) & ((DiagDirection)p1 == DIAGDIR_NE ? ROAD_Y : ROAD_X)))) { + + cmd ^= CMD_AUTO; + SETBIT(p2, 2); // We're building over an existing road + if (IsTileOwner(tile, OWNER_TOWN)) SETBIT(p2, 3); // It's a town owned road + } + } + DoCommandP(tile, p1, p2, CcRoadDepot, cmd); +} + static void PlaceRoad_BusStation(TileIndex tile) { - DoCommandP(tile, _road_station_picker_orientation, RoadStop::BUS, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION)); + if (_remove_button_clicked) { + DoCommandP(tile, 0, RoadStop::BUS, CcPlaySound1D, CMD_REMOVE_ROAD_STOP | CMD_MSG(STR_CAN_T_REMOVE_BUS_STATION)); + } else { + PlaceRoadStop(tile, RoadStop::BUS, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1808_CAN_T_BUILD_BUS_STATION)); + } } static void PlaceRoad_TruckStation(TileIndex tile) { - DoCommandP(tile, _road_station_picker_orientation, RoadStop::TRUCK, CcRoadDepot, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION)); + if (_remove_button_clicked) { + DoCommandP(tile, 0, RoadStop::TRUCK, CcPlaySound1D, CMD_REMOVE_ROAD_STOP | CMD_MSG(STR_CAN_T_REMOVE_TRUCK_STATION)); + } else { + PlaceRoadStop(tile, RoadStop::TRUCK, CMD_BUILD_ROAD_STOP | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1809_CAN_T_BUILD_TRUCK_STATION)); + } } static void PlaceRoad_DemolishArea(TileIndex tile) @@ -195,7 +227,7 @@ case WE_CREATE: DisableWindowWidget(w, RTW_REMOVE); break; case WE_PAINT: - if (IsWindowWidgetLowered(w, RTW_ROAD_X) || IsWindowWidgetLowered(w, RTW_ROAD_Y)) { + if (IsWindowWidgetLowered(w, RTW_ROAD_X) || IsWindowWidgetLowered(w, RTW_ROAD_Y) || IsWindowWidgetLowered(w, RTW_BUS_STATION) || IsWindowWidgetLowered(w, RTW_TRUCK_STATION)) { EnableWindowWidget(w, RTW_REMOVE); } DrawWindowWidgets(w); @@ -428,7 +460,7 @@ switch (e->event) { case WE_CREATE: LowerWindowWidget(w, _road_station_picker_orientation + 3); - LowerWindowWidget(w, _station_show_coverage + 7); + LowerWindowWidget(w, _station_show_coverage + 9); break; case WE_PAINT: { @@ -445,13 +477,18 @@ SetTileSelectSize(1, 1); } - image = (w->window_class == WC_BUS_STATION) ? 0x47 : 0x43; + image = (w->window_class == WC_BUS_STATION) ? GFX_BUS_BASE : GFX_TRUCK_BASE; StationPickerDrawSprite(103, 35, RAILTYPE_BEGIN, image); StationPickerDrawSprite(103, 85, RAILTYPE_BEGIN, image+1); StationPickerDrawSprite(35, 85, RAILTYPE_BEGIN, image+2); StationPickerDrawSprite(35, 35, RAILTYPE_BEGIN, image+3); + image = (w->window_class == WC_BUS_STATION) ? GFX_BUS_BASE_EXT : GFX_TRUCK_BASE_EXT; + + StationPickerDrawSprite(171, 35, RAILTYPE_BEGIN, image); + StationPickerDrawSprite(171, 85, RAILTYPE_BEGIN, image + 1); + DrawStationCoverageAreaText(2, 146, ((w->window_class == WC_BUS_STATION) ? (1<<CT_PASSENGERS) : ~(1<<CT_PASSENGERS)), 3); @@ -460,17 +497,17 @@ case WE_CLICK: { switch (e->we.click.widget) { - case 3: case 4: case 5: case 6: + case 3: case 4: case 5: case 6: case 7: case 8: RaiseWindowWidget(w, _road_station_picker_orientation + 3); _road_station_picker_orientation = (DiagDirection)(e->we.click.widget - 3); LowerWindowWidget(w, _road_station_picker_orientation + 3); SndPlayFx(SND_15_BEEP); SetWindowDirty(w); break; - case 7: case 8: - RaiseWindowWidget(w, _station_show_coverage + 7); - _station_show_coverage = (e->we.click.widget != 7); - LowerWindowWidget(w, _station_show_coverage + 7); + case 9: case 10: + RaiseWindowWidget(w, _station_show_coverage + 9); + _station_show_coverage = (e->we.click.widget != 9); + LowerWindowWidget(w, _station_show_coverage + 9); SndPlayFx(SND_15_BEEP); SetWindowDirty(w); break; @@ -494,12 +531,14 @@ static const Widget _bus_station_picker_widgets[] = { { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_CAPTION, RESIZE_NONE, 7, 11, 139, 0, 13, STR_3042_BUS_STATION_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS}, -{ WWT_PANEL, RESIZE_NONE, 7, 0, 139, 14, 176, 0x0, STR_NULL}, +{ WWT_CAPTION, RESIZE_NONE, 7, 11, 206, 0, 13, STR_3042_BUS_STATION_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_PANEL, RESIZE_NONE, 7, 0, 206, 14, 176, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 14, 71, 136, 17, 66, 0x0, STR_3051_SELECT_BUS_STATION_ORIENTATION}, { WWT_PANEL, RESIZE_NONE, 14, 71, 136, 69, 118, 0x0, STR_3051_SELECT_BUS_STATION_ORIENTATION}, { WWT_PANEL, RESIZE_NONE, 14, 3, 68, 69, 118, 0x0, STR_3051_SELECT_BUS_STATION_ORIENTATION}, { WWT_PANEL, RESIZE_NONE, 14, 3, 68, 17, 66, 0x0, STR_3051_SELECT_BUS_STATION_ORIENTATION}, +{ WWT_PANEL, RESIZE_NONE, 14, 139, 204, 17, 66, 0x0, STR_3051_SELECT_BUS_STATION_ORIENTATION}, +{ WWT_PANEL, RESIZE_NONE, 14, 139, 204, 69, 118, 0x0, STR_3051_SELECT_BUS_STATION_ORIENTATION}, { WWT_TEXTBTN, RESIZE_NONE, 14, 10, 69, 133, 144, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE}, { WWT_TEXTBTN, RESIZE_NONE, 14, 70, 129, 133, 144, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA}, { WWT_LABEL, RESIZE_NONE, 7, 0, 139, 120, 133, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL}, @@ -507,7 +546,7 @@ }; static const WindowDesc _bus_station_picker_desc = { - WDP_AUTO, WDP_AUTO, 140, 177, + WDP_AUTO, WDP_AUTO, 207, 177, WC_BUS_STATION, WC_BUILD_TOOLBAR, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, _bus_station_picker_widgets, @@ -521,12 +560,14 @@ static const Widget _truck_station_picker_widgets[] = { { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_CAPTION, RESIZE_NONE, 7, 11, 139, 0, 13, STR_3043_TRUCK_STATION_ORIENT, STR_018C_WINDOW_TITLE_DRAG_THIS}, -{ WWT_PANEL, RESIZE_NONE, 7, 0, 139, 14, 176, 0x0, STR_NULL}, +{ WWT_CAPTION, RESIZE_NONE, 7, 11, 206, 0, 13, STR_3043_TRUCK_STATION_ORIENT, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_PANEL, RESIZE_NONE, 7, 0, 206, 14, 176, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 14, 71, 136, 17, 66, 0x0, STR_3052_SELECT_TRUCK_LOADING_BAY}, { WWT_PANEL, RESIZE_NONE, 14, 71, 136, 69, 118, 0x0, STR_3052_SELECT_TRUCK_LOADING_BAY}, { WWT_PANEL, RESIZE_NONE, 14, 3, 68, 69, 118, 0x0, STR_3052_SELECT_TRUCK_LOADING_BAY}, { WWT_PANEL, RESIZE_NONE, 14, 3, 68, 17, 66, 0x0, STR_3052_SELECT_TRUCK_LOADING_BAY}, +{ WWT_PANEL, RESIZE_NONE, 14, 139, 204, 17, 66, 0x0, STR_3052_SELECT_TRUCK_LOADING_BAY}, +{ WWT_PANEL, RESIZE_NONE, 14, 139, 204, 69, 118, 0x0, STR_3052_SELECT_TRUCK_LOADING_BAY}, { WWT_TEXTBTN, RESIZE_NONE, 14, 10, 69, 133, 144, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE}, { WWT_TEXTBTN, RESIZE_NONE, 14, 70, 129, 133, 144, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA}, { WWT_LABEL, RESIZE_NONE, 7, 0, 139, 120, 133, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL}, @@ -534,7 +575,7 @@ }; static const WindowDesc _truck_station_picker_desc = { - WDP_AUTO, WDP_AUTO, 140, 177, + WDP_AUTO, WDP_AUTO, 207, 177, WC_TRUCK_STATION, WC_BUILD_TOOLBAR, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, _truck_station_picker_widgets,
--- a/src/road_map.cpp +++ b/src/road_map.cpp @@ -24,6 +24,7 @@ case MP_STATION: if (!IsRoadStopTile(tile)) return ROAD_NONE; + if (IsDriveThroughStopTile(tile)) return (GetRoadStopDir(tile) == DIAGDIR_NE) ? ROAD_X : ROAD_Y; return DiagDirToRoadBits(GetRoadStopDir(tile)); case MP_TUNNELBRIDGE: @@ -45,7 +46,7 @@ uint32 r; // Don't allow local authorities to build roads through road depots or road stops. - if ((IsTileType(tile, MP_STREET) && IsTileDepotType(tile, TRANSPORT_ROAD)) || IsTileType(tile, MP_STATION)) { + if ((IsTileType(tile, MP_STREET) && IsTileDepotType(tile, TRANSPORT_ROAD)) || (IsTileType(tile, MP_STATION) && !IsDriveThroughStopTile(tile))) { return TRACK_BIT_NONE; }
--- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -1080,7 +1080,8 @@ /* Road depot owned by another player or with the wrong orientation */ trackdirs = TRACKDIR_BIT_NONE; } - } else if (IsTileType(tile, MP_STATION) && IsRoadStopTile(tile)) { + } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) { + /* Standard road stop (drive-through stops are treated as normal road) */ if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir) { /* different station owner or wrong orientation */ trackdirs = TRACKDIR_BIT_NONE; @@ -1093,7 +1094,7 @@ trackdirs = TRACKDIR_BIT_NONE; } else { /* Proper station type, check if there is free loading bay */ - if (!_patches.roadveh_queue && + if (!_patches.roadveh_queue && IsStandardRoadStopTile(tile) && !GetRoadStopByTile(tile, rstype)->HasFreeBay()) { /* Station is full and RV queuing is off */ trackdirs = TRACKDIR_BIT_NONE; @@ -1167,7 +1168,8 @@ goto do_it; } } else if (IsTileType(desttile, MP_STATION)) { - if (IsRoadStop(desttile)) { + /* For drive-through stops we can head for the actual station tile */ + if (IsStandardRoadStopTile(desttile)) { dir = GetRoadStopDir(desttile); do_it:; /* When we are heading for a depot or station, we just @@ -1242,9 +1244,11 @@ /* Start frames for when a vehicle enters a tile/changes its state. * The start frame is different for vehicles that turned around or * are leaving the depot as the do not start at the edge of the tile */ - RVC_DEFAULT_START_FRAME = 0, - RVC_TURN_AROUND_START_FRAME = 1, - RVC_DEPOT_START_FRAME = 6 + RVC_DEFAULT_START_FRAME = 0, + RVC_TURN_AROUND_START_FRAME = 1, + RVC_DEPOT_START_FRAME = 6, + /* Stop frame for a vehicle in a drive-through stop */ + RVC_DRIVE_THROUGH_STOP_FRAME = 7 }; typedef struct RoadDriveEntry { @@ -1376,8 +1380,12 @@ return; } - /* Get move position data for next frame */ - rd = _road_drive_data[(v->u.road.state + (_opt.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking][v->u.road.frame + 1]; + /* Get move position data for next frame. + * For a drive-through road stop use 'straight road' move data. + * In this case v->u.road.state is masked to give the road stop entry direction. */ + rd = _road_drive_data[( + (HASBIT(v->u.road.state, RVS_IN_DT_ROAD_STOP) ? v->u.road.state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->u.road.state) + + (_opt.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking][v->u.road.frame + 1]; if (rd.x & RDE_NEXT_TILE) { TileIndex tile = v->tile + TileOffsByDiagDir(rd.x & 3); @@ -1417,8 +1425,8 @@ goto again; } - if (IS_BYTE_INSIDE(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) { - if (IsReversingRoadTrackdir(dir)) { + if (IS_BYTE_INSIDE(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) { + if (IsReversingRoadTrackdir(dir) && IS_BYTE_INSIDE(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) { /* New direction is trying to turn vehicle around. * We can't turn at the exit of a road stop so wait.*/ v->cur_speed = 0; @@ -1427,9 +1435,13 @@ if (IsRoadStop(v->tile)) { RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile)); - /* Vehicle is leaving a road stop tile, mark bay as free */ - rs->FreeBay(HASBIT(v->u.road.state, RVS_USING_SECOND_BAY)); - rs->SetEntranceBusy(false); + /* Vehicle is leaving a road stop tile, mark bay as free + * For drive-through stops, only do it if the vehicle stopped here */ + if (IsStandardRoadStopTile(v->tile) || HASBIT(v->u.road.state, RVS_IS_STOPPING)) { + rs->FreeBay(HASBIT(v->u.road.state, RVS_USING_SECOND_BAY)); + CLRBIT(v->u.road.state, RVS_IS_STOPPING); + } + if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(false); } } @@ -1523,8 +1535,18 @@ } } - if (v->u.road.state >= RVSB_IN_ROAD_STOP && - _road_veh_data_1[v->u.road.state - RVSB_IN_ROAD_STOP + (_opt.road_side << RVS_DRIVE_SIDE)] == v->u.road.frame) { + /* If the vehicle is in a normal road stop and the frame equals the stop frame OR + * if the vehicle is in a drive-through road stop and this is the destination station + * and it's the correct type of stop (bus or truck) and the frame equals the stop frame... + * (the station test and stop type test ensure that other vehicles, using the road stop as + * a through route, do not stop) */ + if ((IS_BYTE_INSIDE(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) && + _road_veh_data_1[v->u.road.state - RVSB_IN_ROAD_STOP + (_opt.road_side << RVS_DRIVE_SIDE)] == v->u.road.frame) || + (IS_BYTE_INSIDE(v->u.road.state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && + v->current_order.dest == GetStationIndex(v->tile) && + GetRoadStopType(v->tile) == ((v->cargo_type == CT_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK) && + v->u.road.frame == RVC_DRIVE_THROUGH_STOP_FRAME)) { + RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile)); Station* st = GetStationByTile(v->tile); @@ -1536,6 +1558,31 @@ /* Vehicle has arrived at a bay in a road stop */ Order old_order; + if (IsDriveThroughStopTile(v->tile)) { + TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction)); + RoadStop::Type type = (v->cargo_type == CT_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK; + + assert(HASBIT(v->u.road.state, RVS_IS_STOPPING)); + + /* Check if next inline bay is free */ + if (IsDriveThroughStopTile(next_tile) && (GetRoadStopType(next_tile) == type)) { + RoadStop *rs_n = GetRoadStopByTile(next_tile, type); + + if (rs_n->IsFreeBay(HASBIT(v->u.road.state, RVS_USING_SECOND_BAY))) { + /* Bay in next stop along is free - use it */ + ClearSlot(v); + rs_n->num_vehicles++; + v->u.road.slot = rs_n; + v->dest_tile = rs_n->xy; + v->u.road.slot_age = 14; + + v->u.road.frame++; + RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y)); + return; + } + } + } + rs->SetEntranceBusy(false); v->last_station_visited = GetStationIndex(v->tile); @@ -1573,7 +1620,7 @@ ClearSlot(v); } - rs->SetEntranceBusy(true); + if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true); if (rs == v->u.road.slot) { /* We are leaving the correct station */
--- a/src/saveload.cpp +++ b/src/saveload.cpp @@ -30,7 +30,7 @@ #include "variables.h" #include <setjmp.h> -extern const uint16 SAVEGAME_VERSION = 46; +extern const uint16 SAVEGAME_VERSION = 47; uint16 _sl_version; /// the major savegame version identifier byte _sl_minor_version; /// the minor savegame version, DO NOT USE!
--- a/src/settings.cpp +++ b/src/settings.cpp @@ -1340,6 +1340,7 @@ SDT_BOOL(Patches, serviceathelipad, 0, 0, true, STR_CONFIG_PATCHES_SERVICEATHELIPAD, NULL), SDT_BOOL(Patches, modified_catchment, 0, 0, true, STR_CONFIG_PATCHES_CATCHMENT, NULL), SDT_CONDBOOL(Patches, gradual_loading, 40, SL_MAX_VERSION, 0, 0, true, STR_CONFIG_PATCHES_GRADUAL_LOADING, NULL), + SDT_CONDBOOL(Patches, road_stop_on_town_road, 47, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_PATCHES_STOP_ON_TOWN_ROAD, NULL), /***************************************************************************/ /* Economy section of the GUI-configure patches window */ @@ -1431,6 +1432,8 @@ SDT_VAR(Patches, npf_road_curve_penalty, SLE_UINT, 0, 0, 1, 0, 100000, 0, STR_NULL, NULL), /* This is the penalty for level crossings, for both road and rail vehicles */ SDT_VAR(Patches, npf_crossing_penalty, SLE_UINT, 0, 0, (3 * NPF_TILE_LENGTH), 0, 100000, 0, STR_NULL, NULL), + /* This is the penalty for drive-through road, stops. */ + SDT_CONDVAR (Patches, npf_road_drive_through_penalty, SLE_UINT, 47, SL_MAX_VERSION, 0, 0, 8 * NPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL), // The maximum number of nodes to search @@ -1464,6 +1467,7 @@ SDT_CONDVAR (Patches, yapf.road_slope_penalty , SLE_UINT, 33, SL_MAX_VERSION, 0, 0, 2 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL), SDT_CONDVAR (Patches, yapf.road_curve_penalty , SLE_UINT, 33, SL_MAX_VERSION, 0, 0, 1 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL), SDT_CONDVAR (Patches, yapf.road_crossing_penalty , SLE_UINT, 33, SL_MAX_VERSION, 0, 0, 3 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL), + SDT_CONDVAR (Patches, yapf.road_stop_penalty , SLE_UINT, 47, SL_MAX_VERSION, 0, 0, 8 * YAPF_TILE_LENGTH, 0, 1000000, 0, STR_NULL, NULL), /***************************************************************************/ /* Terrain genation related patch options */
--- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -599,6 +599,7 @@ "serviceathelipad", "modified_catchment", "gradual_loading", + "road_stop_on_town_road", }; static const char *_patches_economy[] = {
--- a/src/station.cpp +++ b/src/station.cpp @@ -502,6 +502,13 @@ return GB(status, 0, MAX_BAY_COUNT) != 0; } +/** Checks whether the given bay is free in this road stop */ +bool RoadStop::IsFreeBay(uint nr) const +{ + assert(nr < MAX_BAY_COUNT); + return HASBIT(status, nr); +} + /** * Allocates a bay * @return the allocated bay number @@ -520,6 +527,16 @@ } /** + * Allocates a bay in a drive-through road stop + * @param nr the number of the bay to allocate + */ +void RoadStop::AllocateDriveThroughBay(uint nr) +{ + assert(nr < MAX_BAY_COUNT); + CLRBIT(status, nr); +} + +/** * Frees the given bay * @param nr the number of the bay to free */
--- a/src/station.h +++ b/src/station.h @@ -66,7 +66,9 @@ /* For accessing status */ bool HasFreeBay() const; + bool IsFreeBay(uint nr) const; uint AllocateBay(); + void AllocateDriveThroughBay(uint nr); void FreeBay(uint nr); bool IsEntranceBusy() const; void SetEntranceBusy(bool busy);
--- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -35,6 +35,7 @@ #include "date.h" #include "helpers.hpp" #include "misc/autoptr.hpp" +#include "road.h" /** * Called if a new block is added to the station-pool @@ -1247,7 +1248,10 @@ /** Build a bus or truck stop * @param tile tile to build the stop at * @param p1 entrance direction (DiagDirection) - * @param p2 0 for Bus stops, 1 for truck stops + * @param p2 bit 0: 0 for Bus stops, 1 for truck stops + * bit 1: 0 for normal, 1 for drive-through + * bit 2: 0 for normal, 1 for build over road + * bit 3: 0 for player owned road, 1 for town owned road */ int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { @@ -1255,19 +1259,29 @@ RoadStop *road_stop; int32 cost; int32 ret; - bool type = !!p2; + bool type = HASBIT(p2, 0); + bool is_drive_through = HASBIT(p2, 1); + Owner cur_owner = _current_player; /* Saveguard the parameters */ if (!IsValidDiagDirection((DiagDirection)p1)) return CMD_ERROR; + /* If it is a drive-through stop check for valid axis */ + if (is_drive_through && !IsValidAxis((Axis)p1)) return CMD_ERROR; + /* If overbuilding a road check tile is a valid road tile */ + if (HASBIT(p2, 2) && !(IsTileType(tile, MP_STREET) && GetRoadTileType(tile) == ROAD_TILE_NORMAL)) return CMD_ERROR; + /* If overbuilding a town road,check tile is town owned and patch setting is enabled */ + if (HASBIT(p2, 3) && !(_patches.road_stop_on_town_road && IsTileOwner(tile, OWNER_TOWN))) return CMD_ERROR; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile)) return CMD_ERROR; - ret = CheckFlatLandBelow(tile, 1, 1, flags, 1 << p1, NULL); + if (is_drive_through & HASBIT(p2, 3)) _current_player = OWNER_TOWN; + ret = CheckFlatLandBelow(tile, 1, 1, flags, is_drive_through ? 5 << p1 : 1 << p1, NULL); + _current_player = cur_owner; if (CmdFailed(ret)) return ret; - cost = ret; + cost = HASBIT(p2, 2) ? 0 : ret; // Don't add cost of clearing road when overbuilding st = GetStationAround(tile, 1, 1, INVALID_STATION); if (st == CHECK_STATIONS_ERR) return CMD_ERROR; @@ -1333,7 +1347,8 @@ st->rect.BeforeAddTile(tile, StationRect::ADD_TRY); - MakeRoadStop(tile, st->owner, st->index, type ? RoadStop::TRUCK : RoadStop::BUS, (DiagDirection)p1); + MakeRoadStop(tile, st->owner, st->index, type ? RoadStop::TRUCK : RoadStop::BUS, is_drive_through, (DiagDirection)p1); + if (is_drive_through & HASBIT(p2, 3)) SetStopBuiltOnTownRoad(tile); UpdateStationVirtCoordDirty(st); UpdateStationAcceptance(st, false); @@ -1395,7 +1410,44 @@ return (is_truck) ? _price.remove_truck_station : _price.remove_bus_station; } - +/** Remove a bus or truck stop + * @param tile tile to remove the stop from + * @param p1 not used + * @param p2 bit 0: 0 for Bus stops, 1 for truck stops + */ +int32 CmdRemoveRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) +{ + Station* st; + bool is_drive_through; + bool is_towns_road = false; + RoadBits road_bits; + int32 ret; + + /* Make sure the specified tile is a road stop of the correct type */ + if (!IsTileType(tile, MP_STATION) || !IsRoadStop(tile) || (uint32)GetRoadStopType(tile) != p2) return CMD_ERROR; + st = GetStationByTile(tile); + /* Save the stop info before it is removed */ + is_drive_through = IsDriveThroughStopTile(tile); + road_bits = GetAnyRoadBits(tile); + if (is_drive_through) is_towns_road = GetStopBuiltOnTownRoad(tile); + + ret = RemoveRoadStop(st, flags, tile); + + /* If the stop was a drive-through stop replace the road */ + if ((flags & DC_EXEC) && !CmdFailed(ret) && is_drive_through) { + uint index = 0; + Owner cur_owner = _current_player; + + if (is_towns_road) { + index = ClosestTownFromTile(tile, _patches.dist_local_authority)->index; + _current_player = OWNER_TOWN; + } + DoCommand(tile, road_bits, index, DC_EXEC, CMD_BUILD_ROAD); + _current_player = cur_owner; + } + + return ret; +} // FIXME -- need to move to its corresponding Airport variable // Country Airfield (small) @@ -2227,6 +2279,27 @@ /* Attempt to allocate a parking bay in a road stop */ RoadStop *rs = GetRoadStopByTile(tile, GetRoadStopType(tile)); + if (IsDriveThroughStopTile(tile)) { + /* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */ + byte side = ((DirToDiagDir(v->direction) == ReverseDiagDir(GetRoadStopDir(tile))) == (v->u.road.overtaking == 0)) ? 0 : 1; + + if (!rs->IsFreeBay(side)) return VETSB_CANNOT_ENTER; + + /* Check if the vehicle is stopping at this road stop */ + if (GetRoadStopType(tile) == ((v->cargo_type == CT_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK) && + v->current_order.dest == GetStationIndex(tile)) { + SETBIT(v->u.road.state, RVS_IS_STOPPING); + rs->AllocateDriveThroughBay(side); + } + + /* Indicate if vehicle is using second bay. */ + if (side == 1) SETBIT(v->u.road.state, RVS_USING_SECOND_BAY); + /* Indicate a drive-through stop */ + SETBIT(v->u.road.state, RVS_IN_DT_ROAD_STOP); + return VETSB_CONTINUE; + } + + /* For normal (non drive-through) road stops */ /* Check if station is busy or if there are no free bays. */ if (rs->IsEntranceBusy() || !rs->HasFreeBay()) return VETSB_CANNOT_ENTER; @@ -2693,7 +2766,13 @@ case STATION_RAIL: return RemoveRailroadStation(st, tile, flags); case STATION_AIRPORT: return RemoveAirport(st, flags); case STATION_TRUCK: - case STATION_BUS: return RemoveRoadStop(st, flags, tile); + if (IsDriveThroughStopTile(tile) && GetStopBuiltOnTownRoad(tile)) + return_cmd_error(STR_3047_MUST_DEMOLISH_TRUCK_STATION); + return RemoveRoadStop(st, flags, tile); + case STATION_BUS: + if (IsDriveThroughStopTile(tile) && GetStopBuiltOnTownRoad(tile)) + return_cmd_error(STR_3046_MUST_DEMOLISH_BUS_STATION); + return RemoveRoadStop(st, flags, tile); case STATION_BUOY: return RemoveBuoy(st, flags); case STATION_DOCK: return RemoveDock(st, flags); default: break;
--- a/src/station_map.h +++ b/src/station_map.h @@ -42,7 +42,9 @@ GFX_RADAR_DISTRICTWE_LAST = 156, GFX_WINDSACK_INTERCON_FIRST = 164, GFX_WINDSACK_INTERCON_LAST = 167, - GFX_BASE_END = 168 + GFX_TRUCK_BASE_EXT = 168, + GFX_BUS_BASE_EXT = 170, + GFX_BASE_END = 172 }; enum { @@ -51,7 +53,9 @@ TRUCK_SIZE = GFX_BUS_BASE - GFX_TRUCK_BASE, BUS_SIZE = GFX_OILRIG_BASE - GFX_BUS_BASE, DOCK_SIZE_TOTAL = GFX_BUOY_BASE - GFX_DOCK_BASE, - AIRPORT_SIZE_EXTENDED = GFX_BASE_END - GFX_AIRPORT_BASE_EXTENDED + AIRPORT_SIZE_EXTENDED = GFX_TRUCK_BASE_EXT - GFX_AIRPORT_BASE_EXTENDED, + TRUCK_SIZE_EXT = GFX_BUS_BASE_EXT - GFX_TRUCK_BASE_EXT, + BUS_SIZE_EXT = GFX_BASE_END - GFX_BUS_BASE_EXT, }; typedef enum HangarTiles { @@ -125,12 +129,14 @@ static inline bool IsTruckStop(TileIndex t) { - return IS_BYTE_INSIDE(GetStationGfx(t), GFX_TRUCK_BASE, GFX_TRUCK_BASE + TRUCK_SIZE); + return (IS_BYTE_INSIDE(GetStationGfx(t), GFX_TRUCK_BASE, GFX_TRUCK_BASE + TRUCK_SIZE)) || + (IS_BYTE_INSIDE(GetStationGfx(t), GFX_TRUCK_BASE_EXT, GFX_TRUCK_BASE_EXT + TRUCK_SIZE_EXT)); } static inline bool IsBusStop(TileIndex t) { - return IS_BYTE_INSIDE(GetStationGfx(t), GFX_BUS_BASE, GFX_BUS_BASE + BUS_SIZE); + return (IS_BYTE_INSIDE(GetStationGfx(t), GFX_BUS_BASE, GFX_BUS_BASE + BUS_SIZE)) || + (IS_BYTE_INSIDE(GetStationGfx(t), GFX_BUS_BASE_EXT, GFX_BUS_BASE_EXT + BUS_SIZE_EXT)); } static inline bool IsRoadStop(TileIndex t) @@ -143,13 +149,44 @@ return IsTileType(t, MP_STATION) && IsRoadStop(t); } +static inline bool IsStandardRoadStopTile(TileIndex t) +{ + return IsTileType(t, MP_STATION) && + (IS_BYTE_INSIDE(GetStationGfx(t), GFX_TRUCK_BASE, GFX_TRUCK_BASE + TRUCK_SIZE) || + IS_BYTE_INSIDE(GetStationGfx(t), GFX_BUS_BASE, GFX_BUS_BASE + BUS_SIZE)); +} + +static inline bool IsDriveThroughStopTile(TileIndex t) +{ + return IsTileType(t, MP_STATION) && + (IS_BYTE_INSIDE(GetStationGfx(t), GFX_TRUCK_BASE_EXT, GFX_TRUCK_BASE_EXT + TRUCK_SIZE_EXT) || + IS_BYTE_INSIDE(GetStationGfx(t), GFX_BUS_BASE_EXT, GFX_BUS_BASE_EXT + BUS_SIZE_EXT)); +} + +static inline bool GetStopBuiltOnTownRoad(TileIndex t) +{ + assert(IsDriveThroughStopTile(t)); + return HASBIT(_m[t].m6, 3); +} + +static inline void SetStopBuiltOnTownRoad(TileIndex t) +{ + assert(IsDriveThroughStopTile(t)); + SETBIT(_m[t].m6, 3); +} + /** * Gets the direction the road stop entrance points towards. */ static inline DiagDirection GetRoadStopDir(TileIndex t) { + StationGfx gfx = GetStationGfx(t); assert(IsRoadStopTile(t)); - return (DiagDirection)((GetStationGfx(t) - GFX_TRUCK_BASE) & 3); + if (gfx < GFX_TRUCK_BASE_EXT) { + return (DiagDirection)((gfx - GFX_TRUCK_BASE) & 3); + } else { + return (DiagDirection)((gfx - GFX_TRUCK_BASE_EXT) & 1); + } } static inline bool IsOilRig(TileIndex t) @@ -275,9 +312,13 @@ SetRailType(t, rt); } -static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStop::Type rst, DiagDirection d) +static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStop::Type rst, bool is_drive_through, DiagDirection d) { - MakeStation(t, o, sid, (rst == RoadStop::BUS ? GFX_BUS_BASE : GFX_TRUCK_BASE) + d); + if (is_drive_through) { + MakeStation(t, o, sid, (rst == RoadStop::BUS ? GFX_BUS_BASE_EXT : GFX_TRUCK_BASE_EXT) + d); + } else { + MakeStation(t, o, sid, (rst == RoadStop::BUS ? GFX_BUS_BASE : GFX_TRUCK_BASE) + d); + } } static inline void MakeAirport(TileIndex t, Owner o, StationID sid, byte section)
--- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -117,6 +117,16 @@ SPR_GRASS_RIGHT = SPR_AIRPORTX_BASE + 13, SPR_GRASS_LEFT = SPR_AIRPORTX_BASE + 14, + SPR_ROADSTOP_BASE = SPR_AIRPORTX_BASE + 15, // The sprites used for drive-through road stops + SPR_BUS_STOP_DT_Y_W = SPR_ROADSTOP_BASE, + SPR_BUS_STOP_DT_Y_E = SPR_ROADSTOP_BASE + 1, + SPR_BUS_STOP_DT_X_W = SPR_ROADSTOP_BASE + 2, + SPR_BUS_STOP_DT_X_E = SPR_ROADSTOP_BASE + 3, + SPR_TRUCK_STOP_DT_Y_W = SPR_ROADSTOP_BASE + 4, + SPR_TRUCK_STOP_DT_Y_E = SPR_ROADSTOP_BASE + 5, + SPR_TRUCK_STOP_DT_X_W = SPR_ROADSTOP_BASE + 6, + SPR_TRUCK_STOP_DT_X_E = SPR_ROADSTOP_BASE + 7, + /* Manager face sprites */ SPR_GRADIENT = 874, // background gradient behind manager face @@ -295,6 +305,10 @@ SPR_PYLON_NS_W = SPR_ELRAIL_BASE + 37, SPR_PYLON_NS_E = SPR_ELRAIL_BASE + 38, + /* sprites for roads */ + SPR_ROAD_PAVED_STRAIGHT_Y = 1313, + SPR_ROAD_PAVED_STRAIGHT_X = 1314, + /* sprites for airports and airfields*/ /* Small airports are AIRFIELD, everything else is AIRPORT */ SPR_HELIPORT = 2633,
--- a/src/table/station_land.h +++ b/src/table/station_land.h @@ -959,6 +959,34 @@ TILE_SEQ_END() }; +// drive-through truck stop X +static const DrawTileSeqStruct _station_display_datas_0168[] = { + { 1, 0, 0, 14, 3, 10, SPR_TRUCK_STOP_DT_X_W | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + { 1, 13, 0, 14, 1, 10, SPR_TRUCK_STOP_DT_X_E | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + TILE_SEQ_END() +}; + +// drive-through truck stop Y +static const DrawTileSeqStruct _station_display_datas_0169[] = { + { 13, 1, 0, 1, 14, 10, SPR_TRUCK_STOP_DT_Y_W | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + { 0, 1, 0, 3, 14, 10, SPR_TRUCK_STOP_DT_Y_E | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + TILE_SEQ_END() +}; + +// drive-through bus stop X +static const DrawTileSeqStruct _station_display_datas_0170[] = { + { 5, 0, 0, 8, 3, 10, SPR_BUS_STOP_DT_X_W | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + { 5, 14, 0, 8, 1, 10, SPR_BUS_STOP_DT_X_E | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + TILE_SEQ_END() +}; + +// drive-through bus stop Y +static const DrawTileSeqStruct _station_display_datas_0171[] = { + { 13, 5, 0, 1, 8, 10, SPR_BUS_STOP_DT_Y_W | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + { 0, 5, 0, 3, 8, 10, SPR_BUS_STOP_DT_Y_E | (1 << PALETTE_MODIFIER_COLOR), PAL_NONE }, + TILE_SEQ_END() +}; + static const DrawTileSprites _station_display_datas[] = { { SPR_RAIL_TRACK_X, PAL_NONE, _station_display_datas_0 }, { SPR_RAIL_TRACK_Y, PAL_NONE, _station_display_datas_1 }, @@ -1128,4 +1156,8 @@ { SPR_FLAT_GRASS_TILE, PAL_NONE, _station_display_datas_59 }, { SPR_FLAT_GRASS_TILE, PAL_NONE, _station_display_datas_60 }, { SPR_FLAT_GRASS_TILE, PAL_NONE, _station_display_datas_61 }, + { SPR_ROAD_PAVED_STRAIGHT_X, PAL_NONE, _station_display_datas_0168 }, + { SPR_ROAD_PAVED_STRAIGHT_Y, PAL_NONE, _station_display_datas_0169 }, + { SPR_ROAD_PAVED_STRAIGHT_X, PAL_NONE, _station_display_datas_0170 }, + { SPR_ROAD_PAVED_STRAIGHT_Y, PAL_NONE, _station_display_datas_0171 } };
--- a/src/variables.h +++ b/src/variables.h @@ -166,6 +166,7 @@ bool autosave_on_exit; // save an autosave when you quit the game, but do not ask "Do you really want to quit?" byte max_num_autosaves; // controls how many autosavegames are made before the game starts to overwrite (names them 0 to max_num_autosaves - 1) bool extra_dynamite; // extra dynamite + bool road_stop_on_town_road; // allow building of drive-through road stops on town owned roads bool never_expire_vehicles; // never expire vehicles byte extend_vehicle_life; // extend vehicle life by this many years @@ -211,6 +212,7 @@ uint32 npf_water_curve_penalty; /* The penalty for curves */ uint32 npf_road_curve_penalty; /* The penalty for curves */ uint32 npf_crossing_penalty; /* The penalty for level crossings */ + uint32 npf_road_drive_through_penalty; /* The penalty for going through a drive-through road stop */ bool population_in_label; // Show the population of a town in his label?
--- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2756,9 +2756,11 @@ if (IsRoadVehInDepot(v)) /* We'll assume the road vehicle is facing outwards */ return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile)); - if (IsRoadStopTile(v->tile)) /* We'll assume the road vehicle is facing outwards */ + if (IsStandardRoadStopTile(v->tile)) /* We'll assume the road vehicle is facing outwards */ return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); /* Road vehicle in a station */ + if (IsDriveThroughStopTile(v->tile)) return DiagdirToDiagTrackdir(DirToDiagDir(v->direction)); + /* If vehicle's state is a valid track direction (vehicle is not turning around) return it */ if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state;
--- a/src/vehicle.h +++ b/src/vehicle.h @@ -45,14 +45,18 @@ /* Bit numbers */ RVS_USING_SECOND_BAY = 1, ///< Only used while in a road stop + RVS_IS_STOPPING = 2, ///< Only used for drive-through stops. Vehicle will stop here RVS_DRIVE_SIDE = 4, ///< Only used when retrieving move data and for turning vehicles RVS_IN_ROAD_STOP = 5, ///< The vehicle is in a road stop + RVS_IN_DT_ROAD_STOP = 6, ///< The vehicle is in a drive-through road stop /* Bit sets of the above specified bits */ RVSB_USING_SECOND_BAY = 1 << RVS_USING_SECOND_BAY, ///< Only used while in a road stop RVSB_DRIVE_SIDE = 1 << RVS_DRIVE_SIDE, ///< Only used when retrieving move data and for turning vehicles RVSB_IN_ROAD_STOP = 1 << RVS_IN_ROAD_STOP, ///< The vehicle is in a road stop RVSB_IN_ROAD_STOP_END = RVSB_IN_ROAD_STOP + TRACKDIR_END, + RVSB_IN_DT_ROAD_STOP = 1 << RVS_IN_DT_ROAD_STOP, ///< The vehicle is in a drive-through road stop + RVSB_IN_DT_ROAD_STOP_END = RVSB_IN_DT_ROAD_STOP + TRACKDIR_END, RVSB_TRACKDIR_MASK = 0x0F, ///< The mask used to extract track dirs RVSB_ROAD_STOP_TRACKDIR_MASK = 0x09 ///< Only bits 0 and 3 are used to encode the trackdir for road stops
--- a/src/yapf/follow_track.hpp +++ b/src/yapf/follow_track.hpp @@ -121,8 +121,8 @@ /** return true if we can leave m_old_tile in m_exitdir */ FORCEINLINE bool CanExitOldTile() { - // road stop can be left at one direction only - if (IsRoadTT() && IsRoadStopTile(m_old_tile)) { + // road stop can be left at one direction only unless it's a drive-through stop + if (IsRoadTT() && IsStandardRoadStopTile(m_old_tile)) { DiagDirection exitdir = GetRoadStopDir(m_old_tile); if (exitdir != m_exitdir) return false; @@ -140,8 +140,8 @@ /** return true if we can enter m_new_tile from m_exitdir */ FORCEINLINE bool CanEnterNewTile() { - if (IsRoadTT() && IsRoadStopTile(m_new_tile)) { - // road stop can be entered from one direction only + if (IsRoadTT() && IsStandardRoadStopTile(m_new_tile)) { + // road stop can be entered from one direction only unless it's a drive-through stop DiagDirection exitdir = GetRoadStopDir(m_new_tile); if (ReverseDiagDir(exitdir) != m_exitdir) return false;
--- a/src/yapf/yapf_road.cpp +++ b/src/yapf/yapf_road.cpp @@ -51,6 +51,10 @@ if (IsLevelCrossing(tile)) cost += Yapf().PfGetSettings().road_crossing_penalty; break; + case MP_STATION: + if (IsDriveThroughStopTile(tile)) + cost += Yapf().PfGetSettings().road_stop_penalty; + break; default: break; @@ -76,6 +80,10 @@ // base tile cost depending on distance between edges segment_cost += Yapf().OneTileCost(tile, trackdir); + const Vehicle* v = Yapf().GetVehicle(); + // we have reached the vehicle's destination - segment should end here to avoid target skipping + if (v->current_order.type == OT_GOTO_STATION && tile == v->dest_tile) break; + // stop if we have just entered the depot if (IsTileDepotType(tile, TRANSPORT_ROAD) && trackdir == DiagdirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) { // next time we will reverse and leave the depot @@ -103,7 +111,6 @@ // add min/max speed penalties int min_speed = 0; int max_speed = F.GetSpeedLimit(&min_speed); - const Vehicle* v = Yapf().GetVehicle(); if (max_speed < v->max_speed) segment_cost += 1 * (v->max_speed - max_speed); if (min_speed > v->max_speed) segment_cost += 10 * (min_speed - v->max_speed);
--- a/src/yapf/yapf_settings.h +++ b/src/yapf/yapf_settings.h @@ -39,6 +39,7 @@ YS_DEF(uint32, road_slope_penalty) ///< penalty for up-hill slope YS_DEF(uint32, road_curve_penalty) ///< penalty for curves YS_DEF(uint32, road_crossing_penalty) ///< penalty for level crossing + YS_DEF(uint32, road_stop_penalty) ///< penalty for going through a drive-through road stop YS_DEF(bool , rail_firstred_twoway_eol) ///< treat first red two-way signal as dead end YS_DEF(uint32, rail_firstred_penalty) ///< penalty for first red signal YS_DEF(uint32, rail_firstred_exit_penalty) ///< penalty for first red exit signal