(svn r8735) -Feature: drive-through road stops made possible by the hard work of mart3p.

This commit is contained in:
rubidium 2007-02-14 16:37:16 +00:00
parent 39b73119ca
commit 0e8f006dc1
26 changed files with 372 additions and 60 deletions

BIN
bin/data/roadstops.grf Normal file

Binary file not shown.

View File

@ -45,6 +45,7 @@ DEF_COMMAND(CmdRenameWaypoint);
DEF_COMMAND(CmdRemoveTrainWaypoint);
DEF_COMMAND(CmdBuildRoadStop);
DEF_COMMAND(CmdRemoveRoadStop);
DEF_COMMAND(CmdBuildLongRoad);
DEF_COMMAND(CmdRemoveLongRoad);
@ -188,7 +189,7 @@ static const Command _command_proc_table[] = {
{NULL, 0}, /* 19 */
{NULL, 0}, /* 20 */
{CmdBuildRoadStop, 0}, /* 21 */
{NULL, 0}, /* 22 */
{CmdRemoveRoadStop, 0}, /* 22 */
{CmdBuildLongRoad, 0}, /* 23 */
{CmdRemoveLongRoad, 0}, /* 24 */
{CmdBuildRoad, 0}, /* 25 */

View File

@ -27,6 +27,7 @@ enum {
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,

View File

@ -387,6 +387,9 @@ static void LoadSpriteTables(void)
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();

View File

@ -1041,6 +1041,7 @@ STR_CONFIG_PATCHES_BRIBE :{LTBLUE}Allow b
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_1815_ROAD_WITH_STREETLIGHTS :Road with stree
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

View File

@ -1107,6 +1107,7 @@ STR_CONFIG_PATCHES_BRIBE :{LTBLUE}Önkorm
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_1815_ROAD_WITH_STREETLIGHTS :Út lámpákkal
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

View File

@ -279,6 +279,12 @@ static int32 NPFRoadPathCost(AyStar* as, AyStarNode* current, OpenListNode* pare
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 @@ static bool VehicleMayEnterTile(Owner owner, TileIndex tile, DiagDirection enter
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 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current)
} 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 @@ static void NPFFollowTrack(AyStar* aystar, OpenListNode* current)
}
/* 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)) {

View File

@ -296,7 +296,7 @@ static void TPFMode1(TrackPathFinder* tpf, TileIndex tile, DiagDirection directi
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;
}

View File

@ -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 @@ void CcRoadDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
if (success) {
SndPlayTileFx(SND_1F_SPLAT, tile);
ResetObjectToPlace();
BuildRoadOutsideStation(tile, (DiagDirection)p1);
if (!HASBIT(p2, 1)) BuildRoadOutsideStation(tile, (DiagDirection)p1);
}
}
@ -92,14 +93,45 @@ static void PlaceRoad_Depot(TileIndex tile)
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 @@ static void BuildRoadToolbWndProc(Window *w, WindowEvent *e)
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 @@ static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
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 @@ static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
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 @@ static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
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 void RoadStationPickerWndProc(Window *w, WindowEvent *e)
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 Widget _bus_station_picker_widgets[] = {
};
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 void ShowBusStationPicker(void)
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 Widget _truck_station_picker_widgets[] = {
};
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,

View File

@ -24,6 +24,7 @@ RoadBits GetAnyRoadBits(TileIndex tile)
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 @@ TrackBits GetAnyRoadTrackBits(TileIndex tile)
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;
}

View File

@ -1080,7 +1080,8 @@ static Trackdir RoadFindPathToDest(Vehicle* v, TileIndex tile, DiagDirection ent
/* 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 @@ static Trackdir RoadFindPathToDest(Vehicle* v, TileIndex tile, DiagDirection ent
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 @@ static Trackdir RoadFindPathToDest(Vehicle* v, TileIndex tile, DiagDirection ent
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 @@ enum {
/* 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 @@ static void RoadVehController(Vehicle *v)
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 @@ again:
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 @@ again:
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 @@ again:
}
}
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 @@ again:
/* 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 @@ again:
ClearSlot(v);
}
rs->SetEntranceBusy(true);
if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
if (rs == v->u.road.slot) {
/* We are leaving the correct station */

View File

@ -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!

View File

@ -1340,6 +1340,7 @@ const SettingDesc _patch_settings[] = {
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 @@ const SettingDesc _patch_settings[] = {
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 @@ const SettingDesc _patch_settings[] = {
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 */

View File

@ -599,6 +599,7 @@ static const char *_patches_stations[] = {
"serviceathelipad",
"modified_catchment",
"gradual_loading",
"road_stop_on_town_road",
};
static const char *_patches_economy[] = {

View File

@ -502,6 +502,13 @@ bool RoadStop::HasFreeBay() const
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
@ -519,6 +526,16 @@ uint RoadStop::AllocateBay()
return bay_nr;
}
/**
* 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

View File

@ -66,7 +66,9 @@ struct RoadStop {
/* 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);

View File

@ -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 @@ static RoadStop **FindRoadStopSpot(bool truck_station, Station* st)
/** 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 @@ int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
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 @@ int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
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 @@ static int32 RemoveRoadStop(Station *st, uint32 flags, TileIndex tile)
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 @@ static uint32 VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
/* 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 @@ static int32 ClearTile_Station(TileIndex tile, byte flags)
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;

View File

@ -42,7 +42,9 @@ enum {
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 @@ enum {
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 IsAirport(TileIndex t)
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 @@ static inline bool IsRoadStopTile(TileIndex t)
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 @@ static inline void MakeRailStation(TileIndex t, Owner o, StationID sid, Axis a,
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)

View File

@ -117,6 +117,16 @@ enum Sprites {
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 @@ enum Sprites {
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,

View File

@ -959,6 +959,34 @@ static const DrawTileSeqStruct _station_display_datas_0163[] = {
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 @@ static const DrawTileSprites _station_display_datas[] = {
{ 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 }
};

View File

@ -166,6 +166,7 @@ typedef struct Patches {
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 @@ typedef struct Patches {
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?

View File

@ -2756,9 +2756,11 @@ Trackdir GetVehicleTrackdir(const Vehicle* v)
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;

View File

@ -45,14 +45,18 @@ enum RoadVehicleStates {
/* 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

View File

@ -121,8 +121,8 @@ protected:
/** 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 @@ protected:
/** 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;

View File

@ -51,6 +51,10 @@ protected:
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 @@ public:
// 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 @@ public:
// 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);

View File

@ -39,6 +39,7 @@ YS_DEF_BEGIN
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