Initial support for NewGRF road stops (bus and lorry stops)

This commit is contained in:
Jonathan G Rennison
2022-02-09 02:11:55 +00:00
parent a3c003546b
commit 1084bb8566
28 changed files with 1592 additions and 119 deletions

View File

@@ -58,6 +58,7 @@
#include "zoning.h"
#include "tunnelbridge_map.h"
#include "cheat_type.h"
#include "newgrf_roadstop.h"
#include "table/strings.h"
@@ -2049,10 +2050,12 @@ static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID statio
* bit 3: #Axis of the road for drive-through stops.
* bit 5..10: The roadtype.
* bit 16..31: Station ID to join (NEW_STATION if build new one).
* @param p3 bit 0..7: Roadstop class.
* bit 8..15: Roadstopspec index.
* @param text Unused.
* @return The cost of this operation or an error.
*/
CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length)
{
bool type = HasBit(p2, 0);
bool is_drive_through = HasBit(p2, 1);
@@ -2066,6 +2069,19 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
uint8 width = (uint8)GB(p1, 0, 8);
uint8 length = (uint8)GB(p1, 8, 8);
RoadStopClassID spec_class = Extract<RoadStopClassID, 0, 8>(p3);
byte spec_index = GB(p3, 8, 8);
/* Check if the given station class is valid */
if ((uint)spec_class >= RoadStopClass::GetClassCount() || spec_class == ROADSTOP_CLASS_WAYP) return CMD_ERROR;
if (spec_index >= RoadStopClass::Get(spec_class)->GetSpecCount()) return CMD_ERROR;
const RoadStopSpec *roadstopspec = RoadStopClass::Get(spec_class)->GetSpec(spec_index);
if (roadstopspec != nullptr) {
if (type && roadstopspec->stop_type != ROADSTOPTYPE_FREIGHT && roadstopspec->stop_type != ROADSTOPTYPE_ALL) return CMD_ERROR;
if (!type && roadstopspec->stop_type != ROADSTOPTYPE_PASSENGER && roadstopspec->stop_type != ROADSTOPTYPE_ALL) return CMD_ERROR;
}
/* Check if the requested road stop is too big */
if (width > _settings_game.station.station_spread || length > _settings_game.station.station_spread) return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
/* Check for incorrect width / length. */
@@ -2112,6 +2128,10 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
ret = BuildStationPart(&st, flags, reuse, roadstop_area, STATIONNAMING_ROAD);
if (ret.Failed()) return ret;
/* Check if we can allocate a custom stationspec to this station */
int specindex = AllocateRoadStopSpecToStation(roadstopspec, st, (flags & DC_EXEC) != 0);
if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
if (flags & DC_EXEC) {
/* Check every tile in the area. */
for (TileIndex cur_tile : roadstop_area) {
@@ -2169,6 +2189,9 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
}
Company::Get(st->owner)->infrastructure.station++;
SetCustomRoadStopSpecIndex(cur_tile, specindex);
if (roadstopspec != nullptr) st->SetRoadStopRandomBits(cur_tile, GB(Random(), 0, 4));
MarkTileDirtyByTile(cur_tile);
UpdateRoadCachedOneWayStatesAroundTile(cur_tile);
}
@@ -2222,10 +2245,15 @@ CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlag flags)
Company::Get(wp->owner)->infrastructure.station--;
DirtyCompanyInfrastructureWindows(wp->owner);
uint specindex = GetCustomRoadStopSpecIndex(tile);
DoClearSquare(tile);
wp->rect.AfterRemoveTile(wp, tile);
wp->RemoveRoadStopRandomBits(tile);
DeallocateRoadStopSpecFromStation(wp, specindex);
MakeRoadWaypointStationAreaSmaller(wp, wp->road_waypoint_area);
UpdateStationSignCoord(wp);
@@ -2311,6 +2339,8 @@ CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
Company::Get(st->owner)->infrastructure.station--;
DirtyCompanyInfrastructureWindows(st->owner);
uint specindex = GetCustomRoadStopSpecIndex(tile);
if (IsDriveThroughStopTile(tile)) {
/* Clears the tile for us */
cur_stop->ClearDriveThrough();
@@ -2332,6 +2362,9 @@ CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
st->AfterStationTileSetChange(false, is_truck ? STATION_TRUCK: STATION_BUS);
st->RemoveRoadStopRandomBits(tile);
DeallocateRoadStopSpecFromStation(st, specindex);
/* Update the tile area of the truck/bus stop */
if (is_truck) {
st->truck_station.Clear();
@@ -3417,25 +3450,38 @@ draw_default_foundation:
if (IsAnyRoadStop(ti->tile)) {
RoadType road_rt = GetRoadTypeRoad(ti->tile);
RoadType tram_rt = GetRoadTypeTram(ti->tile);
const RoadTypeInfo* road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
const RoadTypeInfo* tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
DiagDirection dir = GetRoadStopDir(ti->tile);
const RoadStopSpec *stopspec = GetRoadStopSpec(ti->tile);
if (stopspec != nullptr) {
int view = dir;
if (IsDriveThroughStopTile(ti->tile)) view += 4;
st = BaseStation::GetByTile(ti->tile);
RoadStopResolverObject object(stopspec, st, ti->tile, nullptr, GetStationType(ti->tile), view);
const SpriteGroup *group = object.Resolve();
const DrawTileSprites *dts = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(nullptr);
t = dts;
}
if (IsDriveThroughStopTile(ti->tile)) {
Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
uint sprite_offset = axis == AXIS_X ? 1 : 0;
if (stopspec == nullptr || (stopspec->draw_mode & ROADSTOP_DRAW_MODE_OVERLAY) != 0) {
uint sprite_offset = axis == AXIS_X ? 1 : 0;
DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
DisallowedRoadDirections drd = GetDriveThroughStopDisallowedRoadDirections(ti->tile);
if (drd != DRD_NONE) {
DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((axis == AXIS_X) ? 0 : 3), PAL_NONE, 8, 8, 0);
DisallowedRoadDirections drd = GetDriveThroughStopDisallowedRoadDirections(ti->tile);
if (drd != DRD_NONE) {
DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((axis == AXIS_X) ? 0 : 3), PAL_NONE, 8, 8, 0);
}
}
} else {
/* Non-drivethrough road stops are only valid for roads. */
assert_tile(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE, ti->tile);
if (road_rti->UsesOverlay()) {
DiagDirection dir = GetRoadStopDir(ti->tile);
if ((stopspec != nullptr && (stopspec->draw_mode & ROADSTOP_DRAW_MODE_ROAD) != 0) && road_rti->UsesOverlay()) {
SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP);
DrawGroundSprite(ground + dir, PAL_NONE);
}
@@ -4519,6 +4565,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT
TriggerStationRandomisation(st, st->xy, SRT_NEW_CARGO, type);
TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
TriggerRoadStopRandomisation(st, st->xy, RSRT_NEW_CARGO, type);
SetWindowDirty(WC_STATION_VIEW, st->index);
st->MarkTilesDirty(true);