Station rename command (#984)

This re-introduces the possibility of resetting/regenerating station names automatically
by using an empty station name. Previously, our re-implementation (C++ code) inadvertently
removed this option.
This commit is contained in:
Aaron van Geffen 2021-07-01 19:59:37 +02:00 committed by GitHub
parent d10b16e404
commit fbc145a5bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 139 additions and 4 deletions

View File

@ -2,6 +2,7 @@
------------------------------------------------------------------------
- Feature: [#856] Allow filtering the vehicle list by station or cargo type.
- Fix: [#982] Incorrect rating calculation for cargo causing penalty for fast vehicles.
- Fix: [#984] Unable to reset/regenerate station names by using an empty name.
- Fix: [#1008] Inability to decrease max altitude for trees in landscape editor.
- Fix: [#1016] Incorrect detection of station causing incorrect smoke sounds.
- Technical: [#986] Stack misalignment in GCC builds caused unexplained crashes on Linux and Mac during interop hooks with loco.exe.

View File

@ -57,7 +57,7 @@ namespace OpenLoco::GameCommands
{ GameCommand::gc_unk_8, nullptr, 0x0049C7F2, true },
{ GameCommand::changeLoan, nullptr, 0x0046DE88, false },
{ GameCommand::vehicleRename, Vehicles::rename, 0x004B6572, false },
{ GameCommand::changeStationName, nullptr, 0x00490756, false },
{ GameCommand::changeStationName, renameStation, 0x00490756, false },
{ GameCommand::vehicleLocalExpress, nullptr, 0x004B694B, true },
{ GameCommand::gc_unk_13, nullptr, 0x00488BDB, true },
{ GameCommand::gc_unk_14, nullptr, 0x004891E4, true },

View File

@ -675,6 +675,9 @@ namespace OpenLoco::GameCommands
// Defined in GameCommands/RenameIndustry.cpp
void renameIndustry(registers& regs);
// Defined in GameCommands/RenameStation.cpp
void renameStation(registers& regs);
// Defined in GameCommands/RenameTown.cpp
void renameTown(registers& regs);

View File

@ -0,0 +1,109 @@
#include "../Economy/Expenditures.h"
#include "../Industry.h"
#include "../Interop/Interop.hpp"
#include "../Localisation/FormatArguments.hpp"
#include "../Localisation/StringIds.h"
#include "../Localisation/StringManager.h"
#include "../StationManager.h"
#include "../TownManager.h"
#include "../Types.hpp"
#include "GameCommands.h"
using namespace OpenLoco::Interop;
namespace OpenLoco::GameCommands
{
/**
* 0x00490756
* Renames a particular station.
*
* This command is called 3 times before the buffer is applied. Each time, 12 chars of the 36 char buffer are provided.
* The resulting station name has a maximum length of 31 chars; the last bytes are not used.
*
* @param flags @<bl> - game command flags
* @param stationId @<cx> - station id
* @param index @<ax> - update index (in order of: 1, 2, 0)
* @param buffer0 @<edx> - First part (4 chars) of the 12 update buffer
* @param buffer1 @<dx> - Second part (4 chars) of the 12 update buffer
* @param buffer2 @<bp> - Third part (4 chars) of the 12 update buffer
* @return @<ebx> - returns 0 if rename is successful; otherwise GameCommands::FAILURE
*/
static uint32_t renameStation(const uint8_t flags, StationId_t stationId, int16_t index, uint32_t buffer0, uint32_t buffer1, uint32_t buffer2)
{
GameCommands::setExpenditureType(ExpenditureType::Miscellaneous);
// Keep track of the station id over several calls.
static StationId_t _stationId{};
if (index == 1)
_stationId = stationId;
static uint32_t renameBuffer[9];
// Fill buffer over calls into the renameBuffer
if ((flags & GameCommands::Flags::apply) != 0)
{
static const std::array<int, 3> transformTable = { 2, 0, 1 };
int arrayIndex = transformTable.at(index);
renameBuffer[arrayIndex * 3] = buffer0;
renameBuffer[arrayIndex * 3 + 1] = buffer1;
renameBuffer[arrayIndex * 3 + 2] = buffer2;
}
// Applying the buffer?
if (index != 0)
return 0;
char renameStringBuffer[37] = "";
memcpy(renameStringBuffer, renameBuffer, sizeof(renameBuffer));
renameStringBuffer[36] = '\0';
// Figure out the current name for this station.
char currentStationName[256] = "";
auto station = StationManager::get(_stationId);
auto args = FormatArguments::common(station->town);
StringManager::formatString(currentStationName, station->name, &args);
// Verify the new name actually differs from the old one.
if (strcmp(currentStationName, renameStringBuffer) == 0)
return 0;
string_id oldStringId = station->name;
// If an empty string is given, generate one instead.
if (strlen(renameStringBuffer) == 0)
{
// Are we bailing out early?
if ((flags & GameCommands::Flags::apply) == 0)
return 0;
station->name = StationManager::generateNewStationName(_stationId, station->town, Map::Pos3(station->x, station->y, station->z), 0);
}
else
{
// Allocate a string id for the new name.
string_id allocatedStringId = StringManager::userStringAllocate(renameStringBuffer, 0);
if (allocatedStringId == StringIds::empty)
return GameCommands::FAILURE;
// Are we bailing out early?
if ((flags & GameCommands::Flags::apply) == 0)
{
StringManager::emptyUserString(allocatedStringId);
return 0;
}
// Apply the new name to the station.
station->name = allocatedStringId;
}
StringManager::emptyUserString(oldStringId);
station->updateLabel();
Gfx::invalidateScreen();
return 0;
}
void renameStation(registers& regs)
{
regs.ebx = renameStation(regs.bl, regs.cx, regs.ax, regs.edx, regs.ebp, regs.edi);
}
}

View File

@ -249,6 +249,7 @@ namespace OpenLoco::StringIds
constexpr string_id tooltip_signal_single_direction = 277;
constexpr string_id tooltip_bridge_stats = 278;
constexpr string_id tooltip_select_station_type = 279;
constexpr string_id station_name_ordinal = 280;
constexpr string_id vehicle_details_weight = 328;
constexpr string_id vehicle_details_total_power_and_weight = 329;

View File

@ -1,6 +1,7 @@
#include "StationManager.h"
#include "CompanyManager.h"
#include "Interop/Interop.hpp"
#include "Localisation/FormatArguments.hpp"
#include "OpenLoco.h"
#include "TownManager.h"
#include "Ui/WindowManager.h"
@ -120,6 +121,27 @@ namespace OpenLoco::StationManager
}
}
// 0x048F988
string_id generateNewStationName(StationId_t stationId, TownId_t townId, Map::Pos3 position, uint8_t mode)
{
auto* station = get(stationId);
if (station == nullptr)
return StringIds::null;
station->name = StringIds::null;
registers regs;
regs.esi = reinterpret_cast<int32_t>(station);
regs.ebx = townId;
regs.dh = static_cast<uint8_t>(position.z / 4);
regs.dl = mode;
regs.ax = position.x & 0xFFE0;
regs.cx = position.y & 0xFFE0;
call(0x048F988, regs);
return regs.bx;
}
// 0x0049088B
void zeroUnused()
{

View File

@ -15,5 +15,6 @@ namespace OpenLoco::StationManager
void update();
void updateLabels();
void updateDaily();
string_id generateNewStationName(StationId_t stationId, TownId_t townId, Map::Pos3 position, uint8_t mode);
void zeroUnused();
}

View File

@ -846,9 +846,6 @@ namespace OpenLoco::Ui::Windows::Station
if (callingWidget != Common::widx::caption)
return;
if (strlen(input) == 0)
return;
GameCommands::setErrorTitle(StringIds::error_cant_rename_station);
uint32_t* buffer = (uint32_t*)input;

View File

@ -38,6 +38,7 @@
<ClCompile Include="GameCommands\GameCommands.cpp" />
<ClCompile Include="GameCommands\LoadSaveQuit.cpp" />
<ClCompile Include="GameCommands\RenameIndustry.cpp" />
<ClCompile Include="GameCommands\RenameStation.cpp" />
<ClCompile Include="GameCommands\RenameTown.cpp" />
<ClCompile Include="GameCommands\TogglePause.cpp" />
<ClCompile Include="GameCommands\VehiclePickup.cpp" />