mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-09 19:10:38 +00:00
Add: NewGRF custom road waypoint support
This commit is contained in:
parent
c35a5e5cb1
commit
a43dacd988
@ -4818,7 +4818,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteR
|
||||
break;
|
||||
|
||||
case 0x0C: // The draw mode
|
||||
rs->draw_mode = (RoadStopDrawMode)buf.ReadByte();
|
||||
rs->draw_mode = static_cast<RoadStopDrawMode>(buf.ReadByte());
|
||||
break;
|
||||
|
||||
case 0x0D: // Cargo types for random triggers
|
||||
@ -4843,7 +4843,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteR
|
||||
break;
|
||||
|
||||
case 0x12: // General flags
|
||||
rs->flags = (uint8_t)buf.ReadDWord(); // Future-proofing, size this as 4 bytes, but we only need one byte's worth of flags at present
|
||||
rs->flags = (uint16_t)buf.ReadDWord(); // Future-proofing, size this as 4 bytes, but we only need two byte's worth of flags at present
|
||||
break;
|
||||
|
||||
case 0x15: // Cost multipliers
|
||||
|
@ -119,6 +119,15 @@ uint32_t RoadStopScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] u
|
||||
/* Animation frame */
|
||||
case 0x49: return this->tile == INVALID_TILE ? 0 : this->st->GetRoadStopAnimationFrame(this->tile);
|
||||
|
||||
/* Misc info */
|
||||
case 0x50: {
|
||||
uint32_t result = 0;
|
||||
if (this->tile == INVALID_TILE) {
|
||||
SetBit(result, 4);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Variables which use the parameter */
|
||||
/* Variables 0x60 to 0x65 and 0x69 are handled separately below */
|
||||
|
||||
@ -284,7 +293,19 @@ void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec,
|
||||
SpriteID image = dts->ground.sprite;
|
||||
PaletteID pal = dts->ground.pal;
|
||||
|
||||
if (GB(image, 0, SPRITE_WIDTH) != 0) {
|
||||
RoadStopDrawMode draw_mode;
|
||||
if (HasBit(spec->flags, RSF_DRAW_MODE_REGISTER)) {
|
||||
draw_mode = static_cast<RoadStopDrawMode>(GetRegister(0x100));
|
||||
} else {
|
||||
draw_mode = spec->draw_mode;
|
||||
}
|
||||
|
||||
if (type == STATION_ROADWAYPOINT) {
|
||||
DrawSprite(SPR_ROAD_PAVED_STRAIGHT_X, PAL_NONE, x, y);
|
||||
if ((draw_mode & ROADSTOP_DRAW_MODE_WAYP_GROUND) && GB(image, 0, SPRITE_WIDTH) != 0) {
|
||||
DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
|
||||
}
|
||||
} else if (GB(image, 0, SPRITE_WIDTH) != 0) {
|
||||
DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
|
||||
}
|
||||
|
||||
@ -293,7 +314,7 @@ void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec,
|
||||
uint sprite_offset = 5 - view;
|
||||
|
||||
/* Road underlay takes precedence over tram */
|
||||
if (spec->draw_mode & ROADSTOP_DRAW_MODE_OVERLAY) {
|
||||
if (type == STATION_ROADWAYPOINT || draw_mode & ROADSTOP_DRAW_MODE_OVERLAY) {
|
||||
if (rti->UsesOverlay()) {
|
||||
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND);
|
||||
DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
|
||||
@ -306,7 +327,7 @@ void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec,
|
||||
}
|
||||
} else {
|
||||
/* Bay stop */
|
||||
if ((spec->draw_mode & ROADSTOP_DRAW_MODE_ROAD) && rti->UsesOverlay()) {
|
||||
if ((draw_mode & ROADSTOP_DRAW_MODE_ROAD) && rti->UsesOverlay()) {
|
||||
SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP);
|
||||
DrawSprite(ground + view, PAL_NONE, x, y);
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ enum RoadStopDrawMode : uint8_t {
|
||||
ROADSTOP_DRAW_MODE_NONE = 0,
|
||||
ROADSTOP_DRAW_MODE_ROAD = 1 << 0, ///< Bay stops: Draw the road itself
|
||||
ROADSTOP_DRAW_MODE_OVERLAY = 1 << 1, ///< Drive-through stops: Draw the road overlay, e.g. pavement
|
||||
ROADSTOP_DRAW_MODE_WAYP_GROUND = 1 << 2, ///< Waypoints: Draw the sprite layout ground tile (on top of the road)
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(RoadStopDrawMode)
|
||||
|
||||
@ -72,6 +73,7 @@ enum RoadStopSpecFlags {
|
||||
RSF_NO_AUTO_ROAD_CONNECTION = 4, ///< No auto road connection.
|
||||
RSF_BUILD_MENU_ROAD_ONLY = 5, ///< Only show in the road build menu (not tram).
|
||||
RSF_BUILD_MENU_TRAM_ONLY = 6, ///< Only show in the tram build menu (not road).
|
||||
RSF_DRAW_MODE_REGISTER = 8, ///< Read draw mode from register 0x100.
|
||||
};
|
||||
|
||||
enum RoadStopView {
|
||||
@ -143,7 +145,7 @@ struct RoadStopSpec : NewGRFSpecBase<RoadStopClassID> {
|
||||
RoadStopAvailabilityType stop_type = ROADSTOPTYPE_ALL;
|
||||
RoadStopDrawMode draw_mode = ROADSTOP_DRAW_MODE_ROAD | ROADSTOP_DRAW_MODE_OVERLAY;
|
||||
uint8_t callback_mask = 0;
|
||||
uint8_t flags = 0;
|
||||
uint16_t flags = 0;
|
||||
|
||||
CargoTypes cargo_triggers = 0; ///< Bitmask of cargo types which cause trigger re-randomizing
|
||||
|
||||
|
132
src/road_gui.cpp
132
src/road_gui.cpp
@ -32,6 +32,7 @@
|
||||
#include "dropdown_func.h"
|
||||
#include "engine_base.h"
|
||||
#include "station_base.h"
|
||||
#include "waypoint_base.h"
|
||||
#include "strings_func.h"
|
||||
#include "core/geometry_func.hpp"
|
||||
#include "station_cmd.h"
|
||||
@ -51,6 +52,7 @@
|
||||
|
||||
static void ShowRVStationPicker(Window *parent, RoadStopType rs);
|
||||
static void ShowRoadDepotPicker(Window *parent);
|
||||
static void ShowBuildRoadWaypointPicker(Window *parent);
|
||||
|
||||
static bool _remove_button_clicked;
|
||||
static bool _one_way_button_clicked;
|
||||
@ -64,6 +66,12 @@ static RoadType _cur_roadtype;
|
||||
|
||||
static DiagDirection _road_depot_orientation;
|
||||
|
||||
struct RoadWaypointPickerSelection {
|
||||
RoadStopClassID sel_class; ///< Selected road waypoint class.
|
||||
uint16_t sel_type; ///< Selected road waypoint type within the class.
|
||||
};
|
||||
static RoadWaypointPickerSelection _waypoint_gui; ///< Settings of the road waypoint picker.
|
||||
|
||||
struct RoadStopPickerSelection {
|
||||
RoadStopClassID sel_class; ///< Selected road stop class.
|
||||
uint16_t sel_type; ///< Selected road stop type within the class.
|
||||
@ -536,8 +544,9 @@ struct BuildRoadToolbarWindow : Window {
|
||||
break;
|
||||
|
||||
case WID_ROT_BUILD_WAYPOINT:
|
||||
this->last_started_action = widget;
|
||||
if (HandlePlacePushButton(this, WID_ROT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT)) {
|
||||
this->last_started_action = widget;
|
||||
ShowBuildRoadWaypointPicker(this);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -757,13 +766,12 @@ struct BuildRoadToolbarWindow : Window {
|
||||
TileArea ta(start_tile, end_tile);
|
||||
Axis axis = select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y;
|
||||
bool adjacent = _ctrl_pressed;
|
||||
uint16_t waypoint_type = 0;
|
||||
|
||||
auto proc = [=](bool test, StationID to_join) -> bool {
|
||||
if (test) {
|
||||
return Command<CMD_BUILD_ROAD_WAYPOINT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_ROAD_WAYPOINT>()), ta.tile, axis, ta.w, ta.h, ROADSTOP_CLASS_WAYP, waypoint_type, INVALID_STATION, adjacent).Succeeded();
|
||||
return Command<CMD_BUILD_ROAD_WAYPOINT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_ROAD_WAYPOINT>()), ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, INVALID_STATION, adjacent).Succeeded();
|
||||
} else {
|
||||
return Command<CMD_BUILD_ROAD_WAYPOINT>::Post(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT, CcPlaySound_CONSTRUCTION_OTHER, ta.tile, axis, ta.w, ta.h, ROADSTOP_CLASS_WAYP, waypoint_type, to_join, adjacent);
|
||||
return Command<CMD_BUILD_ROAD_WAYPOINT>::Post(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT, CcPlaySound_CONSTRUCTION_OTHER, ta.tile, axis, ta.w, ta.h, _waypoint_gui.sel_class, _waypoint_gui.sel_type, to_join, adjacent);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1589,10 +1597,126 @@ static void ShowRVStationPicker(Window *parent, RoadStopType rs)
|
||||
new BuildRoadStationWindow(RoadTypeIsRoad(_cur_roadtype) ? _road_station_picker_desc : _tram_station_picker_desc, parent, rs);
|
||||
}
|
||||
|
||||
class RoadWaypointPickerCallbacks : public PickerCallbacksNewGRFClass<RoadStopClass> {
|
||||
public:
|
||||
RoadWaypointPickerCallbacks() : PickerCallbacksNewGRFClass<RoadStopClass>("fav_road_waypoints") {}
|
||||
|
||||
StringID GetClassTooltip() const override { return STR_PICKER_WAYPOINT_CLASS_TOOLTIP; }
|
||||
StringID GetTypeTooltip() const override { return STR_PICKER_WAYPOINT_TYPE_TOOLTIP; }
|
||||
|
||||
bool IsActive() const override
|
||||
{
|
||||
for (const auto &cls : RoadStopClass::Classes()) {
|
||||
if (!IsWaypointClass(cls)) continue;
|
||||
for (const auto *spec : cls.Specs()) {
|
||||
if (spec != nullptr) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasClassChoice() const override
|
||||
{
|
||||
return std::count_if(std::begin(RoadStopClass::Classes()), std::end(RoadStopClass::Classes()), IsWaypointClass) > 1;
|
||||
}
|
||||
|
||||
void Close(int) override { ResetObjectToPlace(); }
|
||||
int GetSelectedClass() const override { return _waypoint_gui.sel_class; }
|
||||
void SetSelectedClass(int id) const override { _waypoint_gui.sel_class = this->GetClassIndex(id); }
|
||||
|
||||
StringID GetClassName(int id) const override
|
||||
{
|
||||
const auto *sc = GetClass(id);
|
||||
if (!IsWaypointClass(*sc)) return INVALID_STRING_ID;
|
||||
return sc->name;
|
||||
}
|
||||
|
||||
int GetSelectedType() const override { return _waypoint_gui.sel_type; }
|
||||
void SetSelectedType(int id) const override { _waypoint_gui.sel_type = id; }
|
||||
|
||||
StringID GetTypeName(int cls_id, int id) const override
|
||||
{
|
||||
const auto *spec = this->GetSpec(cls_id, id);
|
||||
return (spec == nullptr) ? STR_STATION_CLASS_WAYP_WAYPOINT : spec->name;
|
||||
}
|
||||
|
||||
bool IsTypeAvailable(int cls_id, int id) const override
|
||||
{
|
||||
return IsRoadStopAvailable(this->GetSpec(cls_id, id), STATION_ROADWAYPOINT);
|
||||
}
|
||||
|
||||
void DrawType(int x, int y, int cls_id, int id) const override
|
||||
{
|
||||
const auto *spec = this->GetSpec(cls_id, id);
|
||||
if (spec == nullptr) {
|
||||
StationPickerDrawSprite(x, y, STATION_ROADWAYPOINT, INVALID_RAILTYPE, _cur_roadtype, RSV_DRIVE_THROUGH_X);
|
||||
} else {
|
||||
DrawRoadStopTile(x, y, _cur_roadtype, spec, STATION_ROADWAYPOINT, RSV_DRIVE_THROUGH_X);
|
||||
}
|
||||
}
|
||||
|
||||
void FillUsedItems(std::set<PickerItem> &items) override
|
||||
{
|
||||
for (const Waypoint *wp : Waypoint::Iterate()) {
|
||||
if (wp->owner != _local_company || !HasBit(wp->waypoint_flags, WPF_ROAD)) continue;
|
||||
items.insert({0, 0, ROADSTOP_CLASS_WAYP, 0}); // We would need to scan the map to find out if default is used.
|
||||
for (const auto &sm : wp->roadstop_speclist) {
|
||||
if (sm.spec == nullptr) continue;
|
||||
items.insert({sm.grfid, sm.localidx, sm.spec->class_index, sm.spec->index});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static RoadWaypointPickerCallbacks instance;
|
||||
};
|
||||
/* static */ RoadWaypointPickerCallbacks RoadWaypointPickerCallbacks::instance;
|
||||
|
||||
struct BuildRoadWaypointWindow : public PickerWindow {
|
||||
BuildRoadWaypointWindow(WindowDesc &desc, Window *parent) : PickerWindow(desc, parent, TRANSPORT_ROAD, RoadWaypointPickerCallbacks::instance)
|
||||
{
|
||||
this->ConstructWindow();
|
||||
this->InvalidateData();
|
||||
}
|
||||
|
||||
static inline HotkeyList hotkeys{"buildroadwaypoint", {
|
||||
Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX),
|
||||
}};
|
||||
};
|
||||
|
||||
/** Nested widget definition for the build NewGRF road waypoint window */
|
||||
static constexpr NWidgetPart _nested_build_road_waypoint_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WAYPOINT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidgetFunction(MakePickerClassWidgets),
|
||||
NWidgetFunction(MakePickerTypeWidgets),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _build_road_waypoint_desc(
|
||||
WDP_AUTO, "build_road_waypoint", 0, 0,
|
||||
WC_BUILD_WAYPOINT, WC_BUILD_TOOLBAR,
|
||||
WDF_CONSTRUCTION,
|
||||
_nested_build_road_waypoint_widgets,
|
||||
&BuildRoadWaypointWindow::hotkeys
|
||||
);
|
||||
|
||||
static void ShowBuildRoadWaypointPicker(Window *parent)
|
||||
{
|
||||
if (!RoadWaypointPickerCallbacks::instance.IsActive()) return;
|
||||
new BuildRoadWaypointWindow(_build_road_waypoint_desc, parent);
|
||||
}
|
||||
|
||||
void InitializeRoadGui()
|
||||
{
|
||||
_road_depot_orientation = DIAGDIR_NW;
|
||||
_roadstop_gui.orientation = DIAGDIR_NW;
|
||||
_waypoint_gui.sel_class = RoadStopClassID::ROADSTOP_CLASS_WAYP;
|
||||
_waypoint_gui.sel_type = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3293,7 +3293,7 @@ draw_default_foundation:
|
||||
draw_ground = true;
|
||||
}
|
||||
|
||||
if (draw_ground && !IsStationRoadStop(ti->tile)) {
|
||||
if (draw_ground && !IsAnyRoadStop(ti->tile)) {
|
||||
SpriteID image = t->ground.sprite;
|
||||
PaletteID pal = t->ground.pal;
|
||||
RailTrackOffset overlay_offset;
|
||||
@ -3320,7 +3320,7 @@ draw_default_foundation:
|
||||
|
||||
if (HasStationRail(ti->tile) && HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti);
|
||||
|
||||
if (IsStationRoadStop(ti->tile)) {
|
||||
if (IsAnyRoadStop(ti->tile)) {
|
||||
RoadType road_rt = GetRoadTypeRoad(ti->tile);
|
||||
RoadType tram_rt = GetRoadTypeTram(ti->tile);
|
||||
const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
|
||||
@ -3331,13 +3331,21 @@ draw_default_foundation:
|
||||
StationType type = GetStationType(ti->tile);
|
||||
|
||||
const RoadStopSpec *stopspec = GetRoadStopSpec(ti->tile);
|
||||
RoadStopDrawMode stop_draw_mode{};
|
||||
if (stopspec != nullptr) {
|
||||
stop_draw_mode = stopspec->draw_mode;
|
||||
int view = dir;
|
||||
if (IsDriveThroughStopTile(ti->tile)) view += 4;
|
||||
st = BaseStation::GetByTile(ti->tile);
|
||||
RoadStopResolverObject object(stopspec, st, ti->tile, INVALID_ROADTYPE, type, view);
|
||||
const SpriteGroup *group = object.Resolve();
|
||||
if (group != nullptr && group->type == SGT_TILELAYOUT) {
|
||||
if (HasBit(stopspec->flags, RSF_DRAW_MODE_REGISTER)) {
|
||||
stop_draw_mode = static_cast<RoadStopDrawMode>(GetRegister(0x100));
|
||||
}
|
||||
if (type == STATION_ROADWAYPOINT && (stop_draw_mode & ROADSTOP_DRAW_MODE_WAYP_GROUND)) {
|
||||
draw_ground = true;
|
||||
}
|
||||
t = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(nullptr);
|
||||
}
|
||||
}
|
||||
@ -3354,14 +3362,15 @@ draw_default_foundation:
|
||||
}
|
||||
|
||||
if (IsDriveThroughStopTile(ti->tile)) {
|
||||
uint sprite_offset = axis == AXIS_X ? 1 : 0;
|
||||
|
||||
DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
|
||||
if (type != STATION_ROADWAYPOINT && (stopspec == nullptr || (stop_draw_mode & ROADSTOP_DRAW_MODE_OVERLAY) != 0)) {
|
||||
uint sprite_offset = axis == AXIS_X ? 1 : 0;
|
||||
DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset);
|
||||
}
|
||||
} else {
|
||||
/* Non-drivethrough road stops are only valid for roads. */
|
||||
assert(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE);
|
||||
|
||||
if ((stopspec == nullptr || (stopspec->draw_mode & ROADSTOP_DRAW_MODE_ROAD) != 0) && road_rti->UsesOverlay()) {
|
||||
if ((stopspec == nullptr || (stop_draw_mode & ROADSTOP_DRAW_MODE_ROAD) != 0) && road_rti->UsesOverlay()) {
|
||||
SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP);
|
||||
DrawGroundSprite(ground + dir, PAL_NONE);
|
||||
}
|
||||
@ -3429,7 +3438,7 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro
|
||||
}
|
||||
|
||||
/* Default waypoint has no railtype specific sprites */
|
||||
DrawRailTileSeqInGUI(x, y, t, st == STATION_WAYPOINT ? 0 : total_offset, 0, pal);
|
||||
DrawRailTileSeqInGUI(x, y, t, (st == STATION_WAYPOINT || st == STATION_ROADWAYPOINT) ? 0 : total_offset, 0, pal);
|
||||
}
|
||||
|
||||
static int GetSlopePixelZ_Station(TileIndex tile, uint, uint, bool)
|
||||
|
Loading…
Reference in New Issue
Block a user