Merge branch 'master' into 1.11

This commit is contained in:
dP
2021-03-18 00:21:09 +03:00
33 changed files with 15184 additions and 130 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,8 @@ void DrawAircraftDetails(const Aircraft *v, int left, int right, int y)
SetDParam(0, u->engine_type);
SetDParam(1, u->build_year);
SetDParam(2, u->value);
DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE);
if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM
DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE);
SetDParam(0, u->cargo_type);
SetDParam(1, u->cargo_cap);

View File

@@ -10,8 +10,14 @@
#include "../fileio_type.h"
#include "../map_type.h"
#include "../map_func.h"
#include "../strings_func.h"
#include "../town.h"
#include "../tree_map.h"
#include <fstream>
#include <sstream>
#include <queue>
#include "../safeguards.h"
bool ReadHeightMap(DetailedFileType dft, const char *filename, uint *x, uint *y, byte **map);
@@ -108,4 +114,87 @@ bool ConTreeMap(byte argc, char *argv[]) {
return true;
}
extern void (*UpdateTownGrowthRate)(Town *t);
bool ConResetTownGrowth(byte argc, char *argv[]) {
if (argc == 0) {
IConsoleHelp("Resets growth to normal for all towns.");
IConsoleHelp("Usage: 'cmresettowngrowth'");
return true;
}
if (argc > 1) return false;
for (Town *town : Town::Iterate()) {
ClrBit(town->flags, TOWN_CUSTOM_GROWTH);
UpdateTownGrowthRate(town);
}
return true;
}
struct FakeCommand {
Date date;
DateFract date_fract;
uint company_id;
uint cmd;
TileIndex tile;
uint32 p1, p2;
std::string text;
};
static std::queue<FakeCommand> _fake_commands;
void ExecuteFakeCommands(Date date, DateFract date_fract) {
auto backup_company = _current_company;
while (!_fake_commands.empty() && _fake_commands.front().date <= date && _fake_commands.front().date_fract <= date_fract) {
auto &x = _fake_commands.front();
if (x.date < date || x.date_fract < date_fract) IConsolePrintF(CC_WARNING,
"Queued command is earlier than execution date: %d/%hu vs %d/%hu",
x.date, x.date_fract, date, date_fract);
fprintf(stderr, "Executing command: company=%u cmd=%u tile=%u p1=%u p2=%u text=%s ... ", x.company_id, x.cmd, x.tile, x.p1, x.p2, x.text.c_str());
_current_company = (CompanyID)x.company_id;
auto res = DoCommandPInternal(x.tile, x.p1, x.p2, x.cmd | CMD_NETWORK_COMMAND, nullptr, x.text.c_str(), false, false);
if (res.Failed()) {
if (res.GetErrorMessage() != INVALID_STRING_ID) {
char buf[DRAW_STRING_BUFFER];
GetString(buf, res.GetErrorMessage(), lastof(buf));
fprintf(stderr, "%s\n", buf);
} else {
fprintf(stderr, "FAIL\n");
}
} else {
fprintf(stderr, "OK\n");
}
_fake_commands.pop();
}
_current_company = backup_company;
}
bool ConLoadCommands(byte argc, char *argv[]) {
if (argc == 0) {
IConsoleHelp("Loads a file with command queue to execute");
IConsoleHelp("Usage: 'cmloadcommands <file>'");
return true;
}
if (argc != 2) return false;
std::queue<FakeCommand>().swap(_fake_commands); // clear queue
std::ifstream file(argv[1], std::ios::in);
std::string str;
while(std::getline(file, str))
{
std::istringstream ss(str);
FakeCommand cmd;
ss >> cmd.date >> cmd.date_fract >> cmd.company_id >> cmd.cmd >> cmd.p1 >> cmd.p2 >> cmd.tile;
std::string s;
ss.get();
std::getline(ss, cmd.text);
// fprintf(stderr, "PARSED: company=%u cmd=%u tile=%u p1=%u p2=%u text=%s\n", cmd.company_id, cmd.cmd, cmd.tile, cmd.p1, cmd.p2, cmd.text.c_str());
_fake_commands.push(cmd);
}
return true;
}
} // namespace citymania

View File

@@ -1,11 +1,16 @@
#ifndef CM_CONSOLE_CMDS_HPP
#define CM_CONSOLE_CMDS_HPP
#include "../date_type.h"
namespace citymania {
bool ConStep(byte argc, char *argv[]);
bool ConExport(byte argc, char *argv[]);
bool ConTreeMap(byte argc, char *argv[]);
bool ConResetTownGrowth(byte argc, char *argv[]);
bool ConLoadCommands(byte argc, char *argv[]);
void ExecuteFakeCommands(Date date, DateFract date_fract);
} // namespace citymania

View File

@@ -1,20 +1,25 @@
#include "../stdafx.h"
#include "cm_highlight.hpp"
// #include "cm_blueprint.hpp"
#include "cm_main.hpp"
#include "cm_station_gui.hpp"
#include "cm_zoning.hpp"
#include "../core/math_func.hpp"
#include "../table/bridge_land.h"
#include "../command_func.h"
#include "../house.h"
#include "../industry.h"
#include "../landscape.h"
#include "../newgrf_railtype.h"
#include "../newgrf_station.h"
#include "../town.h"
#include "../town_kdtree.h"
#include "../tilearea_type.h"
#include "../tilehighlight_type.h"
#include "../tilehighlight_func.h"
#include "../viewport_func.h"
#include "../table/track_land.h"
@@ -36,6 +41,17 @@ extern RailType _cur_railtype;
RoadBits FindRailsToConnect(TileIndex tile);
extern DiagDirection _build_depot_direction; ///< Currently selected depot direction
extern uint32 _realtime_tick;
extern void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec);
struct RailStationGUISettings {
Axis orientation; ///< Currently selected rail station orientation
bool newstations; ///< Are custom station definitions available?
StationClassID station_class; ///< Currently selected custom station class (if newstations is \c true )
byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true )
byte station_count; ///< Number of custom stations (if newstations is \c true )
};
extern RailStationGUISettings _railstation; ///< Settings of the station builder GUI
namespace citymania {
@@ -71,27 +87,58 @@ const byte _tileh_to_sprite[32] = {
0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
};
ObjectTileHighlight ObjectTileHighlight::make_depot(DiagDirection ddir) {
auto oh = ObjectTileHighlight(Type::RAIL_DEPOT);
oh.u.depot.ddir = ddir;
ObjectTileHighlight ObjectTileHighlight::make_rail_depot(SpriteID palette, DiagDirection ddir) {
auto oh = ObjectTileHighlight(Type::RAIL_DEPOT, palette);
oh.u.rail.depot.ddir = ddir;
return oh;
}
ObjectTileHighlight ObjectTileHighlight::make_rail(Track track) {
auto oh = ObjectTileHighlight(Type::RAIL_TRACK);
ObjectTileHighlight ObjectTileHighlight::make_rail_track(SpriteID palette, Track track) {
auto oh = ObjectTileHighlight(Type::RAIL_TRACK, palette);
oh.u.rail.track = track;
return oh;
}
ObjectTileHighlight ObjectTileHighlight::make_rail_station(SpriteID palette, Axis axis, byte section) {
auto oh = ObjectTileHighlight(Type::RAIL_STATION, palette);
oh.u.rail.station.axis = axis;
oh.u.rail.station.section = section;
return oh;
}
ObjectTileHighlight ObjectTileHighlight::make_rail_signal(SpriteID palette, uint pos, SignalType type, SignalVariant variant) {
auto oh = ObjectTileHighlight(Type::RAIL_SIGNAL, palette);
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(SpriteID palette, DiagDirection ddir, BridgeType type) {
auto oh = ObjectTileHighlight(Type::RAIL_BRIDGE_HEAD, palette);
oh.u.rail.bridge_head.ddir = ddir;
oh.u.rail.bridge_head.type = type;
return oh;
}
ObjectTileHighlight ObjectTileHighlight::make_rail_tunnel_head(SpriteID palette, DiagDirection ddir) {
auto oh = ObjectTileHighlight(Type::RAIL_TUNNEL_HEAD, palette);
oh.u.rail.tunnel_head.ddir = ddir;
return oh;
}
bool ObjectHighlight::operator==(const ObjectHighlight& oh) {
if (this->type != oh.type) return false;
switch (this->type) {
case Type::RAIL_DEPOT: return this->u.depot.tile == oh.u.depot.tile && this->u.depot.ddir == oh.u.depot.ddir;
default: return true;
}
return true;
return (this->tile == oh.tile
&& this->end_tile == oh.end_tile
&& this->axis == oh.axis
&& this->ddir == oh.ddir
&& this->blueprint == oh.blueprint);
// switch (this->type) {
// case Type::RAIL_DEPOT: return this->tile == oh.tile && this->ddir == oh.ddir;
// default: return true;
// }
// return true;
}
bool ObjectHighlight::operator!=(const ObjectHighlight& oh) {
@@ -99,13 +146,28 @@ bool ObjectHighlight::operator!=(const ObjectHighlight& oh) {
}
ObjectHighlight ObjectHighlight::make_depot(TileIndex tile, DiagDirection ddir) {
auto oh = ObjectHighlight(ObjectHighlight::Type::RAIL_DEPOT);
oh.u.depot.tile = tile;
oh.u.depot.ddir = ddir;
ObjectHighlight ObjectHighlight::make_rail_depot(TileIndex tile, DiagDirection ddir) {
auto oh = ObjectHighlight{ObjectHighlight::Type::RAIL_DEPOT};
oh.tile = tile;
oh.ddir = ddir;
return oh;
}
ObjectHighlight ObjectHighlight::make_rail_station(TileIndex start_tile, TileIndex end_tile, Axis axis) {
auto oh = ObjectHighlight{ObjectHighlight::Type::RAIL_STATION};
oh.tile = start_tile;
oh.end_tile = end_tile;
oh.axis = axis;
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;
// }
/**
* Try to add an additional rail-track at the entrance of a depot
* @param tile Tile to use for adding the rail-track
@@ -118,7 +180,7 @@ void ObjectHighlight::PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Tra
if (GetRailTileType(tile) != RAIL_TILE_NORMAL) 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(PALETTE_TINT_WHITE, track)));
}
/** Additional pieces of track to add at the entrance of a depot. */
@@ -135,22 +197,84 @@ static const DiagDirection _place_depot_extra_dir[12] = {
DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE,
};
static bool CanBuild(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) {
return DoCommandPInternal(
tile,
p1,
p2,
cmd,
nullptr, // callback
nullptr, // text
true, // my_cmd
true // estimate_only
).Succeeded();
}
void ObjectHighlight::UpdateTiles() {
this->tiles.clear();
switch (this->type) {
case Type::NONE:
break;
case Type::RAIL_DEPOT: {
auto dir = this->u.depot.ddir;
this->tiles.insert(std::make_pair(this->u.depot.tile, ObjectTileHighlight::make_depot(dir)));
auto tile = this->u.depot.tile + TileOffsByDiagDir(dir);
auto dir = this->ddir;
auto palette = (CanBuild(
this->tile,
_cur_railtype,
dir,
CMD_BUILD_TRAIN_DEPOT
) ? PALETTE_TINT_WHITE : PALETTE_TINT_RED_DEEP);
this->tiles.insert(std::make_pair(this->tile, ObjectTileHighlight::make_rail_depot(palette, dir)));
auto tile = this->tile + TileOffsByDiagDir(dir);
if (IsTileType(tile, MP_RAILWAY) && IsCompatibleRail(GetRailType(tile), _cur_railtype)) {
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]);
PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]);
this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]);
this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]);
this->PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]);
}
break;
}
default:
case Type::RAIL_STATION: {
auto ta = OrthogonalTileArea(this->tile, this->end_tile);
auto numtracks = ta.w;
auto plat_len = ta.h;
if (this->axis == AXIS_X) Swap(numtracks, plat_len);
auto palette = (CanBuild(
this->tile,
_cur_railtype
| (this->axis << 6)
| ((uint32)numtracks << 8)
| ((uint32)plat_len << 16),
NEW_STATION << 16,
CMD_BUILD_RAIL_STATION
) ? PALETTE_TINT_WHITE : PALETTE_TINT_RED_DEEP);
auto layout_ptr = AllocaM(byte, (int)numtracks * plat_len);
GetStationLayout(layout_ptr, numtracks, plat_len, nullptr); // TODO statspec
auto tile_delta = (this->axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
TileIndex tile_track = this->tile;
do {
TileIndex tile = tile_track;
int w = plat_len;
do {
byte layout = *layout_ptr++;
this->tiles.insert(std::make_pair(tile, ObjectTileHighlight::make_rail_station(palette, this->axis, layout & ~1)));
tile += tile_delta;
} while (--w);
tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
} while (--numtracks);
break;
}
// case Type::BLUEPRINT:
// if (this->blueprint && this->tile != INVALID_TILE)
// this->tiles = this->blueprint->GetTiles(this->tile);
// break;
default:
NOT_REACHED();
}
}
@@ -162,7 +286,43 @@ void ObjectHighlight::MarkDirty() {
}
void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection ddir)
SpriteID GetTintBySelectionColour(SpriteID colour, bool deep=false) {
switch(colour) {
case SPR_PALETTE_ZONING_RED: return (deep ? PALETTE_TINT_RED_DEEP : PALETTE_TINT_RED);
case SPR_PALETTE_ZONING_ORANGE: return (deep ? PALETTE_TINT_ORANGE_DEEP : PALETTE_TINT_ORANGE);
case SPR_PALETTE_ZONING_GREEN: return (deep ? PALETTE_TINT_GREEN_DEEP : PALETTE_TINT_GREEN);
case SPR_PALETTE_ZONING_LIGHT_BLUE: return (deep ? PALETTE_TINT_CYAN_DEEP : PALETTE_TINT_CYAN);
case SPR_PALETTE_ZONING_YELLOW: return PALETTE_TINT_YELLOW;
// case SPR_PALETTE_ZONING__: return PALETTE_TINT_YELLOW_WHITE;
case SPR_PALETTE_ZONING_WHITE: return PALETTE_TINT_WHITE;
default: return PAL_NONE;
}
}
SpriteID GetSelectionColourByTint(SpriteID colour) {
switch(colour) {
case PALETTE_TINT_RED_DEEP:
case PALETTE_TINT_RED:
return SPR_PALETTE_ZONING_RED;
case PALETTE_TINT_ORANGE_DEEP:
case PALETTE_TINT_ORANGE:
return SPR_PALETTE_ZONING_ORANGE;
case PALETTE_TINT_GREEN_DEEP:
case PALETTE_TINT_GREEN:
return SPR_PALETTE_ZONING_GREEN;
case PALETTE_TINT_CYAN_DEEP:
case PALETTE_TINT_CYAN:
return SPR_PALETTE_ZONING_LIGHT_BLUE;
case PALETTE_TINT_YELLOW:
return SPR_PALETTE_ZONING_YELLOW;
// returnase SPR_PALETTE_ZONING__: return PALETTE_TINT_YELLOW_WHITE;
case PALETTE_TINT_WHITE:
return SPR_PALETTE_ZONING_WHITE;
default: return PAL_NONE;
}
}
void DrawTrainDepotSprite(SpriteID palette, const TileInfo *ti, RailType railtype, DiagDirection ddir)
{
const DrawTileSprites *dts = &_depot_gfx_table[ddir];
const RailtypeInfo *rti = GetRailTypeInfo(railtype);
@@ -170,13 +330,13 @@ void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection d
uint32 offset = rti->GetRailtypeSpriteOffset();
if (image != SPR_FLAT_GRASS_TILE) image += offset;
PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
// PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
// DrawSprite(image, PAL_NONE, x, y);
switch (ddir) {
case DIAGDIR_SW: DrawAutorailSelection(ti, HT_DIR_X, PAL_NONE); break;
case DIAGDIR_SE: DrawAutorailSelection(ti, HT_DIR_Y, PAL_NONE); break;
case DIAGDIR_SW: DrawAutorailSelection(ti, HT_DIR_X, GetSelectionColourByTint(palette)); break;
case DIAGDIR_SE: DrawAutorailSelection(ti, HT_DIR_Y, GetSelectionColourByTint(palette)); break;
default: break;
}
// if (rti->UsesOverlay()) {
@@ -191,27 +351,208 @@ void DrawTrainDepotSprite(const TileInfo *ti, RailType railtype, DiagDirection d
int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, PALETTE_TINT_WHITE);
DrawRailTileSeq(ti, dts, TO_INVALID, offset, 0, palette);
}
void DrawTrainStationSprite(SpriteID palette, const TileInfo *ti, RailType railtype, Axis axis, byte section) {
int32 total_offset = 0;
PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company);
const DrawTileSprites *t = GetStationTileLayout(STATION_RAIL, section + (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), GetSelectionColourByTint(palette));
// 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);
}
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) {
this->UpdateTiles();
auto range = this->tiles.equal_range(ti->tile);
for (auto t = range.first; t != range.second; t++) {
auto &oth = t->second;
switch (oth.type) {
case ObjectTileHighlight::Type::RAIL_DEPOT:
DrawTrainDepotSprite(ti, _cur_railtype, oth.u.depot.ddir);
DrawTrainDepotSprite(oth.palette, ti, _cur_railtype, oth.u.rail.depot.ddir);
break;
case ObjectTileHighlight::Type::RAIL_TRACK: {
auto hs = (HighLightStyle)oth.u.rail.track;
DrawAutorailSelection(ti, hs, PAL_NONE);
break;
}
case ObjectTileHighlight::Type::RAIL_STATION:
DrawTrainStationSprite(oth.palette, ti, _cur_railtype, oth.u.rail.station.axis, oth.u.rail.station.section);
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:
break;
}
}
// fprintf(stderr, "TILEH DRAW %d %d %d\n", ti->tile, (int)i, (int)this->tiles.size());
}
@@ -294,19 +635,6 @@ SpriteID GetIndustryZoningPalette(TileIndex tile) {
return PAL_NONE;
}
SpriteID GetTintBySelectionColour(SpriteID colour, bool deep=false) {
switch(colour) {
case SPR_PALETTE_ZONING_RED: return (deep ? PALETTE_TINT_RED_DEEP : PALETTE_TINT_RED);
case SPR_PALETTE_ZONING_ORANGE: return (deep ? PALETTE_TINT_ORANGE_DEEP : PALETTE_TINT_ORANGE);
case SPR_PALETTE_ZONING_GREEN: return (deep ? PALETTE_TINT_GREEN_DEEP : PALETTE_TINT_GREEN);
case SPR_PALETTE_ZONING_LIGHT_BLUE: return (deep ? PALETTE_TINT_CYAN_DEEP : PALETTE_TINT_CYAN);
case SPR_PALETTE_ZONING_YELLOW: return PALETTE_TINT_YELLOW;
// case SPR_PALETTE_ZONING__: return PALETTE_TINT_YELLOW_WHITE;
case SPR_PALETTE_ZONING_WHITE: return PALETTE_TINT_WHITE;
default: return PAL_NONE;
}
}
static void SetStationSelectionHighlight(const TileInfo *ti, TileHighlight &th) {
bool draw_selection = ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0);
const Station *highlight_station = _viewport_highlight_station;
@@ -314,17 +642,20 @@ static void SetStationSelectionHighlight(const TileInfo *ti, TileHighlight &th)
if (_highlight_station_to_join) highlight_station = _highlight_station_to_join;
if (draw_selection) {
auto b = CalcTileBorders(ti->tile, [](TileIndex t) {
auto x = TileX(t) * TILE_SIZE, y = TileY(t) * TILE_SIZE;
return IsInsideSelectedRectangle(x, y);
});
const SpriteID pal[] = {SPR_PALETTE_ZONING_RED, SPR_PALETTE_ZONING_YELLOW, SPR_PALETTE_ZONING_LIGHT_BLUE, SPR_PALETTE_ZONING_GREEN};
auto color = pal[(int)_station_building_status];
if (_thd.make_square_red) color = SPR_PALETTE_ZONING_RED;
if (b.first != ZoningBorder::NONE)
th.add_border(b.first, color);
// const SpriteID pal[] = {SPR_PALETTE_ZONING_RED, SPR_PALETTE_ZONING_YELLOW, SPR_PALETTE_ZONING_LIGHT_BLUE, SPR_PALETTE_ZONING_GREEN};
// auto color = pal[(int)_station_building_status];
// if (_thd.make_square_red) color = SPR_PALETTE_ZONING_RED;
if (_thd.make_square_red) {
auto b = CalcTileBorders(ti->tile, [](TileIndex t) {
auto x = TileX(t) * TILE_SIZE, y = TileY(t) * TILE_SIZE;
return IsInsideSelectedRectangle(x, y);
});
if (b.first != ZoningBorder::NONE)
th.add_border(b.first, SPR_PALETTE_ZONING_RED);
}
if (IsInsideSelectedRectangle(TileX(ti->tile) * TILE_SIZE, TileY(ti->tile) * TILE_SIZE)) {
th.ground_pal = GetTintBySelectionColour(color);
// th.ground_pal = GetTintBySelectionColour(color);
th.ground_pal = th.structure_pal = (_thd.make_square_red ? PALETTE_TINT_RED : PAL_NONE);
return;
}
}
@@ -529,6 +860,7 @@ TileHighlight GetTileHighlight(const TileInfo *ti) {
}
SetStationSelectionHighlight(ti, th);
// SetBlueprintHighlight(ti, th);
return th;
}
@@ -549,6 +881,8 @@ void DrawTileZoning(const TileInfo *ti, const TileHighlight &th) {
bool DrawTileSelection(const TileInfo *ti, const TileHighlightType &tht) {
_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) {
// station selector, handled by DrawTileZoning
return true;
@@ -612,17 +946,65 @@ DiagDirection AutodetectRailObjectDirection(TileIndex tile, Point pt) {
NOT_REACHED();
}
TileIndex _autodetection_tile = INVALID_TILE;
DiagDirDiff _autodetection_rotation = DIAGDIRDIFF_SAME;
static DiagDirDiff GetAutodetectionRotation() {
auto pt = GetTileBelowCursor();
auto tile = TileVirtXY(pt.x, pt.y);
if (tile != _autodetection_tile) {
_autodetection_tile = tile;
_autodetection_rotation = DIAGDIRDIFF_SAME;
}
return _autodetection_rotation;
}
void RotateAutodetection() {
auto rotation = GetAutodetectionRotation();
if (rotation == DIAGDIRDIFF_90LEFT) rotation = DIAGDIRDIFF_SAME;
else rotation++;
_autodetection_rotation = rotation;
::UpdateTileSelection();
}
void ResetRotateAutodetection() {
_autodetection_tile = INVALID_TILE;
_autodetection_rotation = DIAGDIRDIFF_SAME;
}
DiagDirection AddAutodetectionRotation(DiagDirection ddir) {
return ChangeDiagDir(ddir, GetAutodetectionRotation());
}
HighLightStyle UpdateTileSelection(HighLightStyle new_drawstyle) {
_thd.cm_new = ObjectHighlight(ObjectHighlight::Type::NONE);
auto pt = GetTileBelowCursor();
auto tile = (pt.x == -1 ? INVALID_TILE : TileVirtXY(pt.x, pt.y));
// fprintf(stderr, "UPDATE %d %d %d %d\n", tile, _thd.size.x, _thd.size.y, (int)((_thd.place_mode & HT_DRAG_MASK) == HT_RECT));
// 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) {
auto dir = _build_depot_direction;
auto pt = GetTileBelowCursor();
auto tile = TileVirtXY(pt.x, pt.y);
if (pt.x != -1) {
if (dir >= DiagDirection::DIAGDIR_END)
dir = AutodetectRailObjectDirection(tile, pt);
_thd.cm_new = ObjectHighlight::make_depot(tile, dir);
if (dir >= DiagDirection::DIAGDIR_END) {
dir = AddAutodetectionRotation(AutodetectRailObjectDirection(tile, pt));
}
_thd.cm_new = ObjectHighlight::make_rail_depot(tile, dir);
}
new_drawstyle = HT_RECT;
} else if (((_thd.place_mode & HT_DRAG_MASK) == HT_RECT || ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL && (_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT)) && _thd.new_outersize.x > 0 && !_thd.make_square_red) { // station
if (_thd.size.x >= (int)TILE_SIZE && _thd.size.y >= (int)TILE_SIZE) {
auto start_tile = TileXY(_thd.new_pos.x / TILE_SIZE, _thd.new_pos.y / TILE_SIZE);
auto end_tile = TileXY(
std::min((_thd.new_pos.x + _thd.new_size.x) / TILE_SIZE, MapSizeX()) - 1,
std::min((_thd.new_pos.y + _thd.new_size.y) / TILE_SIZE, MapSizeY()) - 1
);
_thd.cm_new = ObjectHighlight::make_rail_station(start_tile, end_tile, _railstation.orientation);
}
new_drawstyle = HT_RECT;
}

View File

@@ -96,6 +96,9 @@ void SetIndustryForbiddenTilesHighlight(IndustryType type);
PaletteID GetTreeShadePal(TileIndex tile);
void RotateAutodetection();
void ResetRotateAutodetection();
} // namespace citymania
#endif

View File

@@ -1,36 +1,155 @@
#ifndef CITYMANIA_HIGHLIGHT_TYPE_HPP
#define CITYMANIA_HIGHLIGHT_TYPE_HPP
#include "../bridge.h"
#include "../direction_type.h"
#include "../map_func.h"
#include "../signal_type.h"
#include "../station_type.h"
#include "../tile_cmd.h"
#include "../tile_type.h"
#include "../track_type.h"
#include <map>
#include <set>
#include <vector>
namespace citymania {
class ObjectTileHighlight {
public:
enum class Type {
RAIL_DEPOT = 0,
RAIL_TRACK = 1,
BEGIN = 0,
RAIL_DEPOT = BEGIN,
RAIL_TRACK,
RAIL_STATION,
RAIL_SIGNAL,
RAIL_BRIDGE_HEAD,
RAIL_TUNNEL_HEAD,
END,
};
Type type;
SpriteID palette;
union {
struct {
DiagDirection ddir;
} depot;
struct {
struct {
DiagDirection ddir;
} depot;
Track track;
struct {
Axis axis;
byte section;
} 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;
} u;
ObjectTileHighlight(Type type): type{type} {}
static ObjectTileHighlight make_depot(DiagDirection ddir);
static ObjectTileHighlight make_rail(Track track);
ObjectTileHighlight(Type type, SpriteID palette): type{type}, palette{palette} {}
static ObjectTileHighlight make_rail_depot(SpriteID palette, DiagDirection ddir);
static ObjectTileHighlight make_rail_track(SpriteID palette, Track track);
static ObjectTileHighlight make_rail_station(SpriteID palette, Axis axis, byte section);
static ObjectTileHighlight make_rail_signal(SpriteID palette, uint pos, SignalType type, SignalVariant variant);
static ObjectTileHighlight make_rail_bridge_head(SpriteID palette, DiagDirection ddir, BridgeType type);
static ObjectTileHighlight make_rail_tunnel_head(SpriteID palette, DiagDirection ddir);
};
class TileIndexDiffCCompare{
public:
bool operator()(const TileIndexDiffC &a, const TileIndexDiffC &b) const {
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 {
@@ -38,28 +157,31 @@ public:
enum class Type {
NONE = 0,
RAIL_DEPOT = 1,
RAIL_STATION = 2,
// BLUEPRINT = 2,
};
protected:
Type type;
union {
struct {
TileIndex tile;
DiagDirection ddir;
} depot;
} u;
TileIndex tile = INVALID_TILE;
TileIndex end_tile = INVALID_TILE;
Axis axis = INVALID_AXIS;
DiagDirection ddir = INVALID_DIAGDIR;
sp<Blueprint> blueprint = nullptr;
protected:
bool tiles_updated = false;
std::multimap<TileIndex, ObjectTileHighlight> tiles;
void UpdateTiles();
void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track);
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);
static ObjectHighlight make_depot(TileIndex tile, DiagDirection ddir);
static ObjectHighlight make_rail_depot(TileIndex tile, DiagDirection ddir);
static ObjectHighlight make_rail_station(TileIndex start_tile, TileIndex end_tile, Axis axis);
// static ObjectHighlight make_blueprint(TileIndex tile, sp<Blueprint> blueprint);
void Draw(const TileInfo *ti);
void MarkDirty();

View File

@@ -34,6 +34,9 @@ bool _fn_mod = false;
bool _remove_mod = false;
bool _estimate_mod = false;
bool _middle_button_down; ///< Is middle mouse button pressed?
bool _middle_button_clicked; ///< Is middle mouse button clicked?
static uint32 _effective_actions = 0;
static std::optional<std::chrono::steady_clock::time_point> _first_effective_tick = {};
static std::queue<std::chrono::steady_clock::time_point> _last_actions;

View File

@@ -259,6 +259,9 @@ void DecodeSettings(BitIStream &bs, Settings &settings) {
uint16 _last_client_version = 1512;
static u8vector EncodeData() {
// Skip if game is not initialized for some reason (i.e. -d desync)
if (!_game) return {};
BitOStream bs;
bs.Reserve(1000);
bs.WriteBytes(SAVEGAME_DATA_FORMAT_VERSION, 2);

View File

@@ -8,16 +8,28 @@
#include "../command_type.h"
#include "../command_func.h"
#include "../company_func.h"
#include "../industry_map.h"
#include "../industry.h"
#include "../landscape.h"
#include "../newgrf_station.h" // StationClassID
#include "../newgrf_house.h" // GetHouseCallback
#include "../newgrf_cargo.h" // GetCargoTranslation
#include "../object_type.h"
#include "../object_map.h"
#include "../station_base.h"
#include "../strings_func.h" // GetString, SetDParam
#include "../tilehighlight_type.h"
#include "../town_map.h"
#include "../town.h"
#include "../viewport_func.h"
#include "../viewport_kdtree.h"
#include "../window_gui.h"
#include "../zoom_type.h"
#include "../zoom_func.h"
#include <sstream>
extern const Station *_viewport_highlight_station;
extern TileHighlightData _thd;
extern void MarkCatchmentTilesDirty();
@@ -332,21 +344,21 @@ static void FindStationsAroundSelection(const TileArea &location)
_station_building_status = (adjacent == nullptr ? StationBuildingStatus::NEW : StationBuildingStatus::JOIN);
}
void CheckRedrawStationCoverage() {
bool CheckRedrawStationCoverage() {
// static bool last_ctrl_pressed = false;
static TileArea last_location;
static bool last_station_mode = false;
static bool last_coverage = false;
static bool last_fn_mod = false;
TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1);
bool station_mode = ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0);
bool location_changed = (location.tile != last_location.tile || location.w != last_location.w || location.h != last_location.h);
bool mode_changed = (last_station_mode != station_mode);
// if (!location_changed && _ctrl_pressed == last_ctrl_pressed && !mode_changed)
// return;
if (!location_changed && citymania::_fn_mod == last_fn_mod && !mode_changed)
return false;
// last_ctrl_pressed = _ctrl_pressed;
// last_location = location;
// last_station_mode = station_mode;
last_fn_mod = citymania::_fn_mod;
last_location = location;
last_station_mode = station_mode;
if (citymania::_fn_mod) {
Station *st = nullptr;
@@ -363,6 +375,7 @@ void CheckRedrawStationCoverage() {
FindStationsAroundSelection(location);
}
}
return true;
}
@@ -380,4 +393,133 @@ void AbortStationPlacement() {
}
uint GetMonthlyFrom256Tick(uint amount) {
return ((amount * DAY_TICKS * 30) >> 8);
}
uint GetAverageHouseProduction(byte amount) {
static const uint AVG[2][256] = {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 42, 45, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 90, 95, 100, 105, 110, 115, 120, 126, 132, 138, 144, 150, 156, 162, 168, 175, 182, 189, 196, 203, 210, 217, 224, 232, 240, 248, 256, 264, 272, 280, 288, 297, 306, 315, 324, 333, 342, 351, 360, 370, 380, 390, 400, 410, 420, 430, 440, 451, 462, 473, 484, 495, 506, 517, 528, 540, 552, 564, 576, 588, 600, 612, 624, 637, 650, 663, 676, 689, 702, 715, 728, 742, 756, 770, 784, 798, 812, 826, 840, 855, 870, 885, 900, 915, 930, 945, 960, 976, 992, 1008, 1024, 1040, 1056, 1072, 1088, 1105, 1122, 1139, 1156, 1173, 1190, 1207, 1224, 1242, 1260, 1278, 1296, 1314, 1332, 1350, 1368, 1387, 1406, 1425, 1444, 1463, 1482, 1501, 1520, 1540, 1560, 1580, 1600, 1620, 1640, 1660, 1680, 1701, 1722, 1743, 1764, 1785, 1806, 1827, 1848, 1870, 1892, 1914, 1936, 1958, 1980, 2002, 2024, 2047, 2070, 2093, 2116, 2139, 2162, 2185, 2208, 2232, 2256, 2280, 2304, 2328, 2352, 2376, 2400, 2425, 2450, 2475, 2500, 2525, 2550, 2575, 2600, 2626, 2652, 2678, 2704, 2730, 2756, 2782, 2808, 2835, 2862, 2889, 2916, 2943, 2970, 2997, 3024, 3052, 3080, 3108, 3136, 3164, 3192, 3220, 3248, 3277, 3306, 3335, 3364, 3393, 3422, 3451, 3480, 3510, 3540, 3570, 3600, 3630, 3660, 3690, 3720, 3751, 3782, 3813, 3844, 3875, 3906, 3937, 3968, 4000, 4032, 4064, 4096, 4128, 4160, 4192},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 246, 252, 258, 264, 270, 276, 282, 288, 294, 300, 306, 312, 318, 324, 330, 336, 343, 350, 357, 364, 371, 378, 385, 392, 399, 406, 413, 420, 427, 434, 441, 448, 456, 464, 472, 480, 488, 496, 504, 512, 520, 528, 536, 544, 552, 560, 568, 576, 585, 594, 603, 612, 621, 630, 639, 648, 657, 666, 675, 684, 693, 702, 711, 720, 730, 740, 750, 760, 770, 780, 790, 800, 810, 820, 830, 840, 850, 860, 870, 880, 891, 902, 913, 924, 935, 946, 957, 968, 979, 990, 1001, 1012, 1023, 1034, 1045, 1056, 1068, 1080, 1092, 1104, 1116, 1128, 1140, 1152, 1164, 1176, 1188, 1200, 1212, 1224, 1236, 1248, 1261, 1274, 1287, 1300, 1313, 1326, 1339, 1352, 1365, 1378, 1391, 1404, 1417, 1430, 1443, 1456, 1470, 1484, 1498, 1512, 1526, 1540, 1554, 1568, 1582, 1596, 1610, 1624, 1638, 1652, 1666, 1680, 1695, 1710, 1725, 1740, 1755, 1770, 1785, 1800, 1815, 1830, 1845, 1860, 1875, 1890, 1905, 1920, 1936, 1952, 1968, 1984, 2000, 2016, 2032, 2048, 2064, 2080, 2096, 2112, 2128, 2144, 2160}
};
if (amount == 0) return 0;
switch (_settings_game.economy.town_cargogen_mode) {
case TCGM_ORIGINAL:
return GetMonthlyFrom256Tick(AVG[EconomyIsInRecession() ? 1 : 0][amount]);
case TCGM_BITCOUNT: {
uint amt = (amount + 7) / 8;
if (EconomyIsInRecession()) amt += 2;
else amt *= 2;
return GetMonthlyFrom256Tick(amt * 16);
}
default:
NOT_REACHED();
}
return 0;
}
static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced)
{
if (!IsHouseCompleted(tile)) return;
HouseID house_id = GetHouseType(tile);
const HouseSpec *hs = HouseSpec::Get(house_id);
Town *t = Town::GetByTile(tile);
if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
for (uint i = 0; i < 256; i++) {
uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile);
if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile);
if (cargo == CT_INVALID) continue;
produced[cargo] += GetMonthlyFrom256Tick((uint)GB(callback, 0, 8)) ;
}
} else {
produced[CT_PASSENGERS] += GetAverageHouseProduction(hs->population);
produced[CT_MAIL] += GetAverageHouseProduction(hs->mail_generation);
}
}
// Similar to ::GetProductionAroundTiles but counts production total
CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
{
static const uint HQ_AVG_POP[2][5] = {
{48, 64, 84, 128, 384},
{48, 64, 84, 128, 256},
};
static const uint HQ_AVG_MAIL[2][5] = {
{36, 48, 64, 96, 264},
{36, 48, 64, 96, 196}
};
CargoArray produced;
std::set<IndustryID> industries;
TileArea ta = TileArea(tile, w, h).Expand(rad);
/* Loop over all tiles to get the produced cargo of
* everything except industries */
TILE_AREA_LOOP(tile, ta) {
switch (GetTileType(tile)) {
case MP_INDUSTRY:
industries.insert(GetIndustryIndex(tile));
break;
case MP_HOUSE:
AddProducedCargo_Town(tile, produced);
break;
case MP_OBJECT:
if (IsObjectType(tile, OBJECT_HQ)) {
produced[CT_PASSENGERS] += GetMonthlyFrom256Tick(HQ_AVG_POP[EconomyIsInRecession() ? 1 : 0][GetAnimationFrame(tile)]);
produced[CT_MAIL] += GetMonthlyFrom256Tick(HQ_AVG_MAIL[EconomyIsInRecession() ? 1 : 0][GetAnimationFrame(tile)]);
}
default: break;
}
}
/* Loop over the seen industries. They produce cargo for
* anything that is within 'rad' of any one of their tiles.
*/
for (IndustryID industry : industries) {
const Industry *i = Industry::Get(industry);
/* Skip industry with neutral station */
if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) continue;
for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
CargoID cargo = i->produced_cargo[j];
if (cargo != CT_INVALID) produced[cargo] += ((uint)i->last_month_production[j]) << 8;
}
}
return produced;
}
std::string GetStationCoverageProductionText(TileIndex tile, int w, int h, int rad, StationCoverageType sct) {
auto production = GetProductionAroundTiles(tile, w, h, rad);
std::ostringstream s;
char buffer[DRAW_STRING_BUFFER];
GetString(buffer, STR_CM_STATION_BUILD_SUPPLIES, lastof(buffer));
s << buffer;
bool first = true;
for (CargoID i = 0; i < NUM_CARGO; i++) {
switch (sct) {
case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break;
case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break;
case SCT_ALL: break;
default: NOT_REACHED();
}
if (production[i] == 0) continue;
if (!first) s << ", ";
first = false;
SetDParam(0, i);
SetDParam(1, production[i] >> 8);
// GetString(buffer, STR_CM_STATION_BUILD_SUPPLIES_CARGO, lastof(buffer));
GetString(buffer, STR_JUST_CARGO, lastof(buffer));
s << buffer;
}
return s.str();
}
} // namespace citymania

View File

@@ -3,6 +3,7 @@
#include "../core/geometry_type.hpp"
#include "../command_type.h"
#include "../station_gui.h"
#include "../station_type.h"
namespace citymania {
@@ -28,9 +29,11 @@ void PlaceAirport(TileIndex tile);
void SelectStationToJoin(const Station *station);
// const Station *GetStationToJoin();
void MarkCoverageHighlightDirty();
void CheckRedrawStationCoverage();
bool CheckRedrawStationCoverage();
void AbortStationPlacement();
std::string GetStationCoverageProductionText(TileIndex tile, int w, int h, int rad, StationCoverageType sct);
} // namespace citymania
#endif

View File

@@ -590,8 +590,6 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY)
AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index);
Game::NewEvent(new ScriptEventCompanyNew(c->index));
if (!is_ai) UpdateAllTownVirtCoords(); //coloured rating
return c;
}
@@ -862,6 +860,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
* all clients so everything is in sync */
SyncCompanySettings();
UpdateAllTownVirtCoords(); // CityMania (for colouring towns)
MarkWholeScreenDirty();
}

View File

@@ -2459,4 +2459,6 @@ void IConsoleStdLibRegister()
IConsoleCmdRegister("cmexport", citymania::ConExport);
IConsoleCmdRegister("cmstep", citymania::ConStep, ConHookNoNetwork);
IConsoleCmdRegister("cmtreemap", citymania::ConTreeMap, ConHookNoNetwork);
IConsoleCmdRegister("cmresettowngrowth", citymania::ConResetTownGrowth, ConHookNoNetwork);
IConsoleCmdRegister("cmloadcommands", citymania::ConLoadCommands, ConHookNoNetwork);
}

View File

@@ -105,13 +105,17 @@ enum WindowKeyCodes {
WKC_L_BRACE = 154, ///< { Left brace
WKC_R_BRACE = 155, ///< } Right brace
WKC_L_PAREN = 157, ///< ( Left parentheses
WKC_R_PAREN = 158, ///< ) Right parentheses
WKC_PLUS = 159, ///< + Plus
WKC_EXCLAIM = 160, ///< ! Exclamation mark
WKC_ASTERISK = 161, ///< * Asterisk
WKC_DOLLAR = 162, ///< $ Dollar sign
CM_WKC_MOUSE_MIDDLE = 0x703, ///< CityMania: special code for middle mouse button
CM_WKC_MOUSE_OTHER_START = 0x704, ///< CityMania: start of the numbered buttons (whatever number driver reports), starts as MOUSE_4 hotkey
CM_WKC_MOUSE_OTHER_END = 0x71f, ///< CityMania: 30 buttons should be enough for any mouse, right? ;)
};
/** A single sprite of a list of animated cursors */

View File

@@ -95,6 +95,35 @@ static const KeycodeNames _keycode_to_name[] = {
{"R_PAREN", WKC_R_PAREN},
{"EXCLAIM", WKC_EXCLAIM},
{"ASTERISK", WKC_ASTERISK},
{"MOUSE_MIDDLE", CM_WKC_MOUSE_MIDDLE},
{"MOUSE_4", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 0)},
{"MOUSE_5", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 1)},
{"MOUSE_6", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 2)},
{"MOUSE_7", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 3)},
{"MOUSE_8", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 4)},
{"MOUSE_9", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 5)},
{"MOUSE_10", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 6)},
{"MOUSE_11", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 7)},
{"MOUSE_12", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 8)},
{"MOUSE_13", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 9)},
{"MOUSE_14", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 10)},
{"MOUSE_15", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 11)},
{"MOUSE_16", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 12)},
{"MOUSE_17", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 13)},
{"MOUSE_18", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 14)},
{"MOUSE_19", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 15)},
{"MOUSE_20", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 16)},
{"MOUSE_21", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 17)},
{"MOUSE_22", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 18)},
{"MOUSE_23", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 19)},
{"MOUSE_24", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 20)},
{"MOUSE_25", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 21)},
{"MOUSE_26", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 22)},
{"MOUSE_27", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 23)},
{"MOUSE_28", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 24)},
{"MOUSE_29", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 25)},
{"MOUSE_30", (WindowKeyCodes)(CM_WKC_MOUSE_OTHER_START + 26)},
};
/**

View File

@@ -3927,6 +3927,7 @@ STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit t
STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Reliability: {LTBLUE}{COMMA}% {BLACK}Breakdowns since last service: {LTBLUE}{COMMA}
STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}
STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK} ID: {LTBLUE}{NUM}
STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Capacity: {LTBLUE}None{STRING}
STR_VEHICLE_INFO_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING}
STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM})
@@ -3951,7 +3952,9 @@ STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Name air
# Extra buttons for train details windows
STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}
STR_CM_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE_WITH_ID :{LTBLUE}{ENGINE}{BLACK} Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK} ID: {LTBLUE}{NUM}
STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}
STR_CM_VEHICLE_DETAILS_TRAIN_WAGON_VALUE_WITH_ID :{LTBLUE}{ENGINE}{BLACK} Value: {LTBLUE}{CURRENCY_LONG}{BLACK} ID: {LTBLUE}{NUM}
STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Total cargo capacity of this train:
STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT})
@@ -5616,3 +5619,4 @@ 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_HELPTEXT : Adds APM (actions per minute) counter to the statusbar.
STR_CM_STATUSBAR_APM : {WHITE}APM: {NUM} AVG: {NUM}
STR_CM_STATION_BUILD_SUPPLIES :{BLACK}Supplies: {GOLD}

View File

@@ -70,6 +70,7 @@
#include "citymania/cm_highlight.hpp"
#include "citymania/cm_main.hpp"
#include "citymania/cm_console_cmds.hpp"
#include <stdarg.h>
#include <system_error>
@@ -1516,6 +1517,7 @@ void GameLoop()
* We do this here, because it means that the network is really closed */
NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR);
}
citymania::ExecuteFakeCommands(_date, _date_fract);
/* Singleplayer */
StateGameLoop();
}

View File

@@ -43,6 +43,7 @@
#include "widgets/rail_widget.h"
#include "citymania/cm_hotkeys.hpp"
#include "citymania/cm_highlight.hpp"
#include "citymania/cm_station_gui.hpp"
#include "safeguards.h"
@@ -508,30 +509,6 @@ RoadBits FindRailsToConnect(TileIndex tile) {
return passing;
}
/*
* Selects orientation for rail object (depot)
*/
DiagDirection AutodetectRailObjectDirection(TileIndex tile) {
RoadBits bits = FindRailsToConnect(tile);
// FIXME after this point repeats road autodetection
if (HasExactlyOneBit(bits)) return RoadBitsToDiagDir(bits);
if (bits == ROAD_NONE) bits = ROAD_ALL;
RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir());
if (HasExactlyOneBit(frac_bits & bits)) {
return RoadBitsToDiagDir(frac_bits & bits);
}
frac_bits |= MirrorRoadBits(frac_bits);
if (HasExactlyOneBit(frac_bits & bits)) {
return RoadBitsToDiagDir(frac_bits & bits);
}
for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) {
if (DiagDirToRoadBits(ddir) & bits) {
return ddir;
}
}
NOT_REACHED();
}
/** Rail toolbar management class. */
struct BuildRailToolbarWindow : Window {
RailType railtype; ///< Rail type to build.
@@ -719,6 +696,7 @@ struct BuildRailToolbarWindow : Window {
case WID_RAT_BUILD_DEPOT:
if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT | (HighLightStyle)_build_depot_direction)) {
citymania::ResetRotateAutodetection();
ShowBuildTrainDepotPicker(this);
this->last_user_action = widget;
}
@@ -850,7 +828,8 @@ struct BuildRailToolbarWindow : Window {
case WID_RAT_BUILD_DEPOT:
ddir = _build_depot_direction;
if (ddir == DIAGDIR_NW + 1) {
ddir = AutodetectRailObjectDirection(tile);
assert(_thd.cm.type == citymania::ObjectHighlight::Type::RAIL_DEPOT);
ddir = _thd.cm.ddir;
}
DoCommandP(tile, _cur_railtype, ddir,
CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT),
@@ -1120,7 +1099,14 @@ static void HandleStationPlacement(TileIndex start, TileIndex end)
ShowSelectStationIfNeeded(cmdcont, ta);
}
struct BuildRailStationWindow : public PickerWindowBase {
/* CityMania code start */
public:
enum class Hotkey : int {
ROTATE,
};
/* CityMania code end */
private:
uint line_height; ///< Height of a single line in the newstation selection matrix (#WID_BRAS_NEWST_LIST widget).
uint coverage_height; ///< Height of the coverage texts.
@@ -1727,6 +1713,30 @@ public:
{
CheckRedrawStationCoverage(this);
}
/* CityMania code start */
EventState OnHotkey(int hotkey) override
{
switch ((BuildRailStationWindow::Hotkey)hotkey) {
/* Indicate to the OnClick that the action comes from a hotkey rather
* then from a click and that the CTRL state should be ignored. */
case BuildRailStationWindow::Hotkey::ROTATE:
this->RaiseWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X);
_railstation.orientation = OtherAxis(_railstation.orientation);
this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X);
this->SetDirty();
DeleteWindowById(WC_SELECT_STATION, 0);
return ES_HANDLED;
default:
NOT_REACHED();
}
return ES_NOT_HANDLED;
}
static HotkeyList hotkeys;
/* CityMania code end */
};
Listing BuildRailStationWindow::last_sorting = { false, 0 };
@@ -1841,12 +1851,21 @@ static const NWidgetPart _nested_station_builder_widgets[] = {
EndContainer(),
};
/* CityMania code start */
static Hotkey build_station_hotkeys[] = {
Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailStationWindow::Hotkey::ROTATE),
HOTKEY_LIST_END
};
HotkeyList BuildRailStationWindow::hotkeys("cm_build_rail_station", build_station_hotkeys);
/* CityMania code end */
/** High level window description of the station-build window (default & newGRF) */
static WindowDesc _station_builder_desc(
WDP_AUTO, "build_station_rail", 350, 0,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_CONSTRUCTION,
_nested_station_builder_widgets, lengthof(_nested_station_builder_widgets)
_nested_station_builder_widgets, lengthof(_nested_station_builder_widgets),
&BuildRailStationWindow::hotkeys // CityMania addition
);
/** Open station build window */
@@ -2069,7 +2088,15 @@ static void ShowSignalBuilder(Window *parent)
new BuildSignalWindow(&_signal_builder_desc, parent);
}
struct BuildRailDepotWindow : public PickerWindowBase {
/* CityMania code start */
public:
enum class Hotkey : int {
ROTATE,
};
/* CityMania code end */
BuildRailDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent)
{
this->InitNested(TRANSPORT_RAIL);
@@ -2116,8 +2143,43 @@ struct BuildRailDepotWindow : public PickerWindowBase {
break;
}
}
/* CityMania code start */
EventState OnHotkey(int hotkey) override
{
switch ((BuildRailDepotWindow::Hotkey)hotkey) {
/* Indicate to the OnClick that the action comes from a hotkey rather
* then from a click and that the CTRL state should be ignored. */
case BuildRailDepotWindow::Hotkey::ROTATE:
if (_build_depot_direction < DIAGDIR_END) {
this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
_build_depot_direction = ChangeDiagDir(_build_depot_direction, DIAGDIRDIFF_90RIGHT);
this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE);
} else {
citymania::RotateAutodetection();
}
this->SetDirty();
return ES_HANDLED;
default:
NOT_REACHED();
}
return ES_NOT_HANDLED;
}
static HotkeyList hotkeys;
/* CityMania code end */
};
/* CityMania code start */
static Hotkey build_depot_hotkeys[] = {
Hotkey(CM_WKC_MOUSE_MIDDLE, "rotate", (int)BuildRailDepotWindow::Hotkey::ROTATE),
HOTKEY_LIST_END
};
HotkeyList BuildRailDepotWindow::hotkeys("cm_build_rail_depot", build_depot_hotkeys);
/* CityMania code end */
/** Nested widget definition of the build rail depot window */
static const NWidgetPart _nested_build_depot_widgets[] = {
NWidget(NWID_HORIZONTAL),
@@ -2159,7 +2221,8 @@ static WindowDesc _build_depot_desc(
WDP_AUTO, nullptr, 0, 0,
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
WDF_CONSTRUCTION,
_nested_build_depot_widgets, lengthof(_nested_build_depot_widgets)
_nested_build_depot_widgets, lengthof(_nested_build_depot_widgets),
&BuildRailDepotWindow::hotkeys // CityMania addition
);
static void ShowBuildTrainDepotPicker(Window *parent)

View File

@@ -36,7 +36,8 @@ void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y)
SetDParam(0, v->engine_type);
SetDParam(1, v->build_year);
SetDParam(2, v->value);
DrawString(left, right, y + y_offset, STR_VEHICLE_INFO_BUILT_VALUE);
if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM
DrawString(left, right, y + y_offset, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE);
if (v->HasArticulatedPart()) {
CargoArray max_cargo;

View File

@@ -66,7 +66,8 @@ void DrawShipDetails(const Vehicle *v, int left, int right, int y)
SetDParam(0, v->engine_type);
SetDParam(1, v->build_year);
SetDParam(2, v->value);
DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE);
if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM
DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_INFO_BUILT_VALUE_WITH_ID : STR_VEHICLE_INFO_BUILT_VALUE);
SetDParam(0, v->cargo_type);
SetDParam(1, v->cargo_cap);

View File

@@ -60,6 +60,13 @@ int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageTyp
TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
CargoTypes cargo_mask = 0;
if (_thd.drawstyle == HT_RECT && tile < MapSize()) {
/* CityMania code begin */
if (supplies) {
auto s = citymania::GetStationCoverageProductionText(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad, sct);
return DrawStringMultiLine(left, right, top, INT32_MAX, s.c_str());
}
/* CityMania code end */
CargoArray cargoes;
if (supplies) {
cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad);
@@ -146,10 +153,13 @@ static void FindStationsAroundSelection()
*/
void CheckRedrawStationCoverage(const Window *w)
{
/* CityMania code begin */
if (_settings_client.gui.cm_use_improved_station_join) {
citymania::CheckRedrawStationCoverage();
if (citymania::CheckRedrawStationCoverage()) w->SetDirty();
return;
}
/* CityMania code end */
/* Test if ctrl state changed */
static bool _last_fn_pressed;
if (citymania::_fn_mod != _last_fn_pressed) {

View File

@@ -4143,3 +4143,7 @@ void ResetHouses()
/* Reset any overrides that have been set. */
_house_mngr.ResetOverride();
}
namespace citymania {
auto UpdateTownGrowthRate = &::UpdateTownGrowthRate;
}

View File

@@ -223,15 +223,18 @@ static void TrainDetailsCargoTab(const CargoSummaryItem *item, int left, int rig
*/
static void TrainDetailsInfoTab(const Vehicle *v, int left, int right, int y)
{
if (RailVehInfo(v->engine_type)->railveh_type == RAILVEH_WAGON) {
SetDParam(0, v->engine_type);
SetDParam(1, v->value);
DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE);
if (_settings_client.gui.newgrf_developer_tools) SetDParam(2, v->index); // CM
DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_DETAILS_TRAIN_WAGON_VALUE_WITH_ID : STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE);
} else {
SetDParam(0, v->engine_type);
SetDParam(1, v->build_year);
SetDParam(2, v->value);
DrawString(left, right, y, STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE);
if (_settings_client.gui.newgrf_developer_tools) SetDParam(3, v->index); // CM
DrawString(left, right, y, _settings_client.gui.newgrf_developer_tools ? STR_CM_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE_WITH_ID : STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE);
}
}

View File

@@ -354,7 +354,8 @@ static void QZ_MouseMovedEvent(int x, int y)
}
static void QZ_MouseButtonEvent(int button, BOOL down)
static void
QZ_MouseButtonEvent(int button, BOOL down)
{
switch (button) {
case 0:
@@ -376,6 +377,18 @@ static void QZ_MouseButtonEvent(int button, BOOL down)
}
HandleMouseEvents();
break;
case 2:
HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0);
break;
default: {
int cm_button = CM_WKC_MOUSE_OTHER_START + button - 3;
if (!down && cm_button >= CM_WKC_MOUSE_OTHER_START && cm_button < CM_WKC_MOUSE_OTHER_END) {
HandleKeypress(cm_button, 0);
}
break;
}
}
}
@@ -485,11 +498,11 @@ static bool QZ_PollEvent()
QZ_MouseButtonEvent(1, NO);
break;
#if 0
// #if 0 CityMania uses this!
/* This is not needed since openttd currently only use two buttons */
case NSOtherMouseDown:
pt = QZ_GetMouseLocation(event);
if (!QZ_MouseIsInsideView(&pt)) {
pt = _cocoa_subdriver->GetMouseLocation(event);
if (!_cocoa_subdriver->MouseIsInsideView(&pt)) {
[ NSApp sendEvent:event ];
break;
}
@@ -499,8 +512,8 @@ static bool QZ_PollEvent()
break;
case NSOtherMouseUp:
pt = QZ_GetMouseLocation(event);
if (!QZ_MouseIsInsideView(&pt)) {
pt = _cocoa_subdriver->GetMouseLocation(event);
if (!_cocoa_subdriver->MouseIsInsideView(&pt)) {
[ NSApp sendEvent:event ];
break;
}
@@ -508,7 +521,7 @@ static bool QZ_PollEvent()
QZ_MouseMovedEvent((int)pt.x, (int)pt.y);
QZ_MouseButtonEvent([ event buttonNumber ], NO);
break;
#endif
// #endif
case NSKeyDown: {
/* Quit, hide and minimize */

View File

@@ -417,7 +417,7 @@ bool VideoDriver_SDL_Base::PollEvent()
break;
case SDL_MOUSEBUTTONDOWN:
if (_rightclick_emulate && SDL_GetModState() & KMOD_CTRL) {
if (_rightclick_emulate && (SDL_GetModState() & KMOD_CTRL) && ev.button.button == SDL_BUTTON_LEFT) {
ev.button.button = SDL_BUTTON_RIGHT;
}
@@ -437,6 +437,17 @@ bool VideoDriver_SDL_Base::PollEvent()
break;
case SDL_MOUSEBUTTONUP:
if (ev.button.button == SDL_BUTTON_MIDDLE) {
HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0);
break;
} else if (ev.button.button > SDL_BUTTON_RIGHT) {
int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 4;
if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) {
HandleKeypress(button, 0);
}
break;
}
if (_rightclick_emulate) {
_right_button_down = false;
_left_button_down = false;

View File

@@ -24,7 +24,7 @@
#include "sdl_v.h"
#include <SDL.h>
#include "../../citymania/cm_hotkeys.hpp"
#include "../citymania/cm_hotkeys.hpp"
#include "../safeguards.h"
@@ -500,7 +500,7 @@ bool VideoDriver_SDL::PollEvent()
break;
case SDL_MOUSEBUTTONDOWN:
if (_rightclick_emulate && SDL_GetModState() & KMOD_CTRL) {
if (_rightclick_emulate && (SDL_GetModState() & KMOD_CTRL) && ev.button.button == SDL_BUTTON_LEFT) {
ev.button.button = SDL_BUTTON_RIGHT;
}
@@ -523,6 +523,17 @@ bool VideoDriver_SDL::PollEvent()
break;
case SDL_MOUSEBUTTONUP:
if (ev.button.button == SDL_BUTTON_MIDDLE) {
HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0);
break;
} else if (ev.button.button > SDL_BUTTON_WHEELDOWN) {
int button = CM_WKC_MOUSE_OTHER_START + ev.button.button - 4;
if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) {
HandleKeypress(button, 0);
}
break;
}
if (_rightclick_emulate) {
_right_button_down = false;
_left_button_down = false;

View File

@@ -453,6 +453,22 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
HandleMouseEvents();
return 0;
/* CityMania code start */
case WM_MBUTTONUP:
ReleaseCapture();
HandleKeypress(CM_WKC_MOUSE_MIDDLE, 0);
return 0;
case WM_XBUTTONUP: {
ReleaseCapture();
int button = CM_WKC_MOUSE_OTHER_START + GET_XBUTTON_WPARAM(wParam) - 1;
if (button >= CM_WKC_MOUSE_OTHER_START && button < CM_WKC_MOUSE_OTHER_END) {
HandleKeypress(button, 0);
}
return 0;
}
/* CityMania code end */
case WM_MOUSELEAVE:
UndrawMouseCursor();
_cursor.in_window = false;

View File

@@ -2983,6 +2983,7 @@ static void MouseLoop(MouseClick click, int mousewheel)
case MC_HOVER:
DispatchHoverEvent(w, x - w->left, y - w->top);
break;
}
}