Initial version of blueprints (copy/paste)
This commit is contained in:
@@ -1228,6 +1228,8 @@ citymania/extensions/cmext_company.hpp
|
|||||||
# CityMania client
|
# CityMania client
|
||||||
citymania/cm_base64.hpp
|
citymania/cm_base64.hpp
|
||||||
citymania/cm_base64.cpp
|
citymania/cm_base64.cpp
|
||||||
|
citymania/cm_blueprint.hpp
|
||||||
|
citymania/cm_blueprint.cpp
|
||||||
citymania/cm_highlight.hpp
|
citymania/cm_highlight.hpp
|
||||||
citymania/cm_highlight.cpp
|
citymania/cm_highlight.cpp
|
||||||
citymania/cm_highlight_type.hpp
|
citymania/cm_highlight_type.hpp
|
||||||
|
|||||||
563
src/citymania/cm_blueprint.cpp
Normal file
563
src/citymania/cm_blueprint.cpp
Normal file
@@ -0,0 +1,563 @@
|
|||||||
|
#include "../stdafx.h"
|
||||||
|
|
||||||
|
#include "cm_blueprint.hpp"
|
||||||
|
|
||||||
|
#include "cm_highlight.hpp"
|
||||||
|
|
||||||
|
#include "../command_func.h"
|
||||||
|
#include "../direction_type.h"
|
||||||
|
#include "../rail_map.h"
|
||||||
|
#include "../station_map.h"
|
||||||
|
#include "../station_base.h"
|
||||||
|
#include "../tilearea_type.h"
|
||||||
|
#include "../tunnelbridge_map.h"
|
||||||
|
#include "../network/network.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
extern TileHighlightData _thd;
|
||||||
|
extern RailType _cur_railtype;
|
||||||
|
|
||||||
|
namespace citymania {
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<TileIndex, sp<Blueprint>> _active_blueprint = std::make_pair(INVALID_TILE, nullptr);
|
||||||
|
|
||||||
|
TileIndexDiffC operator+(const TileIndexDiffC &a, const TileIndexDiffC &b) {
|
||||||
|
return TileIndexDiffC{(int16)(a.x + b.x), (int16)(a.y + b.y)};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const TileIndexDiffC &a, const TileIndexDiffC &b) {
|
||||||
|
return a.x == b.x && a.y == b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const TileIndexDiffC &a, const TileIndexDiffC &b) {
|
||||||
|
return a.x != b.x || a.y != b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::tuple<TileIndex, uint32, uint32, uint32> CommandTuple;
|
||||||
|
typedef std::function<void(bool)> CommandCallback;
|
||||||
|
std::map<CommandTuple, std::vector<CommandCallback>> _command_callbacks;
|
||||||
|
|
||||||
|
void AddCommandCallback(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback callback) {
|
||||||
|
_command_callbacks[std::make_tuple(tile, p1, p2, cmd)].push_back(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoCommandWithCallback(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback callback) {
|
||||||
|
AddCommandCallback(tile, p1, p2, cmd, callback);
|
||||||
|
DoCommandP(tile, p1, p2, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandExecuted(bool res, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) {
|
||||||
|
CommandTuple ct {tile, p1, p2, cmd};
|
||||||
|
auto p = _command_callbacks.find(ct);
|
||||||
|
if (p == _command_callbacks.end()) return;
|
||||||
|
for (auto &cb : p->second)
|
||||||
|
cb(res);
|
||||||
|
_command_callbacks.erase(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blueprint::Add(Blueprint::Item item) {
|
||||||
|
this->items.push_back(item);
|
||||||
|
switch (item.type) {
|
||||||
|
case Item::Type::RAIL_TRACK: {
|
||||||
|
auto tdir = item.u.rail.track.start_dir;
|
||||||
|
auto tdiff = item.tdiff;
|
||||||
|
// fprintf(stderr, "TRACK %u %u\n", (uint)tdiff, (uint)item.u.rail.track.end_diff);
|
||||||
|
for (auto i = 0; i < item.u.rail.track.length; i++) {
|
||||||
|
this->tiles.insert(tdiff);
|
||||||
|
tdiff = tdiff + TileIndexDiffCByDiagDir(TrackdirToExitdir(tdir));
|
||||||
|
tdir = NextTrackdir(tdir);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Item::Type::RAIL_BRIDGE:
|
||||||
|
case Item::Type::RAIL_TUNNEL:
|
||||||
|
this->tiles.insert(item.u.rail.tunnel.other_end);
|
||||||
|
FALLTHROUGH;
|
||||||
|
case Item::Type::RAIL_DEPOT:
|
||||||
|
case Item::Type::RAIL_STATION:
|
||||||
|
case Item::Type::RAIL_STATION_PART:
|
||||||
|
this->tiles.insert(item.tdiff);
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_SIGNAL: // tile is added for track anyway
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::multimap<TileIndex, ObjectTileHighlight> Blueprint::GetTiles(TileIndex tile) {
|
||||||
|
std::multimap<TileIndex, ObjectTileHighlight> res;
|
||||||
|
if (tile == INVALID_TILE) return res;
|
||||||
|
auto add_tile = [&res](TileIndex tile, const ObjectTileHighlight &ohl) {
|
||||||
|
if (tile == INVALID_TILE) return;
|
||||||
|
res.emplace(tile, ohl);
|
||||||
|
};
|
||||||
|
for (auto &o: this->items) {
|
||||||
|
auto otile = AddTileIndexDiffCWrap(tile, o.tdiff);
|
||||||
|
switch(o.type) {
|
||||||
|
case Item::Type::RAIL_TRACK: {
|
||||||
|
auto end_tile = otile;
|
||||||
|
auto tdir = o.u.rail.track.start_dir;
|
||||||
|
for (auto i = 0; i < o.u.rail.track.length; i++) {
|
||||||
|
add_tile(end_tile, ObjectTileHighlight::make_rail_track(TrackdirToTrack(tdir)));
|
||||||
|
end_tile = TileAddByDiagDir(end_tile, TrackdirToExitdir(tdir));
|
||||||
|
tdir = NextTrackdir(tdir);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Item::Type::RAIL_BRIDGE:
|
||||||
|
add_tile(otile, ObjectTileHighlight::make_rail_bridge_head(o.u.rail.bridge.ddir, o.u.rail.bridge.type));
|
||||||
|
add_tile(AddTileIndexDiffCWrap(tile, o.u.rail.bridge.other_end), ObjectTileHighlight::make_rail_bridge_head(ReverseDiagDir(o.u.rail.bridge.ddir), o.u.rail.bridge.type));
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_TUNNEL:
|
||||||
|
add_tile(otile, ObjectTileHighlight::make_rail_tunnel_head(o.u.rail.tunnel.ddir));
|
||||||
|
add_tile(AddTileIndexDiffCWrap(tile, o.u.rail.tunnel.other_end), ObjectTileHighlight::make_rail_tunnel_head(ReverseDiagDir(o.u.rail.tunnel.ddir)));
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_DEPOT:
|
||||||
|
add_tile(otile, ObjectTileHighlight::make_rail_depot(o.u.rail.depot.ddir));
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_STATION_PART:
|
||||||
|
add_tile(otile, ObjectTileHighlight::make_rail_station(o.u.rail.station_part.axis));
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_SIGNAL:
|
||||||
|
add_tile(otile, ObjectTileHighlight::make_rail_signal(o.u.rail.signal.pos, o.u.rail.signal.type, o.u.rail.signal.variant));
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_STATION:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<Blueprint> Blueprint::Rotate() {
|
||||||
|
static const Trackdir ROTATE_TRACKDIR[] = {
|
||||||
|
TRACKDIR_Y_SE, TRACKDIR_X_SW,
|
||||||
|
TRACKDIR_RIGHT_S, TRACKDIR_LEFT_S,
|
||||||
|
TRACKDIR_UPPER_W, TRACKDIR_LOWER_W,
|
||||||
|
TRACKDIR_RVREV_SE, TRACKDIR_RVREV_SW,
|
||||||
|
TRACKDIR_Y_NW, TRACKDIR_X_NE,
|
||||||
|
TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N,
|
||||||
|
TRACKDIR_UPPER_E, TRACKDIR_LOWER_E,
|
||||||
|
TRACKDIR_RVREV_NW, TRACKDIR_RVREV_NE
|
||||||
|
};
|
||||||
|
static const uint ROTATE_SIGNAL_POS[] = {
|
||||||
|
// 5, 4, 7, 6,
|
||||||
|
// 2, 3, 0, 1,
|
||||||
|
// 11, 10, 8, 9
|
||||||
|
5, 4, 7, 6,
|
||||||
|
2, 3, 0, 1,
|
||||||
|
10, 11, 9, 8
|
||||||
|
};
|
||||||
|
auto res = std::make_shared<Blueprint>();
|
||||||
|
|
||||||
|
auto rotate = [](TileIndexDiffC td) -> TileIndexDiffC {
|
||||||
|
return TileIndexDiffC {td.y, -td.x};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto rotate_dir = [](DiagDirection ddir) -> DiagDirection {
|
||||||
|
return ChangeDiagDir(ddir, DIAGDIRDIFF_90RIGHT);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &o: this->items) {
|
||||||
|
auto odiff = rotate(o.tdiff);
|
||||||
|
Blueprint::Item bi(o.type, odiff);
|
||||||
|
switch(o.type) {
|
||||||
|
case Item::Type::RAIL_TRACK:
|
||||||
|
bi.u.rail.track.length = o.u.rail.track.length;
|
||||||
|
bi.u.rail.track.start_dir = ROTATE_TRACKDIR[o.u.rail.track.start_dir];
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_BRIDGE:
|
||||||
|
bi.u.rail.bridge.type = o.u.rail.bridge.type;
|
||||||
|
bi.u.rail.bridge.ddir = rotate_dir(o.u.rail.bridge.ddir);
|
||||||
|
bi.u.rail.bridge.other_end = rotate(o.u.rail.bridge.other_end);
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_TUNNEL:
|
||||||
|
bi.u.rail.tunnel.ddir = rotate_dir(o.u.rail.tunnel.ddir);
|
||||||
|
bi.u.rail.tunnel.other_end = rotate(o.u.rail.tunnel.other_end);
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_DEPOT:
|
||||||
|
bi.u.rail.depot.ddir = rotate_dir(o.u.rail.depot.ddir);
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_STATION:
|
||||||
|
bi.u.rail.station.id = o.u.rail.station.id;
|
||||||
|
bi.u.rail.station.has_part = o.u.rail.station.has_part;
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_STATION_PART:
|
||||||
|
bi.u.rail.station_part.id = o.u.rail.station_part.id;
|
||||||
|
bi.u.rail.station_part.axis = OtherAxis(o.u.rail.station_part.axis);
|
||||||
|
break;
|
||||||
|
case Item::Type::RAIL_SIGNAL:
|
||||||
|
bi.u.rail.signal.pos = ROTATE_SIGNAL_POS[o.u.rail.signal.pos]; // TODO rotate
|
||||||
|
bi.u.rail.signal.type = o.u.rail.signal.type;
|
||||||
|
bi.u.rail.signal.variant = o.u.rail.signal.variant;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
res->Add(bi);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void BlueprintAddSignals(sp<Blueprint> &blueprint, TileIndex tile, TileIndexDiffC tdiff) {
|
||||||
|
// reference: DrawSignals @ rail_cmd.cpp
|
||||||
|
|
||||||
|
auto add = [&](Track track, uint x, uint pos) {
|
||||||
|
if (!IsSignalPresent(tile, x)) return;
|
||||||
|
Blueprint::Item bi(Blueprint::Item::Type::RAIL_SIGNAL, tdiff);
|
||||||
|
bi.u.rail.signal.pos = pos;
|
||||||
|
bi.u.rail.signal.type = GetSignalType(tile, track);
|
||||||
|
bi.u.rail.signal.variant = GetSignalVariant(tile, track);
|
||||||
|
blueprint->Add(bi);
|
||||||
|
};
|
||||||
|
auto rails = GetTrackBits(tile);
|
||||||
|
if (!(rails & TRACK_BIT_Y)) {
|
||||||
|
if (!(rails & TRACK_BIT_X)) {
|
||||||
|
if (rails & TRACK_BIT_LEFT) {
|
||||||
|
add(TRACK_LEFT, 2, 0);
|
||||||
|
add(TRACK_LEFT, 3, 1);
|
||||||
|
}
|
||||||
|
if (rails & TRACK_BIT_RIGHT) {
|
||||||
|
add(TRACK_RIGHT, 0, 2);
|
||||||
|
add(TRACK_RIGHT, 1, 3);
|
||||||
|
}
|
||||||
|
if (rails & TRACK_BIT_UPPER) {
|
||||||
|
add(TRACK_UPPER, 3, 4);
|
||||||
|
add(TRACK_UPPER, 2, 5);
|
||||||
|
}
|
||||||
|
if (rails & TRACK_BIT_LOWER) {
|
||||||
|
add(TRACK_LOWER, 1, 6);
|
||||||
|
add(TRACK_LOWER, 0, 7);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add(TRACK_X, 3, 8);
|
||||||
|
add(TRACK_X, 2, 9);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add(TRACK_Y, 3, 10);
|
||||||
|
add(TRACK_Y, 2, 11);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// void BlueprintCopyArea(TileIndex start, TileIndex end) {
|
||||||
|
// TileArea ta{start, end};
|
||||||
|
|
||||||
|
// auto blueprint = std::make_shared<Blueprint>();
|
||||||
|
// _active_blueprint = std::make_pair(start, blueprint);
|
||||||
|
|
||||||
|
// TILE_AREA_LOOP(tile, ta) {
|
||||||
|
// TileIndexDiff td = tile - start;
|
||||||
|
// switch (GetTileType(tile)) {
|
||||||
|
// case MP_STATION:
|
||||||
|
// if (IsRailStation(tile))
|
||||||
|
// blueprint->Add(td, ObjectTileHighlight::make_rail_station(GetRailStationAxis(tile)));
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case MP_RAILWAY:
|
||||||
|
// switch (GetRailTileType(tile)) {
|
||||||
|
// case RAIL_TILE_DEPOT:
|
||||||
|
// blueprint->Add(td, ObjectTileHighlight::make_rail_depot(GetRailDepotDirection(tile)));
|
||||||
|
// break;
|
||||||
|
// case RAIL_TILE_SIGNALS:
|
||||||
|
// BlueprintAddSignals(blueprint, tile, td);
|
||||||
|
// FALLTHROUGH;
|
||||||
|
// case RAIL_TILE_NORMAL: {
|
||||||
|
// auto tb = GetTrackBits(tile);
|
||||||
|
// for (Track track = TRACK_BEGIN; track < TRACK_END; track++) {
|
||||||
|
// if (!HasBit(tb, track)) continue;
|
||||||
|
// blueprint->Add(td, ObjectTileHighlight::make_rail_track(track));
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// default:
|
||||||
|
// NOT_REACHED();
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case MP_TUNNELBRIDGE: {
|
||||||
|
// if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) break;
|
||||||
|
// if (IsTunnel(tile)) break;
|
||||||
|
// auto ddir = GetTunnelBridgeDirection(tile);
|
||||||
|
// auto delta = TileOffsByDiagDir(ddir);
|
||||||
|
// auto other = GetOtherTunnelBridgeEnd(tile);
|
||||||
|
// auto axis = DiagDirToAxis(ddir);
|
||||||
|
// auto type = GetBridgeType(tile);
|
||||||
|
// blueprint->Add(td, ObjectTileHighlight::make_rail_bridge_head(ddir, other, type));
|
||||||
|
// for (auto t = tile + delta; t != other; t += delta) {
|
||||||
|
// // blueprint->Add(t - start, ObjectTileHighlight::make_rail_tunnelbridge(axis));
|
||||||
|
// }
|
||||||
|
// blueprint->Add(other - start, ObjectTileHighlight::make_rail_bridge_head(ReverseDiagDir(ddir), INVALID_TILE, type));
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
static void BlueprintAddTracks(sp<Blueprint> &blueprint, TileIndex tile, TileIndexDiffC tdiff, TileArea &area,
|
||||||
|
std::map<TileIndex, Track> &track_tiles) {
|
||||||
|
// tilearea is iterated by x and y so chose direction to go in uniterated area
|
||||||
|
static const Trackdir _track_iterate_dir[TRACK_END] = { TRACKDIR_X_SW, TRACKDIR_Y_SE, TRACKDIR_UPPER_E, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S, TRACKDIR_RIGHT_S};
|
||||||
|
|
||||||
|
for (Track track = TRACK_BEGIN; track < TRACK_END; track++) {
|
||||||
|
TileIndex c_tile = tile;
|
||||||
|
TileIndex end_tile = INVALID_TILE;
|
||||||
|
uint16 length = 0;
|
||||||
|
Track c_track = track;
|
||||||
|
Trackdir c_tdir = _track_iterate_dir[track];
|
||||||
|
// fprintf(stderr, "TTTTTT %u %u %u\n", c_tile, c_track, GetTrackBits(c_tile));
|
||||||
|
while (IsPlainRailTile(c_tile) && HasBit(GetTrackBits(c_tile), c_track)) {
|
||||||
|
if (HasBit(track_tiles[c_tile], c_track)) break;
|
||||||
|
length++;
|
||||||
|
SetBit(track_tiles[c_tile], c_track);
|
||||||
|
end_tile = c_tile;
|
||||||
|
c_tile = TileAddByDiagDir(c_tile, TrackdirToExitdir(c_tdir));
|
||||||
|
if (!area.Contains(c_tile)) break;
|
||||||
|
c_tdir = NextTrackdir(c_tdir);
|
||||||
|
c_track = TrackdirToTrack(c_tdir);
|
||||||
|
// fprintf(stderr, "TTTTTTI %u %u %u\n", c_tile, c_track, GetTrackBits(c_tile));
|
||||||
|
}
|
||||||
|
if (end_tile == INVALID_TILE) continue;
|
||||||
|
Blueprint::Item bi(Blueprint::Item::Type::RAIL_TRACK, tdiff);
|
||||||
|
bi.u.rail.track.length = length;
|
||||||
|
bi.u.rail.track.start_dir = _track_iterate_dir[track];
|
||||||
|
// fprintf(stderr, "TTTTTTEE %u %u %u\n", tdiff, bi.u.rail.track.end_diff, bi.u.rail.track.start_dir);
|
||||||
|
blueprint->Add(bi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlueprintCopyArea(TileIndex start, TileIndex end) {
|
||||||
|
// if (start > end) Swap(start, end);
|
||||||
|
TileArea ta{start, end};
|
||||||
|
start = ta.tile;
|
||||||
|
|
||||||
|
auto blueprint = std::make_shared<Blueprint>();
|
||||||
|
_active_blueprint = std::make_pair(start, blueprint);
|
||||||
|
|
||||||
|
std::map<TileIndex, Track> track_tiles;
|
||||||
|
std::multimap<StationID, TileIndex> station_tiles;
|
||||||
|
std::set<StationID> stations;
|
||||||
|
|
||||||
|
TILE_AREA_LOOP(tile, ta) {
|
||||||
|
TileIndexDiffC td = TileIndexToTileIndexDiffC(tile, start);
|
||||||
|
switch (GetTileType(tile)) {
|
||||||
|
case MP_STATION:
|
||||||
|
if (IsRailStation(tile)) stations.insert(GetStationIndex(tile));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MP_RAILWAY:
|
||||||
|
switch (GetRailTileType(tile)) {
|
||||||
|
case RAIL_TILE_DEPOT: {
|
||||||
|
Blueprint::Item bi(Blueprint::Item::Type::RAIL_DEPOT, td);
|
||||||
|
bi.u.rail.depot.ddir = GetRailDepotDirection(tile);
|
||||||
|
blueprint->Add(bi);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAIL_TILE_SIGNALS:
|
||||||
|
BlueprintAddSignals(blueprint, tile, td);
|
||||||
|
FALLTHROUGH;
|
||||||
|
case RAIL_TILE_NORMAL:
|
||||||
|
BlueprintAddTracks(blueprint, tile, td, ta, track_tiles);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOT_REACHED();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MP_TUNNELBRIDGE: {
|
||||||
|
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) break;
|
||||||
|
auto other = GetOtherTunnelBridgeEnd(tile);
|
||||||
|
if (!ta.Contains(other)) break;
|
||||||
|
if (other < tile) break;
|
||||||
|
Blueprint::Item bi(Blueprint::Item::Type::RAIL_TUNNEL, td);
|
||||||
|
if (!IsTunnel(tile)) {
|
||||||
|
bi.type = Blueprint::Item::Type::RAIL_BRIDGE;
|
||||||
|
bi.u.rail.bridge.type = GetBridgeType(tile);
|
||||||
|
bi.u.rail.bridge.ddir = GetTunnelBridgeDirection(tile);
|
||||||
|
bi.u.rail.bridge.other_end = TileIndexToTileIndexDiffC(other, start);
|
||||||
|
} else {
|
||||||
|
bi.u.rail.tunnel.ddir = GetTunnelBridgeDirection(tile);
|
||||||
|
bi.u.rail.tunnel.other_end = TileIndexToTileIndexDiffC(other, start);
|
||||||
|
}
|
||||||
|
blueprint->Add(bi);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto sid : stations) {
|
||||||
|
auto st = Station::Get(sid);
|
||||||
|
|
||||||
|
if (!ta.Contains(st->xy)) continue;
|
||||||
|
|
||||||
|
TileArea sta(TileXY(st->rect.left, st->rect.top), TileXY(st->rect.right, st->rect.bottom));
|
||||||
|
bool in_area = true;
|
||||||
|
bool sign_part = false;
|
||||||
|
std::vector<TileIndex> tiles;
|
||||||
|
TILE_AREA_LOOP(tile, sta) {
|
||||||
|
if (!IsTileType(tile, MP_STATION) || GetStationIndex(tile) != sid || !IsRailStation(tile)) continue;
|
||||||
|
if (!ta.Contains(tile)) {
|
||||||
|
in_area = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tiles.push_back(tile);
|
||||||
|
if (tile == st->xy) sign_part = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_area) continue;
|
||||||
|
|
||||||
|
Blueprint::Item bi(Blueprint::Item::Type::RAIL_STATION, TileIndexToTileIndexDiffC(st->xy, start));
|
||||||
|
bi.u.rail.station.id = sid;
|
||||||
|
bi.u.rail.station.has_part = sign_part;
|
||||||
|
blueprint->Add(bi);
|
||||||
|
|
||||||
|
for (auto tile : tiles) {
|
||||||
|
Blueprint::Item bi(Blueprint::Item::Type::RAIL_STATION_PART, TileIndexToTileIndexDiffC(tile, start));
|
||||||
|
bi.u.rail.station_part.id = sid;
|
||||||
|
bi.u.rail.station_part.axis = GetRailStationAxis(tile);
|
||||||
|
blueprint->Add(bi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateBlueprintTileSelection(Point pt, TileIndex tile) {
|
||||||
|
if (tile == INVALID_TILE || _active_blueprint.first == INVALID_TILE || !_active_blueprint.second) {
|
||||||
|
_thd.cm_new = ObjectHighlight{};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_thd.cm_new = ObjectHighlight::make_blueprint(tile, _active_blueprint.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetActiveBlueprint() {
|
||||||
|
_active_blueprint = std::make_pair(INVALID_TILE, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBlueprintHighlight(const TileInfo *ti, TileHighlight &th) {
|
||||||
|
if (_active_blueprint.first == INVALID_TILE || !_active_blueprint.second)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TileIndexDiffC td = TileIndexToTileIndexDiffC(ti->tile, _active_blueprint.first);
|
||||||
|
if (_active_blueprint.second->HasTile(td)) {
|
||||||
|
th.ground_pal = th.structure_pal = PALETTE_TINT_BLUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildBlueprint(sp<Blueprint> &blueprint, TileIndex start) {
|
||||||
|
TileIndex last_tile;
|
||||||
|
uint32 last_p1, last_p2, last_cmd = CMD_END;
|
||||||
|
for (auto &item : blueprint->items) {
|
||||||
|
switch (item.type) {
|
||||||
|
case Blueprint::Item::Type::RAIL_TRACK: {
|
||||||
|
auto start_tile = AddTileIndexDiffCWrap(start, item.tdiff);
|
||||||
|
auto end_tile = start_tile;
|
||||||
|
auto tdir = item.u.rail.track.start_dir;
|
||||||
|
for (auto i = 1; i < item.u.rail.track.length; i++) {
|
||||||
|
end_tile = TileAddByDiagDir(end_tile, TrackdirToExitdir(tdir));
|
||||||
|
tdir = NextTrackdir(tdir);
|
||||||
|
}
|
||||||
|
DoCommandP(
|
||||||
|
last_tile = start_tile,
|
||||||
|
last_p1 = end_tile,
|
||||||
|
last_p2 = (uint32)(_cur_railtype | (TrackdirToTrack(item.u.rail.track.start_dir) << 6)),
|
||||||
|
last_cmd = CMD_BUILD_RAILROAD_TRACK
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Blueprint::Item::Type::RAIL_DEPOT:
|
||||||
|
DoCommandP(
|
||||||
|
AddTileIndexDiffCWrap(start, item.tdiff),
|
||||||
|
_cur_railtype,
|
||||||
|
item.u.rail.depot.ddir,
|
||||||
|
CMD_BUILD_TRAIN_DEPOT
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Blueprint::Item::Type::RAIL_TUNNEL:
|
||||||
|
// TODO check that other end is where it should be
|
||||||
|
DoCommandP(
|
||||||
|
AddTileIndexDiffCWrap(start, item.tdiff),
|
||||||
|
_cur_railtype | (TRANSPORT_RAIL << 8),
|
||||||
|
0,
|
||||||
|
CMD_BUILD_TUNNEL
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Blueprint::Item::Type::RAIL_BRIDGE: {
|
||||||
|
DoCommandP(
|
||||||
|
AddTileIndexDiffCWrap(start, item.u.rail.bridge.other_end),
|
||||||
|
AddTileIndexDiffCWrap(start, item.tdiff),
|
||||||
|
item.u.rail.bridge.type | (_cur_railtype << 8) | (TRANSPORT_RAIL << 15),
|
||||||
|
CMD_BUILD_BRIDGE
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Blueprint::Item::Type::RAIL_STATION: {
|
||||||
|
// TODO station types
|
||||||
|
TileIndex tile = AddTileIndexDiffCWrap(start, item.tdiff);
|
||||||
|
DoCommandWithCallback(
|
||||||
|
tile,
|
||||||
|
_cur_railtype | (1 << 8) | (1 << 16) | (1 << 24),
|
||||||
|
NEW_STATION << 16,
|
||||||
|
CMD_BUILD_RAIL_STATION,
|
||||||
|
[&blueprint, tile, start, sign_part=item.u.rail.station.has_part, sid=item.u.rail.station.id] (bool res) {
|
||||||
|
if (!res) return;
|
||||||
|
StationID station_id = GetStationIndex(tile);
|
||||||
|
for (auto &item : blueprint->items) {
|
||||||
|
if (item.type != Blueprint::Item::Type::RAIL_STATION_PART) continue;
|
||||||
|
if (item.u.rail.station_part.id != sid) continue;
|
||||||
|
DoCommandP(
|
||||||
|
AddTileIndexDiffCWrap(start, item.tdiff),
|
||||||
|
_cur_railtype | (item.u.rail.station_part.axis << 6) | (1 << 8) | (1 << 16) | (1 << 24),
|
||||||
|
station_id << 16,
|
||||||
|
CMD_BUILD_RAIL_STATION
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!sign_part) DoCommandP(tile, 0, 0, CMD_REMOVE_FROM_RAIL_STATION);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto signal_callback = [start, &blueprint](bool res) {
|
||||||
|
static const Track SIGNAL_POS_TRACK[] = {
|
||||||
|
TRACK_LEFT, TRACK_LEFT, TRACK_RIGHT, TRACK_RIGHT,
|
||||||
|
TRACK_UPPER, TRACK_UPPER, TRACK_LOWER, TRACK_LOWER,
|
||||||
|
TRACK_X, TRACK_X, TRACK_Y, TRACK_Y,
|
||||||
|
};
|
||||||
|
for (auto &item : blueprint->items) {
|
||||||
|
if (item.type != Blueprint::Item::Type::RAIL_SIGNAL) continue;
|
||||||
|
DoCommandP(
|
||||||
|
AddTileIndexDiffCWrap(start, item.tdiff),
|
||||||
|
SIGNAL_POS_TRACK[item.u.rail.signal.pos] | (item.u.rail.signal.variant << 4) | (item.u.rail.signal.type << 5)
|
||||||
|
| ((item.u.rail.signal.pos % 2) << 15),
|
||||||
|
0,
|
||||||
|
CMD_BUILD_SIGNALS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (last_cmd != CMD_END) { // there can't be any signals if there are no rails
|
||||||
|
if (_networking) AddCommandCallback(last_tile, last_p1, last_p2, last_cmd, signal_callback);
|
||||||
|
else signal_callback(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotateActiveBlueprint() {
|
||||||
|
_active_blueprint.second = _active_blueprint.second->Rotate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildActiveBlueprint(TileIndex start) {
|
||||||
|
BuildBlueprint(_active_blueprint.second, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace citymania
|
||||||
21
src/citymania/cm_blueprint.hpp
Normal file
21
src/citymania/cm_blueprint.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef CM_BLUEPRINT_HPP
|
||||||
|
#define CM_BLUEPRINT_HPP
|
||||||
|
|
||||||
|
#include "cm_highlight.hpp"
|
||||||
|
|
||||||
|
namespace citymania {
|
||||||
|
|
||||||
|
void BlueprintCopyArea(TileIndex start, TileIndex end);
|
||||||
|
void ResetActiveBlueprint();
|
||||||
|
void SetBlueprintHighlight(const TileInfo *ti, TileHighlight &th);
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateBlueprintTileSelection(Point pt, TileIndex tile);
|
||||||
|
void BuildActiveBlueprint(TileIndex start);
|
||||||
|
void RotateActiveBlueprint();
|
||||||
|
|
||||||
|
void CommandExecuted(bool res, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd);
|
||||||
|
|
||||||
|
} //- namespace citymania
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
|
|
||||||
#include "cm_highlight.hpp"
|
#include "cm_highlight.hpp"
|
||||||
|
|
||||||
|
#include "cm_blueprint.hpp"
|
||||||
#include "cm_main.hpp"
|
#include "cm_main.hpp"
|
||||||
#include "cm_station_gui.hpp"
|
#include "cm_station_gui.hpp"
|
||||||
|
|
||||||
#include "../core/math_func.hpp"
|
#include "../core/math_func.hpp"
|
||||||
|
#include "../table/bridge_land.h"
|
||||||
#include "../command_func.h"
|
#include "../command_func.h"
|
||||||
#include "../house.h"
|
#include "../house.h"
|
||||||
#include "../industry.h"
|
#include "../industry.h"
|
||||||
@@ -71,27 +74,53 @@ const byte _tileh_to_sprite[32] = {
|
|||||||
0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
|
0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ObjectTileHighlight ObjectTileHighlight::make_rail_depot(DiagDirection ddir) {
|
||||||
ObjectTileHighlight ObjectTileHighlight::make_depot(DiagDirection ddir) {
|
|
||||||
auto oh = ObjectTileHighlight(Type::RAIL_DEPOT);
|
auto oh = ObjectTileHighlight(Type::RAIL_DEPOT);
|
||||||
oh.u.depot.ddir = ddir;
|
oh.u.rail.depot.ddir = ddir;
|
||||||
return oh;
|
return oh;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectTileHighlight ObjectTileHighlight::make_rail(Track track) {
|
ObjectTileHighlight ObjectTileHighlight::make_rail_track(Track track) {
|
||||||
auto oh = ObjectTileHighlight(Type::RAIL_TRACK);
|
auto oh = ObjectTileHighlight(Type::RAIL_TRACK);
|
||||||
oh.u.rail.track = track;
|
oh.u.rail.track = track;
|
||||||
return oh;
|
return oh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectTileHighlight ObjectTileHighlight::make_rail_station(Axis axis) {
|
||||||
|
auto oh = ObjectTileHighlight(Type::RAIL_STATION);
|
||||||
|
oh.u.rail.station.axis = axis;
|
||||||
|
return oh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectTileHighlight ObjectTileHighlight::make_rail_signal(uint pos, SignalType type, SignalVariant variant) {
|
||||||
|
auto oh = ObjectTileHighlight(Type::RAIL_SIGNAL);
|
||||||
|
oh.u.rail.signal.pos = pos;
|
||||||
|
oh.u.rail.signal.type = type;
|
||||||
|
oh.u.rail.signal.variant = variant;
|
||||||
|
return oh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectTileHighlight ObjectTileHighlight::make_rail_bridge_head(DiagDirection ddir, BridgeType type) {
|
||||||
|
auto oh = ObjectTileHighlight(Type::RAIL_BRIDGE_HEAD);
|
||||||
|
oh.u.rail.bridge_head.ddir = ddir;
|
||||||
|
oh.u.rail.bridge_head.type = type;
|
||||||
|
return oh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectTileHighlight ObjectTileHighlight::make_rail_tunnel_head(DiagDirection ddir) {
|
||||||
|
auto oh = ObjectTileHighlight(Type::RAIL_TUNNEL_HEAD);
|
||||||
|
oh.u.rail.tunnel_head.ddir = ddir;
|
||||||
|
return oh;
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectHighlight::operator==(const ObjectHighlight& oh) {
|
bool ObjectHighlight::operator==(const ObjectHighlight& oh) {
|
||||||
if (this->type != oh.type) return false;
|
if (this->type != oh.type) return false;
|
||||||
switch (this->type) {
|
return (this->tile == oh.tile && this->ddir == oh.ddir && this->blueprint == oh.blueprint);
|
||||||
case Type::RAIL_DEPOT: return this->u.depot.tile == oh.u.depot.tile && this->u.depot.ddir == oh.u.depot.ddir;
|
// switch (this->type) {
|
||||||
default: return true;
|
// case Type::RAIL_DEPOT: return this->tile == oh.tile && this->ddir == oh.ddir;
|
||||||
}
|
// default: return true;
|
||||||
return true;
|
// }
|
||||||
|
// return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ObjectHighlight::operator!=(const ObjectHighlight& oh) {
|
bool ObjectHighlight::operator!=(const ObjectHighlight& oh) {
|
||||||
@@ -100,9 +129,16 @@ bool ObjectHighlight::operator!=(const ObjectHighlight& oh) {
|
|||||||
|
|
||||||
|
|
||||||
ObjectHighlight ObjectHighlight::make_depot(TileIndex tile, DiagDirection ddir) {
|
ObjectHighlight ObjectHighlight::make_depot(TileIndex tile, DiagDirection ddir) {
|
||||||
auto oh = ObjectHighlight(ObjectHighlight::Type::RAIL_DEPOT);
|
auto oh = ObjectHighlight{ObjectHighlight::Type::RAIL_DEPOT};
|
||||||
oh.u.depot.tile = tile;
|
oh.tile = tile;
|
||||||
oh.u.depot.ddir = ddir;
|
oh.ddir = ddir;
|
||||||
|
return oh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectHighlight ObjectHighlight::make_blueprint(TileIndex tile, sp<Blueprint> blueprint) {
|
||||||
|
auto oh = ObjectHighlight{ObjectHighlight::Type::BLUEPRINT};
|
||||||
|
oh.tile = tile;
|
||||||
|
oh.blueprint = blueprint;
|
||||||
return oh;
|
return oh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +154,7 @@ void ObjectHighlight::PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Tra
|
|||||||
if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
|
if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
|
||||||
if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return;
|
if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return;
|
||||||
|
|
||||||
this->tiles.insert(std::make_pair(tile, ObjectTileHighlight::make_rail(track)));
|
this->tiles.insert(std::make_pair(tile, ObjectTileHighlight::make_rail_track(track)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Additional pieces of track to add at the entrance of a depot. */
|
/** Additional pieces of track to add at the entrance of a depot. */
|
||||||
@@ -139,16 +175,20 @@ void ObjectHighlight::UpdateTiles() {
|
|||||||
this->tiles.clear();
|
this->tiles.clear();
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case Type::RAIL_DEPOT: {
|
case Type::RAIL_DEPOT: {
|
||||||
auto dir = this->u.depot.ddir;
|
auto dir = this->ddir;
|
||||||
this->tiles.insert(std::make_pair(this->u.depot.tile, ObjectTileHighlight::make_depot(dir)));
|
this->tiles.insert(std::make_pair(this->tile, ObjectTileHighlight::make_rail_depot(dir)));
|
||||||
auto tile = this->u.depot.tile + TileOffsByDiagDir(dir);
|
auto tile = this->tile + TileOffsByDiagDir(dir);
|
||||||
if (IsTileType(tile, MP_RAILWAY) && IsCompatibleRail(GetRailType(tile), _cur_railtype)) {
|
if (IsTileType(tile, MP_RAILWAY) && IsCompatibleRail(GetRailType(tile), _cur_railtype)) {
|
||||||
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]);
|
this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]);
|
||||||
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]);
|
this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]);
|
||||||
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]);
|
this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Type::BLUEPRINT:
|
||||||
|
if (this->blueprint && this->tile != INVALID_TILE)
|
||||||
|
this->tiles = this->blueprint->GetTiles(this->tile);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -194,24 +234,208 @@ void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection d
|
|||||||
DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, PALETTE_TINT_WHITE);
|
DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, PALETTE_TINT_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawTrainStationSprite(const TileInfo *ti, RailType railtype, Axis axis) {
|
||||||
|
int32 total_offset = 0;
|
||||||
|
PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company);
|
||||||
|
const DrawTileSprites *t = GetStationTileLayout(STATION_RAIL, (axis == AXIS_X ? 0 : 1));
|
||||||
|
const RailtypeInfo *rti = nullptr;
|
||||||
|
|
||||||
|
if (railtype != INVALID_RAILTYPE) {
|
||||||
|
rti = GetRailTypeInfo(railtype);
|
||||||
|
total_offset = rti->GetRailtypeSpriteOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawAutorailSelection(ti, (axis == AXIS_X ? HT_DIR_X : HT_DIR_Y), PAL_NONE);
|
||||||
|
|
||||||
|
// if (roadtype != INVALID_ROADTYPE) {
|
||||||
|
// const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype);
|
||||||
|
// if (image >= 4) {
|
||||||
|
// /* Drive-through stop */
|
||||||
|
// uint sprite_offset = 5 - image;
|
||||||
|
|
||||||
|
// /* Road underlay takes precedence over tram */
|
||||||
|
// if (rti->UsesOverlay()) {
|
||||||
|
// SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND);
|
||||||
|
// DrawSprite(ground + sprite_offset, PAL_NONE, x, y);
|
||||||
|
|
||||||
|
// SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY);
|
||||||
|
// if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y);
|
||||||
|
// } else if (RoadTypeIsTram(roadtype)) {
|
||||||
|
// DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// /* Drive-in stop */
|
||||||
|
// if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) {
|
||||||
|
// SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP);
|
||||||
|
// DrawSprite(ground + image, PAL_NONE, x, y);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/* Default waypoint has no railtype specific sprites */
|
||||||
|
// DrawRailTileSeq(ti, t, TO_INVALID, (st == STATION_WAYPOINT ? 0 : total_offset), 0, PALETTE_TINT_WHITE);
|
||||||
|
DrawRailTileSeq(ti, t, TO_INVALID, total_offset, 0, PALETTE_TINT_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SignalOffsets { // from rail_cmd.cpp
|
||||||
|
SIGNAL_TO_SOUTHWEST,
|
||||||
|
SIGNAL_TO_NORTHEAST,
|
||||||
|
SIGNAL_TO_SOUTHEAST,
|
||||||
|
SIGNAL_TO_NORTHWEST,
|
||||||
|
SIGNAL_TO_EAST,
|
||||||
|
SIGNAL_TO_WEST,
|
||||||
|
SIGNAL_TO_SOUTH,
|
||||||
|
SIGNAL_TO_NORTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copied from rail_cmd.cpp
|
||||||
|
* Get surface height in point (x,y)
|
||||||
|
* On tiles with halftile foundations move (x,y) to a safe point wrt. track
|
||||||
|
*/
|
||||||
|
static uint GetSaveSlopeZ(uint x, uint y, Track track)
|
||||||
|
{
|
||||||
|
switch (track) {
|
||||||
|
case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
|
||||||
|
case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
|
||||||
|
case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
|
||||||
|
case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return GetSlopePixelZ(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawSignal(const TileInfo *ti, RailType railtype, uint pos, SignalType type, SignalVariant variant) {
|
||||||
|
// reference: DraawSingleSignal in rail_cmd.cpp
|
||||||
|
bool side;
|
||||||
|
switch (_settings_game.construction.train_signal_side) {
|
||||||
|
case 0: side = false; break; // left
|
||||||
|
case 2: side = true; break; // right
|
||||||
|
default: side = _settings_game.vehicle.road_side != 0; break; // driving side
|
||||||
|
}
|
||||||
|
static const Point SignalPositions[2][12] = {
|
||||||
|
{ // Signals on the left side
|
||||||
|
/* LEFT LEFT RIGHT RIGHT UPPER UPPER */
|
||||||
|
{ 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
|
||||||
|
/* LOWER LOWER X X Y Y */
|
||||||
|
{11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
|
||||||
|
}, { // Signals on the right side
|
||||||
|
/* LEFT LEFT RIGHT RIGHT UPPER UPPER */
|
||||||
|
{14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
|
||||||
|
/* LOWER LOWER X X Y Y */
|
||||||
|
{14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint x = TileX(ti->tile) * TILE_SIZE + SignalPositions[side][pos].x;
|
||||||
|
uint y = TileY(ti->tile) * TILE_SIZE + SignalPositions[side][pos].y;
|
||||||
|
|
||||||
|
static const Track pos_track[] = {
|
||||||
|
TRACK_LEFT, TRACK_LEFT, TRACK_RIGHT, TRACK_RIGHT,
|
||||||
|
TRACK_UPPER, TRACK_UPPER, TRACK_LOWER, TRACK_LOWER,
|
||||||
|
TRACK_X, TRACK_X, TRACK_Y, TRACK_Y,
|
||||||
|
};
|
||||||
|
static const SignalOffsets pos_offset[] = {
|
||||||
|
SIGNAL_TO_NORTH, SIGNAL_TO_SOUTH, SIGNAL_TO_NORTH, SIGNAL_TO_SOUTH,
|
||||||
|
SIGNAL_TO_WEST, SIGNAL_TO_EAST, SIGNAL_TO_WEST, SIGNAL_TO_EAST,
|
||||||
|
SIGNAL_TO_SOUTHWEST, SIGNAL_TO_NORTHEAST, SIGNAL_TO_SOUTHEAST, SIGNAL_TO_NORTHWEST,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto track = pos_track[pos];
|
||||||
|
auto image = pos_offset[pos];
|
||||||
|
static const SignalState condition = SIGNAL_STATE_GREEN;
|
||||||
|
|
||||||
|
auto rti = GetRailTypeInfo(railtype);
|
||||||
|
SpriteID sprite = GetCustomSignalSprite(rti, ti->tile, type, variant, condition);
|
||||||
|
if (sprite != 0) {
|
||||||
|
sprite += image;
|
||||||
|
} else {
|
||||||
|
/* Normal electric signals are stored in a different sprite block than all other signals. */
|
||||||
|
sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16;
|
||||||
|
sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddSortableSpriteToDraw(sprite, PALETTE_TINT_WHITE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
|
||||||
|
}
|
||||||
|
|
||||||
|
// copied from tunnelbridge_cmd.cpp
|
||||||
|
static inline const PalSpriteID *GetBridgeSpriteTable(int index, BridgePieces table)
|
||||||
|
{
|
||||||
|
const BridgeSpec *bridge = GetBridgeSpec(index);
|
||||||
|
assert(table < BRIDGE_PIECE_INVALID);
|
||||||
|
if (bridge->sprite_table == nullptr || bridge->sprite_table[table] == nullptr) {
|
||||||
|
return _bridge_sprite_table[index][table];
|
||||||
|
} else {
|
||||||
|
return bridge->sprite_table[table];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawBridgeHead(const TileInfo *ti, RailType railtype, DiagDirection ddir, BridgeType type) {
|
||||||
|
auto rti = GetRailTypeInfo(railtype);
|
||||||
|
int base_offset = rti->bridge_offset;
|
||||||
|
const PalSpriteID *psid;
|
||||||
|
|
||||||
|
/* HACK Wizardry to convert the bridge ramp direction into a sprite offset */
|
||||||
|
base_offset += (6 - ddir) % 4;
|
||||||
|
|
||||||
|
/* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */
|
||||||
|
if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
|
||||||
|
psid = &GetBridgeSpriteTable(type, BRIDGE_PIECE_HEAD)[base_offset];
|
||||||
|
|
||||||
|
AddSortableSpriteToDraw(psid->sprite, PALETTE_TINT_WHITE, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z);
|
||||||
|
// DrawAutorailSelection(ti, (ddir == DIAGDIR_SW || ddir == DIAGDIR_NE ? HT_DIR_X : HT_DIR_Y), PAL_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTunnelHead(const TileInfo *ti, RailType railtype, DiagDirection ddir) {
|
||||||
|
auto rti = GetRailTypeInfo(railtype);
|
||||||
|
|
||||||
|
SpriteID image;
|
||||||
|
SpriteID railtype_overlay = 0;
|
||||||
|
|
||||||
|
image = rti->base_sprites.tunnel;
|
||||||
|
if (rti->UsesOverlay()) {
|
||||||
|
/* Check if the railtype has custom tunnel portals. */
|
||||||
|
railtype_overlay = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL_PORTAL);
|
||||||
|
if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base.
|
||||||
|
}
|
||||||
|
|
||||||
|
image += ddir * 2;
|
||||||
|
AddSortableSpriteToDraw(image, PALETTE_TINT_WHITE, ti->x, ti->y, 16, 16, 0, ti->z);
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectHighlight::Draw(const TileInfo *ti) {
|
void ObjectHighlight::Draw(const TileInfo *ti) {
|
||||||
this->UpdateTiles();
|
this->UpdateTiles();
|
||||||
auto range = this->tiles.equal_range(ti->tile);
|
auto range = this->tiles.equal_range(ti->tile);
|
||||||
|
auto i=0;
|
||||||
for (auto t = range.first; t != range.second; t++) {
|
for (auto t = range.first; t != range.second; t++) {
|
||||||
|
i++;
|
||||||
auto &oth = t->second;
|
auto &oth = t->second;
|
||||||
switch (oth.type) {
|
switch (oth.type) {
|
||||||
case ObjectTileHighlight::Type::RAIL_DEPOT:
|
case ObjectTileHighlight::Type::RAIL_DEPOT:
|
||||||
DrawTrainDepotSprite(ti, _cur_railtype, oth.u.depot.ddir);
|
DrawTrainDepotSprite(ti, _cur_railtype, oth.u.rail.depot.ddir);
|
||||||
break;
|
break;
|
||||||
case ObjectTileHighlight::Type::RAIL_TRACK: {
|
case ObjectTileHighlight::Type::RAIL_TRACK: {
|
||||||
auto hs = (HighLightStyle)oth.u.rail.track;
|
auto hs = (HighLightStyle)oth.u.rail.track;
|
||||||
DrawAutorailSelection(ti, hs, PAL_NONE);
|
DrawAutorailSelection(ti, hs, PAL_NONE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ObjectTileHighlight::Type::RAIL_STATION:
|
||||||
|
DrawTrainStationSprite(ti, _cur_railtype, oth.u.rail.station.axis);
|
||||||
|
break;
|
||||||
|
case ObjectTileHighlight::Type::RAIL_SIGNAL:
|
||||||
|
DrawSignal(ti, _cur_railtype, oth.u.rail.signal.pos, oth.u.rail.signal.type, oth.u.rail.signal.variant);
|
||||||
|
break;
|
||||||
|
case ObjectTileHighlight::Type::RAIL_BRIDGE_HEAD:
|
||||||
|
DrawBridgeHead(ti, _cur_railtype, oth.u.rail.bridge_head.ddir, oth.u.rail.bridge_head.type);
|
||||||
|
break;
|
||||||
|
case ObjectTileHighlight::Type::RAIL_TUNNEL_HEAD:
|
||||||
|
DrawTunnelHead(ti, _cur_railtype, oth.u.rail.tunnel_head.ddir);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// fprintf(stderr, "TILEH DRAW %d %d %d\n", ti->tile, (int)i, (int)this->tiles.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -525,6 +749,7 @@ TileHighlight GetTileHighlight(const TileInfo *ti) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetStationSelectionHighlight(ti, th);
|
SetStationSelectionHighlight(ti, th);
|
||||||
|
SetBlueprintHighlight(ti, th);
|
||||||
|
|
||||||
return th;
|
return th;
|
||||||
}
|
}
|
||||||
@@ -545,6 +770,8 @@ void DrawTileZoning(const TileInfo *ti, const TileHighlight &th) {
|
|||||||
bool DrawTileSelection(const TileInfo *ti, const TileHighlightType &tht) {
|
bool DrawTileSelection(const TileInfo *ti, const TileHighlightType &tht) {
|
||||||
_thd.cm.Draw(ti);
|
_thd.cm.Draw(ti);
|
||||||
|
|
||||||
|
if (_thd.drawstyle == CM_HT_BLUEPRINT_PLACE) return true;
|
||||||
|
|
||||||
if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0) {
|
if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0) {
|
||||||
// station selector, handled by DrawTileZoning
|
// station selector, handled by DrawTileZoning
|
||||||
return true;
|
return true;
|
||||||
@@ -610,11 +837,14 @@ DiagDirection AutodetectRailObjectDirection(TileIndex tile, Point pt) {
|
|||||||
|
|
||||||
HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) {
|
HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) {
|
||||||
_thd.cm_new = ObjectHighlight(ObjectHighlight::Type::NONE);
|
_thd.cm_new = ObjectHighlight(ObjectHighlight::Type::NONE);
|
||||||
if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT &&
|
auto pt = GetTileBelowCursor();
|
||||||
|
auto tile = (pt.x == -1 ? INVALID_TILE : TileVirtXY(pt.x, pt.y));
|
||||||
|
if (_thd.place_mode == CM_HT_BLUEPRINT_PLACE) {
|
||||||
|
UpdateBlueprintTileSelection(pt, tile);
|
||||||
|
new_drawstyle = CM_HT_BLUEPRINT_PLACE;
|
||||||
|
} else if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT &&
|
||||||
_cursor.sprite_seq[0].sprite == GetRailTypeInfo(_cur_railtype)->cursor.depot) {
|
_cursor.sprite_seq[0].sprite == GetRailTypeInfo(_cur_railtype)->cursor.depot) {
|
||||||
auto dir = _build_depot_direction;
|
auto dir = _build_depot_direction;
|
||||||
auto pt = GetTileBelowCursor();
|
|
||||||
auto tile = TileVirtXY(pt.x, pt.y);
|
|
||||||
if (pt.x != -1) {
|
if (pt.x != -1) {
|
||||||
if (dir >= DiagDirection::DIAGDIR_END)
|
if (dir >= DiagDirection::DIAGDIR_END)
|
||||||
dir = AutodetectRailObjectDirection(tile, pt);
|
dir = AutodetectRailObjectDirection(tile, pt);
|
||||||
|
|||||||
@@ -1,36 +1,152 @@
|
|||||||
#ifndef CITYMANIA_HIGHLIGHT_TYPE_HPP
|
#ifndef CITYMANIA_HIGHLIGHT_TYPE_HPP
|
||||||
#define CITYMANIA_HIGHLIGHT_TYPE_HPP
|
#define CITYMANIA_HIGHLIGHT_TYPE_HPP
|
||||||
|
|
||||||
|
#include "../bridge.h"
|
||||||
#include "../direction_type.h"
|
#include "../direction_type.h"
|
||||||
|
#include "../map_func.h"
|
||||||
|
#include "../signal_type.h"
|
||||||
|
#include "../station_type.h"
|
||||||
#include "../tile_cmd.h"
|
#include "../tile_cmd.h"
|
||||||
#include "../tile_type.h"
|
#include "../tile_type.h"
|
||||||
#include "../track_type.h"
|
#include "../track_type.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace citymania {
|
namespace citymania {
|
||||||
|
|
||||||
|
|
||||||
class ObjectTileHighlight {
|
class ObjectTileHighlight {
|
||||||
public:
|
public:
|
||||||
enum class Type {
|
enum class Type {
|
||||||
RAIL_DEPOT = 0,
|
BEGIN = 0,
|
||||||
RAIL_TRACK = 1,
|
RAIL_DEPOT = BEGIN,
|
||||||
|
RAIL_TRACK,
|
||||||
|
RAIL_STATION,
|
||||||
|
RAIL_SIGNAL,
|
||||||
|
RAIL_BRIDGE_HEAD,
|
||||||
|
RAIL_TUNNEL_HEAD,
|
||||||
|
END,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
DiagDirection ddir;
|
struct {
|
||||||
} depot;
|
DiagDirection ddir;
|
||||||
struct {
|
} depot;
|
||||||
Track track;
|
Track track;
|
||||||
|
struct {
|
||||||
|
Axis axis;
|
||||||
|
} station;
|
||||||
|
struct {
|
||||||
|
uint pos;
|
||||||
|
SignalType type;
|
||||||
|
SignalVariant variant;
|
||||||
|
} signal;
|
||||||
|
struct {
|
||||||
|
DiagDirection ddir;
|
||||||
|
TileIndex other_end;
|
||||||
|
BridgeType type;
|
||||||
|
} bridge_head;
|
||||||
|
struct {
|
||||||
|
DiagDirection ddir;
|
||||||
|
} tunnel_head;
|
||||||
} rail;
|
} rail;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
ObjectTileHighlight(Type type): type{type} {}
|
ObjectTileHighlight(Type type): type{type} {}
|
||||||
static ObjectTileHighlight make_depot(DiagDirection ddir);
|
static ObjectTileHighlight make_rail_depot(DiagDirection ddir);
|
||||||
static ObjectTileHighlight make_rail(Track track);
|
static ObjectTileHighlight make_rail_track(Track track);
|
||||||
|
static ObjectTileHighlight make_rail_station(Axis axis);
|
||||||
|
static ObjectTileHighlight make_rail_signal(uint pos, SignalType type, SignalVariant variant);
|
||||||
|
static ObjectTileHighlight make_rail_bridge_head(DiagDirection ddir, BridgeType type);
|
||||||
|
static ObjectTileHighlight make_rail_tunnel_head(DiagDirection ddir);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TileIndexDiffCCompare{
|
||||||
|
public:
|
||||||
|
bool operator()(const TileIndexDiffC &a, const TileIndexDiffC &b) {
|
||||||
|
if (a.x < b.x) return true;
|
||||||
|
if (a.x == b.x && a.y < b.y) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Blueprint {
|
||||||
|
public:
|
||||||
|
class Item {
|
||||||
|
public:
|
||||||
|
enum class Type {
|
||||||
|
BEGIN = 0,
|
||||||
|
RAIL_DEPOT = BEGIN,
|
||||||
|
RAIL_TRACK,
|
||||||
|
RAIL_STATION,
|
||||||
|
RAIL_STATION_PART,
|
||||||
|
RAIL_SIGNAL,
|
||||||
|
RAIL_BRIDGE,
|
||||||
|
RAIL_TUNNEL,
|
||||||
|
END,
|
||||||
|
};
|
||||||
|
Type type;
|
||||||
|
TileIndexDiffC tdiff;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
DiagDirection ddir;
|
||||||
|
} depot;
|
||||||
|
struct {
|
||||||
|
uint16 length;
|
||||||
|
Trackdir start_dir;
|
||||||
|
} track;
|
||||||
|
struct {
|
||||||
|
StationID id;
|
||||||
|
bool has_part;
|
||||||
|
} station;
|
||||||
|
struct {
|
||||||
|
Axis axis;
|
||||||
|
StationID id;
|
||||||
|
} station_part;
|
||||||
|
struct {
|
||||||
|
uint pos;
|
||||||
|
SignalType type;
|
||||||
|
SignalVariant variant;
|
||||||
|
} signal;
|
||||||
|
struct {
|
||||||
|
DiagDirection ddir;
|
||||||
|
TileIndexDiffC other_end;
|
||||||
|
BridgeType type;
|
||||||
|
} bridge;
|
||||||
|
struct {
|
||||||
|
DiagDirection ddir;
|
||||||
|
TileIndexDiffC other_end;
|
||||||
|
} tunnel;
|
||||||
|
} rail;
|
||||||
|
} u;
|
||||||
|
Item(Type type, TileIndexDiffC tdiff)
|
||||||
|
: type{type}, tdiff{tdiff} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Item> items;
|
||||||
|
std::set<TileIndexDiffC, TileIndexDiffCCompare> tiles;
|
||||||
|
|
||||||
|
Blueprint() {}
|
||||||
|
|
||||||
|
void Clear() {
|
||||||
|
this->items.clear();
|
||||||
|
this->tiles.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Add(Item item);
|
||||||
|
|
||||||
|
bool HasTile(TileIndexDiffC tdiff) {
|
||||||
|
return (this->tiles.find(tdiff) != this->tiles.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<Blueprint> Rotate();
|
||||||
|
|
||||||
|
std::multimap<TileIndex, ObjectTileHighlight> GetTiles(TileIndex tile);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ObjectHighlight {
|
class ObjectHighlight {
|
||||||
@@ -38,16 +154,14 @@ public:
|
|||||||
enum class Type {
|
enum class Type {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
RAIL_DEPOT = 1,
|
RAIL_DEPOT = 1,
|
||||||
|
BLUEPRINT = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type type;
|
Type type;
|
||||||
union {
|
TileIndex tile = INVALID_TILE;
|
||||||
struct {
|
DiagDirection ddir = INVALID_DIAGDIR;
|
||||||
TileIndex tile;
|
sp<Blueprint> blueprint = nullptr;
|
||||||
DiagDirection ddir;
|
|
||||||
} depot;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
bool tiles_updated = false;
|
bool tiles_updated = false;
|
||||||
std::multimap<TileIndex, ObjectTileHighlight> tiles;
|
std::multimap<TileIndex, ObjectTileHighlight> tiles;
|
||||||
@@ -55,11 +169,12 @@ protected:
|
|||||||
void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track);
|
void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ObjectHighlight(Type type = Type::NONE): type{type} { /* get rid of uninitualized warning */ this->u.depot.tile = INVALID_TILE; }
|
ObjectHighlight(Type type = Type::NONE): type{type} {}
|
||||||
bool operator==(const ObjectHighlight& oh);
|
bool operator==(const ObjectHighlight& oh);
|
||||||
bool operator!=(const ObjectHighlight& oh);
|
bool operator!=(const ObjectHighlight& oh);
|
||||||
|
|
||||||
static ObjectHighlight make_depot(TileIndex tile, DiagDirection ddir);
|
static ObjectHighlight make_depot(TileIndex tile, DiagDirection ddir);
|
||||||
|
static ObjectHighlight make_blueprint(TileIndex tile, sp<Blueprint> blueprint);
|
||||||
|
|
||||||
void Draw(const TileInfo *ti);
|
void Draw(const TileInfo *ti);
|
||||||
void MarkDirty();
|
void MarkDirty();
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
#include "citymania/cm_hotkeys.hpp"
|
#include "citymania/cm_hotkeys.hpp"
|
||||||
|
#include "citymania/cm_blueprint.hpp"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
@@ -610,6 +611,8 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
|
|||||||
if (!estimate_only && !only_sending && callback != nullptr) {
|
if (!estimate_only && !only_sending && callback != nullptr) {
|
||||||
callback(res, tile, p1, p2, cmd);
|
callback(res, tile, p1, p2, cmd);
|
||||||
}
|
}
|
||||||
|
if (!estimate_only && !only_sending)
|
||||||
|
citymania::CommandExecuted(res.Succeeded(), tile, p1, p2, cmd);
|
||||||
|
|
||||||
return res.Succeeded();
|
return res.Succeeded();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5545,3 +5545,5 @@ STR_CM_CONFIG_SETTING_SHADED_TREES_SERVER : As server
|
|||||||
STR_CM_CONFIG_SETTING_SHOW_APM : Show APM counter: {STRING2}
|
STR_CM_CONFIG_SETTING_SHOW_APM : Show APM counter: {STRING2}
|
||||||
STR_CM_CONFIG_SETTING_SHOW_APM_HELPTEXT : Adds APM (actions per minute) counter to the statusbar.
|
STR_CM_CONFIG_SETTING_SHOW_APM_HELPTEXT : Adds APM (actions per minute) counter to the statusbar.
|
||||||
STR_CM_STATUSBAR_APM : {WHITE}APM: {NUM} AVG: {NUM}
|
STR_CM_STATUSBAR_APM : {WHITE}APM: {NUM} AVG: {NUM}
|
||||||
|
|
||||||
|
STR_CM_RAIL_TOOLBAR_TOOLTIP_BLUEPRINT : {BLACK}Rail blueprint tool (copy-paste)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "widgets/rail_widget.h"
|
#include "widgets/rail_widget.h"
|
||||||
|
|
||||||
|
#include "citymania/cm_blueprint.hpp"
|
||||||
#include "citymania/cm_hotkeys.hpp"
|
#include "citymania/cm_hotkeys.hpp"
|
||||||
#include "citymania/cm_station_gui.hpp"
|
#include "citymania/cm_station_gui.hpp"
|
||||||
|
|
||||||
@@ -768,6 +769,11 @@ struct BuildRailToolbarWindow : Window {
|
|||||||
this->last_user_action = widget;
|
this->last_user_action = widget;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CM_WID_RAT_BLUEPRINT:
|
||||||
|
HandlePlacePushButton(this, CM_WID_RAT_BLUEPRINT, SPR_CURSOR_RAIL_STATION, HT_RECT);
|
||||||
|
this->last_user_action = widget;
|
||||||
|
break;
|
||||||
|
|
||||||
case WID_RAT_REMOVE:
|
case WID_RAT_REMOVE:
|
||||||
_remove_button_clicked = citymania::RailToolbar_RemoveModChanged(this, _cm_invert_remove, _remove_button_clicked, true);
|
_remove_button_clicked = citymania::RailToolbar_RemoveModChanged(this, _cm_invert_remove, _remove_button_clicked, true);
|
||||||
// BuildRailClick_Remove(this);
|
// BuildRailClick_Remove(this);
|
||||||
@@ -871,6 +877,15 @@ struct BuildRailToolbarWindow : Window {
|
|||||||
PlaceRail_Bridge(tile, this);
|
PlaceRail_Bridge(tile, this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CM_WID_RAT_BLUEPRINT:
|
||||||
|
VpStartPlaceSizing(tile, VPM_X_AND_Y, CM_DDSP_BLUEPRINT_AREA);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CM_WID_RAT_BLUEPRINT_PLACE:
|
||||||
|
citymania::BuildActiveBlueprint(tile);
|
||||||
|
ResetObjectToPlace();
|
||||||
|
break;
|
||||||
|
|
||||||
case WID_RAT_BUILD_TUNNEL:
|
case WID_RAT_BUILD_TUNNEL:
|
||||||
DoCommandP(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel);
|
DoCommandP(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel);
|
||||||
break;
|
break;
|
||||||
@@ -940,6 +955,12 @@ struct BuildRailToolbarWindow : Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CM_DDSP_BLUEPRINT_AREA:
|
||||||
|
SetObjectToPlace(SPR_CURSOR_RAIL_STATION, PAL_NONE, CM_HT_BLUEPRINT_PLACE, this->window_class, this->window_number);
|
||||||
|
citymania::BlueprintCopyArea(start_tile, end_tile);
|
||||||
|
this->last_user_action = CM_WID_RAT_BLUEPRINT_PLACE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -960,6 +981,7 @@ struct BuildRailToolbarWindow : Window {
|
|||||||
DeleteWindowByClass(WC_BUILD_BRIDGE);
|
DeleteWindowByClass(WC_BUILD_BRIDGE);
|
||||||
|
|
||||||
citymania::AbortStationPlacement();
|
citymania::AbortStationPlacement();
|
||||||
|
citymania::ResetActiveBlueprint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnPlacePresize(Point pt, TileIndex tile) override
|
void OnPlacePresize(Point pt, TileIndex tile) override
|
||||||
@@ -970,6 +992,10 @@ struct BuildRailToolbarWindow : Window {
|
|||||||
|
|
||||||
EventState CM_OnRemoveModStateChange() override
|
EventState CM_OnRemoveModStateChange() override
|
||||||
{
|
{
|
||||||
|
if (this->last_user_action == CM_WID_RAT_BLUEPRINT_PLACE) {
|
||||||
|
citymania::RotateActiveBlueprint();
|
||||||
|
return ES_HANDLED;
|
||||||
|
}
|
||||||
auto new_remove = citymania::RailToolbar_RemoveModChanged(this, _cm_invert_remove, _remove_button_clicked, false);
|
auto new_remove = citymania::RailToolbar_RemoveModChanged(this, _cm_invert_remove, _remove_button_clicked, false);
|
||||||
if (new_remove != _remove_button_clicked) {
|
if (new_remove != _remove_button_clicked) {
|
||||||
_remove_button_clicked = new_remove;
|
_remove_button_clicked = new_remove;
|
||||||
@@ -1058,6 +1084,8 @@ static const NWidgetPart _nested_build_rail_widgets[] = {
|
|||||||
SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE),
|
SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE),
|
||||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_TUNNEL),
|
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_TUNNEL),
|
||||||
SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL),
|
SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL),
|
||||||
|
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, CM_WID_RAT_BLUEPRINT),
|
||||||
|
SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_BUY_LAND, STR_CM_RAIL_TOOLBAR_TOOLTIP_BLUEPRINT),
|
||||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_REMOVE),
|
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_REMOVE),
|
||||||
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR),
|
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR),
|
||||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_CONVERT_RAIL),
|
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_CONVERT_RAIL),
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ enum HighLightStyle {
|
|||||||
HT_VEHICLE = 0x100, ///< vehicle is accepted as target as well (bitmask)
|
HT_VEHICLE = 0x100, ///< vehicle is accepted as target as well (bitmask)
|
||||||
HT_DIAGONAL = 0x200, ///< Also allow 'diagonal rectangles'. Only usable in combination with #HT_RECT or #HT_POINT.
|
HT_DIAGONAL = 0x200, ///< Also allow 'diagonal rectangles'. Only usable in combination with #HT_RECT or #HT_POINT.
|
||||||
HT_POLY = 0x400, ///< polyline mode; connect highlighted track with previous one
|
HT_POLY = 0x400, ///< polyline mode; connect highlighted track with previous one
|
||||||
|
CM_HT_BLUEPRINT_PLACE = 0x800, ///< CityMania blueprint placemment
|
||||||
HT_DRAG_MASK = 0x0F8, ///< Mask for the tile drag-type modes.
|
HT_DRAG_MASK = 0x0F8, ///< Mask for the tile drag-type modes.
|
||||||
|
|
||||||
/* lower bits (used with HT_LINE and HT_RAIL):
|
/* lower bits (used with HT_LINE and HT_RAIL):
|
||||||
|
|||||||
@@ -261,6 +261,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
TileIndex tile_start = p1;
|
TileIndex tile_start = p1;
|
||||||
TileIndex tile_end = end_tile;
|
TileIndex tile_end = end_tile;
|
||||||
|
|
||||||
|
fprintf(stderr, "BRIDGE %d %d %d %d\n", tile_start, tile_end, bridge_type, railtype);
|
||||||
if (company == OWNER_DEITY) {
|
if (company == OWNER_DEITY) {
|
||||||
if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
|
if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
|
||||||
const Town *town = CalcClosestTownFromTile(tile_start);
|
const Town *town = CalcClosestTownFromTile(tile_start);
|
||||||
|
|||||||
@@ -2415,7 +2415,7 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Vehicle placement mode already handled above. */
|
/* Vehicle placement mode already handled above. */
|
||||||
if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) {
|
if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE || _thd.place_mode == CM_HT_BLUEPRINT_PLACE) {
|
||||||
if (_thd.place_mode & HT_POLY) {
|
if (_thd.place_mode & HT_POLY) {
|
||||||
/* In polyline mode double-clicking on a single white line, finishes current polyline.
|
/* In polyline mode double-clicking on a single white line, finishes current polyline.
|
||||||
* If however the user double-clicks on a line that has a white and a blue section,
|
* If however the user double-clicks on a line that has a white and a blue section,
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ enum ViewportDragDropSelectionProcess {
|
|||||||
DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses)
|
DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses)
|
||||||
DDSP_REMOVE_TRUCKSTOP, ///< Road stop removal (trucks)
|
DDSP_REMOVE_TRUCKSTOP, ///< Road stop removal (trucks)
|
||||||
DDSP_CONVERT_ROAD, ///< Road conversion
|
DDSP_CONVERT_ROAD, ///< Road conversion
|
||||||
|
|
||||||
|
CM_DDSP_BLUEPRINT_AREA, ///< Blueprint area to copy selection
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ enum RailToolbarWidgets {
|
|||||||
WID_RAT_BUILD_SIGNALS, ///< Build signals.
|
WID_RAT_BUILD_SIGNALS, ///< Build signals.
|
||||||
WID_RAT_BUILD_BRIDGE, ///< Build a bridge.
|
WID_RAT_BUILD_BRIDGE, ///< Build a bridge.
|
||||||
WID_RAT_BUILD_TUNNEL, ///< Build a tunnel.
|
WID_RAT_BUILD_TUNNEL, ///< Build a tunnel.
|
||||||
|
CM_WID_RAT_BLUEPRINT, ///< CityMania rail blueprint tool.
|
||||||
WID_RAT_REMOVE, ///< Bulldozer to remove rail.
|
WID_RAT_REMOVE, ///< Bulldozer to remove rail.
|
||||||
WID_RAT_CONVERT_RAIL, ///< Convert other rail to this type.
|
WID_RAT_CONVERT_RAIL, ///< Convert other rail to this type.
|
||||||
|
CM_WID_RAT_BLUEPRINT_PLACE, ///< CityMania rail blueprint tool placement (fake widget).
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Widgets of the #BuildRailStationWindow class. */
|
/** Widgets of the #BuildRailStationWindow class. */
|
||||||
|
|||||||
Reference in New Issue
Block a user