1601 lines
43 KiB
C++
1601 lines
43 KiB
C++
#pragma once
|
|
|
|
#include "../Economy/Currency.h"
|
|
#include "../Entities/Entity.h"
|
|
#include "../Interop/Interop.hpp"
|
|
#include "../Map/Tile.h"
|
|
#include "../Objects/ObjectManager.h"
|
|
|
|
using namespace OpenLoco::Interop;
|
|
|
|
namespace OpenLoco
|
|
{
|
|
enum ExpenditureType : uint8_t;
|
|
}
|
|
|
|
namespace OpenLoco::Vehicles
|
|
{
|
|
struct VehicleHead;
|
|
}
|
|
|
|
namespace OpenLoco::GameCommands
|
|
{
|
|
namespace Flags
|
|
{
|
|
constexpr uint8_t apply = 1 << 0; // 0x01
|
|
constexpr uint8_t flag_1 = 1 << 1; // 0x02
|
|
constexpr uint8_t flag_2 = 1 << 2; // 0x04
|
|
constexpr uint8_t flag_3 = 1 << 3; // 0x08
|
|
constexpr uint8_t flag_4 = 1 << 4; // 0x10
|
|
constexpr uint8_t flag_5 = 1 << 5; // 0x20
|
|
constexpr uint8_t flag_6 = 1 << 6; // 0x40
|
|
}
|
|
|
|
enum class GameCommand : uint8_t
|
|
{
|
|
vehicleRearrange = 0,
|
|
vehiclePlace = 1,
|
|
vehiclePickup = 2,
|
|
vehicleReverse = 3,
|
|
vehiclePassSignal = 4,
|
|
vehicleCreate = 5,
|
|
vehicleSell = 6,
|
|
createTrack = 7,
|
|
removeTrack = 8,
|
|
changeLoan = 9,
|
|
vehicleRename = 10,
|
|
changeStationName = 11,
|
|
vehicleLocalExpress = 12,
|
|
createSignal = 13,
|
|
removeSignal = 14,
|
|
createTrainStation = 15,
|
|
removeTrackStation = 16,
|
|
createTrackMod = 17,
|
|
removeTrackMod = 18,
|
|
changeCompanyColourScheme = 19,
|
|
pauseGame = 20,
|
|
loadSaveQuitGame = 21,
|
|
removeTree = 22,
|
|
createTree = 23,
|
|
changeLandMaterial = 24,
|
|
raiseLand = 25,
|
|
lowerLand = 26,
|
|
lowerRaiseLandMountain = 27,
|
|
raiseWater = 28,
|
|
lowerWater = 29,
|
|
changeCompanyName = 30,
|
|
changeCompanyOwnerName = 31,
|
|
createWall = 32,
|
|
removeWall = 33,
|
|
gc_unk_34 = 34,
|
|
vehicleOrderInsert = 35,
|
|
vehicleOrderDelete = 36,
|
|
vehicleOrderSkip = 37,
|
|
createRoad = 38,
|
|
removeRoad = 39,
|
|
createRoadMod = 40,
|
|
removeRoadMod = 41,
|
|
createRoadStation = 42,
|
|
removeRoadStation = 43,
|
|
createBuilding = 44,
|
|
removeBuilding = 45,
|
|
renameTown = 46,
|
|
createIndustry = 47,
|
|
removeIndustry = 48,
|
|
createTown = 49,
|
|
removeTown = 50,
|
|
gc_unk_51 = 51,
|
|
gc_unk_52 = 52,
|
|
gc_unk_53 = 53,
|
|
buildCompanyHeadquarters = 54,
|
|
removeCompanyHeadquarters = 55,
|
|
createAirport = 56,
|
|
removeAirport = 57,
|
|
vehiclePlaceAir = 58,
|
|
vehiclePickupAir = 59,
|
|
createPort = 60,
|
|
removePort = 61,
|
|
vehiclePlaceWater = 62,
|
|
vehiclePickupWater = 63,
|
|
vehicleRefit = 64,
|
|
changeCompanyFace = 65,
|
|
clearLand = 66,
|
|
loadMultiplayerMap = 67,
|
|
gc_unk_68 = 68,
|
|
gc_unk_69 = 69,
|
|
gc_unk_70 = 70,
|
|
sendChatMessage = 71,
|
|
multiplayerSave = 72,
|
|
updateOwnerStatus = 73,
|
|
vehicleSpeedControl = 74,
|
|
vehicleOrderUp = 75,
|
|
vehicleOrderDown = 76,
|
|
vehicleApplyShuntCheat = 77,
|
|
applyFreeCashCheat = 78,
|
|
renameIndustry = 79,
|
|
vehicleClone = 80,
|
|
cheat = 81,
|
|
};
|
|
|
|
enum class LoadOrQuitMode : uint16_t
|
|
{
|
|
loadGamePrompt,
|
|
returnToTitlePrompt,
|
|
quitGamePrompt,
|
|
};
|
|
|
|
constexpr uint32_t FAILURE = 0x80000000;
|
|
|
|
void registerHooks();
|
|
uint32_t doCommand(GameCommand command, const registers& registers);
|
|
bool sub_431E6A(const CompanyId_t company, Map::TileElement* const tile = nullptr);
|
|
|
|
template<typename T>
|
|
uint32_t doCommand(const T& args, uint8_t flags)
|
|
{
|
|
registers regs = registers(args);
|
|
regs.bl = flags;
|
|
return doCommand(T::command, regs);
|
|
}
|
|
|
|
inline void do_0(EntityId_t source, EntityId_t dest)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.dx = source;
|
|
regs.di = dest;
|
|
doCommand(GameCommand::vehicleRearrange, regs);
|
|
}
|
|
|
|
struct VehiclePlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::vehiclePlace;
|
|
|
|
VehiclePlacementArgs() = default;
|
|
explicit VehiclePlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.dx * 4)
|
|
, trackAndDirection(regs.bp)
|
|
, trackProgress(regs.ebx >> 16)
|
|
, head(regs.di)
|
|
, convertGhost((regs.ebx >> 16) == 0xFFFF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint16_t trackAndDirection;
|
|
uint16_t trackProgress;
|
|
EntityId_t head;
|
|
bool convertGhost = false;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ebp = trackAndDirection;
|
|
regs.di = head;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.dx = pos.z / 4;
|
|
regs.ebx = convertGhost ? 0xFFFF0000 : (trackProgress << 16);
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
inline bool do_2(EntityId_t head)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply | Flags::flag_3 | Flags::flag_6;
|
|
regs.di = head;
|
|
return doCommand(GameCommand::vehiclePickup, regs) != FAILURE;
|
|
}
|
|
|
|
// Reverse (vehicle)
|
|
inline void do_3(EntityId_t vehicleHead, Vehicles::VehicleHead* const head)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.dx = vehicleHead;
|
|
// Bug in game command 3 requires to set edi to a vehicle prior to calling
|
|
regs.edi = X86Pointer(head);
|
|
|
|
doCommand(GameCommand::vehicleReverse, regs);
|
|
}
|
|
|
|
// Pass signal (vehicle)
|
|
inline void do_4(EntityId_t vehicleHead)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.di = vehicleHead;
|
|
|
|
doCommand(GameCommand::vehiclePassSignal, regs);
|
|
}
|
|
|
|
// Build vehicle
|
|
inline uint32_t do_5(uint16_t vehicle_type, uint16_t vehicle_id = 0xFFFF)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.di = vehicle_id;
|
|
regs.edx = vehicle_type;
|
|
|
|
return doCommand(GameCommand::vehicleCreate, regs);
|
|
}
|
|
|
|
// Build vehicle
|
|
inline uint32_t queryDo_5(uint16_t vehicle_type, uint16_t vehicle_id = 0xFFFF)
|
|
{
|
|
registers regs;
|
|
regs.bl = 0;
|
|
regs.di = vehicle_id;
|
|
regs.edx = vehicle_type;
|
|
|
|
return doCommand(GameCommand::vehicleCreate, regs);
|
|
}
|
|
|
|
inline void do_6(EntityId_t car)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.dx = car;
|
|
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 = (0xFFFF & pos.z) | (mods << 16) | (unk ? 0x800000 : 0);
|
|
regs.bh = rotation;
|
|
regs.edx = trackObjectId | (trackId << 8) | (bridge << 24);
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct TrackRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeTrack;
|
|
|
|
TrackRemovalArgs() = default;
|
|
explicit TrackRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, trackId(regs.dl & 0x3F)
|
|
, index(regs.dh)
|
|
, trackObjectId(regs.ebp)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t trackId;
|
|
uint8_t index;
|
|
uint8_t trackObjectId;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.eax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
regs.bh = rotation;
|
|
regs.dl = trackId;
|
|
regs.dh = index;
|
|
regs.ebp = trackObjectId;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
// Change loan
|
|
inline void do_9(currency32_t newLoan)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.edx = newLoan;
|
|
doCommand(GameCommand::changeLoan, regs);
|
|
}
|
|
|
|
// Change vehicle name
|
|
inline void do_10(EntityId_t head, uint16_t i, uint32_t edx, uint32_t ebp, uint32_t edi)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = head; // vehicle head id
|
|
regs.ax = i; // [ 0, 1, 2]
|
|
regs.edx = edx; // part of name buffer
|
|
regs.ebp = ebp; // part of name buffer
|
|
regs.edi = edi; // part of name buffer
|
|
doCommand(GameCommand::vehicleRename, regs);
|
|
}
|
|
|
|
// Change station name
|
|
inline void do_11(uint16_t cx, uint16_t ax, uint32_t edx, uint32_t ebp, uint32_t edi)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = cx; // station number or 0
|
|
regs.ax = ax; // [ 0, 1, 2]
|
|
regs.edx = edx; // part of name buffer
|
|
regs.ebp = ebp; // part of name buffer
|
|
regs.edi = edi; // part of name buffer
|
|
doCommand(GameCommand::changeStationName, regs);
|
|
}
|
|
|
|
inline void do12(EntityId_t head, uint8_t bh)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.bh = bh;
|
|
regs.dx = head;
|
|
doCommand(GameCommand::vehicleLocalExpress, regs);
|
|
}
|
|
|
|
struct SignalPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createSignal;
|
|
|
|
SignalPlacementArgs() = default;
|
|
explicit SignalPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, trackId(regs.dl & 0x3F)
|
|
, index(regs.dh & 0x3)
|
|
, type((regs.edi >> 16) & 0xFF)
|
|
, trackObjType(regs.ebp & 0xFF)
|
|
, sides((regs.edi >> 16) & 0xC000)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t trackId;
|
|
uint8_t index;
|
|
uint8_t type;
|
|
uint8_t trackObjType;
|
|
uint16_t sides;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.bh = rotation;
|
|
regs.dl = trackId;
|
|
regs.dh = index;
|
|
regs.edi = pos.z | (type << 16) | ((sides & 0xC000) << 16);
|
|
regs.ebp = trackObjType;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct SignalRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeSignal;
|
|
|
|
SignalRemovalArgs() = default;
|
|
explicit SignalRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, trackId(regs.dl & 0x3F)
|
|
, index(regs.dh & 0xF)
|
|
, type(regs.bp & 0xF)
|
|
, flags(regs.edi >> 16)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t trackId;
|
|
uint8_t index;
|
|
uint8_t type;
|
|
uint16_t flags;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.edi = pos.z | (flags << 16);
|
|
regs.bh = rotation;
|
|
regs.dl = trackId;
|
|
regs.dh = index;
|
|
regs.bp = type;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct TrackStationPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createTrainStation;
|
|
|
|
TrackStationPlacementArgs() = default;
|
|
explicit TrackStationPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, trackId(regs.dl & 0xF)
|
|
, index(regs.dh & 0x3)
|
|
, trackObjectId(regs.bp)
|
|
, type(regs.edi >> 16)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t trackId;
|
|
uint8_t index;
|
|
uint8_t trackObjectId;
|
|
uint8_t type;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.edi = pos.z | (type << 16);
|
|
regs.bh = rotation;
|
|
regs.dl = trackId;
|
|
regs.dh = index;
|
|
regs.bp = trackObjectId;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct TrackStationRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeTrackStation;
|
|
|
|
TrackStationRemovalArgs() = default;
|
|
explicit TrackStationRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, trackId(regs.dl & 0x3F)
|
|
, index(regs.dh & 0xF)
|
|
, type(regs.bp & 0xF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t trackId;
|
|
uint8_t index;
|
|
uint8_t type;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
regs.bh = rotation;
|
|
regs.dl = trackId;
|
|
regs.dh = index;
|
|
regs.bp = type;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct TrackModsPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createTrackMod;
|
|
|
|
TrackModsPlacementArgs() = default;
|
|
explicit TrackModsPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, trackId(regs.dl & 0x3F)
|
|
, index(regs.dh & 0x3)
|
|
, type((regs.edi >> 16) & 0xF)
|
|
, trackObjType(regs.ebp & 0xFF)
|
|
, modSection((regs.ebp >> 16) & 0xFF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t trackId;
|
|
uint8_t index;
|
|
uint8_t type;
|
|
uint8_t trackObjType;
|
|
uint8_t modSection;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.bh = rotation;
|
|
regs.dl = trackId;
|
|
regs.dh = index;
|
|
regs.edi = pos.z | (type << 16);
|
|
regs.ebp = trackObjType | (modSection << 16);
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
// Change company colour scheme
|
|
inline void do_19(int8_t isPrimary, int8_t value, int8_t colourType, int8_t setColourMode, uint8_t companyId)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cl = colourType; // vehicle type or main
|
|
regs.dh = setColourMode; // [ 0, 1 ] -- 0 = set colour, 1 = toggle enabled/disabled;
|
|
regs.dl = companyId; // company id
|
|
|
|
if (setColourMode == 0)
|
|
{
|
|
// cl is divided by 2 when used
|
|
regs.ah = isPrimary; // [ 0, 1 ] -- primary or secondary palette
|
|
regs.al = value; // new colour
|
|
}
|
|
else if (setColourMode == 1)
|
|
{
|
|
regs.al = value; // [ 0, 1 ] -- off or on
|
|
}
|
|
|
|
doCommand(GameCommand::changeCompanyColourScheme, regs);
|
|
}
|
|
|
|
// Pause game
|
|
inline void do_20()
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
doCommand(GameCommand::pauseGame, regs);
|
|
}
|
|
|
|
// Load/save/quit game
|
|
inline void do_21(uint8_t dl, uint8_t di)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.dl = dl; // [ 0 = save, 1 = close save prompt, 2 = don't save ]
|
|
regs.di = di; // [ 0 = load game, 1 = return to title screen, 2 = quit to desktop ]
|
|
doCommand(GameCommand::loadSaveQuitGame, regs);
|
|
}
|
|
|
|
struct TreeRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeTree;
|
|
|
|
TreeRemovalArgs() = default;
|
|
explicit TreeRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.dl * 4)
|
|
, type(regs.dh)
|
|
, elementType(regs.bh)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t type;
|
|
uint8_t elementType;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.dl = pos.z / 4;
|
|
regs.dh = type;
|
|
regs.bh = elementType;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct TreePlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createTree;
|
|
|
|
TreePlacementArgs() = default;
|
|
explicit TreePlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx)
|
|
, rotation(regs.di & 0x3)
|
|
, type(regs.bh)
|
|
, quadrant(regs.dl)
|
|
, colour(regs.dh)
|
|
, buildImmediately(regs.di & 0x8000)
|
|
, requiresFullClearance(regs.di & 0x4000)
|
|
{
|
|
}
|
|
|
|
Map::Pos2 pos;
|
|
uint8_t rotation;
|
|
uint8_t type;
|
|
uint8_t quadrant;
|
|
Colour_t colour;
|
|
bool buildImmediately = false;
|
|
bool requiresFullClearance = false;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.dl = quadrant;
|
|
regs.dh = colour;
|
|
regs.di = rotation | (buildImmediately ? 0x8000 : 0) | (requiresFullClearance ? 0x4000 : 0);
|
|
regs.bh = type;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
// Change Land Material
|
|
inline void do_24(Map::Pos2 pointA, Map::Pos2 pointB, uint8_t landType, uint8_t flags)
|
|
{
|
|
registers regs;
|
|
regs.ax = pointA.x;
|
|
regs.cx = pointA.y;
|
|
regs.di = pointB.x;
|
|
regs.bp = pointB.y;
|
|
regs.dl = landType;
|
|
regs.bl = flags;
|
|
doCommand(GameCommand::changeLandMaterial, regs);
|
|
}
|
|
|
|
// Raise Land
|
|
inline uint32_t do_25(Map::Pos2 centre, Map::Pos2 pointA, Map::Pos2 pointB, uint16_t di, uint8_t flags)
|
|
{
|
|
registers regs;
|
|
regs.ax = centre.x;
|
|
regs.cx = centre.y;
|
|
regs.edx = pointB.x << 16 | pointA.x;
|
|
regs.ebp = pointB.y << 16 | pointA.y;
|
|
regs.bl = flags;
|
|
regs.di = di;
|
|
return doCommand(GameCommand::raiseLand, regs);
|
|
}
|
|
|
|
// Lower Land
|
|
inline uint32_t do_26(Map::Pos2 centre, Map::Pos2 pointA, Map::Pos2 pointB, uint16_t di, uint8_t flags)
|
|
{
|
|
registers regs;
|
|
regs.ax = centre.x;
|
|
regs.cx = centre.y;
|
|
regs.edx = pointB.x << 16 | pointA.x;
|
|
regs.ebp = pointB.y << 16 | pointA.y;
|
|
regs.bl = flags;
|
|
regs.di = di;
|
|
return doCommand(GameCommand::lowerLand, regs);
|
|
}
|
|
|
|
// Lower/Raise Land Mountain
|
|
inline uint32_t do_27(Map::Pos2 centre, Map::Pos2 pointA, Map::Pos2 pointB, uint16_t di, uint8_t flags)
|
|
{
|
|
registers regs;
|
|
regs.ax = centre.x;
|
|
regs.cx = centre.y;
|
|
regs.edx = pointB.x << 16 | pointA.x;
|
|
regs.ebp = pointB.y << 16 | pointA.y;
|
|
regs.bl = flags;
|
|
regs.di = di;
|
|
return doCommand(GameCommand::lowerRaiseLandMountain, regs);
|
|
}
|
|
|
|
// Raise Water
|
|
inline uint32_t do_28(Map::Pos2 pointA, Map::Pos2 pointB, uint8_t flags)
|
|
{
|
|
registers regs;
|
|
regs.ax = pointA.x;
|
|
regs.cx = pointA.y;
|
|
regs.di = pointB.x;
|
|
regs.bp = pointB.y;
|
|
regs.bl = flags;
|
|
return doCommand(GameCommand::raiseWater, regs);
|
|
}
|
|
|
|
// Lower Water
|
|
inline uint32_t do_29(Map::Pos2 pointA, Map::Pos2 pointB, uint8_t flags)
|
|
{
|
|
registers regs;
|
|
regs.ax = pointA.x;
|
|
regs.cx = pointA.y;
|
|
regs.di = pointB.x;
|
|
regs.bp = pointB.y;
|
|
regs.bl = flags;
|
|
return doCommand(GameCommand::lowerWater, regs);
|
|
}
|
|
|
|
// Change company name
|
|
inline bool do_30(uint16_t cx, uint16_t ax, uint32_t edx, uint32_t ebp, uint32_t edi)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = cx; // company id
|
|
regs.ax = ax; // [ 0, 1, 2]
|
|
regs.edx = edx; // part of name buffer
|
|
regs.ebp = ebp; // part of name buffer
|
|
regs.edi = edi; // part of name buffer
|
|
return doCommand(GameCommand::changeCompanyName, regs) != FAILURE;
|
|
}
|
|
|
|
// Change company owner name
|
|
inline bool do_31(uint16_t cx, uint16_t ax, uint32_t edx, uint32_t ebp, uint32_t edi)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = cx; // company id
|
|
regs.ax = ax; // [ 0, 1, 2]
|
|
regs.edx = edx; // part of name buffer
|
|
regs.ebp = ebp; // part of name buffer
|
|
regs.edi = edi; // part of name buffer
|
|
return doCommand(GameCommand::changeCompanyOwnerName, regs) != FAILURE;
|
|
}
|
|
|
|
struct WallPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createWall;
|
|
|
|
WallPlacementArgs() = default;
|
|
explicit WallPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.dl)
|
|
, type(regs.bh)
|
|
, unk(regs.dh)
|
|
, primaryColour(regs.bp & 0xFF)
|
|
, secondaryColour((regs.bp >> 8) & 0xFF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t type;
|
|
uint8_t unk;
|
|
Colour_t primaryColour;
|
|
Colour_t secondaryColour;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.dl = rotation;
|
|
regs.dh = unk;
|
|
regs.di = pos.z;
|
|
regs.bp = primaryColour | (secondaryColour << 8);
|
|
regs.bh = type;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct WallRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeWall;
|
|
|
|
WallRemovalArgs() = default;
|
|
explicit WallRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.dh * 4)
|
|
, rotation(regs.dl)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.dh = pos.z / 4;
|
|
regs.dl = rotation;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
inline bool do_35(EntityId_t head, uint64_t rawOrder, uint32_t orderOffset)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.eax = rawOrder & 0xFFFFFFFF;
|
|
regs.cx = rawOrder >> 32;
|
|
regs.di = head;
|
|
regs.edx = orderOffset;
|
|
return doCommand(GameCommand::vehicleOrderInsert, regs);
|
|
}
|
|
|
|
inline bool do_36(EntityId_t head, uint32_t orderOffset)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.di = head;
|
|
regs.edx = orderOffset;
|
|
return doCommand(GameCommand::vehicleOrderDelete, regs);
|
|
}
|
|
|
|
inline bool do_37(EntityId_t head)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.di = head;
|
|
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;
|
|
|
|
RoadRemovalArgs() = default;
|
|
explicit RoadRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, unkDirection(regs.bh & 0x3)
|
|
, roadId(regs.dl & 0xF)
|
|
, sequenceIndex(regs.dh & 0x3)
|
|
, objectId(regs.bp & 0xF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t unkDirection;
|
|
uint8_t roadId;
|
|
uint8_t sequenceIndex;
|
|
uint8_t objectId;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
regs.bh = unkDirection;
|
|
regs.dl = roadId;
|
|
regs.dh = sequenceIndex;
|
|
regs.bp = objectId;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct RoadModsPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createRoadMod;
|
|
|
|
RoadModsPlacementArgs() = default;
|
|
explicit RoadModsPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, roadId(regs.dl & 0xF)
|
|
, index(regs.dh & 0x3)
|
|
, type((regs.edi >> 16) & 0xF)
|
|
, roadObjType(regs.ebp & 0xFF)
|
|
, modSection((regs.ebp >> 16) & 0xFF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t roadId;
|
|
uint8_t index;
|
|
uint8_t type;
|
|
uint8_t roadObjType;
|
|
uint8_t modSection;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.bh = rotation;
|
|
regs.dl = roadId;
|
|
regs.dh = index;
|
|
regs.edi = pos.z | (type << 16);
|
|
regs.ebp = roadObjType | (modSection << 16);
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct RoadStationPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createRoadStation;
|
|
|
|
RoadStationPlacementArgs() = default;
|
|
explicit RoadStationPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, roadId(regs.dl & 0xF)
|
|
, index(regs.dh & 0x3)
|
|
, roadObjectId(regs.bp)
|
|
, type(regs.edi >> 16)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t roadId;
|
|
uint8_t index;
|
|
uint8_t roadObjectId;
|
|
uint8_t type;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.edi = pos.z | (type << 16);
|
|
regs.bh = rotation;
|
|
regs.dl = roadId;
|
|
regs.dh = index;
|
|
regs.bp = roadObjectId;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct RoadStationRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeRoadStation;
|
|
|
|
RoadStationRemovalArgs() = default;
|
|
explicit RoadStationRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, roadId(regs.dl & 0xF)
|
|
, index(regs.dh & 0x3)
|
|
, type(regs.bp & 0xF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t roadId;
|
|
uint8_t index;
|
|
uint8_t type;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
regs.bh = rotation;
|
|
regs.dl = roadId;
|
|
regs.dh = index;
|
|
regs.bp = type;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct BuildingPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createBuilding;
|
|
|
|
BuildingPlacementArgs() = default;
|
|
explicit BuildingPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, type(regs.dl)
|
|
, variation(regs.dh)
|
|
, colour(regs.edi >> 16)
|
|
, buildImmediately(regs.bh & 0x80)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t type;
|
|
uint8_t variation;
|
|
Colour_t colour;
|
|
bool buildImmediately = false; // No scaffolding required (editor mode)
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.edi = pos.z | (colour << 16);
|
|
regs.dl = type;
|
|
regs.dh = variation;
|
|
regs.bh = rotation | (buildImmediately ? 0x80 : 0);
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct BuildingRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeBuilding;
|
|
|
|
BuildingRemovalArgs() = default;
|
|
explicit BuildingRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
{
|
|
}
|
|
explicit BuildingRemovalArgs(const BuildingPlacementArgs& place)
|
|
: pos(place.pos)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
// Rename town
|
|
inline void do_46(uint16_t cx, uint16_t ax, uint32_t edx, uint32_t ebp, uint32_t edi)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = cx; // town number or 0
|
|
regs.ax = ax; // [ 0, 1, 2]
|
|
regs.edx = edx; // part of name buffer
|
|
regs.ebp = ebp; // part of name buffer
|
|
regs.edi = edi; // part of name buffer
|
|
doCommand(GameCommand::renameTown, regs);
|
|
}
|
|
|
|
struct IndustryPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createIndustry;
|
|
|
|
IndustryPlacementArgs() = default;
|
|
explicit IndustryPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx)
|
|
, type(regs.dl)
|
|
, buildImmediately(regs.bh & 0x80)
|
|
, srand0(regs.ebp)
|
|
, srand1(regs.edi)
|
|
{
|
|
}
|
|
|
|
Map::Pos2 pos;
|
|
uint8_t type;
|
|
bool buildImmediately = false; // No scaffolding required (editor mode)
|
|
uint32_t srand0;
|
|
uint32_t srand1;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.dl = type | (buildImmediately ? 0x80 : 0);
|
|
regs.ebp = srand0;
|
|
regs.edi = srand1;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
// Remove industry
|
|
inline bool do_48(uint8_t flags, uint8_t industryId)
|
|
{
|
|
registers regs;
|
|
regs.bl = flags;
|
|
regs.dx = industryId;
|
|
return doCommand(GameCommand::removeIndustry, regs) != FAILURE;
|
|
}
|
|
|
|
struct TownPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createTown;
|
|
|
|
TownPlacementArgs() = default;
|
|
explicit TownPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx)
|
|
, size(regs.dl)
|
|
{
|
|
}
|
|
|
|
Map::Pos2 pos;
|
|
uint8_t size;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.edx = size;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
// Remove town
|
|
inline bool do_50(uint8_t townId)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.edi = townId;
|
|
return doCommand(GameCommand::removeTown, regs) != FAILURE;
|
|
}
|
|
|
|
struct HeadquarterPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::buildCompanyHeadquarters;
|
|
|
|
HeadquarterPlacementArgs() = default;
|
|
explicit HeadquarterPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh & 0x3)
|
|
, type(regs.dl)
|
|
, buildImmediately(regs.bh & 0x80)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t type;
|
|
bool buildImmediately = false; // No scaffolding required (editor mode)
|
|
explicit operator registers() const
|
|
{
|
|
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
regs.dx = type;
|
|
regs.bh = rotation | (buildImmediately ? 0x80 : 0);
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct HeadquarterRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeCompanyHeadquarters;
|
|
|
|
HeadquarterRemovalArgs() = default;
|
|
explicit HeadquarterRemovalArgs(const HeadquarterPlacementArgs& place)
|
|
: pos(place.pos)
|
|
{
|
|
}
|
|
explicit HeadquarterRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct AirportPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createAirport;
|
|
|
|
AirportPlacementArgs() = default;
|
|
explicit AirportPlacementArgs(const registers regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh)
|
|
, type(regs.dl)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t type;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
regs.bh = rotation;
|
|
regs.dl = type;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct AirportRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removeAirport;
|
|
|
|
AirportRemovalArgs() = default;
|
|
explicit AirportRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct VehicleAirPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::vehiclePlaceAir;
|
|
|
|
VehicleAirPlacementArgs() = default;
|
|
explicit VehicleAirPlacementArgs(const registers& regs)
|
|
: stationId(regs.bp)
|
|
, airportNode(regs.dl)
|
|
, head(regs.di)
|
|
, convertGhost((regs.ebx >> 16) == 0xFFFF)
|
|
{
|
|
}
|
|
|
|
StationId_t stationId;
|
|
uint8_t airportNode;
|
|
EntityId_t head;
|
|
bool convertGhost = false;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.bp = stationId;
|
|
regs.di = head;
|
|
regs.dl = airportNode;
|
|
regs.ebx = convertGhost ? 0xFFFF0000 : 0;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
inline bool do_59(EntityId_t head)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply | Flags::flag_3 | Flags::flag_6;
|
|
regs.di = head;
|
|
return doCommand(GameCommand::vehiclePickupAir, regs) != FAILURE;
|
|
}
|
|
|
|
struct PortPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::createPort;
|
|
|
|
PortPlacementArgs() = default;
|
|
explicit PortPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
, rotation(regs.bh)
|
|
, type(regs.dl)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
uint8_t rotation;
|
|
uint8_t type;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
regs.bh = rotation;
|
|
regs.dl = type;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct PortRemovalArgs
|
|
{
|
|
static constexpr auto command = GameCommand::removePort;
|
|
|
|
PortRemovalArgs() = default;
|
|
explicit PortRemovalArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.di)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.di = pos.z;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
struct VehicleWaterPlacementArgs
|
|
{
|
|
static constexpr auto command = GameCommand::vehiclePlaceWater;
|
|
|
|
VehicleWaterPlacementArgs() = default;
|
|
explicit VehicleWaterPlacementArgs(const registers& regs)
|
|
: pos(regs.ax, regs.cx, regs.dx)
|
|
, head(regs.di)
|
|
, convertGhost((regs.ebx >> 16) == 0xFFFF)
|
|
{
|
|
}
|
|
|
|
Map::Pos3 pos;
|
|
EntityId_t head;
|
|
bool convertGhost = false;
|
|
|
|
explicit operator registers() const
|
|
{
|
|
registers regs;
|
|
regs.ax = pos.x;
|
|
regs.cx = pos.y;
|
|
regs.dx = pos.z;
|
|
regs.di = head;
|
|
regs.ebx = convertGhost ? 0xFFFF0000 : 0;
|
|
return regs;
|
|
}
|
|
};
|
|
|
|
inline bool do_63(EntityId_t head)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply | Flags::flag_3 | Flags::flag_6;
|
|
regs.di = head;
|
|
return doCommand(GameCommand::vehiclePickupWater, regs) != FAILURE;
|
|
}
|
|
|
|
// Refit vehicle
|
|
inline void do_64(EntityId_t vehicleHead, uint16_t option)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.di = vehicleHead;
|
|
regs.dx = option;
|
|
doCommand(GameCommand::vehicleRefit, regs);
|
|
}
|
|
|
|
// Change company face
|
|
inline bool do_65(const ObjectHeader& object, uint8_t company)
|
|
{
|
|
auto objPtr = reinterpret_cast<const int32_t*>(&object);
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.eax = *objPtr++;
|
|
regs.ecx = *objPtr++;
|
|
regs.edx = *objPtr++;
|
|
regs.edi = *objPtr;
|
|
regs.bh = company;
|
|
return doCommand(GameCommand::changeCompanyFace, regs) != FAILURE;
|
|
}
|
|
|
|
// Clear Land
|
|
inline uint32_t do_66(Map::Pos2 centre, Map::Pos2 pointA, Map::Pos2 pointB, uint8_t flags)
|
|
{
|
|
registers regs;
|
|
regs.ax = centre.x;
|
|
regs.cx = centre.y;
|
|
regs.edx = pointB.x << 16 | pointA.x;
|
|
regs.ebp = pointB.y << 16 | pointA.y;
|
|
regs.bl = flags;
|
|
return doCommand(GameCommand::clearLand, regs);
|
|
}
|
|
|
|
// Load multiplayer map
|
|
inline void do_67(const char* filename)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.ebp = X86Pointer(filename);
|
|
doCommand(GameCommand::loadMultiplayerMap, regs);
|
|
}
|
|
|
|
// Multiplayer-related
|
|
inline void do_69()
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
doCommand(GameCommand::gc_unk_69, regs);
|
|
}
|
|
|
|
// Multiplayer-related
|
|
inline void do_70()
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
doCommand(GameCommand::gc_unk_70, regs);
|
|
}
|
|
|
|
// Send chat message
|
|
inline void do_71(int32_t ax, const char* string)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.ax = ax;
|
|
memcpy(®s.ecx, &string[0], 4);
|
|
memcpy(®s.edx, &string[4], 4);
|
|
memcpy(®s.ebp, &string[8], 4);
|
|
memcpy(®s.edi, &string[12], 4);
|
|
doCommand(GameCommand::sendChatMessage, regs);
|
|
}
|
|
|
|
// Multiplayer save
|
|
inline void do_72()
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
doCommand(GameCommand::multiplayerSave, regs);
|
|
}
|
|
|
|
// Update owner status
|
|
inline void do_73(EntityId_t id)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.ax = -2;
|
|
regs.cx = id;
|
|
doCommand(GameCommand::updateOwnerStatus, regs);
|
|
}
|
|
|
|
// Update owner status
|
|
inline void do_73(Map::Pos2 position)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.ax = position.x;
|
|
regs.cx = position.y;
|
|
doCommand(GameCommand::updateOwnerStatus, regs);
|
|
}
|
|
|
|
inline uint32_t do_74(EntityId_t head, int16_t speed)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = head;
|
|
regs.dx = speed;
|
|
return doCommand(GameCommand::vehicleSpeedControl, regs);
|
|
}
|
|
|
|
inline uint32_t do_75(EntityId_t head, uint32_t orderOffset)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.di = head;
|
|
regs.edx = orderOffset;
|
|
return doCommand(GameCommand::vehicleOrderUp, regs);
|
|
}
|
|
|
|
inline uint32_t do_76(EntityId_t head, uint32_t orderOffset)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.di = head;
|
|
regs.edx = orderOffset;
|
|
return doCommand(GameCommand::vehicleOrderDown, regs);
|
|
}
|
|
|
|
inline void do_77(EntityId_t head)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = head;
|
|
doCommand(GameCommand::vehicleApplyShuntCheat, regs);
|
|
}
|
|
|
|
inline void do_78()
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
GameCommands::doCommand(GameCommand::applyFreeCashCheat, regs);
|
|
}
|
|
|
|
// Rename industry
|
|
inline void do_79(uint16_t cx, uint16_t ax, uint32_t edx, uint32_t ebp, uint32_t edi)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.cx = cx; // industry number or 0
|
|
regs.ax = ax; // [ 0, 1, 2]
|
|
regs.edx = edx; // part of name buffer
|
|
regs.ebp = ebp; // part of name buffer
|
|
regs.edi = edi; // part of name buffer
|
|
doCommand(GameCommand::renameIndustry, regs);
|
|
}
|
|
|
|
inline bool do_80(uint16_t head)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.ax = head;
|
|
return GameCommands::doCommand(GameCommand::vehicleClone, regs) != FAILURE;
|
|
}
|
|
|
|
enum class CheatCommand : uint8_t;
|
|
|
|
inline bool do_81(CheatCommand command, int32_t param1 = 0, int32_t param2 = 0, int32_t param3 = 0)
|
|
{
|
|
registers regs;
|
|
regs.bl = Flags::apply;
|
|
regs.eax = static_cast<int32_t>(command);
|
|
regs.ebx = param1;
|
|
regs.ecx = param2;
|
|
regs.edx = param3;
|
|
return GameCommands::doCommand(GameCommand::cheat, regs) != FAILURE;
|
|
}
|
|
|
|
// Defined in GameCommands/ChangeCompanyColour.cpp
|
|
void changeCompanyColour(registers& regs);
|
|
|
|
// Defined in GameCommands/Cheat.cpp
|
|
void cheat(registers& regs);
|
|
|
|
// Defined in GameCommands/LoadSaveQuit.cpp
|
|
void loadSaveQuit(registers& regs);
|
|
|
|
// Defined in GameCommands/RemoveTree.cpp
|
|
void removeTree(registers& regs);
|
|
|
|
// 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);
|
|
|
|
// Defined in GameCommands/TogglePause.cpp
|
|
uint32_t togglePause(uint8_t flags);
|
|
void togglePause(registers& regs);
|
|
|
|
// Defined in GameCommands/VehiclePickup.cpp
|
|
void vehiclePickup(registers& regs);
|
|
|
|
const Map::Pos3& getPosition();
|
|
void setPosition(const Map::Pos3& pos);
|
|
void setErrorText(const string_id message);
|
|
string_id getErrorText();
|
|
void setErrorTitle(const string_id title);
|
|
ExpenditureType getExpenditureType();
|
|
void setExpenditureType(const ExpenditureType type);
|
|
}
|