Initial support for NewGRF road stops (bus and lorry stops)
This commit is contained in:
@@ -1057,6 +1057,7 @@
|
|||||||
<li style="color: blue">m8 bits 14..12: <a href="#RoadCachedOneWayState">Road cached one way state</a></li>
|
<li style="color: blue">m8 bits 14..12: <a href="#RoadCachedOneWayState">Road cached one way state</a></li>
|
||||||
<li>m8 bits 11..6: <a href="#TramType">Tramtype</a></li>
|
<li>m8 bits 11..6: <a href="#TramType">Tramtype</a></li>
|
||||||
<li>m8 bits 5..0: <a href="#TrackType">track type</a> for railway stations/waypoints</li>
|
<li>m8 bits 5..0: <a href="#TrackType">track type</a> for railway stations/waypoints</li>
|
||||||
|
<li style="color: blue">m8 bits 5..0: custom road stop id; 0 means standard graphics</li>
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@@ -207,12 +207,12 @@ the array so you can quickly see what is used and what is not.
|
|||||||
<td class="bits" rowspan=2><span class="usable" title="Graphics index">OOOO O</span><span class="used" title="Graphics index: 00 (exit towards NE), 01 (exit towards SE), 02 (exit towards SW), 03 (exit towards NW), 04 (drive through X), 05 (drive through Y)">XXX</span></td>
|
<td class="bits" rowspan=2><span class="usable" title="Graphics index">OOOO O</span><span class="used" title="Graphics index: 00 (exit towards NE), 01 (exit towards SE), 02 (exit towards SW), 03 (exit towards NW), 04 (drive through X), 05 (drive through Y)">XXX</span></td>
|
||||||
<td class="bits" rowspan=6><span class="free">O<span class="patch" title="Station type (extra bit)">P</span></span><span class="used" title="Station type">XXX</span> <span class="free">OOO</span></td>
|
<td class="bits" rowspan=6><span class="free">O<span class="patch" title="Station type (extra bit)">P</span></span><span class="used" title="Station type">XXX</span> <span class="free">OOO</span></td>
|
||||||
<td class="bits" rowspan=2><span class="free">OOO</span><span class="used" title="Owner of road">X XXXX</span></td>
|
<td class="bits" rowspan=2><span class="free">OOO</span><span class="used" title="Owner of road">X XXXX</span></td>
|
||||||
<td class="bits"><span class="free">O</span><span class="patch" title="Road cached one way state">PPP</span> <span class="used" title="Tram type">XXXX XX<span class="free">OO OOOO</span></td>
|
<td class="bits"><span class="free">O</span><span class="patch" title="Road cached one way state">PPP</span> <span class="used" title="Tram type">XXXX XX</span><span class="patch" title="Custom road stops specifications ID">PP PPPP</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="caption">road waypoint</td>
|
<td class="caption">road waypoint</td>
|
||||||
<td class="bits"><span class="used" title="Owner of tram">XXXX</span> <span class="patch" title="Pavement type">PP</span> <span class="patch" title="Disallow vehicles to go a specific direction (drive-through road stop)">PP</span></td>
|
<td class="bits"><span class="used" title="Owner of tram">XXXX</span> <span class="patch" title="Pavement type">PP</span> <span class="patch" title="Disallow vehicles to go a specific direction (drive-through road stop)">PP</span></td>
|
||||||
<td class="bits"><span class="patch" title="Snow/desert present">P</span> <span class="patch" title="Road cached one way state">PPP</span> <span class="used" title="Tram type">XXXX XX<span class="free">OO OOOO</span></td>
|
<td class="bits"><span class="patch" title="Snow/desert present">P</span> <span class="patch" title="Road cached one way state">PPP</span> <span class="used" title="Tram type">XXXX XX</span><span class="patch" title="Custom road stops specifications ID">PP PPPP</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="caption">airport</td>
|
<td class="caption">airport</td>
|
||||||
|
@@ -280,6 +280,8 @@ add_files(
|
|||||||
newgrf_properties.h
|
newgrf_properties.h
|
||||||
newgrf_railtype.cpp
|
newgrf_railtype.cpp
|
||||||
newgrf_railtype.h
|
newgrf_railtype.h
|
||||||
|
newgrf_roadstop.cpp
|
||||||
|
newgrf_roadstop.h
|
||||||
newgrf_roadtype.cpp
|
newgrf_roadtype.cpp
|
||||||
newgrf_roadtype.h
|
newgrf_roadtype.h
|
||||||
newgrf_sound.cpp
|
newgrf_sound.cpp
|
||||||
|
@@ -27,6 +27,12 @@ struct StationSpecList {
|
|||||||
uint8 localidx; ///< Station ID within GRF of station
|
uint8 localidx; ///< Station ID within GRF of station
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RoadStopSpecList {
|
||||||
|
const RoadStopSpec *spec;
|
||||||
|
uint32 grfid; ///< GRF ID of this custom road stop
|
||||||
|
uint8 localidx; ///< Station ID within GRF of road stop
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */
|
/** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */
|
||||||
struct StationRect : public Rect {
|
struct StationRect : public Rect {
|
||||||
@@ -66,7 +72,9 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
|||||||
StationFacility facilities; ///< The facilities that this station has
|
StationFacility facilities; ///< The facilities that this station has
|
||||||
|
|
||||||
uint8 num_specs; ///< Number of specs in the speclist
|
uint8 num_specs; ///< Number of specs in the speclist
|
||||||
|
uint8 num_roadstop_specs; ///< Number of road stop specs in the roadstop_speclist
|
||||||
StationSpecList *speclist; ///< List of station specs of this station
|
StationSpecList *speclist; ///< List of station specs of this station
|
||||||
|
RoadStopSpecList *roadstop_speclist; ///< List of road stop specs of this station
|
||||||
|
|
||||||
Date build_date; ///< Date of construction
|
Date build_date; ///< Date of construction
|
||||||
|
|
||||||
@@ -74,10 +82,14 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
|||||||
byte waiting_triggers; ///< Waiting triggers (NewGRF) for this station
|
byte waiting_triggers; ///< Waiting triggers (NewGRF) for this station
|
||||||
uint8 cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
|
uint8 cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
|
||||||
CargoTypes cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask
|
CargoTypes cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask
|
||||||
|
CargoTypes roadstop_cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask for road stops
|
||||||
|
|
||||||
TileArea train_station; ///< Tile area the train 'station' part covers
|
TileArea train_station; ///< Tile area the train 'station' part covers
|
||||||
StationRect rect; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions
|
StationRect rect; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions
|
||||||
|
|
||||||
|
std::vector<TileIndex> custom_road_stop_tiles; ///< List of custom road stop tiles
|
||||||
|
std::vector<byte> custom_road_stop_random_bits; ///< Custom road stop random bits in same order as custom_road_stop_tiles
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the base station.
|
* Initialize the base station.
|
||||||
* @param tile The location of the station sign
|
* @param tile The location of the station sign
|
||||||
@@ -181,6 +193,17 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
|||||||
return (this->facilities & facilities) != 0;
|
return (this->facilities & facilities) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline byte GetRoadStopRandomBits(TileIndex tile) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < this->custom_road_stop_tiles.size(); i++) {
|
||||||
|
if (this->custom_road_stop_tiles[i] == tile) return this->custom_road_stop_random_bits[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRoadStopRandomBits(TileIndex tile, byte random_bits);
|
||||||
|
void RemoveRoadStopRandomBits(TileIndex tile);
|
||||||
|
|
||||||
static void PostDestructor(size_t index);
|
static void PostDestructor(size_t index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -116,6 +116,7 @@ static int32 ClickChangeDateCheat(int32 p1, int32 p2)
|
|||||||
SetDate(new_date, _date_fract);
|
SetDate(new_date, _date_fract);
|
||||||
EnginesMonthlyLoop();
|
EnginesMonthlyLoop();
|
||||||
InvalidateWindowClassesData(WC_BUILD_STATION, 0);
|
InvalidateWindowClassesData(WC_BUILD_STATION, 0);
|
||||||
|
InvalidateWindowClassesData(WC_BUS_STATION, 0);
|
||||||
InvalidateWindowClassesData(WC_BUILD_OBJECT, 0);
|
InvalidateWindowClassesData(WC_BUILD_OBJECT, 0);
|
||||||
ResetSignalVariant();
|
ResetSignalVariant();
|
||||||
MarkWholeScreenDirty();
|
MarkWholeScreenDirty();
|
||||||
|
@@ -67,12 +67,12 @@ CommandProc CmdBuildTunnel;
|
|||||||
|
|
||||||
CommandProc CmdBuildTrainDepot;
|
CommandProc CmdBuildTrainDepot;
|
||||||
CommandProcEx CmdBuildRailWaypoint;
|
CommandProcEx CmdBuildRailWaypoint;
|
||||||
CommandProc CmdBuildRoadWaypoint;
|
CommandProcEx CmdBuildRoadWaypoint;
|
||||||
CommandProc CmdRenameWaypoint;
|
CommandProc CmdRenameWaypoint;
|
||||||
CommandProc CmdSetWaypointLabelHidden;
|
CommandProc CmdSetWaypointLabelHidden;
|
||||||
CommandProc CmdRemoveFromRailWaypoint;
|
CommandProc CmdRemoveFromRailWaypoint;
|
||||||
|
|
||||||
CommandProc CmdBuildRoadStop;
|
CommandProcEx CmdBuildRoadStop;
|
||||||
CommandProc CmdRemoveRoadStop;
|
CommandProc CmdRemoveRoadStop;
|
||||||
|
|
||||||
CommandProc CmdBuildLongRoad;
|
CommandProc CmdBuildLongRoad;
|
||||||
|
@@ -215,6 +215,8 @@ static void OnNewYear()
|
|||||||
VehiclesYearlyLoop();
|
VehiclesYearlyLoop();
|
||||||
TownsYearlyLoop();
|
TownsYearlyLoop();
|
||||||
InvalidateWindowClassesData(WC_BUILD_STATION);
|
InvalidateWindowClassesData(WC_BUILD_STATION);
|
||||||
|
InvalidateWindowClassesData(WC_BUS_STATION);
|
||||||
|
InvalidateWindowClassesData(WC_TRUCK_STATION);
|
||||||
if (_network_server) NetworkServerYearlyLoop();
|
if (_network_server) NetworkServerYearlyLoop();
|
||||||
|
|
||||||
if (_cur_date_ymd.year == _settings_client.gui.semaphore_build_before) ResetSignalVariant();
|
if (_cur_date_ymd.year == _settings_client.gui.semaphore_build_before) ResetSignalVariant();
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#include "newgrf_industrytiles.h"
|
#include "newgrf_industrytiles.h"
|
||||||
#include "newgrf_station.h"
|
#include "newgrf_station.h"
|
||||||
#include "newgrf_airporttiles.h"
|
#include "newgrf_airporttiles.h"
|
||||||
|
#include "newgrf_roadstop.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
#include "date_func.h"
|
#include "date_func.h"
|
||||||
@@ -2146,6 +2147,7 @@ static void LoadUnloadVehicle(Vehicle *front)
|
|||||||
TriggerStationRandomisation(st, st->xy, SRT_CARGO_TAKEN, v->cargo_type);
|
TriggerStationRandomisation(st, st->xy, SRT_CARGO_TAKEN, v->cargo_type);
|
||||||
TriggerStationAnimation(st, st->xy, SAT_CARGO_TAKEN, v->cargo_type);
|
TriggerStationAnimation(st, st->xy, SAT_CARGO_TAKEN, v->cargo_type);
|
||||||
AirportAnimationTrigger(st, AAT_STATION_CARGO_TAKEN, v->cargo_type);
|
AirportAnimationTrigger(st, AAT_STATION_CARGO_TAKEN, v->cargo_type);
|
||||||
|
TriggerRoadStopRandomisation(st, st->xy, RSRT_CARGO_TAKEN, v->cargo_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_load_unload_ticks += loaded;
|
new_load_unload_ticks += loaded;
|
||||||
@@ -2166,6 +2168,8 @@ static void LoadUnloadVehicle(Vehicle *front)
|
|||||||
if (front->type == VEH_TRAIN) {
|
if (front->type == VEH_TRAIN) {
|
||||||
TriggerStationRandomisation(st, station_tile, SRT_TRAIN_LOADS);
|
TriggerStationRandomisation(st, station_tile, SRT_TRAIN_LOADS);
|
||||||
TriggerStationAnimation(st, station_tile, SAT_TRAIN_LOADS);
|
TriggerStationAnimation(st, station_tile, SAT_TRAIN_LOADS);
|
||||||
|
} else if (front->type == VEH_ROAD) {
|
||||||
|
TriggerRoadStopRandomisation(st, station_tile, RSRT_VEH_LOADS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
180
src/newgrf.cpp
180
src/newgrf.cpp
@@ -48,6 +48,7 @@
|
|||||||
#include "language.h"
|
#include "language.h"
|
||||||
#include "vehicle_base.h"
|
#include "vehicle_base.h"
|
||||||
#include "road.h"
|
#include "road.h"
|
||||||
|
#include "newgrf_roadstop.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
#include "table/build_industry.h"
|
#include "table/build_industry.h"
|
||||||
@@ -4923,6 +4924,120 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore properties for roadstops
|
||||||
|
* @param prop The property to ignore.
|
||||||
|
* @param buf The property value.
|
||||||
|
* @return ChangeInfoResult.
|
||||||
|
*/
|
||||||
|
static ChangeInfoResult IgnoreRoadStopProperty(uint prop, ByteReader *buf)
|
||||||
|
{
|
||||||
|
ChangeInfoResult ret = CIR_SUCCESS;
|
||||||
|
|
||||||
|
switch (prop) {
|
||||||
|
case 0x09:
|
||||||
|
case 0x0C:
|
||||||
|
buf->ReadByte();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0A:
|
||||||
|
case 0x0B:
|
||||||
|
buf->ReadWord();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x08:
|
||||||
|
case 0x0D:
|
||||||
|
buf->ReadDWord();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = HandleAction0PropertyDefault(buf, prop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf)
|
||||||
|
{
|
||||||
|
ChangeInfoResult ret = CIR_SUCCESS;
|
||||||
|
|
||||||
|
if (id + numinfo > 255) {
|
||||||
|
grfmsg(1, "RoadStopChangeInfo: RoadStop %u is invalid, max %u, ignoring", id + numinfo, 255);
|
||||||
|
return CIR_INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cur.grffile->roadstops == nullptr) _cur.grffile->roadstops = CallocT<RoadStopSpec*>(255);
|
||||||
|
|
||||||
|
for (int i = 0; i < numinfo; i++) {
|
||||||
|
RoadStopSpec *rs = _cur.grffile->roadstops[id + i];
|
||||||
|
|
||||||
|
if (rs == nullptr && prop != 0x08 && prop != A0RPI_ROADSTOP_CLASS_ID) {
|
||||||
|
grfmsg(1, "RoadStopChangeInfo: Attempt to modify undefined road stop %u, ignoring", id + i);
|
||||||
|
ChangeInfoResult cir = IgnoreRoadStopProperty(prop, buf);
|
||||||
|
if (cir > ret) ret = cir;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (prop) {
|
||||||
|
case A0RPI_ROADSTOP_CLASS_ID:
|
||||||
|
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case 0x08: { // Road Stop Class ID
|
||||||
|
RoadStopSpec **spec = &_cur.grffile->roadstops[id + i];
|
||||||
|
|
||||||
|
if (*spec == nullptr) *spec = CallocT<RoadStopSpec>(1);
|
||||||
|
|
||||||
|
uint32 classid = buf->ReadDWord();
|
||||||
|
(*spec)->cls_id = RoadStopClass::Allocate(BSWAP32(classid));
|
||||||
|
(*spec)->spec_id = id + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case A0RPI_ROADSTOP_STOP_TYPE:
|
||||||
|
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case 0x09: // Road stop type
|
||||||
|
rs->stop_type = (RoadStopAvailabilityType)buf->ReadByte();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case A0RPI_ROADSTOP_STOP_NAME:
|
||||||
|
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case 0x0A: // Road Stop Name
|
||||||
|
AddStringForMapping(buf->ReadWord(), &rs->name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case A0RPI_ROADSTOP_CLASS_NAME:
|
||||||
|
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case 0x0B: // Road Stop Class name
|
||||||
|
AddStringForMapping(buf->ReadWord(), &RoadStopClass::Get(rs->cls_id)->name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case A0RPI_ROADSTOP_DRAW_MODE:
|
||||||
|
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case 0x0C: // The draw mode
|
||||||
|
rs->draw_mode = (RoadStopDrawMode)buf->ReadByte();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case A0RPI_ROADSTOP_TRIGGER_CARGOES:
|
||||||
|
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
|
||||||
|
FALLTHROUGH;
|
||||||
|
case 0x0D: // Cargo types for random triggers
|
||||||
|
rs->cargo_triggers = TranslateRefitMask(buf->ReadDWord());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = CIR_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, GrfSpecFeature feature, int property)
|
static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, GrfSpecFeature feature, int property)
|
||||||
{
|
{
|
||||||
switch (cir) {
|
switch (cir) {
|
||||||
@@ -5002,6 +5117,7 @@ static const char *_feature_names[] = {
|
|||||||
"AIRPORTTILES",
|
"AIRPORTTILES",
|
||||||
"ROADTYPES",
|
"ROADTYPES",
|
||||||
"TRAMTYPES",
|
"TRAMTYPES",
|
||||||
|
"ROADSTOPS",
|
||||||
};
|
};
|
||||||
static_assert(lengthof(_feature_names) == GSF_END);
|
static_assert(lengthof(_feature_names) == GSF_END);
|
||||||
|
|
||||||
@@ -5106,6 +5222,7 @@ static void FeatureChangeInfo(ByteReader *buf)
|
|||||||
/* GSF_AIRPORTTILES */ AirportTilesChangeInfo,
|
/* GSF_AIRPORTTILES */ AirportTilesChangeInfo,
|
||||||
/* GSF_ROADTYPES */ RoadTypeChangeInfo,
|
/* GSF_ROADTYPES */ RoadTypeChangeInfo,
|
||||||
/* GSF_TRAMTYPES */ TramTypeChangeInfo,
|
/* GSF_TRAMTYPES */ TramTypeChangeInfo,
|
||||||
|
/* GSF_ROADSTOPS */ RoadStopChangeInfo,
|
||||||
};
|
};
|
||||||
static_assert(GSF_END == lengthof(handler));
|
static_assert(GSF_END == lengthof(handler));
|
||||||
static_assert(lengthof(handler) == lengthof(_cur.grffile->action0_property_remaps), "Action 0 feature list length mismatch");
|
static_assert(lengthof(handler) == lengthof(_cur.grffile->action0_property_remaps), "Action 0 feature list length mismatch");
|
||||||
@@ -5616,7 +5733,8 @@ static void NewSpriteGroup(ByteReader *buf)
|
|||||||
case GSF_HOUSES:
|
case GSF_HOUSES:
|
||||||
case GSF_AIRPORTTILES:
|
case GSF_AIRPORTTILES:
|
||||||
case GSF_OBJECTS:
|
case GSF_OBJECTS:
|
||||||
case GSF_INDUSTRYTILES: {
|
case GSF_INDUSTRYTILES:
|
||||||
|
case GSF_ROADSTOPS: {
|
||||||
byte num_building_sprites = std::max((uint8)1, type);
|
byte num_building_sprites = std::max((uint8)1, type);
|
||||||
|
|
||||||
assert(TileLayoutSpriteGroup::CanAllocateItem());
|
assert(TileLayoutSpriteGroup::CanAllocateItem());
|
||||||
@@ -6283,6 +6401,44 @@ static void AirportTileMapSpriteGroup(ByteReader *buf, uint8 idcount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RoadStopMapSpriteGroup(ByteReader *buf, uint8 idcount)
|
||||||
|
{
|
||||||
|
uint8 *roadstops = AllocaM(uint8, idcount);
|
||||||
|
for (uint i = 0; i < idcount; i++) {
|
||||||
|
roadstops[i] = buf->ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip the cargo type section, we only care about the default group */
|
||||||
|
uint8 cidcount = buf->ReadByte();
|
||||||
|
buf->Skip(cidcount * 3);
|
||||||
|
|
||||||
|
uint16 groupid = buf->ReadWord();
|
||||||
|
if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return;
|
||||||
|
|
||||||
|
if (_cur.grffile->roadstops == nullptr) {
|
||||||
|
grfmsg(0, "RoadStopMapSpriteGroup: No roadstops defined, skipping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < idcount; i++) {
|
||||||
|
RoadStopSpec *roadstopspec = _cur.grffile->roadstops == nullptr ? nullptr : _cur.grffile->roadstops[roadstops[i]];
|
||||||
|
|
||||||
|
if (roadstopspec == nullptr) {
|
||||||
|
grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X does not exist, skipping.", roadstops[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roadstopspec->grf_prop.grffile != nullptr) {
|
||||||
|
grfmsg(1, "RoadStopMapSpriteGroup: Road stop with ID 0x%02X mapped multiple times, skipping", roadstops[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
roadstopspec->grf_prop.spritegroup[CT_DEFAULT] = _cur.spritegroups[groupid];
|
||||||
|
roadstopspec->grf_prop.grffile = _cur.grffile;
|
||||||
|
roadstopspec->grf_prop.local_id = roadstops[i];
|
||||||
|
RoadStopClass::Assign(roadstopspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Action 0x03 */
|
/* Action 0x03 */
|
||||||
static void FeatureMapSpriteGroup(ByteReader *buf)
|
static void FeatureMapSpriteGroup(ByteReader *buf)
|
||||||
@@ -6388,6 +6544,10 @@ static void FeatureMapSpriteGroup(ByteReader *buf)
|
|||||||
AirportTileMapSpriteGroup(buf, idcount);
|
AirportTileMapSpriteGroup(buf, idcount);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case GSF_ROADSTOPS:
|
||||||
|
RoadStopMapSpriteGroup(buf, idcount);
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %s, skipping", GetFeatureString(feature_ref));
|
grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %s, skipping", GetFeatureString(feature_ref));
|
||||||
return;
|
return;
|
||||||
@@ -9620,6 +9780,20 @@ static void ResetCustomObjects()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ResetCustomRoadStops()
|
||||||
|
{
|
||||||
|
for (auto file : _grf_files) {
|
||||||
|
RoadStopSpec **&roadstopspec = file->roadstops;
|
||||||
|
if (roadstopspec == nullptr) continue;
|
||||||
|
for (uint i = 0; i < NUM_ROADSTOPS_PER_GRF; i++) {
|
||||||
|
free(roadstopspec[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(roadstopspec);
|
||||||
|
roadstopspec = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Reset and clear all NewGRFs */
|
/** Reset and clear all NewGRFs */
|
||||||
static void ResetNewGRF()
|
static void ResetNewGRF()
|
||||||
{
|
{
|
||||||
@@ -9707,6 +9881,10 @@ void ResetNewGRFData()
|
|||||||
AirportSpec::ResetAirports();
|
AirportSpec::ResetAirports();
|
||||||
AirportTileSpec::ResetAirportTiles();
|
AirportTileSpec::ResetAirportTiles();
|
||||||
|
|
||||||
|
/* Reset road stop classes */
|
||||||
|
RoadStopClass::Reset();
|
||||||
|
ResetCustomRoadStops();
|
||||||
|
|
||||||
/* Reset canal sprite groups and flags */
|
/* Reset canal sprite groups and flags */
|
||||||
memset(_water_feature, 0, sizeof(_water_feature));
|
memset(_water_feature, 0, sizeof(_water_feature));
|
||||||
|
|
||||||
|
@@ -87,9 +87,11 @@ enum GrfSpecFeature {
|
|||||||
GSF_AIRPORTTILES,
|
GSF_AIRPORTTILES,
|
||||||
GSF_ROADTYPES,
|
GSF_ROADTYPES,
|
||||||
GSF_TRAMTYPES,
|
GSF_TRAMTYPES,
|
||||||
|
|
||||||
|
GSF_ROADSTOPS,
|
||||||
GSF_END,
|
GSF_END,
|
||||||
|
|
||||||
GSF_REAL_FEATURE_END = GSF_END,
|
GSF_REAL_FEATURE_END = GSF_ROADSTOPS,
|
||||||
|
|
||||||
GSF_FAKE_TOWNS = GSF_END, ///< Fake town GrfSpecFeature for NewGRF debugging (parent scope)
|
GSF_FAKE_TOWNS = GSF_END, ///< Fake town GrfSpecFeature for NewGRF debugging (parent scope)
|
||||||
GSF_FAKE_STATION_STRUCT, ///< Fake station struct GrfSpecFeature for NewGRF debugging
|
GSF_FAKE_STATION_STRUCT, ///< Fake station struct GrfSpecFeature for NewGRF debugging
|
||||||
@@ -302,6 +304,7 @@ struct GRFFile : ZeroedMemoryAllocator {
|
|||||||
struct ObjectSpec **objectspec;
|
struct ObjectSpec **objectspec;
|
||||||
struct AirportSpec **airportspec;
|
struct AirportSpec **airportspec;
|
||||||
struct AirportTileSpec **airtspec;
|
struct AirportTileSpec **airtspec;
|
||||||
|
struct RoadStopSpec **roadstops;
|
||||||
|
|
||||||
GRFFeatureMapRemapSet feature_id_remaps;
|
GRFFeatureMapRemapSet feature_id_remaps;
|
||||||
GRFFilePropertyRemapSet action0_property_remaps[GSF_END];
|
GRFFilePropertyRemapSet action0_property_remaps[GSF_END];
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
|
#include "newgrf_roadstop.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@@ -51,11 +51,13 @@ extern const GRFFeatureInfo _grf_feature_list[] = {
|
|||||||
GRFFeatureInfo("action0_object_edge_foundation_mode", 2),
|
GRFFeatureInfo("action0_object_edge_foundation_mode", 2),
|
||||||
GRFFeatureInfo("action0_object_flood_resistant", 1),
|
GRFFeatureInfo("action0_object_flood_resistant", 1),
|
||||||
GRFFeatureInfo("action0_object_viewport_map_tile_type", 1),
|
GRFFeatureInfo("action0_object_viewport_map_tile_type", 1),
|
||||||
|
GRFFeatureInfo("road_stops", 1),
|
||||||
GRFFeatureInfo(),
|
GRFFeatureInfo(),
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Action14 remappable feature list */
|
/** Action14 remappable feature list */
|
||||||
extern const GRFFeatureMapDefinition _grf_remappable_features[] = {
|
extern const GRFFeatureMapDefinition _grf_remappable_features[] = {
|
||||||
|
GRFFeatureMapDefinition(GSF_ROADSTOPS, "road_stops"),
|
||||||
GRFFeatureMapDefinition(),
|
GRFFeatureMapDefinition(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,6 +90,12 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
|
|||||||
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_FLOOD_RESISTANT, "object_flood_resistant"),
|
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_FLOOD_RESISTANT, "object_flood_resistant"),
|
||||||
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_VIEWPORT_MAP_TYPE, "object_viewport_map_tile_type"),
|
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_VIEWPORT_MAP_TYPE, "object_viewport_map_tile_type"),
|
||||||
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_VIEWPORT_MAP_SUBTYPE, "object_viewport_map_tile_subtype"),
|
GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_VIEWPORT_MAP_SUBTYPE, "object_viewport_map_tile_subtype"),
|
||||||
|
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_CLASS_ID, "roadstop_class_id"),
|
||||||
|
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_STOP_TYPE, "roadstop_stop_type"),
|
||||||
|
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_STOP_NAME, "roadstop_stop_name"),
|
||||||
|
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_CLASS_NAME, "roadstop_class_name"),
|
||||||
|
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_DRAW_MODE, "roadstop_draw_mode"),
|
||||||
|
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_TRIGGER_CARGOES, "roadstop_trigger_cargoes"),
|
||||||
GRFPropertyMapDefinition(),
|
GRFPropertyMapDefinition(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,6 +103,13 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
|
|||||||
extern const GRFVariableMapDefinition _grf_action2_remappable_variables[] = {
|
extern const GRFVariableMapDefinition _grf_action2_remappable_variables[] = {
|
||||||
GRFVariableMapDefinition(GSF_OBJECTS, A2VRI_OBJECT_FOUNDATION_SLOPE, "object_foundation_tile_slope"),
|
GRFVariableMapDefinition(GSF_OBJECTS, A2VRI_OBJECT_FOUNDATION_SLOPE, "object_foundation_tile_slope"),
|
||||||
GRFVariableMapDefinition(GSF_OBJECTS, A2VRI_OBJECT_FOUNDATION_SLOPE_CHANGE, "object_foundation_change_tile_slope"),
|
GRFVariableMapDefinition(GSF_OBJECTS, A2VRI_OBJECT_FOUNDATION_SLOPE_CHANGE, "object_foundation_change_tile_slope"),
|
||||||
|
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x40, "roadstop_view"),
|
||||||
|
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x41, "roadstop_type"),
|
||||||
|
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x42, "roadstop_terrain_type"),
|
||||||
|
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x43, "roadstop_road_type"),
|
||||||
|
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x44, "roadstop_tram_type"),
|
||||||
|
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x45, "roadstop_town_zone"),
|
||||||
|
GRFVariableMapDefinition(GSF_ROADSTOPS, 0x46, "roadstop_company_info"),
|
||||||
GRFVariableMapDefinition(),
|
GRFVariableMapDefinition(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -39,6 +39,12 @@ enum Action0RemapPropertyIds {
|
|||||||
A0RPI_OBJECT_FLOOD_RESISTANT,
|
A0RPI_OBJECT_FLOOD_RESISTANT,
|
||||||
A0RPI_OBJECT_VIEWPORT_MAP_TYPE,
|
A0RPI_OBJECT_VIEWPORT_MAP_TYPE,
|
||||||
A0RPI_OBJECT_VIEWPORT_MAP_SUBTYPE,
|
A0RPI_OBJECT_VIEWPORT_MAP_SUBTYPE,
|
||||||
|
A0RPI_ROADSTOP_CLASS_ID,
|
||||||
|
A0RPI_ROADSTOP_STOP_TYPE,
|
||||||
|
A0RPI_ROADSTOP_STOP_NAME,
|
||||||
|
A0RPI_ROADSTOP_CLASS_NAME,
|
||||||
|
A0RPI_ROADSTOP_DRAW_MODE,
|
||||||
|
A0RPI_ROADSTOP_TRIGGER_CARGOES,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
438
src/newgrf_roadstop.cpp
Normal file
438
src/newgrf_roadstop.cpp
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file command.cpp Handling of NewGRF road stops. */
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "station_base.h"
|
||||||
|
#include "roadstop_base.h"
|
||||||
|
#include "newgrf_roadstop.h"
|
||||||
|
#include "newgrf_class_func.h"
|
||||||
|
#include "newgrf_cargo.h"
|
||||||
|
#include "newgrf_roadtype.h"
|
||||||
|
#include "gfx_type.h"
|
||||||
|
#include "company_func.h"
|
||||||
|
#include "road.h"
|
||||||
|
#include "window_type.h"
|
||||||
|
#include "date_func.h"
|
||||||
|
#include "town.h"
|
||||||
|
#include "viewport_func.h"
|
||||||
|
|
||||||
|
#include "safeguards.h"
|
||||||
|
|
||||||
|
template <typename Tspec, typename Tid, Tid Tmax>
|
||||||
|
void NewGRFClass<Tspec, Tid, Tmax>::InsertDefaults()
|
||||||
|
{
|
||||||
|
/* Set up initial data */
|
||||||
|
classes[0].global_id = 'DFLT';
|
||||||
|
classes[0].name = STR_STATION_CLASS_DFLT;
|
||||||
|
classes[0].Insert(nullptr);
|
||||||
|
|
||||||
|
classes[1].global_id = 'WAYP';
|
||||||
|
classes[1].name = STR_STATION_CLASS_WAYP;
|
||||||
|
classes[1].Insert(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Tspec, typename Tid, Tid Tmax>
|
||||||
|
bool NewGRFClass<Tspec, Tid, Tmax>::IsUIAvailable(uint index) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_NEWGRF_CLASS_METHODS(RoadStopClass, RoadStopSpec, RoadStopClassID, ROADSTOP_CLASS_MAX)
|
||||||
|
|
||||||
|
static const uint NUM_ROADSTOPSPECS_PER_STATION = 63; ///< Maximum number of parts per station.
|
||||||
|
|
||||||
|
uint32 RoadStopScopeResolver::GetRandomBits() const
|
||||||
|
{
|
||||||
|
if (this->st == nullptr) return 0;
|
||||||
|
|
||||||
|
uint32 bits = this->st->random_bits;
|
||||||
|
if (this->tile != INVALID_TILE && Station::IsExpected(this->st)) {
|
||||||
|
bits |= Station::From(this->st)->GetRoadStopRandomBits(this->tile) << 16;
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 RoadStopScopeResolver::GetTriggers() const
|
||||||
|
{
|
||||||
|
return this->st == nullptr ? 0 : this->st->waiting_triggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 RoadStopScopeResolver::GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const
|
||||||
|
{
|
||||||
|
switch (variable) {
|
||||||
|
case 0x40: return this->view; // view
|
||||||
|
|
||||||
|
case 0x41: // stop type
|
||||||
|
if (this->type == STATION_BUS) return 0;
|
||||||
|
if (this->type == STATION_TRUCK) return 1;
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case 0x42: return this->tile == INVALID_TILE ? 0 : GetTerrainType(this->tile, TCX_NORMAL); // terrain_type
|
||||||
|
|
||||||
|
case 0x43: return this->tile == INVALID_TILE ? 0 : GetReverseRoadTypeTranslation(GetRoadTypeRoad(this->tile), this->roadstopspec->grf_prop.grffile); // road_type
|
||||||
|
|
||||||
|
case 0x44: return this->tile == INVALID_TILE ? 0 : GetReverseRoadTypeTranslation(GetRoadTypeTram(this->tile), this->roadstopspec->grf_prop.grffile); // tram_type
|
||||||
|
|
||||||
|
case 0x45: { // town_zone
|
||||||
|
if (this->tile == INVALID_TILE) return HZB_TOWN_EDGE;
|
||||||
|
const Town *t = ClosestTownFromTile(this->tile, UINT_MAX);
|
||||||
|
return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x46: return GetCompanyInfo(this->st == nullptr ? _current_company : this->st->owner); // company_type
|
||||||
|
|
||||||
|
case 0xF0: return this->st == nullptr ? 0 : this->st->facilities; // facilities
|
||||||
|
|
||||||
|
case 0xFA: return Clamp((this->st == nullptr ? _date : this->st->build_date) - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // build date
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->st != nullptr) return this->st->GetNewGRFVariable(this->ro, variable, parameter, &(extra->available));
|
||||||
|
|
||||||
|
extra->available = false;
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SpriteGroup *RoadStopResolverObject::ResolveReal(const RealSpriteGroup *group) const
|
||||||
|
{
|
||||||
|
if (group == nullptr) return nullptr;
|
||||||
|
|
||||||
|
return group->loading[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
RoadStopResolverObject::RoadStopResolverObject(const RoadStopSpec *roadstopspec, BaseStation *st, TileIndex tile, const RoadTypeInfo *rti, StationType type, uint8 view,
|
||||||
|
CallbackID callback, uint32 param1, uint32 param2)
|
||||||
|
: ResolverObject(roadstopspec->grf_prop.grffile, callback, param1, param2), roadstop_scope(*this, st, roadstopspec, tile, rti, type, view)
|
||||||
|
{
|
||||||
|
|
||||||
|
this->town_scope = nullptr;
|
||||||
|
this->root_spritegroup = (st == nullptr && roadstopspec->grf_prop.spritegroup[CT_DEFAULT] != nullptr)
|
||||||
|
? roadstopspec->grf_prop.spritegroup[CT_DEFAULT] : roadstopspec->grf_prop.spritegroup[CT_DEFAULT];
|
||||||
|
}
|
||||||
|
|
||||||
|
RoadStopResolverObject::~RoadStopResolverObject()
|
||||||
|
{
|
||||||
|
delete this->town_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
TownScopeResolver* RoadStopResolverObject::GetTown()
|
||||||
|
{
|
||||||
|
if (this->town_scope == nullptr) {
|
||||||
|
Town *t;
|
||||||
|
if (this->roadstop_scope.st != nullptr) {
|
||||||
|
t = this->roadstop_scope.st->town;
|
||||||
|
} else {
|
||||||
|
t = ClosestTownFromTile(this->roadstop_scope.tile, UINT_MAX);
|
||||||
|
}
|
||||||
|
if (t == nullptr) return nullptr;
|
||||||
|
this->town_scope = new TownScopeResolver(*this, t, this->roadstop_scope.st == nullptr);
|
||||||
|
}
|
||||||
|
return this->town_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw representation of a road stop tile for GUI purposes.
|
||||||
|
* @param x position x of image.
|
||||||
|
* @param y position y of image.
|
||||||
|
* @param image an int offset for the sprite.
|
||||||
|
* @param roadtype the RoadType of the underlying road.
|
||||||
|
* @param spec the RoadStop's spec.
|
||||||
|
* @return true of the tile was drawn (allows for fallback to default graphics)
|
||||||
|
*/
|
||||||
|
void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, StationType type, int view)
|
||||||
|
{
|
||||||
|
assert(roadtype != INVALID_ROADTYPE);
|
||||||
|
assert(spec != nullptr);
|
||||||
|
|
||||||
|
const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype);
|
||||||
|
RoadStopResolverObject object(spec, nullptr, INVALID_TILE, rti, type, view);
|
||||||
|
const SpriteGroup *group = object.Resolve();
|
||||||
|
if (group == nullptr || group->type != SGT_TILELAYOUT) return;
|
||||||
|
const DrawTileSprites *dts = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(nullptr);
|
||||||
|
|
||||||
|
PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
|
||||||
|
|
||||||
|
SpriteID image = dts->ground.sprite;
|
||||||
|
PaletteID pal = dts->ground.pal;
|
||||||
|
|
||||||
|
if (GB(image, 0, SPRITE_WIDTH) != 0) {
|
||||||
|
DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view >= 4) {
|
||||||
|
/* Drive-through stop */
|
||||||
|
uint sprite_offset = 5 - view;
|
||||||
|
|
||||||
|
/* Road underlay takes precedence over tram */
|
||||||
|
if (HasBit(spec->draw_mode, ROADSTOP_DRAW_MODE_OVERLAY)) {
|
||||||
|
TileInfo ti {};
|
||||||
|
ti.tile = INVALID_TILE;
|
||||||
|
DrawRoadOverlays(&ti, PAL_NONE, rti, rti, sprite_offset, sprite_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rti->UsesOverlay()) {
|
||||||
|
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND);
|
||||||
|
DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
|
||||||
|
|
||||||
|
SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY);
|
||||||
|
if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
|
||||||
|
} else if (RoadTypeIsTram(roadtype)) {
|
||||||
|
DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Drive-in stop */
|
||||||
|
if (rti->UsesOverlay()) {
|
||||||
|
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP);
|
||||||
|
DrawSprite(ground + view, PAL_NONE, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawCommonTileSeqInGUI(x, y, dts, 0, 0, palette, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger road stop randomisation
|
||||||
|
*
|
||||||
|
* @param st the station being triggered
|
||||||
|
* @param tile the exact tile of the station that should be triggered
|
||||||
|
* @param trigger trigger type
|
||||||
|
* @param cargo_type cargo type causing the trigger
|
||||||
|
*/
|
||||||
|
void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTrigger trigger, CargoID cargo_type)
|
||||||
|
{
|
||||||
|
if (st == nullptr) st = Station::GetByTile(tile);
|
||||||
|
|
||||||
|
/* Check the cached cargo trigger bitmask to see if we need
|
||||||
|
* to bother with any further processing. */
|
||||||
|
if (st->roadstop_cached_cargo_triggers == 0) return;
|
||||||
|
if (cargo_type != CT_INVALID && !HasBit(st->roadstop_cached_cargo_triggers, cargo_type)) return;
|
||||||
|
|
||||||
|
SetBit(st->waiting_triggers, trigger);
|
||||||
|
|
||||||
|
uint32 whole_reseed = 0;
|
||||||
|
|
||||||
|
CargoTypes empty_mask = 0;
|
||||||
|
if (trigger == RSRT_CARGO_TAKEN) {
|
||||||
|
/* Create a bitmask of completely empty cargo types to be matched */
|
||||||
|
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||||
|
if (st->goods[i].cargo.TotalCount() == 0) {
|
||||||
|
SetBit(empty_mask, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 used_triggers = 0;
|
||||||
|
auto process_tile = [&](TileIndex cur_tile) {
|
||||||
|
const RoadStopSpec *ss = GetRoadStopSpec(tile);
|
||||||
|
if (ss == nullptr) return;
|
||||||
|
|
||||||
|
/* Cargo taken "will only be triggered if all of those
|
||||||
|
* cargo types have no more cargo waiting." */
|
||||||
|
if (trigger == RSRT_CARGO_TAKEN) {
|
||||||
|
if ((ss->cargo_triggers & ~empty_mask) != 0) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cargo_type == CT_INVALID || HasBit(ss->cargo_triggers, cargo_type)) {
|
||||||
|
int dir = GetRoadStopDir(cur_tile);
|
||||||
|
if (IsDriveThroughStopTile(cur_tile)) dir += 4;
|
||||||
|
|
||||||
|
RoadStopResolverObject object(ss, st, cur_tile, nullptr, GetStationType(cur_tile), dir);
|
||||||
|
object.waiting_triggers = st->waiting_triggers;
|
||||||
|
|
||||||
|
const SpriteGroup *group = object.Resolve();
|
||||||
|
if (group == nullptr) return;
|
||||||
|
|
||||||
|
used_triggers |= object.used_triggers;
|
||||||
|
|
||||||
|
uint32 reseed = object.GetReseedSum();
|
||||||
|
if (reseed != 0) {
|
||||||
|
whole_reseed |= reseed;
|
||||||
|
reseed >>= 16;
|
||||||
|
|
||||||
|
/* Set individual tile random bits */
|
||||||
|
uint8 random_bits = st->GetRoadStopRandomBits(cur_tile);
|
||||||
|
random_bits &= ~reseed;
|
||||||
|
random_bits |= Random() & reseed;
|
||||||
|
st->SetRoadStopRandomBits(cur_tile, random_bits);
|
||||||
|
|
||||||
|
MarkTileDirtyByTile(cur_tile, VMDF_NOT_MAP_MODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (trigger == RSRT_NEW_CARGO || trigger == RSRT_CARGO_TAKEN) {
|
||||||
|
for (TileIndex cur_tile : st->custom_road_stop_tiles) {
|
||||||
|
process_tile(cur_tile);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
process_tile(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update whole station random bits */
|
||||||
|
st->waiting_triggers &= ~used_triggers;
|
||||||
|
if ((whole_reseed & 0xFFFF) != 0) {
|
||||||
|
st->random_bits &= ~whole_reseed;
|
||||||
|
st->random_bits |= Random() & whole_reseed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there's any new stations by a specific RoadStopType
|
||||||
|
* @param rs the RoadStopType to check for.
|
||||||
|
* @return true if there was any new RoadStopSpec's found for the given RoadStopType, else false.
|
||||||
|
*/
|
||||||
|
bool GetIfNewStopsByType(RoadStopType rs)
|
||||||
|
{
|
||||||
|
if (!(RoadStopClass::GetClassCount() > 1 || RoadStopClass::Get(ROADSTOP_CLASS_DFLT)->GetSpecCount() > 1)) return false;
|
||||||
|
for (uint i = 0; i < RoadStopClass::GetClassCount(); i++) {
|
||||||
|
// We don't want to check the default or waypoint classes. These classes are always available.
|
||||||
|
if (i == ROADSTOP_CLASS_DFLT || i == ROADSTOP_CLASS_WAYP) continue;
|
||||||
|
RoadStopClass *roadstopclass = RoadStopClass::Get((RoadStopClassID)i);
|
||||||
|
if (GetIfClassHasNewStopsByType(roadstopclass, rs)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given RoadStopClass has any specs assigned to it, compatible with the given RoadStopType.
|
||||||
|
* @param roadstopclass the RoadStopClass to check.
|
||||||
|
* @param rs the RoadStopType to check by.
|
||||||
|
* @return true if the roadstopclass has any specs compatible with the given RoadStopType.
|
||||||
|
*/
|
||||||
|
bool GetIfClassHasNewStopsByType(RoadStopClass *roadstopclass, RoadStopType rs)
|
||||||
|
{
|
||||||
|
for (uint j = 0; j < roadstopclass->GetSpecCount(); j++) {
|
||||||
|
if (GetIfStopIsForType(roadstopclass->GetSpec(j), rs)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given RoadStopSpec is compatible with the given RoadStopType.
|
||||||
|
* @param roadstopspec the RoadStopSpec to check.
|
||||||
|
* @param rs the RoadStopType to check by.
|
||||||
|
* @return true if the roadstopspec is compatible with the given RoadStopType.
|
||||||
|
*/
|
||||||
|
bool GetIfStopIsForType(const RoadStopSpec *roadstopspec, RoadStopType rs)
|
||||||
|
{
|
||||||
|
// The roadstopspec is nullptr, must be the default station, always return true.
|
||||||
|
if (roadstopspec == nullptr) return true;
|
||||||
|
if (roadstopspec->stop_type == ROADSTOPTYPE_ALL) return true;
|
||||||
|
|
||||||
|
switch (rs) {
|
||||||
|
case ROADSTOP_BUS: if (roadstopspec->stop_type == ROADSTOPTYPE_PASSENGER) return true; break;
|
||||||
|
case ROADSTOP_TRUCK: if (roadstopspec->stop_type == ROADSTOPTYPE_FREIGHT) return true; break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RoadStopSpec *GetRoadStopSpec(TileIndex t)
|
||||||
|
{
|
||||||
|
if (!IsCustomRoadStopSpecIndex(t)) return nullptr;
|
||||||
|
|
||||||
|
const BaseStation *st = BaseStation::GetByTile(t);
|
||||||
|
uint specindex = GetCustomRoadStopSpecIndex(t);
|
||||||
|
return specindex < st->num_roadstop_specs ? st->roadstop_speclist[specindex].spec : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AllocateRoadStopSpecToStation(const RoadStopSpec *statspec, BaseStation *st, bool exec)
|
||||||
|
{
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
if (statspec == nullptr || st == nullptr) return 0;
|
||||||
|
|
||||||
|
/* Try to find the same spec and return that one */
|
||||||
|
for (i = 1; i < st->num_roadstop_specs && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
|
||||||
|
if (st->roadstop_speclist[i].spec == statspec) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find an unused spec slot */
|
||||||
|
for (i = 1; i < st->num_roadstop_specs && i < NUM_ROADSTOPSPECS_PER_STATION; i++) {
|
||||||
|
if (st->roadstop_speclist[i].spec == nullptr && st->roadstop_speclist[i].grfid == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == NUM_ROADSTOPSPECS_PER_STATION) {
|
||||||
|
/* Full, give up */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exec) {
|
||||||
|
if (i >= st->num_roadstop_specs) {
|
||||||
|
st->num_roadstop_specs = i + 1;
|
||||||
|
st->roadstop_speclist = ReallocT(st->roadstop_speclist, st->num_roadstop_specs);
|
||||||
|
|
||||||
|
if (st->num_roadstop_specs == 2) {
|
||||||
|
/* Initial allocation */
|
||||||
|
st->roadstop_speclist[0].spec = nullptr;
|
||||||
|
st->roadstop_speclist[0].grfid = 0;
|
||||||
|
st->roadstop_speclist[0].localidx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
st->roadstop_speclist[i].spec = statspec;
|
||||||
|
st->roadstop_speclist[i].grfid = statspec->grf_prop.grffile->grfid;
|
||||||
|
st->roadstop_speclist[i].localidx = statspec->grf_prop.local_id;
|
||||||
|
|
||||||
|
StationUpdateRoadStopCachedTriggers(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeallocateRoadStopSpecFromStation(BaseStation *st, byte specindex)
|
||||||
|
{
|
||||||
|
/* specindex of 0 (default) is never freeable */
|
||||||
|
if (specindex == 0) return;
|
||||||
|
|
||||||
|
/* Check custom road stop tiles if the specindex is still in use */
|
||||||
|
for (TileIndex tile : st->custom_road_stop_tiles) {
|
||||||
|
if (GetCustomRoadStopSpecIndex(tile) == specindex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This specindex is no longer in use, so deallocate it */
|
||||||
|
st->roadstop_speclist[specindex].spec = nullptr;
|
||||||
|
st->roadstop_speclist[specindex].grfid = 0;
|
||||||
|
st->roadstop_speclist[specindex].localidx = 0;
|
||||||
|
|
||||||
|
/* If this was the highest spec index, reallocate */
|
||||||
|
if (specindex == st->num_roadstop_specs - 1) {
|
||||||
|
for (; st->roadstop_speclist[st->num_roadstop_specs - 1].grfid == 0 && st->num_roadstop_specs > 1; st->num_roadstop_specs--) {}
|
||||||
|
|
||||||
|
if (st->num_roadstop_specs > 1) {
|
||||||
|
st->roadstop_speclist = ReallocT(st->roadstop_speclist, st->num_roadstop_specs);
|
||||||
|
} else {
|
||||||
|
free(st->roadstop_speclist);
|
||||||
|
st->num_roadstop_specs = 0;
|
||||||
|
st->roadstop_speclist = nullptr;
|
||||||
|
st->roadstop_cached_cargo_triggers = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StationUpdateRoadStopCachedTriggers(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the cached animation trigger bitmask for a station.
|
||||||
|
* @param st Station to update.
|
||||||
|
*/
|
||||||
|
void StationUpdateRoadStopCachedTriggers(BaseStation *st)
|
||||||
|
{
|
||||||
|
st->roadstop_cached_cargo_triggers = 0;
|
||||||
|
|
||||||
|
/* Combine animation trigger bitmask for all road stop specs
|
||||||
|
* of this station. */
|
||||||
|
for (uint i = 0; i < st->num_roadstop_specs; i++) {
|
||||||
|
const RoadStopSpec *ss = st->roadstop_speclist[i].spec;
|
||||||
|
if (ss != nullptr) {
|
||||||
|
st->roadstop_cached_cargo_triggers |= ss->cargo_triggers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
147
src/newgrf_roadstop.h
Normal file
147
src/newgrf_roadstop.h
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file newgrf_roadstop.h NewGRF definitions and structures for road stops.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NEWGRF_ROADSTATION_H
|
||||||
|
#define NEWGRF_ROADSTATION_H
|
||||||
|
|
||||||
|
#include "newgrf_animation_type.h"
|
||||||
|
#include "newgrf_spritegroup.h"
|
||||||
|
#include "newgrf_class.h"
|
||||||
|
#include "newgrf_commons.h"
|
||||||
|
#include "newgrf_town.h"
|
||||||
|
#include "road.h"
|
||||||
|
|
||||||
|
/** The maximum amount of roadstops a single GRF is allowed to add */
|
||||||
|
static const int NUM_ROADSTOPS = 64000U;
|
||||||
|
static const int NUM_ROADSTOPS_PER_GRF = 255;
|
||||||
|
|
||||||
|
enum RoadStopClassID : byte {
|
||||||
|
ROADSTOP_CLASS_BEGIN = 0, ///< The lowest valid value
|
||||||
|
ROADSTOP_CLASS_DFLT = 0, ///< Default road stop class.
|
||||||
|
ROADSTOP_CLASS_WAYP, ///< Waypoint class.
|
||||||
|
ROADSTOP_CLASS_MAX = 255, ///< Maximum number of classes.
|
||||||
|
};
|
||||||
|
DECLARE_POSTFIX_INCREMENT(RoadStopClassID)
|
||||||
|
|
||||||
|
/* Some Triggers etc. */
|
||||||
|
enum RoadStopRandomTrigger {
|
||||||
|
RSRT_NEW_CARGO, ///< Trigger roadstop on arrival of new cargo.
|
||||||
|
RSRT_CARGO_TAKEN, ///< Trigger roadstop when cargo is completely taken.
|
||||||
|
RSRT_VEH_LOADS, ///< Trigger roadstop when road vehicle loads.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various different options for availability, restricting
|
||||||
|
* the roadstop to be only for busses or for trucks.
|
||||||
|
*/
|
||||||
|
enum RoadStopAvailabilityType : byte {
|
||||||
|
ROADSTOPTYPE_PASSENGER, ///< This RoadStop is for passenger (bus) stops.
|
||||||
|
ROADSTOPTYPE_FREIGHT, ///< This RoadStop is for freight (truck) stops.
|
||||||
|
ROADSTOPTYPE_ALL, ///< This RoadStop is for both types of station road stops.
|
||||||
|
|
||||||
|
ROADSTOPTYPE_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Different draw modes to disallow rendering of some parts of the stop
|
||||||
|
* or road.
|
||||||
|
*/
|
||||||
|
enum RoadStopDrawMode : byte {
|
||||||
|
ROADSTOP_DRAW_MODE_NONE = 0,
|
||||||
|
ROADSTOP_DRAW_MODE_ROAD = 1 << 0, ///< 0b01, Draw the road itself
|
||||||
|
ROADSTOP_DRAW_MODE_OVERLAY = 1 << 1, ///< 0b10, Draw the road overlay for roadstops, e.g. pavement
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_AS_BIT_SET(RoadStopDrawMode)
|
||||||
|
|
||||||
|
/** Scope resolver for road stops. */
|
||||||
|
struct RoadStopScopeResolver : public ScopeResolver {
|
||||||
|
TileIndex tile; ///< %Tile of the station.
|
||||||
|
struct BaseStation *st; ///< Instance of the station.
|
||||||
|
const struct RoadStopSpec *roadstopspec; ///< Station (type) specification.
|
||||||
|
CargoID cargo_type; ///< Type of cargo of the station.
|
||||||
|
StationType type; ///< Station type.
|
||||||
|
uint8 view; ///< Station axis.
|
||||||
|
const RoadTypeInfo *rti; ///< Road type info
|
||||||
|
|
||||||
|
RoadStopScopeResolver(ResolverObject& ro, BaseStation* st, const RoadStopSpec *roadstopspec, TileIndex tile, const RoadTypeInfo *rti, StationType type, uint8 view = 0)
|
||||||
|
: ScopeResolver(ro), tile(tile), st(st), roadstopspec(roadstopspec), type(type), view(view), rti(rti)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 GetRandomBits() const override;
|
||||||
|
uint32 GetTriggers() const override;
|
||||||
|
|
||||||
|
uint32 GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Road stop resolver. */
|
||||||
|
struct RoadStopResolverObject : public ResolverObject {
|
||||||
|
RoadStopScopeResolver roadstop_scope; ///< The stop scope resolver.
|
||||||
|
TownScopeResolver *town_scope; ///< The town scope resolver (created on the first call).
|
||||||
|
|
||||||
|
RoadStopResolverObject(const RoadStopSpec* roadstopspec, BaseStation* st, TileIndex tile, const RoadTypeInfo *rti, StationType type, uint8 view, CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0);
|
||||||
|
~RoadStopResolverObject();
|
||||||
|
|
||||||
|
ScopeResolver* GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override {
|
||||||
|
switch (scope) {
|
||||||
|
case VSG_SCOPE_SELF: return &this->roadstop_scope;
|
||||||
|
case VSG_SCOPE_PARENT: {
|
||||||
|
TownScopeResolver *tsr = this->GetTown();
|
||||||
|
if (tsr != nullptr) return tsr;
|
||||||
|
FALLTHROUGH;
|
||||||
|
}
|
||||||
|
default: return ResolverObject::GetScope(scope, relative);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TownScopeResolver *GetTown();
|
||||||
|
|
||||||
|
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Road stop specification. */
|
||||||
|
struct RoadStopSpec {
|
||||||
|
// We'll have a default and a fence "cargo". Or maybe just a default one?
|
||||||
|
GRFFilePropsBase<NUM_CARGO + 1> grf_prop;
|
||||||
|
RoadStopClassID cls_id; ///< The class to which this spec belongs.
|
||||||
|
int spec_id; ///< The ID of this spec inside the class.
|
||||||
|
StringID name; ///< Name of this stop
|
||||||
|
|
||||||
|
RoadStopAvailabilityType stop_type = ROADSTOPTYPE_ALL;
|
||||||
|
RoadStopDrawMode draw_mode = ROADSTOP_DRAW_MODE_ROAD | ROADSTOP_DRAW_MODE_OVERLAY;
|
||||||
|
|
||||||
|
CargoTypes cargo_triggers = 0; ///< Bitmask of cargo types which cause trigger re-randomizing
|
||||||
|
|
||||||
|
static const RoadStopSpec *Get(uint16 index);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct EnumPropsT<RoadStopClassID> : MakeEnumPropsT<RoadStopClassID, byte, ROADSTOP_CLASS_BEGIN, ROADSTOP_CLASS_MAX, ROADSTOP_CLASS_MAX, 8> {};
|
||||||
|
|
||||||
|
typedef NewGRFClass<RoadStopSpec, RoadStopClassID, ROADSTOP_CLASS_MAX> RoadStopClass;
|
||||||
|
|
||||||
|
void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, StationType type, int view);
|
||||||
|
|
||||||
|
void TriggerRoadStopRandomisation(Station *st, TileIndex tile, RoadStopRandomTrigger trigger, CargoID cargo_type = CT_INVALID);
|
||||||
|
|
||||||
|
bool GetIfNewStopsByType(RoadStopType rs);
|
||||||
|
bool GetIfClassHasNewStopsByType(RoadStopClass *roadstopclass, RoadStopType rs);
|
||||||
|
bool GetIfStopIsForType(const RoadStopSpec *roadstopspec, RoadStopType rs);
|
||||||
|
|
||||||
|
uint GetCountOfCompatibleStopsByType(RoadStopClass *roadstopclass, RoadStopType rs);
|
||||||
|
|
||||||
|
const RoadStopSpec *GetRoadStopSpec(TileIndex t);
|
||||||
|
int AllocateRoadStopSpecToStation(const RoadStopSpec *statspec, BaseStation *st, bool exec);
|
||||||
|
void DeallocateRoadStopSpecFromStation(BaseStation *st, byte specindex);
|
||||||
|
void StationUpdateRoadStopCachedTriggers(BaseStation *st);
|
||||||
|
|
||||||
|
#endif /* NEWGRF_ROADSTATION_H */
|
642
src/road_gui.cpp
642
src/road_gui.cpp
@@ -33,6 +33,14 @@
|
|||||||
#include "date_func.h"
|
#include "date_func.h"
|
||||||
#include "station_map.h"
|
#include "station_map.h"
|
||||||
#include "waypoint_func.h"
|
#include "waypoint_func.h"
|
||||||
|
#include "newgrf_roadstop.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "newgrf_station.h"
|
||||||
|
#include "querystring_gui.h"
|
||||||
|
#include "sortlist_type.h"
|
||||||
|
#include "stringfilter_type.h"
|
||||||
|
#include "string_func.h"
|
||||||
|
|
||||||
#include "widgets/road_widget.h"
|
#include "widgets/road_widget.h"
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -46,6 +54,17 @@ static void ShowRoadDepotPicker(Window *parent);
|
|||||||
static bool _remove_button_clicked;
|
static bool _remove_button_clicked;
|
||||||
static bool _one_way_button_clicked;
|
static bool _one_way_button_clicked;
|
||||||
|
|
||||||
|
static DiagDirection _build_depot_direction;
|
||||||
|
|
||||||
|
struct RoadStopGUISettings {
|
||||||
|
DiagDirection orientation; // This replaces _road_station_picker_orientation
|
||||||
|
|
||||||
|
RoadStopClassID roadstop_class;
|
||||||
|
byte roadstop_type;
|
||||||
|
byte roadstop_count;
|
||||||
|
};
|
||||||
|
static RoadStopGUISettings _roadstop_gui_settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the values of the RoadFlags
|
* Define the values of the RoadFlags
|
||||||
* @see CmdBuildLongRoad
|
* @see CmdBuildLongRoad
|
||||||
@@ -65,8 +84,6 @@ static RoadFlags _place_road_flag;
|
|||||||
|
|
||||||
static RoadType _cur_roadtype;
|
static RoadType _cur_roadtype;
|
||||||
|
|
||||||
static DiagDirection _road_depot_orientation;
|
|
||||||
static DiagDirection _road_station_picker_orientation;
|
|
||||||
|
|
||||||
void CcPlaySound_CONSTRUCTION_OTHER(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd)
|
void CcPlaySound_CONSTRUCTION_OTHER(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd)
|
||||||
{
|
{
|
||||||
@@ -184,17 +201,18 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2,
|
|||||||
*/
|
*/
|
||||||
static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, uint32 cmd)
|
static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, uint32 cmd)
|
||||||
{
|
{
|
||||||
uint8 ddir = _road_station_picker_orientation;
|
uint8 ddir = _roadstop_gui_settings.orientation;
|
||||||
SB(p2, 16, 16, INVALID_STATION); // no station to join
|
|
||||||
|
|
||||||
if (ddir >= DIAGDIR_END) {
|
if (ddir >= DIAGDIR_END) {
|
||||||
SetBit(p2, 1); // It's a drive-through stop.
|
SetBit(p2, 1); // It's a drive-through stop.
|
||||||
ddir -= DIAGDIR_END; // Adjust picker result to actual direction.
|
ddir -= DIAGDIR_END; // Adjust picker result to actual direction.
|
||||||
}
|
}
|
||||||
p2 |= ddir << 3; // Set the DiagDirecion into p2 bits 3 and 4.
|
p2 |= ddir << 3; // Set the DiagDirecion into p2 bits 3 and 4.
|
||||||
|
p2 |= INVALID_STATION << 16; // no station to join
|
||||||
|
|
||||||
TileArea ta(start_tile, end_tile);
|
TileArea ta(start_tile, end_tile);
|
||||||
CommandContainer cmdcont = NewCommandContainerBasic(ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop);
|
CommandContainer cmdcont = NewCommandContainerBasic(ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop);
|
||||||
|
cmdcont.p3 = (_roadstop_gui_settings.roadstop_type << 8) | _roadstop_gui_settings.roadstop_class;
|
||||||
ShowSelectStationIfNeeded(cmdcont, ta);
|
ShowSelectStationIfNeeded(cmdcont, ta);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +235,7 @@ static void PlaceRoad_Waypoint(TileIndex tile)
|
|||||||
} else {
|
} else {
|
||||||
/* Tile where we can't build rail waypoints. This is always going to fail,
|
/* Tile where we can't build rail waypoints. This is always going to fail,
|
||||||
* but provides the user with a proper error message. */
|
* but provides the user with a proper error message. */
|
||||||
DoCommandP(tile, 1 | 1 << 8, INVALID_STATION << 16, CMD_BUILD_ROAD_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT));
|
DoCommandP(tile, 1 | 1 << 8, ROADSTOP_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_ROAD_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +248,8 @@ static void PlaceRoad_BusStation(TileIndex tile)
|
|||||||
if (_remove_button_clicked) {
|
if (_remove_button_clicked) {
|
||||||
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP);
|
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP);
|
||||||
} else {
|
} else {
|
||||||
if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop.
|
if (_roadstop_gui_settings.orientation < DIAGDIR_END) { // Not a drive-through stop.
|
||||||
VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP);
|
VpStartPlaceSizing(tile, (DiagDirToAxis(_roadstop_gui_settings.orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP);
|
||||||
} else {
|
} else {
|
||||||
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP);
|
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP);
|
||||||
}
|
}
|
||||||
@@ -248,8 +266,8 @@ static void PlaceRoad_TruckStation(TileIndex tile)
|
|||||||
if (_remove_button_clicked) {
|
if (_remove_button_clicked) {
|
||||||
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP);
|
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP);
|
||||||
} else {
|
} else {
|
||||||
if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop.
|
if (_roadstop_gui_settings.orientation < DIAGDIR_END) { // Not a drive-through stop.
|
||||||
VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
|
VpStartPlaceSizing(tile, (DiagDirToAxis(_roadstop_gui_settings.orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
|
||||||
} else {
|
} else {
|
||||||
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
|
VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
|
||||||
}
|
}
|
||||||
@@ -584,7 +602,7 @@ struct BuildRoadToolbarWindow : Window {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WID_ROT_DEPOT:
|
case WID_ROT_DEPOT:
|
||||||
DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0,
|
DoCommandP(tile, _cur_roadtype << 2 | _build_depot_direction, 0,
|
||||||
CMD_BUILD_ROAD_DEPOT | CMD_MSG(this->rti->strings.err_depot), CcRoadDepot);
|
CMD_BUILD_ROAD_DEPOT | CMD_MSG(this->rti->strings.err_depot), CcRoadDepot);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -721,7 +739,7 @@ struct BuildRoadToolbarWindow : Window {
|
|||||||
DoCommandP(ta.tile, ta.w | ta.h << 8, (1 << 2), CMD_REMOVE_ROAD_STOP | CMD_MSG(STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT), CcPlaySound_CONSTRUCTION_OTHER);
|
DoCommandP(ta.tile, ta.w | ta.h << 8, (1 << 2), CMD_REMOVE_ROAD_STOP | CMD_MSG(STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT), CcPlaySound_CONSTRUCTION_OTHER);
|
||||||
} else {
|
} else {
|
||||||
uint32 p1 = ta.w | ta.h << 8 | _ctrl_pressed << 16 | (select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y) << 17;
|
uint32 p1 = ta.w | ta.h << 8 | _ctrl_pressed << 16 | (select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y) << 17;
|
||||||
uint32 p2 = INVALID_STATION << 16;
|
uint32 p2 = ROADSTOP_CLASS_WAYP | INVALID_STATION << 16;
|
||||||
|
|
||||||
CommandContainer cmdcont = NewCommandContainerBasic(ta.tile, p1, p2, CMD_BUILD_ROAD_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT), CcPlaySound_CONSTRUCTION_OTHER);
|
CommandContainer cmdcont = NewCommandContainerBasic(ta.tile, p1, p2, CMD_BUILD_ROAD_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT), CcPlaySound_CONSTRUCTION_OTHER);
|
||||||
ShowSelectWaypointIfNeeded(cmdcont, ta);
|
ShowSelectWaypointIfNeeded(cmdcont, ta);
|
||||||
@@ -731,24 +749,24 @@ struct BuildRoadToolbarWindow : Window {
|
|||||||
|
|
||||||
case DDSP_BUILD_BUSSTOP:
|
case DDSP_BUILD_BUSSTOP:
|
||||||
case DDSP_REMOVE_BUSSTOP:
|
case DDSP_REMOVE_BUSSTOP:
|
||||||
if (this->IsWidgetLowered(WID_ROT_BUS_STATION)) {
|
if (this->IsWidgetLowered(WID_ROT_BUS_STATION) && GetIfClassHasNewStopsByType(RoadStopClass::Get(_roadstop_gui_settings.roadstop_class), ROADSTOP_BUS)) {
|
||||||
if (_remove_button_clicked) {
|
if (_remove_button_clicked) {
|
||||||
TileArea ta(start_tile, end_tile);
|
TileArea ta(start_tile, end_tile);
|
||||||
DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_BUS]), CcPlaySound_CONSTRUCTION_OTHER);
|
DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_BUS]), CcPlaySound_CONSTRUCTION_OTHER);
|
||||||
} else {
|
} else {
|
||||||
PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_BUS]));
|
PlaceRoadStop(start_tile, end_tile, (_cur_roadtype << 5) | (_ctrl_pressed << 2) | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_BUS]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DDSP_BUILD_TRUCKSTOP:
|
case DDSP_BUILD_TRUCKSTOP:
|
||||||
case DDSP_REMOVE_TRUCKSTOP:
|
case DDSP_REMOVE_TRUCKSTOP:
|
||||||
if (this->IsWidgetLowered(WID_ROT_TRUCK_STATION)) {
|
if (this->IsWidgetLowered(WID_ROT_TRUCK_STATION) && GetIfClassHasNewStopsByType(RoadStopClass::Get(_roadstop_gui_settings.roadstop_class), ROADSTOP_TRUCK)) {
|
||||||
if (_remove_button_clicked) {
|
if (_remove_button_clicked) {
|
||||||
TileArea ta(start_tile, end_tile);
|
TileArea ta(start_tile, end_tile);
|
||||||
DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_CONSTRUCTION_OTHER);
|
DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_CONSTRUCTION_OTHER);
|
||||||
} else {
|
} else {
|
||||||
PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_TRUCK]));
|
PlaceRoadStop(start_tile, end_tile, (_cur_roadtype << 5) | (_ctrl_pressed << 2) | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_TRUCK]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1044,7 +1062,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase {
|
|||||||
{
|
{
|
||||||
this->CreateNestedTree();
|
this->CreateNestedTree();
|
||||||
|
|
||||||
this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
|
this->LowerWidget(_build_depot_direction + WID_BROD_DEPOT_NE);
|
||||||
if (RoadTypeIsTram(_cur_roadtype)) {
|
if (RoadTypeIsTram(_cur_roadtype)) {
|
||||||
this->GetWidget<NWidgetCore>(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION;
|
this->GetWidget<NWidgetCore>(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION;
|
||||||
for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget<NWidgetCore>(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP;
|
for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget<NWidgetCore>(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP;
|
||||||
@@ -1075,9 +1093,9 @@ struct BuildRoadDepotWindow : public PickerWindowBase {
|
|||||||
case WID_BROD_DEPOT_NE:
|
case WID_BROD_DEPOT_NE:
|
||||||
case WID_BROD_DEPOT_SW:
|
case WID_BROD_DEPOT_SW:
|
||||||
case WID_BROD_DEPOT_SE:
|
case WID_BROD_DEPOT_SE:
|
||||||
this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
|
this->RaiseWidget(_build_depot_direction + WID_BROD_DEPOT_NE);
|
||||||
_road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE);
|
_build_depot_direction = (DiagDirection)(widget - WID_BROD_DEPOT_NE);
|
||||||
this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
|
this->LowerWidget(_build_depot_direction + WID_BROD_DEPOT_NE);
|
||||||
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
|
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
|
||||||
this->SetDirty();
|
this->SetDirty();
|
||||||
break;
|
break;
|
||||||
@@ -1130,14 +1148,84 @@ static void ShowRoadDepotPicker(Window *parent)
|
|||||||
new BuildRoadDepotWindow(&_build_road_depot_desc, parent);
|
new BuildRoadDepotWindow(&_build_road_depot_desc, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Enum referring to the Hotkeys in the build road stop window */
|
||||||
|
enum BuildRoadStopHotkeys {
|
||||||
|
BROSHK_FOCUS_FILTER_BOX, ///< Focus the edit box for editing the filter string
|
||||||
|
};
|
||||||
|
|
||||||
struct BuildRoadStationWindow : public PickerWindowBase {
|
struct BuildRoadStationWindow : public PickerWindowBase {
|
||||||
BuildRoadStationWindow(WindowDesc *desc, Window *parent, RoadStopType rs) : PickerWindowBase(desc, parent)
|
private:
|
||||||
|
RoadStopType roadStopType; ///< The RoadStopType for this Window.
|
||||||
|
uint line_height; ///< Height of a single line in the newstation selection matrix.
|
||||||
|
uint coverage_height; ///< Height of the coverage texts.
|
||||||
|
Scrollbar *vscrollList; ///< Vertical scrollbar of the new station list.
|
||||||
|
Scrollbar *vscrollMatrix; ///< Vertical scrollbar of the station picker matrix.
|
||||||
|
|
||||||
|
typedef GUIList<RoadStopClassID, StringFilter &> GUIRoadStopClassList; ///< Type definition for the list to hold available road stop classes.
|
||||||
|
|
||||||
|
static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box.
|
||||||
|
|
||||||
|
static Listing last_sorting; ///< Default sorting of #GUIRoadStopClassList.
|
||||||
|
static Filtering last_filtering; ///< Default filtering of #GUIRoadStopClassList.
|
||||||
|
static GUIRoadStopClassList::SortFunction * const sorter_funcs[]; ///< Sort functions of the #GUIRoadStopClassList.
|
||||||
|
static GUIRoadStopClassList::FilterFunction * const filter_funcs[]; ///< Filter functions of the #GUIRoadStopClassList.
|
||||||
|
GUIRoadStopClassList roadstop_classes; ///< Available road stop classes.
|
||||||
|
StringFilter string_filter; ///< Filter for available road stop classes.
|
||||||
|
QueryString filter_editbox; ///< Filter editbox.
|
||||||
|
|
||||||
|
void EnsureSelectedClassIsVisible()
|
||||||
{
|
{
|
||||||
|
uint pos = 0;
|
||||||
|
for (auto rs_class : this->roadstop_classes) {
|
||||||
|
if (rs_class == _roadstop_gui_settings.roadstop_class) break;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
this->vscrollList->SetCount((int)this->roadstop_classes.size());
|
||||||
|
this->vscrollList->ScrollTowards(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
BuildRoadStationWindow(WindowDesc *desc, Window *parent, RoadStopType rs) : PickerWindowBase(desc, parent), filter_editbox(EDITBOX_MAX_SIZE * MAX_CHAR_LENGTH, EDITBOX_MAX_SIZE)
|
||||||
|
{
|
||||||
|
this->coverage_height = 2 * FONT_HEIGHT_NORMAL + 3 * WD_PAR_VSEP_NORMAL;
|
||||||
|
this->vscrollList = nullptr;
|
||||||
|
this->vscrollMatrix = nullptr;
|
||||||
|
this->roadStopType = rs;
|
||||||
|
bool newstops = GetIfNewStopsByType(rs);
|
||||||
|
|
||||||
this->CreateNestedTree();
|
this->CreateNestedTree();
|
||||||
|
|
||||||
/* Trams don't have non-drivethrough stations */
|
NWidgetStacked *newst_additions = this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_ADDITIONS);
|
||||||
if (RoadTypeIsTram(_cur_roadtype) && _road_station_picker_orientation < DIAGDIR_END) {
|
newst_additions->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
|
||||||
_road_station_picker_orientation = DIAGDIR_END;
|
newst_additions = this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_MATRIX);
|
||||||
|
newst_additions->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
|
||||||
|
newst_additions = this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_DEFSIZE);
|
||||||
|
newst_additions->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
|
||||||
|
newst_additions = this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_RESIZE);
|
||||||
|
newst_additions->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
|
||||||
|
newst_additions = this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_ORIENTATION);
|
||||||
|
newst_additions->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
|
||||||
|
newst_additions = this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_TYPE_SEL);
|
||||||
|
newst_additions->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
|
||||||
|
/* Hide the station class filter if no stations other than the default one are available. */
|
||||||
|
this->GetWidget<NWidgetStacked>(WID_BROS_FILTER_CONTAINER)->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
|
||||||
|
if (newstops) {
|
||||||
|
this->vscrollList = this->GetScrollbar(WID_BROS_NEWST_SCROLL);
|
||||||
|
this->vscrollMatrix = this->GetScrollbar(WID_BROS_MATRIX_SCROLL);
|
||||||
|
|
||||||
|
this->querystrings[WID_BROS_FILTER_EDITBOX] = &this->filter_editbox;
|
||||||
|
this->roadstop_classes.SetListing(this->last_sorting);
|
||||||
|
this->roadstop_classes.SetFiltering(this->last_filtering);
|
||||||
|
this->roadstop_classes.SetSortFuncs(this->sorter_funcs);
|
||||||
|
this->roadstop_classes.SetFilterFuncs(this->filter_funcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->roadstop_classes.ForceRebuild();
|
||||||
|
BuildRoadStopClassesAvailable();
|
||||||
|
|
||||||
|
// Trams don't have non-drivethrough stations
|
||||||
|
if (RoadTypeIsTram(_cur_roadtype) && _roadstop_gui_settings.orientation < DIAGDIR_END) {
|
||||||
|
_roadstop_gui_settings.orientation = DIAGDIR_END;
|
||||||
}
|
}
|
||||||
const RoadTypeInfo *rti = GetRoadTypeInfo(_cur_roadtype);
|
const RoadTypeInfo *rti = GetRoadTypeInfo(_cur_roadtype);
|
||||||
this->GetWidget<NWidgetCore>(WID_BROS_CAPTION)->widget_data = rti->strings.picker_title[rs];
|
this->GetWidget<NWidgetCore>(WID_BROS_CAPTION)->widget_data = rti->strings.picker_title[rs];
|
||||||
@@ -1146,12 +1234,39 @@ struct BuildRoadStationWindow : public PickerWindowBase {
|
|||||||
this->GetWidget<NWidgetCore>(i)->tool_tip = rti->strings.picker_tooltip[rs];
|
this->GetWidget<NWidgetCore>(i)->tool_tip = rti->strings.picker_tooltip[rs];
|
||||||
}
|
}
|
||||||
|
|
||||||
this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
|
this->LowerWidget(_roadstop_gui_settings.orientation + WID_BROS_STATION_NE);
|
||||||
this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
|
this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
|
||||||
|
|
||||||
this->FinishInitNested(TRANSPORT_ROAD);
|
this->FinishInitNested(TRANSPORT_ROAD);
|
||||||
|
|
||||||
this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
|
this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
|
||||||
|
if (!newstops || _roadstop_gui_settings.roadstop_class >= (int)RoadStopClass::GetClassCount()) {
|
||||||
|
/* There's no new stops available or the list has reduced in size.
|
||||||
|
* Now, set the default road stops as selected. */
|
||||||
|
_roadstop_gui_settings.roadstop_class = ROADSTOP_CLASS_DFLT;
|
||||||
|
_roadstop_gui_settings.roadstop_type = 0;
|
||||||
|
}
|
||||||
|
if (newstops) {
|
||||||
|
/* The currently selected class doesn't have any stops for this RoadStopType, reset the selection. */
|
||||||
|
if (!GetIfClassHasNewStopsByType(RoadStopClass::Get(_roadstop_gui_settings.roadstop_class), rs)) {
|
||||||
|
_roadstop_gui_settings.roadstop_class = ROADSTOP_CLASS_DFLT;
|
||||||
|
_roadstop_gui_settings.roadstop_type = 0;
|
||||||
|
}
|
||||||
|
_roadstop_gui_settings.roadstop_count = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpecCount();
|
||||||
|
_roadstop_gui_settings.roadstop_type = std::min((int)_roadstop_gui_settings.roadstop_type, _roadstop_gui_settings.roadstop_count - 1);
|
||||||
|
|
||||||
|
/* Reset back to default class if the previously selected class is not available for this road stop type. */
|
||||||
|
if (!GetIfClassHasNewStopsByType(RoadStopClass::Get(_roadstop_gui_settings.roadstop_class), roadStopType)) {
|
||||||
|
_roadstop_gui_settings.roadstop_class = ROADSTOP_CLASS_DFLT;
|
||||||
|
}
|
||||||
|
|
||||||
|
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_BROS_MATRIX);
|
||||||
|
matrix->SetScrollbar(this->vscrollMatrix);
|
||||||
|
matrix->SetCount(_roadstop_gui_settings.roadstop_count);
|
||||||
|
matrix->SetClicked(_roadstop_gui_settings.roadstop_type);
|
||||||
|
|
||||||
|
this->EnsureSelectedClassIsVisible();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~BuildRoadStationWindow()
|
virtual ~BuildRoadStationWindow()
|
||||||
@@ -1159,10 +1274,86 @@ struct BuildRoadStationWindow : public PickerWindowBase {
|
|||||||
DeleteWindowById(WC_SELECT_STATION, 0);
|
DeleteWindowById(WC_SELECT_STATION, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sort classes by RoadStopClassID. */
|
||||||
|
static bool RoadStopClassIDSorter(RoadStopClassID const &a, RoadStopClassID const &b)
|
||||||
|
{
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Filter classes by class name. */
|
||||||
|
static bool CDECL TagNameFilter(RoadStopClassID const *sc, StringFilter &filter)
|
||||||
|
{
|
||||||
|
char buffer[DRAW_STRING_BUFFER];
|
||||||
|
GetString(buffer, RoadStopClass::Get(*sc)->name, lastof(buffer));
|
||||||
|
|
||||||
|
filter.ResetState();
|
||||||
|
filter.AddLine(buffer);
|
||||||
|
return filter.GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ShowNewStops() const
|
||||||
|
{
|
||||||
|
return this->vscrollList != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildRoadStopClassesAvailable()
|
||||||
|
{
|
||||||
|
if (!this->roadstop_classes.NeedRebuild()) return;
|
||||||
|
|
||||||
|
this->roadstop_classes.clear();
|
||||||
|
|
||||||
|
for (uint i = 0; i < RoadStopClass::GetClassCount(); i++) {
|
||||||
|
RoadStopClassID rs_id = (RoadStopClassID)i;
|
||||||
|
if (rs_id == ROADSTOP_CLASS_WAYP) {
|
||||||
|
// Skip waypoints.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RoadStopClass *rs_class = RoadStopClass::Get(rs_id);
|
||||||
|
if (GetIfClassHasNewStopsByType(rs_class, this->roadStopType)) this->roadstop_classes.push_back(rs_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->ShowNewStops()) {
|
||||||
|
this->roadstop_classes.Filter(this->string_filter);
|
||||||
|
this->roadstop_classes.shrink_to_fit();
|
||||||
|
this->roadstop_classes.RebuildDone();
|
||||||
|
this->roadstop_classes.Sort();
|
||||||
|
|
||||||
|
this->vscrollList->SetCount((uint)this->roadstop_classes.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||||
|
{
|
||||||
|
if (!gui_scope) return;
|
||||||
|
|
||||||
|
this->BuildRoadStopClassesAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventState OnHotkey(int hotkey) override
|
||||||
|
{
|
||||||
|
switch (hotkey) {
|
||||||
|
case BROSHK_FOCUS_FILTER_BOX:
|
||||||
|
this->SetFocusedWidget(WID_BROS_FILTER_EDITBOX);
|
||||||
|
SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ES_NOT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ES_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEditboxChanged(int wid) override
|
||||||
|
{
|
||||||
|
string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||||
|
this->roadstop_classes.SetFilterState(!string_filter.IsEmpty());
|
||||||
|
this->roadstop_classes.ForceRebuild();
|
||||||
|
this->InvalidateData();
|
||||||
|
}
|
||||||
|
|
||||||
void OnPaint() override
|
void OnPaint() override
|
||||||
{
|
{
|
||||||
this->DrawWidgets();
|
|
||||||
|
|
||||||
int rad = _settings_game.station.modified_catchment ? ((this->window_class == WC_BUS_STATION) ? CA_BUS : CA_TRUCK) : CA_UNMODIFIED;
|
int rad = _settings_game.station.modified_catchment ? ((this->window_class == WC_BUS_STATION) ? CA_BUS : CA_TRUCK) : CA_UNMODIFIED;
|
||||||
rad += _settings_game.station.catchment_increase;
|
rad += _settings_game.station.catchment_increase;
|
||||||
if (_settings_client.gui.station_show_coverage) {
|
if (_settings_client.gui.station_show_coverage) {
|
||||||
@@ -1171,50 +1362,172 @@ struct BuildRoadStationWindow : public PickerWindowBase {
|
|||||||
SetTileSelectSize(1, 1);
|
SetTileSelectSize(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->DrawWidgets();
|
||||||
|
|
||||||
|
if (this->IsShaded()) return;
|
||||||
/* 'Accepts' and 'Supplies' texts. */
|
/* 'Accepts' and 'Supplies' texts. */
|
||||||
StationCoverageType sct = (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY;
|
StationCoverageType sct = (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY;
|
||||||
|
|
||||||
|
NWidgetBase *cov = this->GetWidget<NWidgetBase>(WID_BROS_INFO);
|
||||||
|
int top = cov->pos_y + WD_PAR_VSEP_NORMAL;
|
||||||
|
int left = cov->pos_x + WD_FRAMERECT_LEFT;
|
||||||
|
int right = cov->pos_x + cov->current_x - WD_FRAMERECT_RIGHT;
|
||||||
|
int bottom = cov->pos_y + cov->current_y;
|
||||||
|
top = DrawStationCoverageAreaText(left, right, top, sct, rad, false) + WD_PAR_VSEP_NORMAL;
|
||||||
|
top = DrawStationCoverageAreaText(left, right, top, sct, rad, true) + WD_PAR_VSEP_NORMAL;
|
||||||
|
|
||||||
|
/*
|
||||||
int top = this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->pos_y + this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->current_y + WD_PAR_VSEP_NORMAL;
|
int top = this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->pos_y + this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->current_y + WD_PAR_VSEP_NORMAL;
|
||||||
NWidgetBase *back_nwi = this->GetWidget<NWidgetBase>(WID_BROS_BACKGROUND);
|
NWidgetBase *back_nwi = this->GetWidget<NWidgetBase>(WID_BROS_BACKGROUND);
|
||||||
int right = back_nwi->pos_x + back_nwi->current_x;
|
int right = back_nwi->pos_x + back_nwi->current_x;
|
||||||
int bottom = back_nwi->pos_y + back_nwi->current_y;
|
int bottom = back_nwi->pos_y + back_nwi->current_y;
|
||||||
top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, false) + WD_PAR_VSEP_NORMAL;
|
top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, false) + WD_PAR_VSEP_NORMAL;
|
||||||
top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, true) + WD_PAR_VSEP_NORMAL;
|
top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, true) + WD_PAR_VSEP_NORMAL;
|
||||||
|
*/
|
||||||
/* Resize background if the window is too small.
|
/* Resize background if the window is too small.
|
||||||
* Never make the window smaller to avoid oscillating if the size change affects the acceptance.
|
* Never make the window smaller to avoid oscillating if the size change affects the acceptance.
|
||||||
* (This is the case, if making the window bigger moves the mouse into the window.) */
|
* (This is the case, if making the window bigger moves the mouse into the window.) */
|
||||||
if (top > bottom) {
|
if (top > bottom) {
|
||||||
ResizeWindow(this, 0, top - bottom, false);
|
this->coverage_height += top - bottom;
|
||||||
|
this->ReInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||||
{
|
|
||||||
if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return;
|
|
||||||
|
|
||||||
size->width = ScaleGUITrad(64) + 2;
|
|
||||||
size->height = ScaleGUITrad(48) + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawWidget(const Rect &r, int widget) const override
|
|
||||||
{
|
|
||||||
if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return;
|
|
||||||
|
|
||||||
StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK;
|
|
||||||
StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, _cur_roadtype, widget - WID_BROS_STATION_NE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnClick(Point pt, int widget, int click_count) override
|
|
||||||
{
|
{
|
||||||
switch (widget) {
|
switch (widget) {
|
||||||
|
case WID_BROS_NEWST_LIST: {
|
||||||
|
Dimension d = { 0, 0 };
|
||||||
|
for (auto rs_class : this->roadstop_classes) {
|
||||||
|
d = maxdim(d, GetStringBoundingBox(RoadStopClass::Get(rs_class)->name));
|
||||||
|
}
|
||||||
|
size->width = std::max(size->width, d.width + padding.width);
|
||||||
|
this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
|
||||||
|
size->height = 5 * this->line_height;
|
||||||
|
resize->height = this->line_height;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WID_BROS_IMAGE:
|
||||||
|
size->width = ScaleGUITrad(64) + 2;
|
||||||
|
size->height = ScaleGUITrad(58) + 2;
|
||||||
|
break;
|
||||||
|
|
||||||
case WID_BROS_STATION_NE:
|
case WID_BROS_STATION_NE:
|
||||||
case WID_BROS_STATION_SE:
|
case WID_BROS_STATION_SE:
|
||||||
case WID_BROS_STATION_SW:
|
case WID_BROS_STATION_SW:
|
||||||
case WID_BROS_STATION_NW:
|
case WID_BROS_STATION_NW:
|
||||||
case WID_BROS_STATION_X:
|
case WID_BROS_STATION_X:
|
||||||
case WID_BROS_STATION_Y:
|
case WID_BROS_STATION_Y:
|
||||||
this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
|
case WID_BROS_MATRIX:
|
||||||
_road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE);
|
fill->height = 1;
|
||||||
this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
|
resize->height = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WID_BROS_INFO:
|
||||||
|
size->height = this->coverage_height;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simply to have a easier way to get the StationType for bus, truck and trams from the WindowClass.
|
||||||
|
*/
|
||||||
|
StationType GetRoadStationTypeByWindowClass(WindowClass window_class) const {
|
||||||
|
switch (window_class) {
|
||||||
|
case WC_BUS_STATION: return STATION_BUS;
|
||||||
|
case WC_TRUCK_STATION: return STATION_TRUCK;
|
||||||
|
default: NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawWidget(const Rect &r, int widget) const override
|
||||||
|
{
|
||||||
|
DrawPixelInfo tmp_dpi;
|
||||||
|
|
||||||
|
switch (GB(widget, 0, 16)) {
|
||||||
|
case WID_BROS_STATION_NE:
|
||||||
|
case WID_BROS_STATION_SE:
|
||||||
|
case WID_BROS_STATION_SW:
|
||||||
|
case WID_BROS_STATION_NW:
|
||||||
|
case WID_BROS_STATION_X:
|
||||||
|
case WID_BROS_STATION_Y: {
|
||||||
|
StationType st = GetRoadStationTypeByWindowClass(this->window_class);
|
||||||
|
const RoadStopSpec *spec = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpec(_roadstop_gui_settings.roadstop_type);
|
||||||
|
if (spec == nullptr) {
|
||||||
|
StationPickerDrawSprite(r.left + WD_MATRIX_LEFT + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, _cur_roadtype, widget - WID_BROS_STATION_NE);
|
||||||
|
} else {
|
||||||
|
DrawRoadStopTile(r.left + WD_MATRIX_LEFT + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), _cur_roadtype,
|
||||||
|
RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpec(_roadstop_gui_settings.roadstop_type), st, (int)widget - WID_BROS_STATION_NE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WID_BROS_NEWST_LIST: {
|
||||||
|
uint statclass = 0;
|
||||||
|
uint row = 0;
|
||||||
|
for (auto rs_class : this->roadstop_classes) {
|
||||||
|
if (this->vscrollList->IsVisible(statclass)) {
|
||||||
|
DrawString(r.left + WD_MATRIX_LEFT, r.right, row * this->line_height + r.top + WD_MATRIX_TOP,
|
||||||
|
RoadStopClass::Get(rs_class)->name,
|
||||||
|
rs_class == _roadstop_gui_settings.roadstop_class ? TC_WHITE : TC_BLACK);
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
statclass++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WID_BROS_IMAGE: {
|
||||||
|
byte type = GB(widget, 16, 16);
|
||||||
|
assert(type < _roadstop_gui_settings.roadstop_count);
|
||||||
|
|
||||||
|
// Set up a clipping area for the sprite preview.
|
||||||
|
if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) {
|
||||||
|
DrawPixelInfo *old_dpi = _cur_dpi;
|
||||||
|
_cur_dpi = &tmp_dpi;
|
||||||
|
int x = ScaleGUITrad(31) + 1;
|
||||||
|
int y = r.bottom - r.top - ScaleGUITrad(31);
|
||||||
|
// Instead of "5" (5th view), pass the orientation clicked in the selection.
|
||||||
|
const RoadStopSpec *spec = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpec(_roadstop_gui_settings.roadstop_type);
|
||||||
|
StationType st = GetRoadStationTypeByWindowClass(this->window_class);
|
||||||
|
if (spec == nullptr) {
|
||||||
|
StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, _cur_roadtype, _roadstop_gui_settings.orientation);
|
||||||
|
} else {
|
||||||
|
DrawRoadStopTile(x, y, _cur_roadtype, RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpec(type), st, (uint8)_roadstop_gui_settings.orientation);
|
||||||
|
}
|
||||||
|
_cur_dpi = old_dpi;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnResize() override {
|
||||||
|
if (this->vscrollList != nullptr) {
|
||||||
|
this->vscrollList->SetCapacityFromWidget(this, WID_BROS_NEWST_LIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStringParameters(int widget) const override {
|
||||||
|
if (widget == WID_BROS_SHOW_NEWST_TYPE) {
|
||||||
|
const RoadStopSpec *roadstopspec = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpec(_roadstop_gui_settings.roadstop_type);
|
||||||
|
SetDParam(0, (roadstopspec != nullptr && roadstopspec->name != 0) ? roadstopspec->name : STR_STATION_CLASS_DFLT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnClick(Point pt, int widget, int click_count) override
|
||||||
|
{
|
||||||
|
switch (GB(widget, 0, 16)) {
|
||||||
|
case WID_BROS_STATION_NE:
|
||||||
|
case WID_BROS_STATION_SE:
|
||||||
|
case WID_BROS_STATION_SW:
|
||||||
|
case WID_BROS_STATION_NW:
|
||||||
|
case WID_BROS_STATION_X:
|
||||||
|
case WID_BROS_STATION_Y:
|
||||||
|
this->RaiseWidget(_roadstop_gui_settings.orientation + WID_BROS_STATION_NE);
|
||||||
|
_roadstop_gui_settings.orientation = (DiagDirection)(widget - WID_BROS_STATION_NE);
|
||||||
|
this->LowerWidget(_roadstop_gui_settings.orientation + WID_BROS_STATION_NE);
|
||||||
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
|
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
|
||||||
this->SetDirty();
|
this->SetDirty();
|
||||||
DeleteWindowById(WC_SELECT_STATION, 0);
|
DeleteWindowById(WC_SELECT_STATION, 0);
|
||||||
@@ -1230,6 +1543,41 @@ struct BuildRoadStationWindow : public PickerWindowBase {
|
|||||||
SetViewportCatchmentStation(nullptr, true);
|
SetViewportCatchmentStation(nullptr, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WID_BROS_NEWST_LIST: {
|
||||||
|
int y = this->vscrollList->GetScrolledRowFromWidget(pt.y, this, WID_BROS_NEWST_LIST);
|
||||||
|
if (y >= (int)this->roadstop_classes.size()) return;
|
||||||
|
RoadStopClassID class_id = this->roadstop_classes[y];
|
||||||
|
if (_roadstop_gui_settings.roadstop_class != class_id && GetIfClassHasNewStopsByType(RoadStopClass::Get(class_id), roadStopType)) {
|
||||||
|
_roadstop_gui_settings.roadstop_class = class_id;
|
||||||
|
RoadStopClass *rsclass = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class);
|
||||||
|
_roadstop_gui_settings.roadstop_count = rsclass->GetSpecCount();
|
||||||
|
_roadstop_gui_settings.roadstop_type = std::min((int)_roadstop_gui_settings.roadstop_type, std::max(0, (int)_roadstop_gui_settings.roadstop_count - 1));
|
||||||
|
|
||||||
|
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_BROS_MATRIX);
|
||||||
|
matrix->SetCount(_roadstop_gui_settings.roadstop_count);
|
||||||
|
matrix->SetClicked(_roadstop_gui_settings.roadstop_type);
|
||||||
|
}
|
||||||
|
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
|
||||||
|
this->SetDirty();
|
||||||
|
DeleteWindowById(WC_SELECT_STATION, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WID_BROS_IMAGE: {
|
||||||
|
int y = GB(widget, 16, 16);
|
||||||
|
if (y >= _roadstop_gui_settings.roadstop_count) return;
|
||||||
|
|
||||||
|
/* Check station availability callback */
|
||||||
|
_roadstop_gui_settings.roadstop_type = y;
|
||||||
|
|
||||||
|
this->GetWidget<NWidgetMatrix>(WID_BROS_MATRIX)->SetClicked(_roadstop_gui_settings.roadstop_type);
|
||||||
|
|
||||||
|
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
|
||||||
|
this->SetDirty();
|
||||||
|
DeleteWindowById(WC_SELECT_STATION, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1239,6 +1587,25 @@ struct BuildRoadStationWindow : public PickerWindowBase {
|
|||||||
{
|
{
|
||||||
CheckRedrawStationCoverage(this);
|
CheckRedrawStationCoverage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HotkeyList hotkeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Hotkey buildroadstop_hotkeys[] = {
|
||||||
|
Hotkey('F', "focus_filter_box", BROSHK_FOCUS_FILTER_BOX),
|
||||||
|
HOTKEY_LIST_END
|
||||||
|
};
|
||||||
|
HotkeyList BuildRoadStationWindow::hotkeys("buildroadstop", buildroadstop_hotkeys);
|
||||||
|
|
||||||
|
Listing BuildRoadStationWindow::last_sorting = { false, 0 };
|
||||||
|
Filtering BuildRoadStationWindow::last_filtering = { false, 0 };
|
||||||
|
|
||||||
|
BuildRoadStationWindow::GUIRoadStopClassList::SortFunction * const BuildRoadStationWindow::sorter_funcs[] = {
|
||||||
|
&RoadStopClassIDSorter,
|
||||||
|
};
|
||||||
|
|
||||||
|
BuildRoadStationWindow::GUIRoadStopClassList::FilterFunction * const BuildRoadStationWindow::filter_funcs[] = {
|
||||||
|
&TagNameFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Widget definition of the build road station window */
|
/** Widget definition of the build road station window */
|
||||||
@@ -1246,38 +1613,82 @@ static const NWidgetPart _nested_road_station_picker_widgets[] = {
|
|||||||
NWidget(NWID_HORIZONTAL),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION),
|
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION),
|
||||||
|
NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
|
||||||
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_DEFSIZE),
|
||||||
|
NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
|
||||||
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND),
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND),
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 3),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
|
NWidget(NWID_VERTICAL),
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_FILTER_CONTAINER),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 0),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(WWT_TEXT, COLOUR_DARK_GREEN), SetFill(0, 1), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_BROS_FILTER_EDITBOX), SetFill(1, 0), SetResize(1, 0),
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_ADDITIONS),
|
||||||
|
NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), SetPadding(2, 0, 1, 0),
|
||||||
|
NWidget(WWT_MATRIX, COLOUR_GREY, WID_BROS_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0),
|
||||||
|
SetMatrixDataTip(1, 0, STR_STATION_BUILD_STATION_CLASS_TOOLTIP), SetScrollbar(WID_BROS_NEWST_SCROLL),
|
||||||
|
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BROS_NEWST_SCROLL),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_ORIENTATION),
|
||||||
|
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(4, 2, 1, 2),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_HORIZONTAL), SetPIP(5, 2, 5), SetPadding(0, 0, 1, 0),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SPACER), SetMinimalSize(0, 2),
|
||||||
|
NWidget(NWID_HORIZONTAL), SetPIP(5, 2, 5), SetPadding(0, 0, 1, 0), // For PIP, 5 because the 2 is applied before and after aswell. We want to use 7 to be the same as the class list
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_TYPE_SEL),
|
||||||
|
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_SHOW_NEWST_TYPE), SetMinimalSize(144, 8), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(4, 2, 4, 2),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2),
|
||||||
|
NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12),
|
||||||
|
SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
|
||||||
|
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12),
|
||||||
|
SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_MATRIX),
|
||||||
|
/* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */
|
||||||
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BROS_MATRIX_SCROLL),
|
||||||
|
NWidget(NWID_HORIZONTAL),
|
||||||
|
NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BROS_MATRIX), SetScrollbar(WID_BROS_MATRIX_SCROLL), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_IMAGE), SetMinimalSize(66, 60),
|
||||||
|
SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BROS_MATRIX_SCROLL),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BROS_MATRIX_SCROLL),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 2),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
|
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BROS_INFO), SetPadding(2, 5, 0, 1), SetFill(1, 1), SetResize(1, 0),
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_RESIZE),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(NWID_VERTICAL),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 1),
|
|
||||||
NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
|
|
||||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL),
|
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
|
||||||
EndContainer(),
|
|
||||||
NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
|
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
|
||||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12),
|
|
||||||
SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
|
|
||||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12),
|
|
||||||
SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
|
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
|
||||||
EndContainer(),
|
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1),
|
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1293,29 +1704,66 @@ static const NWidgetPart _nested_tram_station_picker_widgets[] = {
|
|||||||
NWidget(NWID_HORIZONTAL),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION),
|
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION),
|
||||||
|
NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
|
||||||
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_DEFSIZE),
|
||||||
|
NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
|
||||||
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND),
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND),
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 3),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
|
NWidget(NWID_VERTICAL),
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_ADDITIONS),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), SetPadding(2, 0, 1, 0),
|
||||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
NWidget(WWT_MATRIX, COLOUR_GREY, WID_BROS_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0),
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
SetMatrixDataTip(1, 0, STR_STATION_BUILD_STATION_CLASS_TOOLTIP), SetScrollbar(WID_BROS_NEWST_SCROLL),
|
||||||
|
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BROS_NEWST_SCROLL),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SPACER), SetMinimalSize(0, 3),
|
||||||
|
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2),
|
||||||
|
NWidget(NWID_SPACER), SetMinimalSize(0, 1),
|
||||||
|
NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SPACER), SetMinimalSize(0, 3),
|
||||||
|
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_SHOW_NEWST_TYPE), SetMinimalSize(144, 11), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(1, 2, 4, 2),
|
||||||
|
NWidget(NWID_SPACER), SetMinimalSize(0, 1),
|
||||||
|
NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12),
|
||||||
|
SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
|
||||||
|
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12),
|
||||||
|
SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
|
||||||
|
NWidget(NWID_SPACER), SetFill(1, 0),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_MATRIX),
|
||||||
|
/* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */
|
||||||
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BROS_MATRIX_SCROLL),
|
||||||
|
NWidget(NWID_HORIZONTAL),
|
||||||
|
NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BROS_MATRIX), SetScrollbar(WID_BROS_MATRIX_SCROLL), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_IMAGE), SetMinimalSize(66, 60),
|
||||||
|
SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BROS_MATRIX_SCROLL),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BROS_MATRIX_SCROLL),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 1),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
|
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BROS_INFO), SetFill(1, 1), SetResize(1, 0),
|
||||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL),
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_RESIZE),
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
NWidget(NWID_VERTICAL),
|
||||||
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(),
|
||||||
|
NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
|
||||||
|
EndContainer(),
|
||||||
|
EndContainer(),
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
|
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
|
||||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12),
|
|
||||||
SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
|
|
||||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12),
|
|
||||||
SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
|
|
||||||
NWidget(NWID_SPACER), SetFill(1, 0),
|
|
||||||
EndContainer(),
|
|
||||||
NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1),
|
|
||||||
EndContainer(),
|
EndContainer(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1333,8 +1781,8 @@ static void ShowRVStationPicker(Window *parent, RoadStopType rs)
|
|||||||
|
|
||||||
void InitializeRoadGui()
|
void InitializeRoadGui()
|
||||||
{
|
{
|
||||||
_road_depot_orientation = DIAGDIR_NW;
|
_build_depot_direction = DIAGDIR_NW;
|
||||||
_road_station_picker_orientation = DIAGDIR_NW;
|
_roadstop_gui_settings.orientation = DIAGDIR_NW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -170,6 +170,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
|||||||
{ XSLFI_ROAD_WAYPOINTS, XSCF_NULL, 1, 1, "road_waypoints", nullptr, nullptr, nullptr },
|
{ XSLFI_ROAD_WAYPOINTS, XSCF_NULL, 1, 1, "road_waypoints", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_MORE_STATION_TYPES, XSCF_NULL, 1, 1, "more_station_types", nullptr, nullptr, nullptr },
|
{ XSLFI_MORE_STATION_TYPES, XSCF_NULL, 1, 1, "more_station_types", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr },
|
{ XSLFI_RV_ORDER_EXTRA_FLAGS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "rv_order_extra_flags", nullptr, nullptr, nullptr },
|
||||||
|
{ XSLFI_GRF_ROADSTOPS, XSCF_NULL, 1, 1, "grf_road_stops", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr },
|
{ XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr },
|
||||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
||||||
};
|
};
|
||||||
|
@@ -123,6 +123,7 @@ enum SlXvFeatureIndex {
|
|||||||
XSLFI_ROAD_WAYPOINTS, ///< Road waypoints
|
XSLFI_ROAD_WAYPOINTS, ///< Road waypoints
|
||||||
XSLFI_MORE_STATION_TYPES, ///< More station types (field widening)
|
XSLFI_MORE_STATION_TYPES, ///< More station types (field widening)
|
||||||
XSLFI_RV_ORDER_EXTRA_FLAGS, ///< Road vehicle order extra flags
|
XSLFI_RV_ORDER_EXTRA_FLAGS, ///< Road vehicle order extra flags
|
||||||
|
XSLFI_GRF_ROADSTOPS, ///< NewGRF road stops
|
||||||
|
|
||||||
XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64
|
XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64
|
||||||
|
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "../roadstop_base.h"
|
#include "../roadstop_base.h"
|
||||||
#include "../vehicle_base.h"
|
#include "../vehicle_base.h"
|
||||||
#include "../newgrf_station.h"
|
#include "../newgrf_station.h"
|
||||||
|
#include "../newgrf_roadstop.h"
|
||||||
|
|
||||||
#include "saveload.h"
|
#include "saveload.h"
|
||||||
#include "saveload_buffer.h"
|
#include "saveload_buffer.h"
|
||||||
@@ -114,6 +115,11 @@ void AfterLoadStations()
|
|||||||
|
|
||||||
st->speclist[i].spec = StationClass::GetByGrf(st->speclist[i].grfid, st->speclist[i].localidx, nullptr);
|
st->speclist[i].spec = StationClass::GetByGrf(st->speclist[i].grfid, st->speclist[i].localidx, nullptr);
|
||||||
}
|
}
|
||||||
|
for (uint i = 0; i < st->num_roadstop_specs; i++) {
|
||||||
|
if (st->roadstop_speclist[i].grfid == 0) continue;
|
||||||
|
|
||||||
|
st->roadstop_speclist[i].spec = RoadStopClass::GetByGrf(st->roadstop_speclist[i].grfid, st->roadstop_speclist[i].localidx, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (Station::IsExpected(st)) {
|
if (Station::IsExpected(st)) {
|
||||||
Station *sta = Station::From(st);
|
Station *sta = Station::From(st);
|
||||||
@@ -122,6 +128,7 @@ void AfterLoadStations()
|
|||||||
}
|
}
|
||||||
|
|
||||||
StationUpdateCachedTriggers(st);
|
StationUpdateCachedTriggers(st);
|
||||||
|
StationUpdateRoadStopCachedTriggers(st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,6 +409,9 @@ static const SaveLoad _base_station_desc[] = {
|
|||||||
SLE_VAR(BaseStation, random_bits, SLE_UINT16),
|
SLE_VAR(BaseStation, random_bits, SLE_UINT16),
|
||||||
SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8),
|
SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8),
|
||||||
SLE_VAR(BaseStation, num_specs, SLE_UINT8),
|
SLE_VAR(BaseStation, num_specs, SLE_UINT8),
|
||||||
|
SLE_CONDVAR_X(BaseStation, num_roadstop_specs, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS)),
|
||||||
|
SLE_CONDVARVEC_X(BaseStation, custom_road_stop_tiles, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS)),
|
||||||
|
SLE_CONDVARVEC_X(BaseStation, custom_road_stop_random_bits, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_GRF_ROADSTOPS)),
|
||||||
};
|
};
|
||||||
|
|
||||||
static OldPersistentStorage _old_st_persistent_storage;
|
static OldPersistentStorage _old_st_persistent_storage;
|
||||||
@@ -554,6 +564,10 @@ static void RealSave_STNN(BaseStation *bst)
|
|||||||
for (uint i = 0; i < bst->num_specs; i++) {
|
for (uint i = 0; i < bst->num_specs; i++) {
|
||||||
SlObjectSaveFiltered(&bst->speclist[i], _filtered_station_speclist_desc);
|
SlObjectSaveFiltered(&bst->speclist[i], _filtered_station_speclist_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < bst->num_roadstop_specs; i++) {
|
||||||
|
SlObjectSaveFiltered(&bst->roadstop_speclist[i], _filtered_station_speclist_desc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Save_STNN()
|
static void Save_STNN()
|
||||||
@@ -676,6 +690,14 @@ static void Load_STNN()
|
|||||||
SlObjectLoadFiltered(&bst->speclist[i], _filtered_station_speclist_desc);
|
SlObjectLoadFiltered(&bst->speclist[i], _filtered_station_speclist_desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bst->num_roadstop_specs != 0) {
|
||||||
|
/* Allocate speclist memory when loading a game */
|
||||||
|
bst->roadstop_speclist = CallocT<RoadStopSpecList>(bst->num_roadstop_specs);
|
||||||
|
for (uint i = 0; i < bst->num_roadstop_specs; i++) {
|
||||||
|
SlObjectLoadFiltered(&bst->roadstop_speclist[i], _filtered_station_speclist_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -933,6 +933,8 @@ static void StationSpreadChanged(int32 new_value)
|
|||||||
{
|
{
|
||||||
InvalidateWindowData(WC_SELECT_STATION, 0);
|
InvalidateWindowData(WC_SELECT_STATION, 0);
|
||||||
InvalidateWindowData(WC_BUILD_STATION, 0);
|
InvalidateWindowData(WC_BUILD_STATION, 0);
|
||||||
|
InvalidateWindowData(WC_BUS_STATION, 0);
|
||||||
|
InvalidateWindowData(WC_TRUCK_STATION, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateConsists(int32 new_value)
|
static void UpdateConsists(int32 new_value)
|
||||||
|
@@ -57,6 +57,7 @@ void RebuildStationKdtree()
|
|||||||
BaseStation::~BaseStation()
|
BaseStation::~BaseStation()
|
||||||
{
|
{
|
||||||
free(this->speclist);
|
free(this->speclist);
|
||||||
|
free(this->roadstop_speclist);
|
||||||
|
|
||||||
if (CleaningPool()) return;
|
if (CleaningPool()) return;
|
||||||
|
|
||||||
@@ -184,6 +185,31 @@ void BaseStation::PostDestructor(size_t index)
|
|||||||
InvalidateWindowData(WC_SELECT_STATION, 0, 0);
|
InvalidateWindowData(WC_SELECT_STATION, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseStation::SetRoadStopRandomBits(TileIndex tile, byte random_bits)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < this->custom_road_stop_tiles.size(); i++) {
|
||||||
|
if (this->custom_road_stop_tiles[i] == tile) {
|
||||||
|
this->custom_road_stop_random_bits[i] = random_bits;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->custom_road_stop_tiles.push_back(tile);
|
||||||
|
this->custom_road_stop_random_bits.push_back(random_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseStation::RemoveRoadStopRandomBits(TileIndex tile)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < this->custom_road_stop_tiles.size(); i++) {
|
||||||
|
if (this->custom_road_stop_tiles[i] == tile) {
|
||||||
|
this->custom_road_stop_tiles[i] = this->custom_road_stop_tiles.back();
|
||||||
|
this->custom_road_stop_random_bits[i] = this->custom_road_stop_random_bits.back();
|
||||||
|
this->custom_road_stop_tiles.pop_back();
|
||||||
|
this->custom_road_stop_random_bits.pop_back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the primary road stop (the first road stop) that the given vehicle can load/unload.
|
* Get the primary road stop (the first road stop) that the given vehicle can load/unload.
|
||||||
* @param v the vehicle to get the first road stop for
|
* @param v the vehicle to get the first road stop for
|
||||||
|
@@ -873,6 +873,11 @@ public:
|
|||||||
return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
|
return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool TileBelongsToRoadStop(TileIndex tile) const
|
||||||
|
{
|
||||||
|
return IsAnyRoadStopTile(tile) && GetStationIndex(tile) == this->index;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool TileBelongsToAirport(TileIndex tile) const
|
inline bool TileBelongsToAirport(TileIndex tile) const
|
||||||
{
|
{
|
||||||
return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
|
return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
|
||||||
|
@@ -58,6 +58,7 @@
|
|||||||
#include "zoning.h"
|
#include "zoning.h"
|
||||||
#include "tunnelbridge_map.h"
|
#include "tunnelbridge_map.h"
|
||||||
#include "cheat_type.h"
|
#include "cheat_type.h"
|
||||||
|
#include "newgrf_roadstop.h"
|
||||||
|
|
||||||
#include "table/strings.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 3: #Axis of the road for drive-through stops.
|
||||||
* bit 5..10: The roadtype.
|
* bit 5..10: The roadtype.
|
||||||
* bit 16..31: Station ID to join (NEW_STATION if build new one).
|
* 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.
|
* @param text Unused.
|
||||||
* @return The cost of this operation or an error.
|
* @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 type = HasBit(p2, 0);
|
||||||
bool is_drive_through = HasBit(p2, 1);
|
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 width = (uint8)GB(p1, 0, 8);
|
||||||
uint8 length = (uint8)GB(p1, 8, 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 */
|
/* 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);
|
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. */
|
/* 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);
|
ret = BuildStationPart(&st, flags, reuse, roadstop_area, STATIONNAMING_ROAD);
|
||||||
if (ret.Failed()) return ret;
|
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) {
|
if (flags & DC_EXEC) {
|
||||||
/* Check every tile in the area. */
|
/* Check every tile in the area. */
|
||||||
for (TileIndex cur_tile : roadstop_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++;
|
Company::Get(st->owner)->infrastructure.station++;
|
||||||
|
|
||||||
|
SetCustomRoadStopSpecIndex(cur_tile, specindex);
|
||||||
|
if (roadstopspec != nullptr) st->SetRoadStopRandomBits(cur_tile, GB(Random(), 0, 4));
|
||||||
|
|
||||||
MarkTileDirtyByTile(cur_tile);
|
MarkTileDirtyByTile(cur_tile);
|
||||||
UpdateRoadCachedOneWayStatesAroundTile(cur_tile);
|
UpdateRoadCachedOneWayStatesAroundTile(cur_tile);
|
||||||
}
|
}
|
||||||
@@ -2222,10 +2245,15 @@ CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlag flags)
|
|||||||
Company::Get(wp->owner)->infrastructure.station--;
|
Company::Get(wp->owner)->infrastructure.station--;
|
||||||
DirtyCompanyInfrastructureWindows(wp->owner);
|
DirtyCompanyInfrastructureWindows(wp->owner);
|
||||||
|
|
||||||
|
uint specindex = GetCustomRoadStopSpecIndex(tile);
|
||||||
|
|
||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
|
|
||||||
wp->rect.AfterRemoveTile(wp, tile);
|
wp->rect.AfterRemoveTile(wp, tile);
|
||||||
|
|
||||||
|
wp->RemoveRoadStopRandomBits(tile);
|
||||||
|
DeallocateRoadStopSpecFromStation(wp, specindex);
|
||||||
|
|
||||||
MakeRoadWaypointStationAreaSmaller(wp, wp->road_waypoint_area);
|
MakeRoadWaypointStationAreaSmaller(wp, wp->road_waypoint_area);
|
||||||
|
|
||||||
UpdateStationSignCoord(wp);
|
UpdateStationSignCoord(wp);
|
||||||
@@ -2311,6 +2339,8 @@ CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
|
|||||||
Company::Get(st->owner)->infrastructure.station--;
|
Company::Get(st->owner)->infrastructure.station--;
|
||||||
DirtyCompanyInfrastructureWindows(st->owner);
|
DirtyCompanyInfrastructureWindows(st->owner);
|
||||||
|
|
||||||
|
uint specindex = GetCustomRoadStopSpecIndex(tile);
|
||||||
|
|
||||||
if (IsDriveThroughStopTile(tile)) {
|
if (IsDriveThroughStopTile(tile)) {
|
||||||
/* Clears the tile for us */
|
/* Clears the tile for us */
|
||||||
cur_stop->ClearDriveThrough();
|
cur_stop->ClearDriveThrough();
|
||||||
@@ -2332,6 +2362,9 @@ CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
|
|||||||
|
|
||||||
st->AfterStationTileSetChange(false, is_truck ? STATION_TRUCK: STATION_BUS);
|
st->AfterStationTileSetChange(false, is_truck ? STATION_TRUCK: STATION_BUS);
|
||||||
|
|
||||||
|
st->RemoveRoadStopRandomBits(tile);
|
||||||
|
DeallocateRoadStopSpecFromStation(st, specindex);
|
||||||
|
|
||||||
/* Update the tile area of the truck/bus stop */
|
/* Update the tile area of the truck/bus stop */
|
||||||
if (is_truck) {
|
if (is_truck) {
|
||||||
st->truck_station.Clear();
|
st->truck_station.Clear();
|
||||||
@@ -3417,25 +3450,38 @@ draw_default_foundation:
|
|||||||
if (IsAnyRoadStop(ti->tile)) {
|
if (IsAnyRoadStop(ti->tile)) {
|
||||||
RoadType road_rt = GetRoadTypeRoad(ti->tile);
|
RoadType road_rt = GetRoadTypeRoad(ti->tile);
|
||||||
RoadType tram_rt = GetRoadTypeTram(ti->tile);
|
RoadType tram_rt = GetRoadTypeTram(ti->tile);
|
||||||
const RoadTypeInfo* road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_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);
|
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)) {
|
if (IsDriveThroughStopTile(ti->tile)) {
|
||||||
Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
|
if (stopspec == nullptr || (stopspec->draw_mode & ROADSTOP_DRAW_MODE_OVERLAY) != 0) {
|
||||||
uint sprite_offset = axis == AXIS_X ? 1 : 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) {
|
||||||
DisallowedRoadDirections drd = GetDriveThroughStopDisallowedRoadDirections(ti->tile);
|
DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((axis == AXIS_X) ? 0 : 3), PAL_NONE, 8, 8, 0);
|
||||||
if (drd != DRD_NONE) {
|
}
|
||||||
DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((axis == AXIS_X) ? 0 : 3), PAL_NONE, 8, 8, 0);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Non-drivethrough road stops are only valid for roads. */
|
/* Non-drivethrough road stops are only valid for roads. */
|
||||||
assert_tile(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE, ti->tile);
|
assert_tile(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE, ti->tile);
|
||||||
|
|
||||||
if (road_rti->UsesOverlay()) {
|
if ((stopspec != nullptr && (stopspec->draw_mode & ROADSTOP_DRAW_MODE_ROAD) != 0) && road_rti->UsesOverlay()) {
|
||||||
DiagDirection dir = GetRoadStopDir(ti->tile);
|
|
||||||
SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP);
|
SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP);
|
||||||
DrawGroundSprite(ground + dir, PAL_NONE);
|
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);
|
TriggerStationRandomisation(st, st->xy, SRT_NEW_CARGO, type);
|
||||||
TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
|
TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
|
||||||
AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
|
AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
|
||||||
|
TriggerRoadStopRandomisation(st, st->xy, RSRT_NEW_CARGO, type);
|
||||||
|
|
||||||
SetWindowDirty(WC_STATION_VIEW, st->index);
|
SetWindowDirty(WC_STATION_VIEW, st->index);
|
||||||
st->MarkTilesDirty(true);
|
st->MarkTilesDirty(true);
|
||||||
|
@@ -605,6 +605,42 @@ static inline uint GetCustomStationSpecIndex(TileIndex t)
|
|||||||
return _m[t].m4;
|
return _m[t].m4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is there a custom road stop spec on this tile?
|
||||||
|
* @param t Tile to query
|
||||||
|
* @pre IsAnyRoadStopTile(t)
|
||||||
|
* @return True if this station is part of a newgrf station.
|
||||||
|
*/
|
||||||
|
static inline bool IsCustomRoadStopSpecIndex(TileIndex t)
|
||||||
|
{
|
||||||
|
assert_tile(IsAnyRoadStopTile(t), t);
|
||||||
|
return GB(_me[t].m8, 0, 6) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the custom road stop spec for this tile.
|
||||||
|
* @param t Tile to set the stationspec of.
|
||||||
|
* @param specindex The new spec.
|
||||||
|
* @pre IsAnyRoadStopTile(t)
|
||||||
|
*/
|
||||||
|
static inline void SetCustomRoadStopSpecIndex(TileIndex t, byte specindex)
|
||||||
|
{
|
||||||
|
assert_tile(IsAnyRoadStopTile(t), t);
|
||||||
|
SB(_me[t].m8, 0, 6, specindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the custom road stop spec for this tile.
|
||||||
|
* @param t Tile to query
|
||||||
|
* @pre IsAnyRoadStopTile(t)
|
||||||
|
* @return The custom station spec of this tile.
|
||||||
|
*/
|
||||||
|
static inline uint GetCustomRoadStopSpecIndex(TileIndex t)
|
||||||
|
{
|
||||||
|
assert_tile(IsAnyRoadStopTile(t), t);
|
||||||
|
return GB(_me[t].m8, 0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the random bits for a station tile.
|
* Set the random bits for a station tile.
|
||||||
* @param t Tile to set random bits for.
|
* @param t Tile to set random bits for.
|
||||||
|
@@ -1370,6 +1370,34 @@ static const NIFeature _nif_roadtype = {
|
|||||||
new NIHRoadType(),
|
new NIHRoadType(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*** ***/
|
||||||
|
|
||||||
|
static const NIVariable _nif_roadstops[] = {
|
||||||
|
NIV(0x40, "test"),
|
||||||
|
NIV_END(),
|
||||||
|
};
|
||||||
|
|
||||||
|
class NIHRoadStop : public NIHelper {
|
||||||
|
bool IsInspectable(uint index) const override { return false; }
|
||||||
|
uint GetParent(uint index) const override { return UINT32_MAX; }
|
||||||
|
const void *GetInstance(uint index)const override { return nullptr; }
|
||||||
|
const void *GetSpec(uint index) const override { return nullptr; }
|
||||||
|
void SetStringParameters(uint index) const override { }
|
||||||
|
uint32 GetGRFID(uint index) const override { return 0; }
|
||||||
|
|
||||||
|
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
|
||||||
|
{
|
||||||
|
return UINT32_MAX;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NIFeature _nif_roadstop = {
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
_nif_roadstops,
|
||||||
|
new NIHRoadStop(),
|
||||||
|
};
|
||||||
|
|
||||||
/** Table with all NIFeatures. */
|
/** Table with all NIFeatures. */
|
||||||
static const NIFeature * const _nifeatures[] = {
|
static const NIFeature * const _nifeatures[] = {
|
||||||
&_nif_vehicle, // GSF_TRAINS
|
&_nif_vehicle, // GSF_TRAINS
|
||||||
@@ -1392,6 +1420,7 @@ static const NIFeature * const _nifeatures[] = {
|
|||||||
&_nif_airporttile, // GSF_AIRPORTTILES
|
&_nif_airporttile, // GSF_AIRPORTTILES
|
||||||
&_nif_roadtype, // GSF_ROADTYPES
|
&_nif_roadtype, // GSF_ROADTYPES
|
||||||
&_nif_roadtype, // GSF_TRAMTYPES
|
&_nif_roadtype, // GSF_TRAMTYPES
|
||||||
|
&_nif_roadstop, // GSF_ROADSTATIONS
|
||||||
&_nif_town, // GSF_FAKE_TOWNS
|
&_nif_town, // GSF_FAKE_TOWNS
|
||||||
&_nif_station_struct, // GSF_FAKE_STATION_STRUCT
|
&_nif_station_struct, // GSF_FAKE_STATION_STRUCT
|
||||||
};
|
};
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include "string_func.h"
|
#include "string_func.h"
|
||||||
#include "company_func.h"
|
#include "company_func.h"
|
||||||
#include "newgrf_station.h"
|
#include "newgrf_station.h"
|
||||||
|
#include "newgrf_roadstop.h"
|
||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
#include "water.h"
|
#include "water.h"
|
||||||
#include "company_gui.h"
|
#include "company_gui.h"
|
||||||
@@ -192,7 +193,6 @@ extern CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec
|
|||||||
* - p1 = (bit 24) - allow waypoints directly adjacent to other waypoints.
|
* - p1 = (bit 24) - allow waypoints directly adjacent to other waypoints.
|
||||||
* @param p2 various bitstuffed elements
|
* @param p2 various bitstuffed elements
|
||||||
* - p2 = (bit 0- 7) - custom station class
|
* - p2 = (bit 0- 7) - custom station class
|
||||||
* - p2 = (bit 8-15) - custom station id
|
|
||||||
* - p2 = (bit 31-16) - station ID to join
|
* - p2 = (bit 31-16) - station ID to join
|
||||||
* @param p3 various bitstuffed elements
|
* @param p3 various bitstuffed elements
|
||||||
* - p3 = (bit 0-31) - custom station id
|
* - p3 = (bit 0-31) - custom station id
|
||||||
@@ -337,11 +337,14 @@ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
|
|||||||
* bit 8..15: Length of the road stop.
|
* bit 8..15: Length of the road stop.
|
||||||
* bit 16: Allow stations directly adjacent to other stations.
|
* bit 16: Allow stations directly adjacent to other stations.
|
||||||
* bit 17: #Axis of the road.
|
* bit 17: #Axis of the road.
|
||||||
* @param p2 bit 16..31: Station ID to join (NEW_STATION if build new one).
|
* @param p2 bit 0..7: Custom road stop class
|
||||||
|
* bit 16..31: Station ID to join (NEW_STATION if build new one).
|
||||||
|
* @param p3 various bitstuffed elements
|
||||||
|
* - p3 = (bit 0-31) - custom road stop id
|
||||||
* @param text Unused.
|
* @param text Unused.
|
||||||
* @return The cost of this operation or an error.
|
* @return The cost of this operation or an error.
|
||||||
*/
|
*/
|
||||||
CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, uint64 p3, const char *text, uint32 binary_length)
|
||||||
{
|
{
|
||||||
StationID station_to_join = GB(p2, 16, 16);
|
StationID station_to_join = GB(p2, 16, 16);
|
||||||
byte width = GB(p1, 0, 8);
|
byte width = GB(p1, 0, 8);
|
||||||
@@ -349,6 +352,15 @@ CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
|
|||||||
bool adjacent = HasBit(p1, 16);
|
bool adjacent = HasBit(p1, 16);
|
||||||
Axis axis = Extract<Axis, 17, 1>(p1);
|
Axis axis = Extract<Axis, 17, 1>(p1);
|
||||||
|
|
||||||
|
RoadStopClassID spec_class = Extract<RoadStopClassID, 0, 8>(p2);
|
||||||
|
uint spec_index = GB(p3, 0, 32);
|
||||||
|
|
||||||
|
/* Check if the given road stop class is valid */
|
||||||
|
if (spec_class != ROADSTOP_CLASS_WAYP) return CMD_ERROR;
|
||||||
|
if (spec_index >= RoadStopClass::Get(spec_class)->GetSpecCount()) return CMD_ERROR;
|
||||||
|
|
||||||
|
const RoadStopSpec *spec = RoadStopClass::Get(spec_class)->GetSpec(spec_index);
|
||||||
|
|
||||||
/* The number of parts to build */
|
/* The number of parts to build */
|
||||||
byte count = axis == AXIS_X ? height : width;
|
byte count = axis == AXIS_X ? height : width;
|
||||||
|
|
||||||
@@ -393,6 +405,9 @@ CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
|
|||||||
if (!Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
|
if (!Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if we can allocate a custom stationspec to this station */
|
||||||
|
if (AllocateRoadStopSpecToStation(spec, wp, false) == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
if (wp == nullptr) {
|
if (wp == nullptr) {
|
||||||
wp = new Waypoint(start_tile);
|
wp = new Waypoint(start_tile);
|
||||||
@@ -414,6 +429,8 @@ CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
|
|||||||
|
|
||||||
wp->UpdateVirtCoord();
|
wp->UpdateVirtCoord();
|
||||||
|
|
||||||
|
byte map_spec_index = AllocateRoadStopSpecToStation(spec, wp, true);
|
||||||
|
|
||||||
/* Check every tile in the area. */
|
/* Check every tile in the area. */
|
||||||
for (TileIndex cur_tile : roadstop_area) {
|
for (TileIndex cur_tile : roadstop_area) {
|
||||||
/* Get existing road types and owners before any tile clearing */
|
/* Get existing road types and owners before any tile clearing */
|
||||||
@@ -444,6 +461,8 @@ CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
|
|||||||
|
|
||||||
MakeDriveThroughRoadStop(cur_tile, wp->owner, road_owner, tram_owner, wp->index, STATION_ROADWAYPOINT, road_rt, tram_rt, axis);
|
MakeDriveThroughRoadStop(cur_tile, wp->owner, road_owner, tram_owner, wp->index, STATION_ROADWAYPOINT, road_rt, tram_rt, axis);
|
||||||
SetDriveThroughStopDisallowedRoadDirections(cur_tile, drd);
|
SetDriveThroughStopDisallowedRoadDirections(cur_tile, drd);
|
||||||
|
SetCustomRoadStopSpecIndex(cur_tile, map_spec_index);
|
||||||
|
if (spec != nullptr) wp->SetRoadStopRandomBits(cur_tile, 0);
|
||||||
|
|
||||||
Company::Get(wp->owner)->infrastructure.station++;
|
Company::Get(wp->owner)->infrastructure.station++;
|
||||||
|
|
||||||
|
@@ -53,6 +53,22 @@ enum BuildRoadStationWidgets {
|
|||||||
WID_BROS_LT_OFF, ///< Turn off area highlight.
|
WID_BROS_LT_OFF, ///< Turn off area highlight.
|
||||||
WID_BROS_LT_ON, ///< Turn on area highlight.
|
WID_BROS_LT_ON, ///< Turn on area highlight.
|
||||||
WID_BROS_INFO, ///< Station acceptance info.
|
WID_BROS_INFO, ///< Station acceptance info.
|
||||||
|
|
||||||
|
WID_BROS_MATRIX, ///< Matrix widget displaying all available road stops.
|
||||||
|
WID_BROS_IMAGE, ///< Panel used for each image of the matrix.
|
||||||
|
WID_BROS_MATRIX_SCROLL, ///< Scrollbar of the #WID_BROS_SHOW_NEWST_ADDITIONS.
|
||||||
|
|
||||||
|
WID_BROS_FILTER_CONTAINER, ///< Container for the filter text box for the road stop class list.
|
||||||
|
WID_BROS_FILTER_EDITBOX, ///< Filter text box for the road stop class list.
|
||||||
|
WID_BROS_SHOW_NEWST_DEFSIZE, ///< Selection for default-size button for new road stops.
|
||||||
|
WID_BROS_SHOW_NEWST_ADDITIONS, ///< Selection for new class selection list.
|
||||||
|
WID_BROS_SHOW_NEWST_MATRIX, ///< Selection for new stop image matrix.
|
||||||
|
WID_BROS_SHOW_NEWST_RESIZE, ///< Selection for panel and resize at bottom right for new stops.
|
||||||
|
WID_BROS_SHOW_NEWST_ORIENTATION, ///< Selection for the orientation string for new stops.
|
||||||
|
WID_BROS_SHOW_NEWST_TYPE_SEL, ///< Selection for the type name.
|
||||||
|
WID_BROS_SHOW_NEWST_TYPE, ///< Display of selected stop type.
|
||||||
|
WID_BROS_NEWST_LIST, ///< List with new road stops.
|
||||||
|
WID_BROS_NEWST_SCROLL, ///< Scrollbar of the #WID_BROS_NEWST_LIST.
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* WIDGETS_ROAD_WIDGET_H */
|
#endif /* WIDGETS_ROAD_WIDGET_H */
|
||||||
|
@@ -106,7 +106,7 @@ enum WindowClass {
|
|||||||
* - 0 = #ToolTipsWidgets
|
* - 0 = #ToolTipsWidgets
|
||||||
*/
|
*/
|
||||||
WC_TOOLTIPS,
|
WC_TOOLTIPS,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Station rating tooltip window; %Window numbers:
|
* Station rating tooltip window; %Window numbers:
|
||||||
* - 0 = #ToolTipsWidgets
|
* - 0 = #ToolTipsWidgets
|
||||||
|
Reference in New Issue
Block a user