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

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;
}
}