Implement RoadElement::update (#1106)

This commit is contained in:
Aaron van Geffen 2021-08-16 15:19:02 +02:00 committed by GitHub
parent 14edc842b6
commit 51789bd329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 128 additions and 3 deletions

View File

@ -85,7 +85,7 @@ namespace OpenLoco::GameCommands
{ GameCommand::vehicleOrderDelete, nullptr, 0x0047057A, false },
{ GameCommand::vehicleOrderSkip, Vehicles::orderSkip, 0x0047071A, false },
{ GameCommand::gc_unk_38, nullptr, 0x00475FBC, true },
{ GameCommand::gc_unk_39, nullptr, 0x004775A5, true },
{ GameCommand::removeRoad, nullptr, 0x004775A5, true },
{ GameCommand::createRoadMod, nullptr, 0x0047A21E, true },
{ GameCommand::removeRoadMod, nullptr, 0x0047A42F, true },
{ GameCommand::gc_unk_42, nullptr, 0x0048C708, true },

View File

@ -72,7 +72,7 @@ namespace OpenLoco::GameCommands
vehicleOrderDelete = 36,
vehicleOrderSkip = 37,
gc_unk_38 = 38,
gc_unk_39 = 39,
removeRoad = 39,
createRoadMod = 40,
removeRoadMod = 41,
gc_unk_42 = 42,
@ -727,6 +727,40 @@ namespace OpenLoco::GameCommands
return doCommand(GameCommand::vehicleOrderSkip, 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;

View File

@ -0,0 +1,81 @@
#include "../CompanyManager.h"
#include "../GameCommands/GameCommands.h"
#include "../Interop/Interop.hpp"
#include "../Objects/RoadObject.h"
#include "Tile.h"
#include "TileManager.h"
using namespace OpenLoco::Interop;
namespace OpenLoco::Map
{
static loco_global<uint32_t, 0x00525FBC> _525FBC;
// 0x00477FC2
bool RoadElement::update(const Map::Pos2& loc)
{
if (owner() == CompanyId::neutral || isPlayerCompany(owner()))
return true;
if (!(_525FBC & (1 << roadObjectId())))
return true;
if (sequenceIndex())
return true;
if (hasUnkBit4() || hasLevelCrossing() || mods())
return true;
if (isGhost() || isFlag5())
return true;
if (hasStationElement())
return true;
// Verify there are no other conflicting tile elements on the current tile either.
// This probably duplicates the above series of checks as well?
auto tile = TileManager::get(loc);
for (auto& el : tile)
{
auto* roadEl = el.asRoad();
if (roadEl == nullptr)
continue;
if (roadEl->baseZ() != baseZ())
continue;
if (roadEl->owner() == CompanyId::neutral || isPlayerCompany(roadEl->owner()))
continue;
if (!(_525FBC & (1 << roadEl->roadObjectId())))
continue;
if (roadEl->sequenceIndex())
return true;
if (hasUnkBit4() || hasLevelCrossing() || mods())
return true;
if (roadEl->isGhost() || roadEl->isFlag5())
return true;
if (roadEl->hasStationElement())
return true;
}
CompanyId_t backup = CompanyManager::updatingCompanyId();
CompanyManager::updatingCompanyId(owner());
GameCommands::RoadRemovalArgs args;
args.pos = Map::Pos3(loc.x, loc.y, baseZ() * 4);
args.unkDirection = unkDirection();
args.roadId = roadId();
args.sequenceIndex = sequenceIndex();
args.objectId = roadObjectId();
GameCommands::doCommand(args, GameCommands::Flags::apply);
CompanyManager::updatingCompanyId(backup);
return false;
}
}

View File

@ -314,10 +314,13 @@ namespace OpenLoco::Map
uint8_t sequenceIndex() const { return _5 & 0x3; } // _5l
uint8_t bridge() const { return _6 >> 5; } // _6u
bool hasStationElement() const { return (_type & 0x80) != 0; }
bool hasUnkBit4() const { return _7 & (1 << 4); }
bool hasLevelCrossing() const { return _7 & (1 << 5); }
bool hasMod(uint8_t mod) const { return _7 & (1 << (mod + 6)); } // _7u (bits 6 and 7)
uint8_t mods() const { return _7 >> 6; } // _7u
uint8_t owner() const { return _7 & 0xF; } // _7l
void setOwner(uint8_t newOwner) { _7 = (_7 & 0xF0) | (newOwner & 0xF); }
bool update(const Map::Pos2& loc);
};
struct IndustryElement : public TileElementBase

View File

@ -598,8 +598,14 @@ namespace OpenLoco::Map::TileManager
call(0x004BD52B, regs);
break;
case ElementType::road:
call(0x00477FC2, regs);
{
auto* elRoad = el.asRoad();
if (elRoad != nullptr)
return elRoad->update(loc);
else
return false;
break;
}
case ElementType::industry:
call(0x00456FF7, regs);
break;

View File

@ -65,6 +65,7 @@
<ClCompile Include="Map\BuildingTile.cpp" />
<ClCompile Include="Map\AnimationManager.cpp" />
<ClCompile Include="Map\MapGenerator.cpp" />
<ClCompile Include="Map\RoadTile.cpp" />
<ClCompile Include="Map\SurfaceTile.cpp" />
<ClCompile Include="Map\Tile.cpp" />
<ClCompile Include="Map\TileManager.cpp" />