Construction Window Tab1 Refactor (#1086)

* Split up two functions

* Rename and split off duplications

* Reorg and label

* Extract out function

* Reintroduce code back from function

* Split out function

* Remove dead code

* Integrate function into base code

* Split out into function

* Refactor track similarly

* Consolidate into one templated function

* Pass by ref

* Fix compile error

* Add missing static
This commit is contained in:
Duncan 2021-08-08 13:39:57 +01:00 committed by GitHub
parent e698c13357
commit 4e3f77a1d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 220 additions and 270 deletions

View File

@ -621,7 +621,7 @@ namespace OpenLoco::Input
auto* window = WindowManager::find(WindowType::construction);
if (window != nullptr)
{
Ui::Windows::Construction::sub_49FEC7();
Ui::Windows::Construction::removeConstructionGhosts();
}
GameCommands::setErrorTitle(StringIds::cant_remove_signal);

View File

@ -1,4 +1,5 @@
#include "TrackData.h"
#include "Interop/Interop.hpp"
#include <array>
#include <cassert>
@ -303,4 +304,17 @@ namespace OpenLoco::Map::TrackData
assert(trackId < roadPieces.size());
return roadPieces[trackId];
}
static Interop::loco_global<TrackCoordinates[80], 0x004F6F8C> _4F6F8C;
static Interop::loco_global<TrackCoordinates[352], 0x004F7B5C> _4F7B5C;
const TrackCoordinates& getUnkTrack(uint16_t trackAndDirection)
{
return _4F7B5C[trackAndDirection];
}
const TrackCoordinates& getUnkRoad(uint16_t trackAndDirection)
{
return _4F6F8C[trackAndDirection];
}
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "Map/Map.hpp"
#include "Types.hpp"
#include <cstddef>
#include <cstdlib>
@ -32,6 +33,19 @@ namespace OpenLoco::Map::TrackData
constexpr uint8_t diagonal = 1 << 7;
}
#pragma pack(push, 1)
// Pos is difference from the next first tile and the track first tile
struct TrackCoordinates
{
uint8_t rotationBegin; // 0x00
uint8_t rotationEnd; // 0x01
Map::Pos3 pos; // 0x02
};
static_assert(sizeof(TrackCoordinates) == 0x8);
#pragma pack(pop)
const std::vector<PreviewTrack>& getTrackPiece(size_t trackId);
const std::vector<PreviewTrack>& getRoadPiece(size_t trackId);
const TrackCoordinates& getUnkTrack(uint16_t trackAndDirection);
const TrackCoordinates& getUnkRoad(uint16_t trackAndDirection);
}

View File

@ -136,7 +136,7 @@ namespace OpenLoco::Ui::Windows
void sub_4A6FAC();
bool isStationTabOpen();
bool rotate(Window* self);
void sub_49FEC7();
void removeConstructionGhosts();
void registerHooks();
}

View File

@ -363,7 +363,7 @@ namespace OpenLoco::Ui::Windows::Construction
}
// 0x0049FEC7
void sub_49FEC7()
void removeConstructionGhosts()
{
registers regs;
call(0x0049FEC7, regs);
@ -418,7 +418,7 @@ namespace OpenLoco::Ui::Windows::Construction
Construction::activateSelectedConstructionWidgets();
}
sub_49FEC7();
removeConstructionGhosts();
TileManager::mapInvalidateMapSelectionTiles();
Input::resetMapSelectionFlag(Input::MapSelectionFlags::enableConstruct);
_trackCost = 0x80000000;
@ -698,7 +698,7 @@ namespace OpenLoco::Ui::Windows::Construction
// 0x0049DD14
void onClose(Window* self)
{
sub_49FEC7();
removeConstructionGhosts();
WindowManager::viewportSetVisibility(WindowManager::ViewportVisibility::reset);
TileManager::mapInvalidateMapSelectionTiles();
Input::resetMapSelectionFlag(Input::MapSelectionFlags::enableConstruct);
@ -719,7 +719,7 @@ namespace OpenLoco::Ui::Windows::Construction
if (!(_byte_522096 & flag))
return;
sub_49FEC7();
removeConstructionGhosts();
}
void initEvents()
@ -1151,7 +1151,7 @@ namespace OpenLoco::Ui::Windows::Construction
// 0x004A3A50
void sub_4A3A50()
{
sub_49FEC7();
removeConstructionGhosts();
setTrackOptions(_trackType);
refreshStationList(_stationList, _trackType, TransportMode::road);
@ -1247,7 +1247,7 @@ namespace OpenLoco::Ui::Windows::Construction
if (_constructionHover == 1)
{
self->callOnMouseUp(Construction::widx::rotate_90);
sub_49FEC7();
removeConstructionGhosts();
return true;
}
break;

View File

@ -51,7 +51,7 @@ namespace OpenLoco::Ui::Windows::Construction
static loco_global<uint16_t, 0x01135FD8> _word_1135FD8;
static loco_global<uint16_t, 0x01135FE4> _lastSelectedMods;
static loco_global<uint16_t, 0x01135FFE> _word_1135FFE;
static loco_global<uint16_t, 0x01136000> _word_1136000;
static loco_global<int16_t, 0x01136000> _word_1136000;
static loco_global<uint8_t[17], 0x0113601D> _signalList;
static loco_global<uint8_t, 0x0113602E> _lastSelectedSignal;
static loco_global<uint8_t, 0x0113602F> _isSignalBothDirections;
@ -61,7 +61,7 @@ namespace OpenLoco::Ui::Windows::Construction
static loco_global<uint8_t[17], 0x0113603B> _stationList;
static loco_global<uint8_t, 0x0113604C> _lastSelectedStationType;
static loco_global<uint8_t[4], 0x01136054> _modList;
static loco_global<uint8_t, 0x0113605D> _byte_113605D;
static loco_global<uint8_t, 0x0113605D> _makeJunction;
static loco_global<uint8_t, 0x01136061> _constructionHover;
static loco_global<uint8_t, 0x01136062> _trackType;
static loco_global<uint8_t, 0x01136063> _byte_1136063;

View File

@ -20,7 +20,6 @@ using namespace OpenLoco::Map::TileManager;
namespace OpenLoco::Ui::Windows::Construction::Construction
{
static loco_global<uint16_t[351][4], 0x004F7B62> _word_4F7B62; // TODO: Not sure on size?
static loco_global<uint8_t, 0x00508F09> _byte_508F09;
static loco_global<uint8_t, 0x00522090> _byte_522090;
static loco_global<uint8_t, 0x00522091> _byte_522091;
@ -175,7 +174,7 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
activateSelectedConstructionWidgets();
break;
}
sub_49FEC7();
removeConstructionGhosts();
WindowManager::viewportSetVisibility(WindowManager::ViewportVisibility::overgroundView);
Input::toolSet(self, widx::construct, CursorId::crosshair);
Input::setFlag(Input::Flags::flag6);
@ -1211,7 +1210,7 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
static void changeTrackPiece(uint8_t trackPiece, bool slope)
{
_byte_113603A = 0xFF;
sub_49FEC7();
removeConstructionGhosts();
if (slope)
_lastSelectedTrackGradient = trackPiece;
@ -1326,7 +1325,7 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
case widx::s_bend_dual_track_left:
{
_byte_113603A = 0xFF;
sub_49FEC7();
removeConstructionGhosts();
_lastSelectedTrackPiece = TrackPiece::s_bend_to_dual_track;
_trackCost = 0x80000000;
if (self->widgets[widx::s_bend_dual_track_left].image != ImageIds::construction_s_bend_dual_track_left)
@ -1345,7 +1344,7 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
case widx::s_bend_dual_track_right:
{
_byte_113603A = 0xFF;
sub_49FEC7();
removeConstructionGhosts();
_lastSelectedTrackPiece = TrackPiece::s_bend_to_single_track;
_trackCost = 0x80000000;
if (self->widgets[widx::s_bend_dual_track_right].image != ImageIds::construction_s_bend_dual_track_right)
@ -1412,7 +1411,7 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
// TODO: & ~(1 << 7) added to prevent crashing when selecting bridges for road/trams
_scenarioBridges[_trackType & ~(1 << 7)] = bridge;
sub_49FEC7();
removeConstructionGhosts();
_trackCost = 0x80000000;
activateSelectedConstructionWidgets();
}
@ -1445,8 +1444,8 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
sub_49FD66();
}
// 0x004A2395
static std::optional<int16_t> getConstructionHeight(const Pos2& mapPos, int16_t height, bool isSelected)
// Simplified TileManager::getHeight that only considers flat height
static std::optional<Map::TileHeight> getConstructionHeight(const Pos2& mapPos)
{
auto tile = TileManager::get(mapPos);
@ -1455,60 +1454,21 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
if (surfaceTile == nullptr)
return std::nullopt;
int16_t tileHeight = surfaceTile->baseZ() * 4;
Map::TileHeight height = { static_cast<coord_t>(surfaceTile->baseZ() * 4), static_cast<coord_t>(surfaceTile->water() * 16) };
if (surfaceTile->slopeCorners())
{
tileHeight += 16;
height.landHeight += 16;
}
if (surfaceTile->isSlopeDoubleHeight())
{
tileHeight += 16;
height.landHeight += 16;
}
if (isSelected)
{
if (tileHeight > height)
{
height = tileHeight;
}
}
else
{
if (tileHeight > _word_1136000)
{
height = _word_1136000;
}
}
if (isSelected)
{
if (surfaceTile->water())
{
tileHeight = surfaceTile->water() * 16;
tileHeight += 16;
if (tileHeight > height)
{
height = tileHeight;
}
}
}
else
{
tileHeight = surfaceTile->water() * 16;
if (tileHeight > height)
{
height = tileHeight;
}
}
return height;
return { height };
}
// 0x00478361
static std::optional<std::pair<int16_t, int16_t>> sub_478361(int16_t x, int16_t y)
static std::optional<std::pair<int16_t, int16_t>> getExistingRoadAtLoc(int16_t x, int16_t y)
{
registers regs;
regs.ax = x;
@ -1522,7 +1482,7 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
}
// 0x004A4011
static std::optional<std::pair<int16_t, int16_t>> sub_4A4011(int16_t x, int16_t y)
static std::optional<std::pair<int16_t, int16_t>> getExistingTrackAtLoc(int16_t x, int16_t y)
{
registers regs;
regs.ax = x;
@ -1535,7 +1495,7 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
return { std::make_pair(regs.di, regs.dl) };
}
static void constructionLoop(Pos2 mapPos, uint32_t maxRetries, int16_t height)
static void constructionLoop(const Pos2& mapPos, uint32_t maxRetries, int16_t height)
{
while (true)
{
@ -1608,6 +1568,165 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
call(0x0049DC8C, regs);
}
static int16_t getMaxPieceHeight(const std::vector<TrackData::PreviewTrack>& piece)
{
int16_t maxPieceHeight = 0;
for (const auto& part : piece)
{
maxPieceHeight = std::max(maxPieceHeight, part.z);
}
return maxPieceHeight;
}
// 0 if nothing currently selected
static int16_t getMaxConstructHeightFromExistingSelection()
{
int16_t maxHeight = 0;
if (Input::hasMapSelectionFlag(Input::MapSelectionFlags::enableConstruct))
{
auto i = 0;
for (auto& tile = _mapSelectedTiles[i]; tile.x != -1; tile = _mapSelectedTiles[++i])
{
if (!Map::validCoords(tile))
continue;
const auto tileHeight = getConstructionHeight(_mapSelectedTiles[i]);
if (!tileHeight)
{
continue;
}
maxHeight = std::max(tileHeight->landHeight, maxHeight);
if (tileHeight->waterHeight)
{
// Constructing over water is always +16
maxHeight = std::max<int16_t>(tileHeight->waterHeight + 16, maxHeight);
}
}
}
return maxHeight;
}
static std::optional<std::pair<Map::TilePos2, int16_t>> tryMakeRoadJunctionAtLoc(const int16_t x, const int16_t y)
{
const auto existingRoad = getExistingRoadAtLoc(x, y);
if (existingRoad)
{
const auto& existingHeight = existingRoad->first;
const auto mapPos = screenGetMapXyWithZ(Point(x, y), existingHeight);
if (mapPos)
{
return { std::make_pair(Map::TilePos2(*mapPos), existingHeight) };
}
}
return std::nullopt;
}
static std::optional<std::pair<Map::TilePos2, int16_t>> tryMakeTrackJunctionAtLoc(const int16_t x, const int16_t y)
{
const auto existingTrack = getExistingTrackAtLoc(x, y);
if (existingTrack)
{
const auto [existingHeight, existingTrackId] = *existingTrack;
if (TrackData::getUnkTrack(existingTrackId << 3).pos.z == 0)
{
const auto mapPos = screenGetMapXyWithZ(Point(x, y), existingHeight);
if (mapPos)
{
return { std::make_pair(Map::TilePos2(*mapPos), existingHeight) };
}
}
}
return std::nullopt;
}
static std::optional<std::pair<Map::TilePos2, int16_t>> getConstructionPos(const int16_t x, const int16_t y, const int16_t baseHeight)
{
auto mapPos = ViewportInteraction::getSurfaceOrWaterLocFromUi({ x, y });
if (!mapPos)
return std::nullopt;
auto tileHeight = getConstructionHeight(*mapPos);
if (!tileHeight)
{
return std::nullopt;
}
auto height = std::min(tileHeight->landHeight, baseHeight);
height = std::max(height, tileHeight->waterHeight);
return { std::make_pair(Map::TilePos2(*mapPos), height) };
}
template<typename TGetPieceId, typename TTryMakeJunction, typename TGetPiece>
static void onToolDownT(const int16_t x, const int16_t y, TGetPieceId&& getPieceId, TTryMakeJunction&& tryMakeJunction, TGetPiece&& getPiece)
{
mapInvalidateMapSelectionTiles();
removeConstructionGhosts();
auto pieceId = getPieceId(_lastSelectedTrackPiece, _lastSelectedTrackGradient, _constructionRotation);
if (!pieceId)
return;
_byte_1136065 = pieceId->id;
int16_t constructHeight = getMaxConstructHeightFromExistingSelection();
_word_1136000 = constructHeight;
Input::resetMapSelectionFlag(Input::MapSelectionFlags::enable | Input::MapSelectionFlags::enableConstruct | Input::MapSelectionFlags::unk_02);
Pos2 constructPos;
const auto junctionRes = tryMakeJunction(x, y);
if (junctionRes)
{
constructPos = junctionRes->first;
_makeJunction = 1;
_word_1135FFE = junctionRes->second;
}
else
{
const auto constRes = getConstructionPos(x, y, _word_1136000);
if (!constRes)
{
return;
}
constructPos = constRes->first;
constructHeight = constRes->second;
_makeJunction = 0;
}
Input::toolCancel();
auto maxRetries = 0;
if (Input::hasKeyModifier(Input::KeyModifier::shift) || _makeJunction != 1)
{
const auto& piece = getPiece(_byte_1136065);
constructHeight -= getMaxPieceHeight(piece);
constructHeight -= 16;
maxRetries = 2;
if (Input::hasKeyModifier(Input::KeyModifier::shift))
{
maxRetries = 0x80000008;
constructHeight -= 16;
}
}
else
{
maxRetries = 1;
constructHeight = _word_1135FFE;
}
constructionLoop(constructPos, maxRetries, constructHeight);
}
// 0x0049DC97
static void onToolDown(Window& self, const WidgetIndex_t widgetIndex, const int16_t x, const int16_t y)
{
@ -1616,195 +1735,11 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
if (_trackType & (1 << 7))
{
mapInvalidateMapSelectionTiles();
sub_49FEC7();
auto road = getRoadPieceId(_lastSelectedTrackPiece, _lastSelectedTrackGradient, _constructionRotation);
if (!road)
return;
_byte_1136065 = road->id;
int16_t roadHeight = 0;
auto i = 0;
if (Input::hasMapSelectionFlag(Input::MapSelectionFlags::enableConstruct))
{
for (auto& tile = _mapSelectedTiles[i]; tile.x != -1; tile = _mapSelectedTiles[++i])
{
if (tile.x >= 0x2FFF)
continue;
if (tile.y >= 0x2FFF)
continue;
auto height = getConstructionHeight(_mapSelectedTiles[i], roadHeight, true);
if (height)
roadHeight = *height;
}
}
// loc_4A23F8
_word_1136000 = roadHeight;
Input::resetMapSelectionFlag(Input::MapSelectionFlags::enable | Input::MapSelectionFlags::enableConstruct | Input::MapSelectionFlags::unk_02);
auto height = sub_478361(x, y);
std::optional<Pos2> mapPos;
if (height)
{
mapPos = screenGetMapXyWithZ(Point(x, y), height->first);
if (mapPos)
{
mapPos->x &= 0xFFE0;
mapPos->y &= 0xFFE0;
_byte_113605D = 1;
_word_1135FFE = roadHeight;
}
}
if (!height || !mapPos)
{
mapPos = ViewportInteraction::getSurfaceOrWaterLocFromUi({ x, y });
if (!mapPos)
return;
auto constructionHeight = getConstructionHeight(*mapPos, roadHeight, false);
if (constructionHeight)
roadHeight = *constructionHeight;
_byte_113605D = 0;
}
Input::toolCancel();
auto maxRetries = 0;
if (Input::hasKeyModifier(Input::KeyModifier::shift) || _byte_113605D != 1)
{
const auto& roadPiece = Map::TrackData::getRoadPiece(_byte_1136065);
auto maxRoadPieceHeight = 0;
for (const auto& roadPart : roadPiece)
{
if (maxRoadPieceHeight > roadPart.z)
maxRoadPieceHeight = roadPart.z;
}
roadHeight -= maxRoadPieceHeight;
roadHeight -= 16;
maxRetries = 2;
if (Input::hasKeyModifier(Input::KeyModifier::shift))
{
maxRetries = 0x80000008;
roadHeight -= 16;
}
}
else
{
maxRetries = 1;
roadHeight = _word_1135FFE;
}
constructionLoop(*mapPos, maxRetries, roadHeight);
onToolDownT(x, y, getRoadPieceId, tryMakeRoadJunctionAtLoc, TrackData::getRoadPiece);
}
else
{
mapInvalidateMapSelectionTiles();
sub_49FEC7();
auto track = getTrackPieceId(_lastSelectedTrackPiece, _lastSelectedTrackGradient, _constructionRotation);
if (!track)
return;
_byte_1136065 = track->id;
int16_t trackHeight = 0;
auto i = 0;
if (Input::hasMapSelectionFlag(Input::MapSelectionFlags::enableConstruct))
{
for (auto& tile = _mapSelectedTiles[i]; tile.x != -1; tile = _mapSelectedTiles[++i])
{
if (tile.x >= 0x2FFF)
continue;
if (tile.y >= 0x2FFF)
continue;
auto height = getConstructionHeight(_mapSelectedTiles[i], trackHeight, true);
if (height)
trackHeight = *height;
}
}
_word_1136000 = trackHeight;
Input::resetMapSelectionFlag(Input::MapSelectionFlags::enable | Input::MapSelectionFlags::enableConstruct | Input::MapSelectionFlags::unk_02);
auto height = sub_4A4011(x, y);
std::optional<Pos2> mapPos;
if (height)
{
if (_word_4F7B62[height->second] == 0)
{
mapPos = screenGetMapXyWithZ(Point(x, y), height->first);
if (mapPos)
{
mapPos->x &= 0xFFE0;
mapPos->y &= 0xFFE0;
_byte_113605D = 1;
_word_1135FFE = trackHeight;
}
}
}
if (!height || !mapPos || _word_4F7B62[track->id * 8] != 0)
{
mapPos = ViewportInteraction::getSurfaceOrWaterLocFromUi({ x, y });
if (!mapPos)
return;
auto constructionHeight = getConstructionHeight(*mapPos, trackHeight, false);
if (constructionHeight)
trackHeight = *constructionHeight;
_byte_113605D = 0;
}
Input::toolCancel();
auto maxRetries = 0;
if (Input::hasKeyModifier(Input::KeyModifier::shift) || _byte_113605D != 1)
{
const auto& trackPiece = Map::TrackData::getTrackPiece(_byte_1136065);
auto maxTrackPieceHeight = 0;
for (const auto& trackPart : trackPiece)
{
if (maxTrackPieceHeight > trackPart.z)
maxTrackPieceHeight = trackPart.z;
}
trackHeight -= maxTrackPieceHeight;
trackHeight -= 16;
maxRetries = 2;
if (Input::hasKeyModifier(Input::KeyModifier::shift))
{
maxRetries = 0x80000008;
trackHeight -= 16;
}
}
else
{
maxRetries = 1;
trackHeight = _word_1135FFE;
}
constructionLoop(*mapPos, maxRetries, trackHeight);
onToolDownT(x, y, getTrackPieceId, tryMakeTrackJunctionAtLoc, TrackData::getTrackPiece);
}
}
@ -2094,5 +2029,4 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
events.prepare_draw = prepareDraw;
events.draw = draw;
}
}

View File

@ -2603,7 +2603,7 @@ namespace OpenLoco::Ui::Windows::Terraform
auto* window = WindowManager::find(WindowType::construction);
if (window != nullptr)
{
Ui::Windows::Construction::sub_49FEC7();
Ui::Windows::Construction::removeConstructionGhosts();
}
}

View File

@ -3655,16 +3655,6 @@ namespace OpenLoco::Ui::Windows::Vehicle
return { placementArgs };
}
#pragma pack(push, 1)
struct UnkTrack
{
uint8_t var_00; // 0x00
uint8_t var_01; // 0x01
Map::Pos3 pos; // 0x02
};
static_assert(sizeof(UnkTrack) == 0x8);
#pragma pack(pop)
// 0x00479707
static std::optional<GameCommands::VehiclePlacementArgs> getVehicleRoadPlacementArgsFromCursor(const Vehicles::VehicleHead& head, const int16_t x, const int16_t y)
{
@ -3688,13 +3678,12 @@ namespace OpenLoco::Ui::Windows::Vehicle
unkYaw &= 0x3F;
if (unkYaw <= 0x20)
{
static loco_global<UnkTrack[352], 0x004F6F8C> _4F6F8C;
static loco_global<Map::Pos2[352], 0x00503C6C> _503C6C;
const auto& unkItem = _4F6F8C[placementArgs->trackAndDirection];
const auto& unkItem = TrackData::getUnkRoad(placementArgs->trackAndDirection);
placementArgs->pos += unkItem.pos;
if (unkItem.var_01 < 12)
if (unkItem.rotationEnd < 12)
{
placementArgs->pos -= _503C6C[unkItem.var_01];
placementArgs->pos -= _503C6C[unkItem.rotationEnd];
}
placementArgs->trackProgress = std::max<uint16_t>(static_cast<uint16_t>(moveInfoArr.size()) - placementArgs->trackProgress, 0);
if (placementArgs->trackProgress >= moveInfoArr.size())
@ -3795,13 +3784,12 @@ namespace OpenLoco::Ui::Windows::Vehicle
unkYaw &= 0x3F;
if (unkYaw <= 0x20)
{
static loco_global<UnkTrack[352], 0x004F7B5C> _4F7B5C;
static loco_global<Map::Pos2[352], 0x00503C6C> _503C6C;
const auto& unkItem = _4F7B5C[placementArgs->trackAndDirection];
const auto& unkItem = TrackData::getUnkTrack(placementArgs->trackAndDirection);
placementArgs->pos += unkItem.pos;
if (unkItem.var_01 < 12)
if (unkItem.rotationEnd < 12)
{
placementArgs->pos -= _503C6C[unkItem.var_01];
placementArgs->pos -= _503C6C[unkItem.rotationEnd];
}
placementArgs->trackProgress = std::max<uint16_t>(static_cast<uint16_t>(moveInfoArr.size()) - placementArgs->trackProgress, 0);
if (placementArgs->trackProgress >= moveInfoArr.size())