Implement constructTrack (#1109)
This commit is contained in:
parent
f4f3d0d72c
commit
191e6d567c
|
@ -53,7 +53,7 @@ namespace OpenLoco::GameCommands
|
|||
{ GameCommand::vehiclePassSignal, nullptr, 0x004B0B50, true },
|
||||
{ GameCommand::vehicleCreate, Vehicles::create, 0x004AE5E4, true },
|
||||
{ GameCommand::vehicleSell, nullptr, 0x004AED34, true },
|
||||
{ GameCommand::gc_unk_7, nullptr, 0x0049BB98, true },
|
||||
{ GameCommand::createTrack, nullptr, 0x0049BB98, true },
|
||||
{ GameCommand::gc_unk_8, nullptr, 0x0049C7F2, true },
|
||||
{ GameCommand::changeLoan, nullptr, 0x0046DE88, false },
|
||||
{ GameCommand::vehicleRename, Vehicles::rename, 0x004B6572, false },
|
||||
|
@ -84,7 +84,7 @@ namespace OpenLoco::GameCommands
|
|||
{ GameCommand::vehicleOrderInsert, nullptr, 0x0047036E, false },
|
||||
{ GameCommand::vehicleOrderDelete, nullptr, 0x0047057A, false },
|
||||
{ GameCommand::vehicleOrderSkip, Vehicles::orderSkip, 0x0047071A, false },
|
||||
{ GameCommand::gc_unk_38, nullptr, 0x00475FBC, true },
|
||||
{ GameCommand::createRoad, nullptr, 0x00475FBC, true },
|
||||
{ GameCommand::removeRoad, nullptr, 0x004775A5, true },
|
||||
{ GameCommand::createRoadMod, nullptr, 0x0047A21E, true },
|
||||
{ GameCommand::removeRoadMod, nullptr, 0x0047A42F, true },
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace OpenLoco::GameCommands
|
|||
vehiclePassSignal = 4,
|
||||
vehicleCreate = 5,
|
||||
vehicleSell = 6,
|
||||
gc_unk_7 = 7,
|
||||
createTrack = 7,
|
||||
gc_unk_8 = 8,
|
||||
changeLoan = 9,
|
||||
vehicleRename = 10,
|
||||
|
@ -71,7 +71,7 @@ namespace OpenLoco::GameCommands
|
|||
vehicleOrderInsert = 35,
|
||||
vehicleOrderDelete = 36,
|
||||
vehicleOrderSkip = 37,
|
||||
gc_unk_38 = 38,
|
||||
createRoad = 38,
|
||||
removeRoad = 39,
|
||||
createRoadMod = 40,
|
||||
removeRoadMod = 41,
|
||||
|
@ -240,6 +240,42 @@ namespace OpenLoco::GameCommands
|
|||
doCommand(GameCommand::vehicleSell, regs);
|
||||
}
|
||||
|
||||
struct TrackPlacementArgs
|
||||
{
|
||||
static constexpr auto command = GameCommand::createTrack;
|
||||
|
||||
TrackPlacementArgs() = default;
|
||||
explicit TrackPlacementArgs(const registers& regs)
|
||||
: pos(regs.ax, regs.cx, regs.di)
|
||||
, rotation(regs.bh & 0x3)
|
||||
, trackId(regs.dh & 0x3F)
|
||||
, mods(regs.di >> 16)
|
||||
, bridge(regs.edx >> 24)
|
||||
, trackObjectId(regs.dl)
|
||||
, unk(regs.edi & 0x800000)
|
||||
{
|
||||
}
|
||||
|
||||
Map::Pos3 pos;
|
||||
uint8_t rotation;
|
||||
uint8_t trackId;
|
||||
uint8_t mods;
|
||||
uint8_t bridge;
|
||||
uint8_t trackObjectId;
|
||||
bool unk;
|
||||
|
||||
explicit operator registers() const
|
||||
{
|
||||
registers regs;
|
||||
regs.eax = pos.x;
|
||||
regs.cx = pos.y;
|
||||
regs.edi = pos.z | (mods << 16) | (unk ? 0x800000 : 0);
|
||||
regs.bh = rotation;
|
||||
regs.edx = trackObjectId | (trackId << 8) | (bridge << 24);
|
||||
return regs;
|
||||
}
|
||||
};
|
||||
|
||||
// Change loan
|
||||
inline void do_9(currency32_t newLoan)
|
||||
{
|
||||
|
@ -727,6 +763,40 @@ namespace OpenLoco::GameCommands
|
|||
return doCommand(GameCommand::vehicleOrderSkip, regs);
|
||||
}
|
||||
|
||||
struct RoadPlacementArgs
|
||||
{
|
||||
static constexpr auto command = GameCommand::createRoad;
|
||||
|
||||
RoadPlacementArgs() = default;
|
||||
explicit RoadPlacementArgs(const registers& regs)
|
||||
: pos(regs.ax, regs.cx, regs.di)
|
||||
, rotation(regs.bh & 0x3)
|
||||
, roadId(regs.dh & 0xF)
|
||||
, mods(regs.di >> 16)
|
||||
, bridge(regs.edx >> 24)
|
||||
, roadObjectId(regs.dl)
|
||||
{
|
||||
}
|
||||
|
||||
Map::Pos3 pos;
|
||||
uint8_t rotation;
|
||||
uint8_t roadId;
|
||||
uint8_t mods;
|
||||
uint8_t bridge;
|
||||
uint8_t roadObjectId;
|
||||
|
||||
explicit operator registers() const
|
||||
{
|
||||
registers regs;
|
||||
regs.eax = pos.x;
|
||||
regs.cx = pos.y;
|
||||
regs.edi = pos.z | (mods << 16);
|
||||
regs.bh = rotation;
|
||||
regs.edx = roadObjectId | (roadId << 8) | (bridge << 24);
|
||||
return regs;
|
||||
}
|
||||
};
|
||||
|
||||
struct RoadRemovalArgs
|
||||
{
|
||||
static constexpr auto command = GameCommand::removeRoad;
|
||||
|
|
|
@ -142,9 +142,13 @@ namespace OpenLoco::StringIds
|
|||
constexpr string_id cant_build_signals_here = 140;
|
||||
constexpr string_id cant_remove_signal = 141;
|
||||
|
||||
constexpr string_id cant_build_pop3_string = 143;
|
||||
|
||||
constexpr string_id menu_underground_view = 145;
|
||||
constexpr string_id menu_hide_foreground_tracks_roads = 146;
|
||||
|
||||
constexpr string_id unable_to_cross_or_create_junction_with_string = 156;
|
||||
|
||||
constexpr string_id capt_signal = 158;
|
||||
constexpr string_id capt_station = 159;
|
||||
constexpr string_id capt_airport = 160;
|
||||
|
|
|
@ -29,6 +29,8 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
|
|||
static loco_global<uint32_t, 0x00523394> _toolWidgetIndex;
|
||||
|
||||
static loco_global<int32_t, 0x00E3F0B8> gCurrentRotation;
|
||||
static loco_global<uint8_t, 0x0112C2E9> _alternateTrackObjectId; // set from GameCommands::createRoad
|
||||
static loco_global<uint8_t[18], 0x0050A006> available_objects; // toptoolbar
|
||||
|
||||
namespace TrackPiece
|
||||
{
|
||||
|
@ -131,13 +133,175 @@ namespace OpenLoco::Ui::Windows::Construction::Construction
|
|||
_pickupDirection = 0;
|
||||
}
|
||||
|
||||
// 0x004A18D4
|
||||
static void sub_4A18D4()
|
||||
{
|
||||
if (_alternateTrackObjectId == 0xFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((_alternateTrackObjectId | (1 << 7)) == _trackType)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto* alternativeRoadObj = ObjectManager::get<RoadObject>(_alternateTrackObjectId);
|
||||
if (!(alternativeRoadObj->flags & Flags12::unk_03))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto* curRoadObj = ObjectManager::get<RoadObject>(_trackType & ~(1 << 7));
|
||||
if (!(curRoadObj->flags & Flags12::unk_03))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto objId : available_objects)
|
||||
{
|
||||
if (objId == 0xFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (objId == (_alternateTrackObjectId | (1 << 7)))
|
||||
{
|
||||
_trackType = _alternateTrackObjectId | (1 << 7);
|
||||
Common::sub_4A3A50();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x0049FA10
|
||||
static void constructRoad()
|
||||
{
|
||||
_trackCost = 0x80000000;
|
||||
_byte_1136076 = 0;
|
||||
_dword_1135F42 = 0x80000000;
|
||||
removeConstructionGhosts();
|
||||
auto roadPiece = getRoadPieceId(_lastSelectedTrackPiece, _lastSelectedTrackGradient, _constructionRotation);
|
||||
if (!roadPiece)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto* roadObj = ObjectManager::get<RoadObject>(_trackType & ~(1 << 7));
|
||||
auto formatArgs = FormatArguments::common();
|
||||
formatArgs.skip(3 * sizeof(string_id));
|
||||
formatArgs.push(roadObj->name);
|
||||
GameCommands::setErrorTitle(StringIds::cant_build_pop3_string);
|
||||
|
||||
GameCommands::RoadPlacementArgs args;
|
||||
args.pos = Map::Pos3(_x, _y, _constructionZ);
|
||||
args.rotation = roadPiece->rotation;
|
||||
args.roadId = roadPiece->id;
|
||||
args.mods = _lastSelectedMods;
|
||||
args.bridge = _lastSelectedBridge;
|
||||
args.roadObjectId = _trackType & ~(1 << 7);
|
||||
|
||||
_dword_1135F42 = GameCommands::doCommand(args, GameCommands::Flags::apply);
|
||||
if (_dword_1135F42 == GameCommands::FAILURE)
|
||||
{
|
||||
if (GameCommands::getErrorText() != StringIds::unable_to_cross_or_create_junction_with_string
|
||||
|| _alternateTrackObjectId == 0xFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sub_4A18D4();
|
||||
roadPiece = getRoadPieceId(_lastSelectedTrackPiece, _lastSelectedTrackGradient, _constructionRotation);
|
||||
if (!roadPiece)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WindowManager::close(WindowType::error);
|
||||
args.pos = Map::Pos3(_x, _y, _constructionZ);
|
||||
args.rotation = roadPiece->rotation;
|
||||
args.roadId = roadPiece->id;
|
||||
args.mods = _lastSelectedMods;
|
||||
args.bridge = _lastSelectedBridge;
|
||||
args.roadObjectId = _trackType & ~(1 << 7);
|
||||
|
||||
_dword_1135F42 = GameCommands::doCommand(args, GameCommands::Flags::apply);
|
||||
}
|
||||
|
||||
if (_dword_1135F42 != GameCommands::FAILURE)
|
||||
{
|
||||
const auto& trackSize = TrackData::getUnkRoad((args.roadId << 3) | (args.rotation & 0x3));
|
||||
const auto newPosition = args.pos + trackSize.pos;
|
||||
_x = newPosition.x;
|
||||
_y = newPosition.y;
|
||||
_constructionZ = newPosition.z;
|
||||
_constructionRotation = trackSize.rotationEnd;
|
||||
_byte_522096 = 0;
|
||||
_byte_1136066 = 0;
|
||||
if (_lastSelectedTrackPiece >= 9)
|
||||
{
|
||||
_lastSelectedTrackPiece = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x0049F93A
|
||||
static void constructTrack()
|
||||
{
|
||||
_trackCost = 0x80000000;
|
||||
_byte_1136076 = 0;
|
||||
_dword_1135F42 = 0x80000000;
|
||||
removeConstructionGhosts();
|
||||
auto trackPiece = getTrackPieceId(_lastSelectedTrackPiece, _lastSelectedTrackGradient, _constructionRotation);
|
||||
if (!trackPiece)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto* roadObj = ObjectManager::get<TrackObject>(_trackType);
|
||||
auto formatArgs = FormatArguments::common();
|
||||
formatArgs.skip(3 * sizeof(string_id));
|
||||
formatArgs.push(roadObj->name);
|
||||
GameCommands::setErrorTitle(StringIds::cant_build_pop3_string);
|
||||
|
||||
GameCommands::TrackPlacementArgs args;
|
||||
args.pos = Map::Pos3(_x, _y, _constructionZ);
|
||||
args.rotation = trackPiece->rotation;
|
||||
args.trackId = trackPiece->id;
|
||||
args.mods = _lastSelectedMods;
|
||||
args.bridge = _lastSelectedBridge;
|
||||
args.trackObjectId = _trackType;
|
||||
args.unk = _byte_113607E & (1 << 0);
|
||||
|
||||
_dword_1135F42 = GameCommands::doCommand(args, GameCommands::Flags::apply);
|
||||
|
||||
if (_dword_1135F42 == GameCommands::FAILURE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& trackSize = TrackData::getUnkTrack((args.trackId << 3) | (args.rotation & 0x3));
|
||||
const auto newPosition = args.pos + trackSize.pos;
|
||||
_x = newPosition.x;
|
||||
_y = newPosition.y;
|
||||
_constructionZ = newPosition.z;
|
||||
_constructionRotation = trackSize.rotationEnd;
|
||||
_byte_522096 = 0;
|
||||
_byte_1136066 = 0;
|
||||
if (_lastSelectedTrackPiece >= 9)
|
||||
{
|
||||
_lastSelectedTrackPiece = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x0049F92D
|
||||
static void constructTrack(Window* self, WidgetIndex_t widgetIndex)
|
||||
{
|
||||
registers regs;
|
||||
regs.edx = widgetIndex;
|
||||
regs.esi = X86Pointer(self);
|
||||
call(0x0049F92D, regs);
|
||||
if (_trackType & (1 << 7))
|
||||
{
|
||||
constructRoad();
|
||||
}
|
||||
else
|
||||
{
|
||||
constructTrack();
|
||||
}
|
||||
activateSelectedConstructionWidgets();
|
||||
}
|
||||
|
||||
// 0x004A0121
|
||||
|
|
|
@ -335,7 +335,7 @@ namespace OpenLoco::Ui::Windows::ToolbarTop::Game
|
|||
// 0x0043A2B0
|
||||
static void railroadMenuMouseDown(Window* window, WidgetIndex_t widgetIndex)
|
||||
{
|
||||
// Load objects.
|
||||
// Load dropdown objects removing any that are not unlocked.
|
||||
registers regs;
|
||||
regs.edi = X86Pointer(&available_objects[0]);
|
||||
call(0x004A6841, regs);
|
||||
|
|
Loading…
Reference in New Issue