1
0
Fork 0

Compare commits

...

11 Commits

Author SHA1 Message Date
Peter Nelson 2f1a3ecd5a
Codechange: Unify structures with sprite sub-tile bounds and simplify bounding boxes.
Lots of different structs contain variations on sub-tile bounds with different naming. Unify into a single struct that can be inherited and passed directly to AddSortableSpriteToDraw.

At the same time, offsets now work more logically: sub-tile bounds now specify the bounding box, and an offset can be applied to the sprite.
2025-07-13 20:42:47 +01:00
translators baced00e9f Update: Translations from eints
spanish (mexican): 1 change by absay
english (us): 1 change by 2TallTyler
galician: 10 changes by pvillaverde
dutch: 1 change by Afoklala
portuguese: 10 changes by jcteotonio
2025-07-13 04:45:12 +00:00
translators aaf5d39b15 Update: Translations from eints
english (au): 1 change by krysclarke
chinese (traditional): 1 change by KogentaSan
chinese (simplified): 1 change by WenSimEHRP
korean: 1 change by telk5093
greek: 1 change by gh658804
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
portuguese: 1 change by azulcosta
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by pAter-exe
2025-07-11 04:45:38 +00:00
Richard Wheeler 7db135099a
Fix: Scale graph gridlines and axes with GUI scale (#12131) 2025-07-10 00:05:48 +01:00
Peter Nelson 290144c5c9 Fix #14396: Industry production graph showed zero instead of N/A.
Record the number of valid history records per industry so that the graph avoids showing values which are not present as zero.
2025-07-09 23:02:58 +01:00
Peter Nelson 9b55ad5b8d Codechange: Generic type and container for history statistics. 2025-07-09 23:02:58 +01:00
Peter Nelson f6e78a480d
Change: Make truncation ellipsis translatable. (#14417) 2025-07-09 22:55:43 +01:00
Tyler Trahan 259830777c
Fix #14375: When loading config, validate timekeeping mode and minutes per year (#14405) 2025-07-09 16:04:38 -04:00
Tyler Trahan 753905ae2d
Fix #14377: Make house picker window remember house protection state when closed (#14406) 2025-07-09 14:18:19 +00:00
Peter Nelson d2ee2add28
Codechange: Remove ZOOM_LVL_GUI macro. (#14423) 2025-07-09 11:05:06 +01:00
translators 8de32c4509 Update: Translations from eints
portuguese: 7 changes by jcteotonio
2025-07-09 04:45:29 +00:00
68 changed files with 651 additions and 473 deletions

View File

@ -48,10 +48,7 @@
void Aircraft::UpdateDeltaXY()
{
this->x_offs = -1;
this->y_offs = -1;
this->x_extent = 2;
this->y_extent = 2;
this->bounds = {{-1, -1, 0}, {2, 2, 0}, {}};
switch (this->subtype) {
default: NOT_REACHED();
@ -64,21 +61,21 @@ void Aircraft::UpdateDeltaXY()
case LANDING:
case HELILANDING:
case FLYING:
this->x_extent = 24;
this->y_extent = 24;
/* Bounds are not centred on the aircraft. */
this->bounds.extent.x = 24;
this->bounds.extent.y = 24;
break;
}
this->z_extent = 5;
this->bounds.extent.z = 5;
break;
case AIR_SHADOW:
this->z_extent = 1;
this->x_offs = 0;
this->y_offs = 0;
this->bounds.extent.z = 1;
this->bounds.origin = {};
break;
case AIR_ROTOR:
this->z_extent = 1;
this->bounds.extent.z = 1;
break;
}
}

View File

@ -69,36 +69,45 @@ static void DrawClearLandFence(const TileInfo *ti)
/* combine fences into one sprite object */
StartSpriteCombine();
int maxz = GetSlopeMaxPixelZ(ti->tileh);
SpriteBounds bounds = {{}, {TILE_SIZE, TILE_SIZE, 4}, {}};
bounds.extent.z += GetSlopeMaxPixelZ(ti->tileh);
uint fence_nw = GetFence(ti->tile, DIAGDIR_NW);
if (fence_nw != 0) {
int z = GetSlopePixelZInCorner(ti->tileh, CORNER_W);
bounds.offset.x = 0;
bounds.offset.y = -static_cast<int>(TILE_SIZE);
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_W);
SpriteID sprite = _clear_land_fence_sprites[fence_nw - 1] + _fence_mod_by_tileh_nw[ti->tileh];
AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y - 16, 16, 32, maxz - z + 4, ti->z + z, false, 0, 16, -z);
AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false);
}
uint fence_ne = GetFence(ti->tile, DIAGDIR_NE);
if (fence_ne != 0) {
int z = GetSlopePixelZInCorner(ti->tileh, CORNER_E);
bounds.offset.x = -static_cast<int>(TILE_SIZE);
bounds.offset.y = 0;
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_E);
SpriteID sprite = _clear_land_fence_sprites[fence_ne - 1] + _fence_mod_by_tileh_ne[ti->tileh];
AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x - 16, ti->y, 32, 16, maxz - z + 4, ti->z + z, false, 16, 0, -z);
AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false);
}
uint fence_sw = GetFence(ti->tile, DIAGDIR_SW);
uint fence_se = GetFence(ti->tile, DIAGDIR_SE);
if (fence_sw != 0 || fence_se != 0) {
int z = GetSlopePixelZInCorner(ti->tileh, CORNER_S);
bounds.offset.x = 0;
bounds.offset.y = 0;
bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_S);
if (fence_sw != 0) {
SpriteID sprite = _clear_land_fence_sprites[fence_sw - 1] + _fence_mod_by_tileh_sw[ti->tileh];
AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z);
AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false);
}
if (fence_se != 0) {
SpriteID sprite = _clear_land_fence_sprites[fence_se - 1] + _fence_mod_by_tileh_se[ti->tileh];
AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z);
AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false);
}
}
EndSpriteCombine();

View File

@ -28,15 +28,30 @@ inline int CentreBounds(int min, int max, int size)
return (min + max - size + 1) / 2;
}
/** Coordinates of a point in 2D */
struct Point {
int x;
int y;
/** Coordinates of a point in 2D. */
template <typename T>
struct PointXy {
T x = 0; ///< X coordinate of point.
T y = 0; ///< Y coordinate of point.
constexpr Point() : x(0), y(0) {}
constexpr Point(int x, int y) : x(x), y(y) {}
constexpr PointXy() = default;
constexpr PointXy(T x, T y) : x(x), y(y) {}
};
/** Coordinates of a point in 3D. */
template <typename T>
struct PointXyz {
T x = 0; ///< X coordinate of point.
T y = 0; ///< Y coordinate of point.
T z = 0; ///< Z coordinate of point.
constexpr PointXyz() = default;
constexpr PointXyz(T x, T y, T z) : x(x), y(y), z(z) {}
};
/** Coordinates of a point in 2D */
using Point = PointXy<int>;
/** Dimensions (a width and height) of a rectangle in 2D */
struct Dimension {
uint width;

View File

@ -992,9 +992,5 @@ void ReleaseDisasterVehicle(VehicleID vehicle)
void DisasterVehicle::UpdateDeltaXY()
{
this->x_offs = -1;
this->y_offs = -1;
this->x_extent = 2;
this->y_extent = 2;
this->z_extent = 5;
this->bounds = {{-1, -1, 0}, {2, 2, 5}, {}};
}

View File

@ -619,11 +619,7 @@ bool EffectVehicle::Tick()
void EffectVehicle::UpdateDeltaXY()
{
this->x_offs = 0;
this->y_offs = 0;
this->x_extent = 1;
this->y_extent = 1;
this->z_extent = 1;
this->bounds = {{}, {1, 1, 1}, {}};
}
/**

View File

@ -248,27 +248,12 @@ static int GetPCPElevation(TileIndex tile, DiagDirection pcp_pos)
*/
void DrawRailCatenaryOnTunnel(const TileInfo *ti)
{
/* xmin, ymin, xmax + 1, ymax + 1 of BB */
static const int tunnel_wire_bb[4][4] = {
{ 0, 1, 16, 15 }, // NE
{ 1, 0, 15, 16 }, // SE
{ 0, 1, 16, 15 }, // SW
{ 1, 0, 15, 16 }, // NW
};
DiagDirection dir = GetTunnelBridgeDirection(ti->tile);
SpriteID wire_base = GetWireBase(ti->tile);
const SortableSpriteStruct *sss = &_rail_catenary_sprite_data_tunnel[dir];
const int *bb_data = tunnel_wire_bb[dir];
AddSortableSpriteToDraw(
wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset,
bb_data[2] - sss->x_offset, bb_data[3] - sss->y_offset, BB_Z_SEPARATOR - sss->z_offset + 1,
GetTilePixelZ(ti->tile) + sss->z_offset,
IsTransparencySet(TO_CATENARY),
bb_data[0] - sss->x_offset, bb_data[1] - sss->y_offset, BB_Z_SEPARATOR - sss->z_offset
);
const SortableSpriteStruct &sss = _rail_catenary_sprite_data_tunnel[dir];
AddSortableSpriteToDraw(wire_base + sss.image_offset, PAL_NONE, ti->x, ti->y, GetTilePixelZ(ti->tile), sss, IsTransparencySet(TO_CATENARY));
}
/**
@ -440,8 +425,8 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
continue; // No neighbour, go looking for a better position
}
AddSortableSpriteToDraw(pylon_base + _pylon_sprites[temp], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE,
elevation, IsTransparencySet(TO_CATENARY), -1, -1);
AddSortableSpriteToDraw(pylon_base + _pylon_sprites[temp], PAL_NONE, x, y, elevation,
{{-1, -1, 0}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {1, 1, 0}}, IsTransparencySet(TO_CATENARY));
break; // We already have drawn a pylon, bail out
}
@ -482,7 +467,7 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
assert(pcp_config != 0); // We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that)
assert(!IsSteepSlope(tileh[TS_HOME]));
const SortableSpriteStruct *sss = &_rail_catenary_sprite_data[_rail_wires[tileh_selector][t][pcp_config]];
const SortableSpriteStruct &sss = _rail_catenary_sprite_data[_rail_wires[tileh_selector][t][pcp_config]];
/*
* The "wire"-sprite position is inside the tile, i.e. 0 <= sss->?_offset < TILE_SIZE.
@ -490,9 +475,8 @@ static void DrawRailCatenaryRailway(const TileInfo *ti)
* Also note that the result of GetSlopePixelZ() is very special for bridge-ramps, so we round the result up or
* down to the nearest full height change.
*/
AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset,
sss->x_size, sss->y_size, sss->z_size, (GetSlopePixelZ(ti->x + sss->x_offset, ti->y + sss->y_offset, true) + 4) / 8 * 8 + sss->z_offset,
IsTransparencySet(TO_CATENARY));
int z = (GetSlopePixelZ(ti->x + sss.origin.x, ti->y + sss.origin.y, true) + 4) / 8 * 8;
AddSortableSpriteToDraw(wire_base + sss.image_offset, PAL_NONE, ti->x, ti->y, z, sss, IsTransparencySet(TO_CATENARY));
}
}
@ -530,13 +514,12 @@ void DrawRailCatenaryOnBridge(const TileInfo *ti)
SpriteID wire_base = GetWireBase(end, TCX_ON_BRIDGE);
AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset,
sss->x_size, sss->y_size, sss->z_size, height + sss->z_offset,
IsTransparencySet(TO_CATENARY)
);
AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x, ti->y, height, *sss, IsTransparencySet(TO_CATENARY));
SpriteID pylon_base = GetPylonBase(end, TCX_ON_BRIDGE);
static constexpr SpriteBounds pylon_bounds{{-1, -1, 0}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {1, 1, 0}};
/* Finished with wires, draw pylons
* every other tile needs a pylon on the northern end */
if (num % 2) {
@ -545,7 +528,7 @@ void DrawRailCatenaryOnBridge(const TileInfo *ti)
if (HasBit(tlg, (axis == AXIS_X ? 0 : 1))) ppp_pos = ReverseDir(ppp_pos);
uint x = ti->x + _x_pcp_offsets[pcp_pos] + _x_ppp_offsets[ppp_pos];
uint y = ti->y + _y_pcp_offsets[pcp_pos] + _y_ppp_offsets[ppp_pos];
AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, height, IsTransparencySet(TO_CATENARY), -1, -1);
AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, height, pylon_bounds, IsTransparencySet(TO_CATENARY));
}
/* need a pylon on the southern end of the bridge */
@ -555,7 +538,7 @@ void DrawRailCatenaryOnBridge(const TileInfo *ti)
if (HasBit(tlg, (axis == AXIS_X ? 0 : 1))) ppp_pos = ReverseDir(ppp_pos);
uint x = ti->x + _x_pcp_offsets[pcp_pos] + _x_ppp_offsets[ppp_pos];
uint y = ti->y + _y_pcp_offsets[pcp_pos] + _y_ppp_offsets[ppp_pos];
AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, height, IsTransparencySet(TO_CATENARY), -1, -1);
AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, height, pylon_bounds, IsTransparencySet(TO_CATENARY));
}
}
@ -569,17 +552,12 @@ void DrawRailCatenary(const TileInfo *ti)
switch (GetTileType(ti->tile)) {
case MP_RAILWAY:
if (IsRailDepot(ti->tile)) {
const SortableSpriteStruct *sss = &_rail_catenary_sprite_data_depot[GetRailDepotDirection(ti->tile)];
const SortableSpriteStruct &sss = _rail_catenary_sprite_data_depot[GetRailDepotDirection(ti->tile)];
SpriteID wire_base = GetWireBase(ti->tile);
/* This wire is not visible with the default depot sprites */
AddSortableSpriteToDraw(
wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset,
sss->x_size, sss->y_size, sss->z_size,
GetTileMaxPixelZ(ti->tile) + sss->z_offset,
IsTransparencySet(TO_CATENARY)
);
AddSortableSpriteToDraw(wire_base + sss.image_offset, PAL_NONE, ti->x, ti->y, GetTileMaxPixelZ(ti->tile), sss, IsTransparencySet(TO_CATENARY));
return;
}
break;

View File

@ -523,10 +523,9 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
int max_x = right; // The maximum x position to draw normal glyphs on.
truncation &= max_w < w; // Whether we need to do truncation.
int dot_width = 0; // Cache for the width of the dot.
const Sprite *dot_sprite = nullptr; // Cache for the sprite of the dot.
bool dot_has_shadow = false; // Whether the dot's font requires shadows.
int truncation_width = 0; // Width of the ellipsis string.
std::optional<Layouter> truncation_layout; ///< Layout for truncation ellipsis.
if (truncation) {
/*
* Assumption may be made that all fonts of a run are of the same size.
@ -534,20 +533,17 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
* another size would be chosen it won't have truncated too little for
* the truncation dots.
*/
FontCache *fc = line.GetVisualRun(0).GetFont()->fc;
dot_has_shadow = fc->GetDrawGlyphShadow();
GlyphID dot_glyph = fc->MapCharToGlyph('.');
dot_width = fc->GetGlyphWidth(dot_glyph);
dot_sprite = fc->GetGlyph(dot_glyph);
truncation_layout.emplace(GetEllipsis(), INT32_MAX, line.GetVisualRun(0).GetFont()->fc->GetSize());
truncation_width = truncation_layout->GetBounds().width;
/* Is there enough space even for an ellipsis? */
if (max_w < dot_width * 3) return (_current_text_dir == TD_RTL) ? left : right;
if (max_w < truncation_width) return (_current_text_dir == TD_RTL) ? left : right;
if (_current_text_dir == TD_RTL) {
min_x += 3 * dot_width;
min_x += truncation_width;
offset_x = w - max_w;
} else {
max_x -= 3 * dot_width;
max_x -= truncation_width;
}
w = max_w;
@ -583,9 +579,11 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
const uint shadow_offset = ScaleGUITrad(1);
/* Draw shadow, then foreground */
for (bool do_shadow : { true, false }) {
bool colour_has_shadow = false;
auto draw_line = [&](const ParagraphLayouter::Line &line, bool do_shadow, int left, int min_x, int max_x, bool truncation) {
const DrawPixelInfo *dpi = _cur_dpi;
int dpi_left = dpi->left;
int dpi_right = dpi->left + dpi->width - 1;
for (int run_index = 0; run_index < line.CountRuns(); run_index++) {
const ParagraphLayouter::VisualRun &run = line.GetVisualRun(run_index);
const auto &glyphs = run.GetGlyphs();
@ -595,22 +593,18 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
FontCache *fc = f->fc;
TextColour colour = f->colour;
if (colour == TC_INVALID || HasFlag(default_colour, TC_FORCED)) colour = default_colour;
colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
bool colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
SetColourRemap(do_shadow ? TC_BLACK : colour); // the last run also sets the colour for the truncation dots
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
DrawPixelInfo *dpi = _cur_dpi;
int dpi_left = dpi->left;
int dpi_right = dpi->left + dpi->width - 1;
for (int i = 0; i < run.GetGlyphCount(); i++) {
GlyphID glyph = glyphs[i];
/* Not a valid glyph (empty) */
if (glyph == 0xFFFF) continue;
int begin_x = positions[i].left + left - offset_x;
int end_x = positions[i].right + left - offset_x;
int begin_x = positions[i].left + left;
int end_x = positions[i].right + left;
int top = positions[i].top + y;
/* Truncated away. */
@ -625,12 +619,15 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
GfxMainBlitter(sprite, begin_x + (do_shadow ? shadow_offset : 0), top + (do_shadow ? shadow_offset : 0), BlitterMode::ColourRemap);
}
}
};
if (truncation && (!do_shadow || (dot_has_shadow && colour_has_shadow))) {
int x = (_current_text_dir == TD_RTL) ? left : (right - 3 * dot_width);
for (int i = 0; i < 3; i++, x += dot_width) {
GfxMainBlitter(dot_sprite, x + (do_shadow ? shadow_offset : 0), y + (do_shadow ? shadow_offset : 0), BlitterMode::ColourRemap);
}
/* Draw shadow, then foreground */
for (bool do_shadow : {true, false}) {
draw_line(line, do_shadow, left - offset_x, min_x, max_x, truncation);
if (truncation) {
int x = (_current_text_dir == TD_RTL) ? left : (right - truncation_width);
draw_line(*truncation_layout->front(), do_shadow, x, INT32_MIN, INT32_MAX, false);
}
}

View File

@ -88,12 +88,12 @@ void UndrawMouseCursor();
void RedrawScreenRect(int left, int top, int right, int bottom);
void GfxScroll(int left, int top, int width, int height, int xo, int yo);
Dimension GetSpriteSize(SpriteID sprid, Point *offset = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
Dimension GetSpriteSize(SpriteID sprid, Point *offset = nullptr, ZoomLevel zoom = _gui_zoom);
Dimension GetScaledSpriteSize(SpriteID sprid); /* widget.cpp */
void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr);
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr, ZoomLevel zoom = _gui_zoom);
void DrawSpriteIgnorePadding(SpriteID img, PaletteID pal, const Rect &r, StringAlignment align); /* widget.cpp */
std::unique_ptr<uint32_t[]> DrawSpriteToRgbaBuffer(SpriteID spriteId, ZoomLevel zoom = ZOOM_LVL_GUI);
std::unique_ptr<uint32_t[]> DrawSpriteToRgbaBuffer(SpriteID spriteId, ZoomLevel zoom = _gui_zoom);
int DrawString(int left, int right, int top, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);

View File

@ -8,6 +8,7 @@
/** @file graph_gui.cpp GUI that shows performance graphs. */
#include "stdafx.h"
#include "misc/history_func.hpp"
#include "graph_gui.h"
#include "window_gui.h"
#include "company_base.h"
@ -215,6 +216,15 @@ protected:
uint8_t highlight_range = UINT8_MAX; ///< Data range that should be highlighted, or UINT8_MAX for none.
bool highlight_state = false; ///< Current state of highlight, toggled every TIMER_BLINK_INTERVAL period.
template <typename Tprojection>
struct Filler {
DataSet &dataset; ///< Dataset to fill.
const Tprojection &proj; ///< Projection to apply.
inline void Fill(uint i, const auto &data) const { this->dataset.values[i] = std::invoke(this->proj, data); }
inline void MakeInvalid(uint i) const { this->dataset.values[i] = INVALID_DATAPOINT; }
};
/**
* Get appropriate part of dataset values for the current number of horizontal points.
* @param dataset Dataset to get values of
@ -378,7 +388,9 @@ protected:
/* Draw the background of the graph itself. */
GfxFillRect(r.left, r.top, r.right, r.bottom, GRAPH_BASE_COLOUR);
/* Draw the vertical grid lines. */
/* Draw the grid lines. */
int gridline_width = WidgetDimensions::scaled.bevel.top;
int grid_colour = GRAPH_GRID_COLOUR;
/* Don't draw the first line, as that's where the axis will be. */
if (rtl) {
@ -388,13 +400,12 @@ protected:
x = r.left + x_sep;
}
int grid_colour = GRAPH_GRID_COLOUR;
for (int i = 1; i < this->num_vert_lines + 1; i++) {
/* If using wallclock units, we separate periods with a lighter line. */
if (TimerGameEconomy::UsingWallclockUnits()) {
grid_colour = (i % 4 == 0) ? GRAPH_YEAR_LINE_COLOUR : GRAPH_GRID_COLOUR;
}
GfxFillRect(x, r.top, x, r.bottom, grid_colour);
GfxFillRect(x, r.top, x + gridline_width - 1, r.bottom, grid_colour);
x += x_sep;
}
@ -403,20 +414,20 @@ protected:
for (int i = 0; i < (num_hori_lines + 1); i++) {
if (rtl) {
GfxFillRect(r.right + 1, y, r.right + ScaleGUITrad(3), y, GRAPH_AXIS_LINE_COLOUR);
GfxFillRect(r.right + 1, y, r.right + ScaleGUITrad(3), y + gridline_width - 1, GRAPH_AXIS_LINE_COLOUR);
} else {
GfxFillRect(r.left - ScaleGUITrad(3), y, r.left - 1, y, GRAPH_AXIS_LINE_COLOUR);
GfxFillRect(r.left - ScaleGUITrad(3), y, r.left - 1, y + gridline_width - 1, GRAPH_AXIS_LINE_COLOUR);
}
GfxFillRect(r.left, y, r.right, y, GRAPH_GRID_COLOUR);
GfxFillRect(r.left, y, r.right + gridline_width - 1, y + gridline_width - 1, GRAPH_GRID_COLOUR);
y -= y_sep;
}
/* Draw the y axis. */
GfxFillRect(r.left, r.top, r.left, r.bottom, GRAPH_AXIS_LINE_COLOUR);
GfxFillRect(r.left, r.top, r.left + gridline_width - 1, r.bottom + gridline_width - 1, GRAPH_AXIS_LINE_COLOUR);
/* Draw the x axis. */
y = x_axis_offset + r.top;
GfxFillRect(r.left, y, r.right, y, GRAPH_ZERO_LINE_COLOUR);
GfxFillRect(r.left, y, r.right + gridline_width - 1, y + gridline_width - 1, GRAPH_ZERO_LINE_COLOUR);
/* Find the largest value that will be drawn. */
if (this->num_on_x_axis == 0) return;
@ -471,7 +482,7 @@ protected:
year++;
/* Draw a lighter grid line between years. Top and bottom adjustments ensure we don't draw over top and bottom horizontal grid lines. */
GfxFillRect(x + x_sep, r.top + 1, x + x_sep, r.bottom - 1, GRAPH_YEAR_LINE_COLOUR);
GfxFillRect(x + x_sep, r.top + gridline_width, x + x_sep + gridline_width - 1, r.bottom - 1, GRAPH_YEAR_LINE_COLOUR);
}
x += x_sep;
}
@ -499,10 +510,11 @@ protected:
}
}
/* draw lines and dots */
uint linewidth = _settings_client.gui.graph_line_thickness;
uint pointoffs1 = (linewidth + 1) / 2;
uint pointoffs2 = linewidth + 1 - pointoffs1;
/* Draw lines and dots. */
uint linewidth = ScaleGUITrad(_settings_client.gui.graph_line_thickness);
uint pointwidth = ScaleGUITrad(_settings_client.gui.graph_line_thickness + 1);
uint pointoffs1 = pointwidth / 2;
uint pointoffs2 = pointwidth - pointoffs1;
auto draw_dataset = [&](const DataSet &dataset, uint8_t colour) {
if (HasBit(this->excluded_data, dataset.exclude_bit)) return;
@ -1661,24 +1673,22 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow {
if (!IsValidCargoType(p.cargo)) continue;
const CargoSpec *cs = CargoSpec::Get(p.cargo);
this->data.reserve(this->data.size() + 2);
DataSet &produced = this->data.emplace_back();
produced.colour = cs->legend_colour;
produced.exclude_bit = cs->Index();
produced.range_bit = 0;
for (uint j = 0; j < GRAPH_NUM_MONTHS; j++) {
produced.values[j] = p.history[GRAPH_NUM_MONTHS - j].production;
}
auto produced_filler = Filler{produced, &Industry::ProducedHistory::production};
DataSet &transported = this->data.emplace_back();
transported.colour = cs->legend_colour;
transported.exclude_bit = cs->Index();
transported.range_bit = 1;
transported.dash = 2;
auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported};
for (uint j = 0; j < GRAPH_NUM_MONTHS; j++) {
transported.values[j] = p.history[GRAPH_NUM_MONTHS - j].transported;
}
FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->valid_history, produced_filler, transported_filler);
}
this->SetDirty();

View File

@ -11,6 +11,7 @@
#define INDUSTRY_H
#include "core/flatset_type.hpp"
#include "misc/history_type.hpp"
#include "newgrf_storage.h"
#include "subsidy_type.h"
#include "industry_map.h"
@ -55,9 +56,6 @@ enum class IndustryControlFlag : uint8_t {
};
using IndustryControlFlags = EnumBitSet<IndustryControlFlag, uint8_t, IndustryControlFlag::End>;
static const int THIS_MONTH = 0;
static const int LAST_MONTH = 1;
/**
* Defines the internal data of a functional industry.
*/
@ -72,12 +70,11 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
return ClampTo<uint8_t>(this->transported * 256 / this->production);
}
};
struct ProducedCargo {
CargoType cargo = 0; ///< Cargo type
uint16_t waiting = 0; ///< Amount of cargo produced
uint8_t rate = 0; ///< Production rate
std::array<ProducedHistory, 25> history{}; ///< History of cargo produced and transported for this month and 24 previous months
HistoryData<ProducedHistory> history{}; ///< History of cargo produced and transported for this month and 24 previous months
};
struct AcceptedCargo {
@ -92,6 +89,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
TileArea location{INVALID_TILE, 0, 0}; ///< Location of the industry
Town *town = nullptr; ///< Nearest town
Station *neutral_station = nullptr; ///< Associated neutral station
ValidHistoryMask valid_history = 0; ///< Mask of valid history records.
ProducedCargoes produced{}; ///< produced cargo slots
AcceptedCargoes accepted{}; ///< accepted cargo slots
uint8_t prod_level = 0; ///< general production level

View File

@ -8,6 +8,8 @@
/** @file industry_cmd.cpp Handling of industry tiles. */
#include "stdafx.h"
#include "misc/history_type.hpp"
#include "misc/history_func.hpp"
#include "clear_map.h"
#include "industry.h"
#include "station_base.h"
@ -372,13 +374,7 @@ static void DrawTile_Industry(TileInfo *ti)
image = dits->building.sprite;
if (image != 0) {
AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GetColourPalette(ind->random_colour)),
ti->x + dits->subtile_x,
ti->y + dits->subtile_y,
dits->width,
dits->height,
dits->dz,
ti->z,
IsTransparencySet(TO_INDUSTRIES));
*ti, *dits, IsTransparencySet(TO_INDUSTRIES));
if (IsTransparencySet(TO_INDUSTRIES)) return;
}
@ -1835,6 +1831,8 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
for (auto &p : i->produced) {
p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
}
UpdateValidHistory(i->valid_history);
}
if (indspec->callback_mask.Test(IndustryCallbackMask::DecideColour)) {
@ -2492,14 +2490,13 @@ void GenerateIndustries()
*/
static void UpdateIndustryStatistics(Industry *i)
{
UpdateValidHistory(i->valid_history);
for (auto &p : i->produced) {
if (IsValidCargoType(p.cargo)) {
if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
/* Move history from this month to last month. */
std::rotate(std::rbegin(p.history), std::rbegin(p.history) + 1, std::rend(p.history));
p.history[THIS_MONTH].production = 0;
p.history[THIS_MONTH].transported = 0;
RotateHistory(p.history);
}
}
}

View File

@ -450,9 +450,8 @@ void DrawFoundation(TileInfo *ti, Foundation f)
if (IsSteepSlope(ti->tileh)) {
if (!IsNonContinuousFoundation(f)) {
/* Lower part of foundation */
AddSortableSpriteToDraw(
leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z
);
static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
AddSortableSpriteToDraw(leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, *ti, bounds);
}
Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
@ -462,24 +461,25 @@ void DrawFoundation(TileInfo *ti, Foundation f)
/* inclined foundation */
uint8_t inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
f == FOUNDATION_INCLINED_X ? TILE_SIZE : 1,
f == FOUNDATION_INCLINED_Y ? TILE_SIZE : 1,
TILE_HEIGHT, ti->z
);
SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
OffsetGroundSprite(0, 0);
} else if (IsLeveledFoundation(f)) {
AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z - TILE_HEIGHT);
static constexpr SpriteBounds bounds{{0, 0, -(int)TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, *ti, bounds);
OffsetGroundSprite(0, -(int)TILE_HEIGHT);
} else if (f == FOUNDATION_STEEP_LOWER) {
/* one corner raised */
OffsetGroundSprite(0, -(int)TILE_HEIGHT);
} else {
/* halftile foundation */
int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
int8_t x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
int8_t y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1, ti->z + TILE_HEIGHT);
SpriteBounds bounds{{x_bb, y_bb, TILE_HEIGHT}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, *ti, bounds);
/* Reposition ground sprite back to original position after bounding box change above. This is similar to
* RemapCoords() but without zoom scaling. */
Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
@ -488,15 +488,17 @@ void DrawFoundation(TileInfo *ti, Foundation f)
} else {
if (IsLeveledFoundation(f)) {
/* leveled foundation */
AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z);
static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, *ti, bounds);
OffsetGroundSprite(0, -(int)TILE_HEIGHT);
} else if (IsNonContinuousFoundation(f)) {
/* halftile foundation */
Corner halftile_corner = GetHalftileFoundationCorner(f);
int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
int8_t x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? TILE_SIZE / 2 : 0);
int8_t y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? TILE_SIZE / 2 : 0);
AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1, ti->z);
SpriteBounds bounds{{x_bb, y_bb, 0}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}};
AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, *ti, bounds);
/* Reposition ground sprite back to original position after bounding box change above. This is similar to
* RemapCoords() but without zoom scaling. */
Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb};
@ -511,17 +513,17 @@ void DrawFoundation(TileInfo *ti, Foundation f)
/* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
}
AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z);
static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}};
AddSortableSpriteToDraw(spr, PAL_NONE, *ti, bounds);
OffsetGroundSprite(0, 0);
} else {
/* inclined foundation */
uint8_t inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
f == FOUNDATION_INCLINED_X ? TILE_SIZE : 1,
f == FOUNDATION_INCLINED_Y ? TILE_SIZE : 1,
TILE_HEIGHT, ti->z
);
SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}};
if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE;
if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE;
AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds);
OffsetGroundSprite(0, 0);
}
ti->z += ApplyPixelFoundationToSlope(f, ti->tileh);

View File

@ -268,6 +268,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}ano{
STR_UNITS_PERIODS :{NUM}{NBSP}período{P "" s}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtro:

View File

@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}jaar
STR_UNITS_PERIODS :{NUM}{NBSP}period{P "" en}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filter:

View File

@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}year
STR_UNITS_PERIODS :{NUM}{NBSP}period{P "" s}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filter:

View File

@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}year
STR_UNITS_PERIODS :{NUM}{NBSP}period{P "" s}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filter:

View File

@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}year
STR_UNITS_PERIODS :{NUM}{NBSP}period{P "" s}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filter:

View File

@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}vuo{
STR_UNITS_PERIODS :{NUM}{NBSP}jakso{P "" a}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :…
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Suodatin:

View File

@ -268,6 +268,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}ano{
STR_UNITS_PERIODS :{NUM}{NBSP}período{P "" s}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtrar:
@ -1302,6 +1303,9 @@ STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :A taxa de inter
STR_CONFIG_SETTING_RUNNING_COSTS :Custos de explotación: {STRING}
STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Establece o nivel de mantemento e custo de operación de vehículos e infraestrutura
###length 3
STR_CONFIG_SETTING_RUNNING_COSTS_LOW :Baixo
STR_CONFIG_SETTING_RUNNING_COSTS_MEDIUM :Medio
STR_CONFIG_SETTING_RUNNING_COSTS_HIGH :Alto
STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Velocidade de construción: {STRING}
STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limita a cantidade de accións construtivas das IAs
@ -1324,6 +1328,9 @@ STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Sen subvención
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Custos de construción: {STRING}
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Fixa o nivel de custos de construción e compra
###length 3
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_LOW :Baixo
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_MEDIUM :Medio
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HIGH :Alto
STR_CONFIG_SETTING_RECESSIONS :Recesións económicas: {STRING}
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Se está activado, a economía pode entrar en recesión periódicamente. Durante unha recesión tódalas producións son significativamente máis baixas (volvendo ao nivel anterior cando a recesión remata)
@ -2079,9 +2086,9 @@ STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :A clase de merc
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Xeito de distribución para outros tipos de mercadoría: {STRING}
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Asimétrico" significa que calquera cantidade de mercadorías pode ser enviada en calquera dirección. "Manual" significa que non haberá distribución automática para estas mercadorías
###length 3
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manual
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimétrica
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simétrica
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :Manual
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :Asimétrica
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :Simétrica
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Precisión da distribución: {STRING}
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Canto máis alto sexa o valor, máis tempo de CPU levará o cálculo de distribución. Se leva demasiado tempo podes experimentar retraso. Se sen embargo o fixas nun valor baixo, a distribución será imprecisa, e pode que a carga non sexa enviada aos destinos que ti queres

View File

@ -329,6 +329,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}έτ
STR_UNITS_PERIODS :{NUM}{NBSP}περίοδ{P 0 ος οι}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Φιλτράρισμα λίστας:

View File

@ -268,6 +268,7 @@ STR_UNITS_YEARS :{NUM}년
STR_UNITS_PERIODS :{NUM}기간
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :…
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}검색:

View File

@ -646,6 +646,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}{P r
STR_UNITS_PERIODS :{NUM}{NBSP}okres{P "" y ów}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtr:

View File

@ -268,6 +268,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}ano{
STR_UNITS_PERIODS :{NUM}{NBSP}período{P "" s}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtro:
@ -738,7 +739,7 @@ STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Clique n
STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Clique numa faixa para a remover da lista (apenas Personalização 1 ou Personalização 2)
# Highscore window
STR_HIGHSCORE_TOP_COMPANIES :{BIG_FONT}{BLACK}Melhores empresas
STR_HIGHSCORE_TOP_COMPANIES :{BIG_FONT}{BLACK}As melhores empresas
STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}.
STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Negociante
STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Empresário
@ -748,7 +749,7 @@ STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnata
STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Grande magnata
STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Magnata do século
STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY}
STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA})
STR_HIGHSCORE_STATS :{BIG_FONT}"{STRING}" ({COMMA})
STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} conquista o estatuto de '{STRING}'!
STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} de {COMPANY} conquista o estatuto de '{STRING}'!
@ -3116,8 +3117,8 @@ STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Selecion
# Land area window
STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Informações do Terreno
STR_LAND_AREA_INFORMATION_LOCATION_TOOLTIP :{BLACK}Centrar visualização na localização do mosaico. Ctrl+Clique para abrir uma nova janela de visualização nesse mosaico.
STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Custo para limpar: {LTBLUE}N/D
STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Custo para limpar: {RED}{CURRENCY_LONG}
STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Custo de desobstrução: {LTBLUE}N/D
STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Custo de desobstrução: {RED}{CURRENCY_LONG}
STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Receitas apuradas: {LTBLUE}{CURRENCY_LONG}
STR_LAND_AREA_INFORMATION_OWNER_N_A :N/D
STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Proprietário: {LTBLUE}{STRING}
@ -3125,7 +3126,7 @@ STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Dono da
STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Dono da linha de eléctrico: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Dono da linha férrea: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Autoridade local: {LTBLUE}{STRING}
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nenhum
STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nenhuma
STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordenadas: {LTBLUE}{NUM} x {NUM} x {NUM}
STR_LAND_AREA_INFORMATION_LANDINFO_INDEX :{BLACK}Índice do mosaico: {LTBLUE}{NUM} ({HEX})
STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Construído/renovado: {LTBLUE}{DATE_LONG}
@ -3684,9 +3685,9 @@ STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{BLACK}No inver
STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} fo{G 0 i i i ram ram} entregue{G 0 "" "" "" s s}
STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (ainda necessário)
STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (entregue)
STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Localidade cresce a cada {ORANGE}{UNITS_DAYS_OR_SECONDS}
STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Localidade cresce a cada {ORANGE}{UNITS_DAYS_OR_SECONDS} (financiada)
STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Localidade {RED}não{BLACK} está a crescer
STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}A localidade cresce a cada {ORANGE}{UNITS_DAYS_OR_SECONDS}
STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}A localidade cresce a cada {ORANGE}{UNITS_DAYS_OR_SECONDS} (financiada)
STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}A localidade {RED}não{BLACK} está a crescer
STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Limite de ruído na localidade: {ORANGE}{COMMA}{BLACK} máx: {ORANGE}{COMMA}
STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centrar visualização na localização da localidade. Ctrl+Clique para abrir um novo visualizador na localização da localidade
STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Autoridade Local
@ -3699,8 +3700,8 @@ STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON :{BLACK}Expandir
STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP :{BLACK}Aumentar os edifícios da localidade
STR_TOWN_VIEW_EXPAND_ROADS_BUTTON :{BLACK}Expandir estradas
STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP :{BLACK}Aumentar as estradas da localidade
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Apagar
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Apagar completamente esta localidade
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Remover
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Remover completamente esta localidade
STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Renomear Localidade
@ -3854,12 +3855,12 @@ STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_S
STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} para esta estação
STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} sem parar
STR_STATION_VIEW_GROUP_S_V_D :Fonte-Via-Destino
STR_STATION_VIEW_GROUP_S_D_V :Fonte-Destino-Via
STR_STATION_VIEW_GROUP_V_S_D :Via-Fonte-Destino
STR_STATION_VIEW_GROUP_V_D_S :Via-Destino-Fonte
STR_STATION_VIEW_GROUP_D_S_V :Destino-Fonte-Via
STR_STATION_VIEW_GROUP_D_V_S :Destino-Via-Fonte
STR_STATION_VIEW_GROUP_S_V_D :Origem-Via-Destino
STR_STATION_VIEW_GROUP_S_D_V :Origem-Destino-Via
STR_STATION_VIEW_GROUP_V_S_D :Via-Origem-Destino
STR_STATION_VIEW_GROUP_V_D_S :Via-Destino-Origem
STR_STATION_VIEW_GROUP_D_S_V :Destino-Origem-Via
STR_STATION_VIEW_GROUP_D_V_S :Destino-Via-Origem
###length 8
STR_CARGO_RATING_APPALLING :Inexistente
@ -3942,7 +3943,7 @@ STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infraest
STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM}
STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Presidente)
STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Inaugurado: {WHITE}{NUM}
STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Inaugurada em: {WHITE}{NUM}
STR_COMPANY_VIEW_INAUGURATED_TITLE_WALLCLOCK :{GOLD}Inaugurada: {WHITE}{NUM} (período {NUM})
STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Cores:
STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Veículos:

View File

@ -393,6 +393,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}{P
STR_UNITS_PERIODS :{NUM}{NBSP}цикл{P "" а ов}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Фильтр:

View File

@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}年
STR_UNITS_PERIODS :{NUM}{NBSP}个周期
STR_LIST_SEPARATOR :、
STR_TRUNCATION_ELLIPSIS :…
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}搜索:

View File

@ -268,6 +268,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}año
STR_UNITS_PERIODS :{NUM}{NBSP}período{P "" s}
STR_LIST_SEPARATOR :,{SPACE}
STR_TRUNCATION_ELLIPSIS :...
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}Filtrar:

View File

@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}年
STR_UNITS_PERIODS :{NUM}{NBSP}個週期
STR_LIST_SEPARATOR :、
STR_TRUNCATION_ELLIPSIS :……
# Common window strings
STR_LIST_FILTER_TITLE :{BLACK}篩選:

View File

@ -8,5 +8,7 @@ add_files(
getoptdata.cpp
getoptdata.h
hashtable.hpp
history_func.hpp
history_type.hpp
lrucache.hpp
)

View File

@ -0,0 +1,56 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file history_func.hpp Functions for storing historical data. */
#ifndef HISTORY_FUNC_HPP
#define HISTORY_FUNC_HPP
#include "../core/bitmath_func.hpp"
#include "history_type.hpp"
/**
* Update mask of valid history records.
* @param[in,out] valid_history Valid history records.
*/
inline void UpdateValidHistory(ValidHistoryMask &valid_history)
{
SB(valid_history, LAST_MONTH, HISTORY_RECORDS - LAST_MONTH, GB(valid_history, LAST_MONTH, HISTORY_RECORDS - LAST_MONTH) << 1ULL | 1ULL);
}
/**
* Rotate history.
* @tparam T type of history data element.
* @param history Historical data to rotate.
*/
template <typename T>
void RotateHistory(HistoryData<T> &history)
{
std::rotate(std::rbegin(history), std::rbegin(history) + 1, std::rend(history));
history[THIS_MONTH] = {};
}
/**
* Fill some data with historical data.
* @param history Historical data to fill from.
* @param valid_history Mask of valid history records.
* @param fillers Fillers to fill with history data.
*/
template <uint N, typename T, typename... Tfillers>
void FillFromHistory(const HistoryData<T> &history, ValidHistoryMask valid_history, Tfillers... fillers)
{
for (uint i = 0; i != N; ++i) {
if (HasBit(valid_history, N - i)) {
auto &data = history[N - i];
(fillers.Fill(i, data), ...);
} else {
(fillers.MakeInvalid(i), ...);
}
}
}
#endif /* HISTORY_FUNC_HPP */

View File

@ -0,0 +1,28 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file history_type.hpp Types for storing historical data. */
#ifndef HISTORY_TYPE_HPP
#define HISTORY_TYPE_HPP
static constexpr uint8_t HISTORY_RECORDS = 25;
static constexpr uint8_t THIS_MONTH = 0;
static constexpr uint8_t LAST_MONTH = 1;
/**
* Container type for storing history data.
* @tparam T type of history data.
*/
template <typename T>
using HistoryData = std::array<T, HISTORY_RECORDS>;
/** Mask of valid history records. */
using ValidHistoryMask = uint64_t;
#endif /* HISTORY_TYPE_HPP */

View File

@ -90,12 +90,12 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR
/* no relative bounding box support */
DrawTileSeqStruct &dtss = tmp_layout.emplace_back();
dtss.delta_x = delta_x;
dtss.delta_y = buf.ReadByte();
dtss.delta_z = buf.ReadByte();
dtss.size_x = buf.ReadByte();
dtss.size_y = buf.ReadByte();
dtss.size_z = buf.ReadByte();
dtss.origin.x = delta_x;
dtss.origin.y = buf.ReadByte();
dtss.origin.z = buf.ReadByte();
dtss.extent.x = buf.ReadByte();
dtss.extent.y = buf.ReadByte();
dtss.extent.z = buf.ReadByte();
ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss.image);
/* On error, bail out immediately. Temporary GRF data was already freed */

View File

@ -207,15 +207,15 @@ bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_s
return true;
}
seq->delta_x = buf.ReadByte();
seq->delta_y = buf.ReadByte();
seq->origin.x = buf.ReadByte();
seq->origin.y = buf.ReadByte();
if (!no_z_position) seq->delta_z = buf.ReadByte();
if (!no_z_position) seq->origin.z = buf.ReadByte();
if (seq->IsParentSprite()) {
seq->size_x = buf.ReadByte();
seq->size_y = buf.ReadByte();
seq->size_z = buf.ReadByte();
seq->extent.x = buf.ReadByte();
seq->extent.y = buf.ReadByte();
seq->extent.z = buf.ReadByte();
}
ReadSpriteLayoutRegisters(buf, flags, seq->IsParentSprite(), dts, i + 1);

View File

@ -609,7 +609,7 @@ SpriteLayoutProcessor::SpriteLayoutProcessor(const NewGRFSpriteLayout &raw_layou
* Also include the groundsprite into the sequence for easier processing. */
DrawTileSeqStruct &copy = this->result_seq.emplace_back();
copy.image = this->raw_layout->ground;
copy.delta_z = static_cast<int8_t>(0x80);
copy.origin.z = static_cast<int8_t>(0x80);
this->result_seq.insert(this->result_seq.end(), this->raw_layout->seq.begin(), this->raw_layout->seq.end());
@ -692,13 +692,13 @@ void SpriteLayoutProcessor::ProcessRegisters(const ResolverObject &object, uint8
if (result.IsParentSprite()) {
if (flags & TLF_BB_XY_OFFSET) {
result.delta_x += object.GetRegister(regs->delta.parent[0]);
result.delta_y += object.GetRegister(regs->delta.parent[1]);
result.origin.x += object.GetRegister(regs->delta.parent[0]);
result.origin.y += object.GetRegister(regs->delta.parent[1]);
}
if (flags & TLF_BB_Z_OFFSET) result.delta_z += object.GetRegister(regs->delta.parent[2]);
if (flags & TLF_BB_Z_OFFSET) result.origin.z += object.GetRegister(regs->delta.parent[2]);
} else {
if (flags & TLF_CHILD_X_OFFSET) result.delta_x += object.GetRegister(regs->delta.child[0]);
if (flags & TLF_CHILD_Y_OFFSET) result.delta_y += object.GetRegister(regs->delta.child[1]);
if (flags & TLF_CHILD_X_OFFSET) result.origin.x += object.GetRegister(regs->delta.child[0]);
if (flags & TLF_CHILD_Y_OFFSET) result.origin.y += object.GetRegister(regs->delta.child[1]);
}
}
}

View File

@ -476,13 +476,7 @@ static void DrawTile_Object(TileInfo *ti)
if (!IsInvisibilitySet(TO_STRUCTURES)) {
for (const DrawTileSeqStruct &dtss : dts->GetSequence()) {
AddSortableSpriteToDraw(
dtss.image.sprite, palette,
ti->x + dtss.delta_x, ti->y + dtss.delta_y,
dtss.size_x, dtss.size_y,
dtss.size_z, ti->z + dtss.delta_z,
IsTransparencySet(TO_STRUCTURES)
);
AddSortableSpriteToDraw(dtss.image.sprite, palette, *ti, dtss, IsTransparencySet(TO_STRUCTURES));
}
}
} else {

View File

@ -1899,7 +1899,7 @@ static void DrawSingleSignal(TileIndex tile, const RailTypeInfo *rti, Track trac
sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
}
AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, GetSaveSlopeZ(x, y, track), {{}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {}});
}
static uint32_t _drawtile_track_palette;
@ -1907,12 +1907,11 @@ static uint32_t _drawtile_track_palette;
/** Offsets for drawing fences */
struct FenceOffset {
Corner height_ref; //!< Corner to use height offset from.
int x_offs; //!< Bounding box X offset.
int y_offs; //!< Bounding box Y offset.
int x_size; //!< Bounding box X size.
int y_size; //!< Bounding box Y size.
struct FenceOffset : SpriteBounds {
Corner height_ref; ///< Corner to use height offset from.
constexpr FenceOffset(Corner height_ref, int8_t origin_x, int8_t origin_y, uint8_t extent_x, uint8_t extent_y) :
SpriteBounds({origin_x, origin_y, 0}, {extent_x, extent_y, 4}, {}), height_ref(height_ref) {}
};
/** Offsets for drawing fences */
@ -1948,12 +1947,7 @@ static void DrawTrackFence(const TileInfo *ti, SpriteID base_image, uint num_spr
if (_fence_offsets[rfo].height_ref != CORNER_INVALID) {
z += GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), _fence_offsets[rfo].height_ref);
}
AddSortableSpriteToDraw(base_image + (rfo % num_sprites), _drawtile_track_palette,
ti->x + _fence_offsets[rfo].x_offs,
ti->y + _fence_offsets[rfo].y_offs,
_fence_offsets[rfo].x_size,
_fence_offsets[rfo].y_size,
4, z);
AddSortableSpriteToDraw(base_image + (rfo % num_sprites), _drawtile_track_palette, ti->x, ti->y, z, _fence_offsets[rfo]);
}
/**

View File

@ -1418,7 +1418,7 @@ void DrawRoadTypeCatenary(const TileInfo *ti, RoadType rt, RoadBits rb)
* For tiles with OWNER_TOWN or OWNER_NONE, recolour CC to grey as a neutral colour. */
Owner owner = GetRoadOwner(ti->tile, GetRoadTramType(rt));
PaletteID pal = (owner == OWNER_NONE || owner == OWNER_TOWN ? GetColourPalette(COLOUR_GREY) : GetCompanyPalette(owner));
int z_wires = (ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT) + BB_HEIGHT_UNDER_BRIDGE;
uint8_t z_wires = (ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT) + BB_HEIGHT_UNDER_BRIDGE;
if (back != 0) {
/* The "back" sprite contains the west, north and east pillars.
* We cut the sprite at 3/8 of the west/east edges to create 3 sprites.
@ -1427,13 +1427,16 @@ void DrawRoadTypeCatenary(const TileInfo *ti, RoadType rt, RoadBits rb)
static const SubSprite west = { -INF, -INF, -12, INF };
static const SubSprite north = { -12, -INF, 12, INF };
static const SubSprite east = { 12, -INF, INF, INF };
AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 16, 1, z_wires, ti->z, IsTransparencySet(TO_CATENARY), 15, 0, GetSlopePixelZInCorner(ti->tileh, CORNER_W), &west);
AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 1, 1, z_wires, ti->z, IsTransparencySet(TO_CATENARY), 0, 0, GetSlopePixelZInCorner(ti->tileh, CORNER_N), &north);
AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 1, 16, z_wires, ti->z, IsTransparencySet(TO_CATENARY), 0, 15, GetSlopePixelZInCorner(ti->tileh, CORNER_E), &east);
int8_t west_z = GetSlopePixelZInCorner(ti->tileh, CORNER_W);
int8_t north_z = GetSlopePixelZInCorner(ti->tileh, CORNER_N);
int8_t east_z = GetSlopePixelZInCorner(ti->tileh, CORNER_E);
AddSortableSpriteToDraw(back, pal, *ti, {{15, 0, west_z}, {1, 1, z_wires}, {-15, 0, static_cast<int8_t>(-west_z)}}, IsTransparencySet(TO_CATENARY), &west);
AddSortableSpriteToDraw(back, pal, *ti, {{0, 0, north_z}, {1, 1, z_wires}, {0, 0, static_cast<int8_t>(-north_z)}}, IsTransparencySet(TO_CATENARY), &north);
AddSortableSpriteToDraw(back, pal, *ti, {{0, 15, east_z}, {1, 1, z_wires}, {0, -15, static_cast<int8_t>(-east_z)}}, IsTransparencySet(TO_CATENARY), &east);
}
if (front != 0) {
/* Draw the "front" sprite (containing south pillar and wires) at a Z height that is both above the vehicles and above the "back" pillars. */
AddSortableSpriteToDraw(front, pal, ti->x, ti->y, 16, 16, z_wires + 1, ti->z, IsTransparencySet(TO_CATENARY), 0, 0, z_wires);
AddSortableSpriteToDraw(front, pal, *ti, {{0, 0, static_cast<int8_t>(z_wires)}, {TILE_SIZE, TILE_SIZE, 1}, {0, 0, static_cast<int8_t>(-z_wires)}}, IsTransparencySet(TO_CATENARY));
}
}
@ -1487,13 +1490,13 @@ void DrawRoadCatenary(const TileInfo *ti)
* @param h the height of the sprite to draw
* @param transparent whether the sprite should be transparent (used for roadside trees)
*/
static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int dx, int dy, int h, bool transparent)
static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int8_t dx, int8_t dy, uint8_t h, bool transparent)
{
int x = ti->x | dx;
int y = ti->y | dy;
int z = ti->z;
if (ti->tileh != SLOPE_FLAT) z = GetSlopePixelZ(x, y);
AddSortableSpriteToDraw(img, PAL_NONE, x, y, 2, 2, h, z, transparent);
AddSortableSpriteToDraw(img, PAL_NONE, ti->x, ti->y, z, {{dx, dy, 0}, {2, 2, h}, {}}, transparent);
}
/**

View File

@ -405,29 +405,56 @@ void RoadVehicle::MarkDirty()
void RoadVehicle::UpdateDeltaXY()
{
static const int8_t _delta_xy_table[8][10] = {
/* y_extent, x_extent, y_offs, x_offs, y_bb_offs, x_bb_offs, y_extent_shorten, x_extent_shorten, y_bb_offs_shorten, x_bb_offs_shorten */
{3, 3, -1, -1, 0, 0, -1, -1, -1, -1}, // N
{3, 7, -1, -3, 0, -1, 0, -1, 0, 0}, // NE
{3, 3, -1, -1, 0, 0, 1, -1, 1, -1}, // E
{7, 3, -3, -1, -1, 0, 0, 0, 1, 0}, // SE
{3, 3, -1, -1, 0, 0, 1, 1, 1, 1}, // S
{3, 7, -1, -3, 0, -1, 0, 0, 0, 1}, // SW
{3, 3, -1, -1, 0, 0, -1, 1, -1, 1}, // W
{7, 3, -3, -1, -1, 0, -1, 0, 0, 0}, // NW
};
/* Set common defaults. */
this->bounds = {{-1, -1, 0}, {3, 3, 6}, {}};
int shorten = VEHICLE_LENGTH - this->gcache.cached_veh_length;
if (!IsDiagonalDirection(this->direction)) shorten >>= 1;
if (!IsDiagonalDirection(this->direction)) {
static const Point _sign_table[] = {
/* x, y */
{-1, -1}, // DIR_N
{-1, 1}, // DIR_E
{ 1, 1}, // DIR_S
{ 1, -1}, // DIR_W
};
const int8_t *bb = _delta_xy_table[this->direction];
this->x_bb_offs = bb[5] + bb[9] * shorten;
this->y_bb_offs = bb[4] + bb[8] * shorten;;
this->x_offs = bb[3];
this->y_offs = bb[2];
this->x_extent = bb[1] + bb[7] * shorten;
this->y_extent = bb[0] + bb[6] * shorten;
this->z_extent = 6;
int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2;
/* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
this->bounds.offset.x -= half_shorten * _sign_table[DirToDiagDir(this->direction)].x;
this->bounds.offset.y -= half_shorten * _sign_table[DirToDiagDir(this->direction)].y;
} else {
/* Unlike trains, road vehicles do not have their offsets moved to the centre. */
switch (this->direction) {
/* Shorten southern corner of the bounding box according the vehicle length. */
case DIR_NE:
this->bounds.origin.x = -3;
this->bounds.extent.x = this->gcache.cached_veh_length;
this->bounds.offset.x = 1;
break;
case DIR_NW:
this->bounds.origin.y = -3;
this->bounds.extent.y = this->gcache.cached_veh_length;
this->bounds.offset.y = 1;
break;
/* Move northern corner of the bounding box down according to vehicle length. */
case DIR_SW:
this->bounds.origin.x = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
this->bounds.extent.x = this->gcache.cached_veh_length;
this->bounds.offset.x = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
break;
case DIR_SE:
this->bounds.origin.y = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
this->bounds.extent.y = this->gcache.cached_veh_length;
this->bounds.offset.y = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
break;
default:
NOT_REACHED();
}
}
}
/**

View File

@ -162,6 +162,8 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION),
SLE_CONDVAR(Industry, valid_history, SLE_UINT64, SLV_INDUSTRY_NUM_VALID_HISTORY, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("accepted", SlIndustryAccepted, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("produced", SlIndustryProduced, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
};
@ -228,6 +230,24 @@ struct INDYChunkHandler : ChunkHandler {
} else if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) {
LoadMoveAcceptsProduced(i, INDUSTRY_NUM_INPUTS, INDUSTRY_NUM_OUTPUTS);
}
if (IsSavegameVersionBefore(SLV_INDUSTRY_NUM_VALID_HISTORY)) {
/* The last month has always been recorded. */
size_t oldest_valid = LAST_MONTH;
if (!IsSavegameVersionBefore(SLV_PRODUCTION_HISTORY)) {
/* History was extended but we did not keep track of valid history, so assume it from the oldest non-zero value. */
for (const auto &p : i->produced) {
if (!IsValidCargoType(p.cargo)) continue;
for (size_t n = LAST_MONTH; n < std::size(p.history); ++n) {
if (p.history[n].production == 0 && p.history[n].transported == 0) continue;
oldest_valid = std::max(oldest_valid, n);
}
}
}
/* Set mask bits up to and including the oldest valid record. */
i->valid_history = (std::numeric_limits<uint64_t>::max() >> (std::numeric_limits<uint64_t>::digits - (oldest_valid + 1 - LAST_MONTH))) << LAST_MONTH;
}
Industry::industries[i->type].insert(i->index);
}
}

View File

@ -404,6 +404,7 @@ enum SaveLoadVersion : uint16_t {
SLV_ORDERS_OWNED_BY_ORDERLIST, ///< 354 PR#13948 Orders stored in OrderList, pool removed.
SLV_FACE_STYLES, ///< 355 PR#14319 Addition of face styles, replacing gender and ethnicity.
SLV_INDUSTRY_NUM_VALID_HISTORY, ///< 356 PR#14416 Store number of valid history records for industries.
SL_MAX_VERSION, ///< Highest possible saveload version
};

View File

@ -667,6 +667,15 @@ static void ChangeMinutesPerYear(int32_t new_value)
}
}
/* Get the valid range of the "minutes per calendar year" setting. */
static std::tuple<int32_t, uint32_t> GetMinutesPerYearRange(const IntSettingDesc &)
{
/* Allow a non-default value only if using Wallclock timekeeping units. */
if (_settings_newgame.economy.timekeeping_units == TKU_WALLCLOCK) return { CalendarTime::FROZEN_MINUTES_PER_YEAR, CalendarTime::MAX_MINUTES_PER_YEAR };
return { CalendarTime::DEF_MINUTES_PER_YEAR, CalendarTime::DEF_MINUTES_PER_YEAR };
}
/**
* Pre-callback check when trying to change the timetable mode. This is locked to Seconds when using wallclock units.
* @param Unused.

View File

@ -330,32 +330,26 @@ TileIndex Ship::GetOrderStationLocation(StationID station)
void Ship::UpdateDeltaXY()
{
static const int8_t _delta_xy_table[8][4] = {
/* y_extent, x_extent, y_offs, x_offs */
{ 6, 6, -3, -3}, // N
{ 6, 32, -3, -16}, // NE
{ 6, 6, -3, -3}, // E
{32, 6, -16, -3}, // SE
{ 6, 6, -3, -3}, // S
{ 6, 32, -3, -16}, // SW
{ 6, 6, -3, -3}, // W
{32, 6, -16, -3}, // NW
static constexpr SpriteBounds ship_bounds[DIR_END] = {
{{ -3, -3, 0}, { 6, 6, 6}, {}}, // N
{{-16, -3, 0}, {32, 6, 6}, {}}, // NE
{{ -3, -3, 0}, { 6, 6, 6}, {}}, // E
{{ -3, -16, 0}, { 6, 32, 6}, {}}, // SE
{{ -3, -3, 0}, { 6, 6, 6}, {}}, // S
{{-16, -3, 0}, {32, 6, 6}, {}}, // SW
{{ -3, -3, 0}, { 6, 6, 6}, {}}, // W
{{ -3, -16, 0}, { 6, 32, 6}, {}}, // NW
};
const int8_t *bb = _delta_xy_table[this->rotation];
this->x_offs = bb[3];
this->y_offs = bb[2];
this->x_extent = bb[1];
this->y_extent = bb[0];
this->z_extent = 6;
this->bounds = ship_bounds[this->rotation];
if (this->direction != this->rotation) {
/* If we are rotating, then it is possible the ship was moved to its next position. In that
* case, because we are still showing the old direction, the ship will appear to glitch sideways
* slightly. We can work around this by applying an additional offset to make the ship appear
* where it was before it moved. */
this->x_offs -= this->x_pos - this->rotation_x_pos;
this->y_offs -= this->y_pos - this->rotation_y_pos;
this->bounds.origin.x -= this->x_pos - this->rotation_x_pos;
this->bounds.origin.y -= this->y_pos - this->rotation_y_pos;
}
}

View File

@ -54,16 +54,11 @@ void DrawCommonTileSeq(const TileInfo *ti, const DrawTileSprites *dts, Transpare
if (dtss.IsParentSprite()) {
parent_sprite_encountered = true;
AddSortableSpriteToDraw(
image, pal,
ti->x + dtss.delta_x, ti->y + dtss.delta_y,
dtss.size_x, dtss.size_y,
dtss.size_z, ti->z + dtss.delta_z,
!HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to)
AddSortableSpriteToDraw(image, pal, *ti, dtss, !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to)
);
} else {
int offs_x = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.delta_x) : dtss.delta_x;
int offs_y = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.delta_y) : dtss.delta_y;
int offs_x = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.origin.x) : dtss.origin.x;
int offs_y = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.origin.y) : dtss.origin.y;
bool transparent = !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to);
if (parent_sprite_encountered) {
AddChildSpriteScreen(image, pal, offs_x, offs_y, transparent);
@ -114,15 +109,15 @@ void DrawCommonTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32_t or
pal = SpriteLayoutPaletteTransform(image, pal, default_palette);
if (dtss.IsParentSprite()) {
Point pt = RemapCoords(dtss.delta_x, dtss.delta_y, dtss.delta_z);
Point pt = RemapCoords(dtss.origin.x, dtss.origin.y, dtss.origin.z);
DrawSprite(image, pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y));
const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal);
child_offset.x = UnScaleGUI(pt.x + spr->x_offs);
child_offset.y = UnScaleGUI(pt.y + spr->y_offs);
} else {
int offs_x = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.delta_x) : dtss.delta_x;
int offs_y = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.delta_y) : dtss.delta_y;
int offs_x = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.origin.x) : dtss.origin.x;
int offs_y = child_offset_is_unsigned ? static_cast<uint8_t>(dtss.origin.y) : dtss.origin.y;
DrawSprite(image, pal, x + child_offset.x + ScaleSpriteTrad(offs_x), y + child_offset.y + ScaleSpriteTrad(offs_y));
}
}

View File

@ -10,28 +10,33 @@
#ifndef SPRITE_H
#define SPRITE_H
#include "core/geometry_type.hpp"
#include "transparency.h"
#include "table/sprites.h"
struct SpriteBounds {
PointXyz<int8_t> origin; ///< Position of northern corner within tile.
PointXyz<uint8_t> extent; ///< Size of bounding box.
PointXyz<int8_t> offset; ///< Relative position of sprite from bounding box.
};
/* The following describes bunch of sprites to be drawn together in a single 3D
* bounding box. Used especially for various multi-sprite buildings (like
* depots or stations): */
/** A tile child sprite and palette to draw for stations etc, with 3D bounding box */
struct DrawTileSeqStruct {
int8_t delta_x = 0;
int8_t delta_y = 0;
int8_t delta_z = 0; ///< \c 0x80 identifies child sprites
uint8_t size_x = 0;
uint8_t size_y = 0;
uint8_t size_z = 0;
PalSpriteID image{};
struct DrawTileSeqStruct : SpriteBounds {
PalSpriteID image;
constexpr DrawTileSeqStruct() = default;
constexpr DrawTileSeqStruct(int8_t origin_x, int8_t origin_y, int8_t origin_z, uint8_t extent_x, uint8_t extent_y, uint8_t extent_z, PalSpriteID image) :
SpriteBounds({origin_x, origin_y, origin_z}, {extent_x, extent_y, extent_z}, {}), image(image) {}
/** Check whether this is a parent sprite with a boundingbox. */
bool IsParentSprite() const
inline bool IsParentSprite() const
{
return (uint8_t)this->delta_z != 0x80;
return static_cast<uint8_t>(this->origin.z) != 0x80;
}
};
@ -69,14 +74,9 @@ struct DrawTileSpriteSpan : DrawTileSprites {
* This structure is the same for both Industries and Houses.
* Buildings here reference a general type of construction
*/
struct DrawBuildingsTileStruct {
struct DrawBuildingsTileStruct : SpriteBounds {
PalSpriteID ground;
PalSpriteID building;
uint8_t subtile_x;
uint8_t subtile_y;
uint8_t width;
uint8_t height;
uint8_t dz;
uint8_t draw_proc; // this allows to specify a special drawing procedure.
};

View File

@ -526,7 +526,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
}
if (sprite_type == SpriteType::Font && _font_zoom != ZoomLevel::Min) {
/* Make ZoomLevel::Min be ZOOM_LVL_GUI */
/* Make ZoomLevel::Min the desired font zoom level. */
sprite[ZoomLevel::Min] = sprite[_font_zoom];
}

View File

@ -3184,7 +3184,7 @@ static void DrawTile_Station(TileInfo *ti)
7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN
};
AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, 7}, {}});
} else {
/* Draw simple foundations, built up from 8 possible foundation sprites. */
@ -3218,7 +3218,7 @@ static void DrawTile_Station(TileInfo *ti)
StartSpriteCombine();
for (int i = 0; i < 8; i++) {
if (HasBit(parts, i)) {
AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
AddSortableSpriteToDraw(image + i, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, 7}, {}});
}
}
EndSpriteCombine();

View File

@ -286,6 +286,7 @@ struct LoadedLanguagePack {
std::array<uint, TEXT_TAB_END> langtab_start; ///< Offset into langpack offs
std::string list_separator; ///< Current list separator string.
std::string ellipsis; ///< Current ellipsis string.
};
static LoadedLanguagePack _langpack;
@ -301,6 +302,15 @@ std::string_view GetListSeparator()
return _langpack.list_separator;
}
/**
* Get the ellipsis string for the current language.
* @returns string containing ellipsis to use.
*/
std::string_view GetEllipsis()
{
return _langpack.ellipsis;
}
std::string_view GetStringPtr(StringID string)
{
switch (GetStringTab(string)) {
@ -2063,6 +2073,7 @@ bool ReadLanguagePack(const LanguageMetadata *lang)
_config_language_file = FS2OTTD(_current_language->file.filename().native());
SetCurrentGrfLangID(_current_language->newgrflangid);
_langpack.list_separator = GetString(STR_LIST_SEPARATOR);
_langpack.ellipsis = GetString(STR_TRUNCATION_ELLIPSIS);
#ifdef _WIN32
extern void Win32SetCurrentLocaleName(std::string iso_code);

View File

@ -98,6 +98,7 @@ extern TextDirection _current_text_dir; ///< Text direction of the currently sel
void InitializeLanguagePacks();
std::string_view GetCurrentLanguageIsoCode();
std::string_view GetListSeparator();
std::string_view GetEllipsis();
/**
* Helper to create the StringParameters with its own buffer with the given

View File

@ -313,14 +313,12 @@ enum WireSpriteOffset : uint8_t {
WSO_ENTRANCE_SE,
};
struct SortableSpriteStruct {
struct SortableSpriteStruct : SpriteBounds {
uint8_t image_offset;
int8_t x_offset;
int8_t y_offset;
int8_t x_size;
int8_t y_size;
int8_t z_size;
int8_t z_offset;
constexpr SortableSpriteStruct(uint8_t image_offset, const SpriteBounds &bounds) : SpriteBounds(bounds), image_offset(image_offset) {}
constexpr SortableSpriteStruct(uint8_t image_offset, int8_t x_offset, int8_t y_offset, uint8_t x_size, uint8_t y_size, uint8_t z_size, int8_t z_offset) :
SpriteBounds({x_offset, y_offset, z_offset}, {x_size, y_size, z_size}, {}), image_offset(image_offset) {}
};
/** Distance between wire and rail */
@ -398,11 +396,17 @@ static const SortableSpriteStruct _rail_catenary_sprite_data_depot[] = {
{ WSO_ENTRANCE_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW depot exit
};
/**
* In tunnelheads, the bounding box for wires covers nearly the full tile, and is lowered a bit.
* ELRAIL_TUNNEL_OFFSET is the difference between visual position and bounding box.
*/
static const int8_t ELRAIL_TUNNEL_OFFSET = ELRAIL_ELEVATION - BB_Z_SEPARATOR;
static const SortableSpriteStruct _rail_catenary_sprite_data_tunnel[] = {
{ WSO_ENTRANCE_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE tunnel (SW facing exit)
{ WSO_ENTRANCE_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! Wire for SE tunnel (NW facing exit)
{ WSO_ENTRANCE_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW tunnel (NE facing exit)
{ WSO_ENTRANCE_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW tunnel (SE facing exit)
{ WSO_ENTRANCE_SW, {{0, 0, BB_Z_SEPARATOR}, {16, 15, 1}, {0, 7, ELRAIL_TUNNEL_OFFSET}} }, //! Wire for NE tunnel (SW facing exit)
{ WSO_ENTRANCE_NW, {{0, 0, BB_Z_SEPARATOR}, {15, 16, 1}, {7, 0, ELRAIL_TUNNEL_OFFSET}} }, //! Wire for SE tunnel (NW facing exit)
{ WSO_ENTRANCE_NE, {{0, 0, BB_Z_SEPARATOR}, {16, 15, 1}, {0, 7, ELRAIL_TUNNEL_OFFSET}} }, //! Wire for SW tunnel (NE facing exit)
{ WSO_ENTRANCE_SE, {{0, 0, BB_Z_SEPARATOR}, {15, 16, 1}, {7, 0, ELRAIL_TUNNEL_OFFSET}} } //! Wire for NW tunnel (SE facing exit)
};

View File

@ -37,15 +37,15 @@ struct DrawIndustryCoordinates {
* @param p1 palette ID of ground sprite
* @param s2 sprite ID of building sprite
* @param p2 palette ID of building sprite
* @param sx coordinate x of the sprite
* @param sy coordinate y of the sprite
* @param w width of the sprite
* @param h height of the sprite
* @param dz virtual height of the sprite
* @param dx The x-position of the sprite within the tile.
* @param dy the y-position of the sprite within the tile.
* @param sx the x-extent of the sprite.
* @param sy the y-extent of the sprite.
* @param sz the z-extent of the sprite.
* @param p this allows to specify a special drawing procedure.
* @see DrawBuildingsTileStruct
*/
#define M(s1, p1, s2, p2, sx, sy, w, h, dz, p) { { s1, p1 }, { s2, p2 }, sx, sy, w, h, dz, p }
#define M(s1, p1, s2, p2, dx, dy, sx, sy, sz, p) { {{dx, dy, 0}, {sx, sy, sz}, {}}, { s1, p1 }, { s2, p2 }, p}
/** Structure for industry tiles drawing */
static const DrawBuildingsTileStruct _industry_draw_tile_data[NEW_INDUSTRYTILEOFFSET * 4] = {

View File

@ -11,6 +11,7 @@
static void TownFoundingChanged(int32_t new_value);
static void ChangeTimekeepingUnits(int32_t new_value);
static void ChangeMinutesPerYear(int32_t new_value);
static std::tuple<int32_t, uint32_t> GetMinutesPerYearRange(const IntSettingDesc &sd);
static constexpr std::initializer_list<std::string_view> _place_houses{"forbidden"sv, "allowed"sv, "fully constructed"sv};
@ -332,6 +333,7 @@ strhelp = STR_CONFIG_SETTING_MINUTES_PER_YEAR_HELPTEXT
strval = STR_CONFIG_SETTING_MINUTES_PER_YEAR_VALUE
pre_cb = [](auto) { return _game_mode == GM_MENU || _settings_game.economy.timekeeping_units == 1; }
post_cb = ChangeMinutesPerYear
range_cb = GetMinutesPerYearRange
cat = SC_BASIC
[SDT_VAR]

View File

@ -13,15 +13,15 @@
* @param p1 The first sprite's palette of the building, mostly the ground sprite
* @param s2 The second sprite of the building.
* @param p2 The second sprite's palette of the building.
* @param sx The x-position of the sprite within the tile
* @param sy the y-position of the sprite within the tile
* @param w the width of the sprite
* @param h the height of the sprite
* @param dz the virtual height of the sprite
* @param dx The x-position of the sprite within the tile.
* @param dy the y-position of the sprite within the tile.
* @param sx the x-extent of the sprite.
* @param sy the y-extent of the sprite.
* @param sz the z-extent of the sprite.
* @param p set to 1 if a lift is present ()
* @see DrawBuildingsTileStruct
*/
#define M(s1, p1, s2, p2, sx, sy, w, h, dz, p) { { s1, p1 }, { s2, p2 }, sx, sy, w, h, dz, p}
#define M(s1, p1, s2, p2, dx, dy, sx, sy, sz, p) { {{dx, dy, 0}, {sx, sy, sz}, {}}, { s1, p1 }, { s2, p2 }, p}
/** structure of houses graphics*/
static const DrawBuildingsTileStruct _town_draw_tile_data[] = {

View File

@ -10,6 +10,7 @@
#ifndef TILE_CMD_H
#define TILE_CMD_H
#include "core/geometry_type.hpp"
#include "command_type.h"
#include "vehicle_type.h"
#include "cargo_type.h"
@ -26,12 +27,9 @@ enum class VehicleEnterTileState : uint8_t {
using VehicleEnterTileStates = EnumBitSet<VehicleEnterTileState, uint8_t>;
/** Tile information, used while rendering the tile */
struct TileInfo {
int x; ///< X position of the tile in unit coordinates
int y; ///< Y position of the tile in unit coordinates
struct TileInfo : PointXyz<int> {
Slope tileh; ///< Slope of the tile
TileIndex tile; ///< Tile index
int z; ///< Height
};
/** Tile description for the 'land area information' tool */

View File

@ -12,29 +12,29 @@
#include "core/strong_typedef_type.hpp"
static const uint TILE_SIZE = 16; ///< Tile size in world coordinates.
static const uint TILE_UNIT_MASK = TILE_SIZE - 1; ///< For masking in/out the inner-tile world coordinate units.
static const uint TILE_PIXELS = 32; ///< Pixel distance between tile columns/rows in #ZOOM_BASE.
static const uint TILE_HEIGHT = 8; ///< Height of a height level in world coordinate AND in pixels in #ZOOM_BASE.
static constexpr uint TILE_SIZE = 16; ///< Tile size in world coordinates.
static constexpr uint TILE_UNIT_MASK = TILE_SIZE - 1; ///< For masking in/out the inner-tile world coordinate units.
static constexpr uint TILE_PIXELS = 32; ///< Pixel distance between tile columns/rows in #ZOOM_BASE.
static constexpr uint TILE_HEIGHT = 8; ///< Height of a height level in world coordinate AND in pixels in #ZOOM_BASE.
static const uint MAX_BUILDING_PIXELS = 200; ///< Maximum height of a building in pixels in #ZOOM_BASE. (Also applies to "bridge buildings" on the bridge floor.)
static const int MAX_VEHICLE_PIXEL_X = 192; ///< Maximum width of a vehicle in pixels in #ZOOM_BASE.
static const int MAX_VEHICLE_PIXEL_Y = 96; ///< Maximum height of a vehicle in pixels in #ZOOM_BASE.
static constexpr uint MAX_BUILDING_PIXELS = 200; ///< Maximum height of a building in pixels in #ZOOM_BASE. (Also applies to "bridge buildings" on the bridge floor.)
static constexpr int MAX_VEHICLE_PIXEL_X = 192; ///< Maximum width of a vehicle in pixels in #ZOOM_BASE.
static constexpr int MAX_VEHICLE_PIXEL_Y = 96; ///< Maximum height of a vehicle in pixels in #ZOOM_BASE.
static const uint MAX_TILE_HEIGHT = 255; ///< Maximum allowed tile height
static constexpr uint MAX_TILE_HEIGHT = 255; ///< Maximum allowed tile height
static const uint MIN_HEIGHTMAP_HEIGHT = 1; ///< Lowest possible peak value for heightmap creation
static const uint MIN_CUSTOM_TERRAIN_TYPE = 1; ///< Lowest possible peak value for world generation
static constexpr uint MIN_HEIGHTMAP_HEIGHT = 1; ///< Lowest possible peak value for heightmap creation
static constexpr uint MIN_CUSTOM_TERRAIN_TYPE = 1; ///< Lowest possible peak value for world generation
static const uint MIN_MAP_HEIGHT_LIMIT = 15; ///< Lower bound of maximum allowed heightlevel (in the construction settings)
static const uint MAX_MAP_HEIGHT_LIMIT = MAX_TILE_HEIGHT; ///< Upper bound of maximum allowed heightlevel (in the construction settings)
static constexpr uint MIN_MAP_HEIGHT_LIMIT = 15; ///< Lower bound of maximum allowed heightlevel (in the construction settings)
static constexpr uint MAX_MAP_HEIGHT_LIMIT = MAX_TILE_HEIGHT; ///< Upper bound of maximum allowed heightlevel (in the construction settings)
static const uint MIN_SNOWLINE_HEIGHT = 2; ///< Minimum snowline height
static const uint DEF_SNOWLINE_HEIGHT = 10; ///< Default snowline height
static const uint MAX_SNOWLINE_HEIGHT = (MAX_TILE_HEIGHT - 2); ///< Maximum allowed snowline height
static constexpr uint MIN_SNOWLINE_HEIGHT = 2; ///< Minimum snowline height
static constexpr uint DEF_SNOWLINE_HEIGHT = 10; ///< Default snowline height
static constexpr uint MAX_SNOWLINE_HEIGHT = (MAX_TILE_HEIGHT - 2); ///< Maximum allowed snowline height
static const uint DEF_SNOW_COVERAGE = 40; ///< Default snow coverage.
static const uint DEF_DESERT_COVERAGE = 50; ///< Default desert coverage.
static constexpr uint DEF_SNOW_COVERAGE = 40; ///< Default snow coverage.
static constexpr uint DEF_DESERT_COVERAGE = 50; ///< Default desert coverage.
/**

View File

@ -284,15 +284,7 @@ static void DrawTile_Town(TileInfo *ti)
/* Add a house on top of the ground? */
SpriteID image = dcts->building.sprite;
if (image != 0) {
AddSortableSpriteToDraw(image, dcts->building.pal,
ti->x + dcts->subtile_x,
ti->y + dcts->subtile_y,
dcts->width,
dcts->height,
dcts->dz,
ti->z,
IsTransparencySet(TO_HOUSES)
);
AddSortableSpriteToDraw(image, dcts->building.pal, *ti, *dcts, IsTransparencySet(TO_HOUSES));
if (IsTransparencySet(TO_HOUSES)) return;
}

View File

@ -1376,7 +1376,7 @@ void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
/* Add a house on top of the ground? */
if (dcts.building.sprite != 0) {
Point pt = RemapCoords(dcts.subtile_x, dcts.subtile_y, 0);
Point pt = RemapCoords(dcts.origin.x, dcts.origin.y, dcts.origin.z);
DrawSprite(dcts.building.sprite, dcts.building.pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y));
}
};
@ -1628,7 +1628,7 @@ static CargoTypes GetProducedCargoOfHouse(const HouseSpec *hs)
struct BuildHouseWindow : public PickerWindow {
std::string house_info{};
bool house_protected = false;
static inline bool house_protected;
BuildHouseWindow(WindowDesc &desc, Window *parent) : PickerWindow(desc, parent, 0, HousePickerCallbacks::instance)
{
@ -1735,9 +1735,9 @@ struct BuildHouseWindow : public PickerWindow {
switch (widget) {
case WID_BH_PROTECT_OFF:
case WID_BH_PROTECT_ON:
this->house_protected = (widget == WID_BH_PROTECT_ON);
this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !this->house_protected);
this->SetWidgetLoweredState(WID_BH_PROTECT_ON, this->house_protected);
BuildHouseWindow::house_protected = (widget == WID_BH_PROTECT_ON);
this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !BuildHouseWindow::house_protected);
this->SetWidgetLoweredState(WID_BH_PROTECT_ON, BuildHouseWindow::house_protected);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
this->SetDirty();
@ -1764,10 +1764,10 @@ struct BuildHouseWindow : public PickerWindow {
/* If house spec already has the protected flag, handle it automatically and disable the buttons. */
bool hasflag = spec->extra_flags.Test(HouseExtraFlag::BuildingIsProtected);
if (hasflag) this->house_protected = true;
if (hasflag) BuildHouseWindow::house_protected = true;
this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !this->house_protected);
this->SetWidgetLoweredState(WID_BH_PROTECT_ON, this->house_protected);
this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !BuildHouseWindow::house_protected);
this->SetWidgetLoweredState(WID_BH_PROTECT_ON, BuildHouseWindow::house_protected);
this->SetWidgetDisabledState(WID_BH_PROTECT_OFF, hasflag);
this->SetWidgetDisabledState(WID_BH_PROTECT_ON, hasflag);
@ -1776,7 +1776,7 @@ struct BuildHouseWindow : public PickerWindow {
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
{
const HouseSpec *spec = HouseSpec::Get(HousePickerCallbacks::sel_type);
Command<CMD_PLACE_HOUSE>::Post(STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), this->house_protected);
Command<CMD_PLACE_HOUSE>::Post(STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), BuildHouseWindow::house_protected);
}
const IntervalTimer<TimerWindow> view_refresh_interval = {std::chrono::milliseconds(2500), [this](auto) {

View File

@ -1491,13 +1491,7 @@ CommandCost CmdSellRailWagon(DoCommandFlags flags, Vehicle *t, bool sell_chain,
void Train::UpdateDeltaXY()
{
/* Set common defaults. */
this->x_offs = -1;
this->y_offs = -1;
this->x_extent = 3;
this->y_extent = 3;
this->z_extent = 6;
this->x_bb_offs = 0;
this->y_bb_offs = 0;
this->bounds = {{-1, -1, 0}, {3, 3, 6}, {}};
/* Set if flipped and engine is NOT flagged with custom flip handling. */
int flipped = this->flags.Test(VehicleRailFlag::Flipped) && !EngInfo(this->engine_type)->misc_flags.Test(EngineMiscFlag::RailFlips);
@ -1508,50 +1502,47 @@ void Train::UpdateDeltaXY()
if (flipped) dir = ReverseDir(dir);
if (!IsDiagonalDirection(dir)) {
static const int _sign_table[] =
{
static const Point _sign_table[] = {
/* x, y */
-1, -1, // DIR_N
-1, 1, // DIR_E
1, 1, // DIR_S
1, -1, // DIR_W
{-1, -1}, // DIR_N
{-1, 1}, // DIR_E
{ 1, 1}, // DIR_S
{ 1, -1}, // DIR_W
};
int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length + flipped) / 2;
/* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
this->x_offs -= half_shorten * _sign_table[dir];
this->y_offs -= half_shorten * _sign_table[dir + 1];
this->x_extent += this->x_bb_offs = half_shorten * _sign_table[dir];
this->y_extent += this->y_bb_offs = half_shorten * _sign_table[dir + 1];
this->bounds.offset.x -= half_shorten * _sign_table[DirToDiagDir(dir)].x;
this->bounds.offset.y -= half_shorten * _sign_table[DirToDiagDir(dir)].y;
} else {
switch (dir) {
/* Shorten southern corner of the bounding box according the vehicle length
* and center the bounding box on the vehicle. */
case DIR_NE:
this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs;
this->x_extent = this->gcache.cached_veh_length - 1;
this->x_bb_offs = -1;
this->bounds.origin.x = -(this->gcache.cached_veh_length + 1) / 2 + flip_offs;
this->bounds.extent.x = this->gcache.cached_veh_length;
this->bounds.offset.x = 1;
break;
case DIR_NW:
this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs;
this->y_extent = this->gcache.cached_veh_length - 1;
this->y_bb_offs = -1;
this->bounds.origin.y = -(this->gcache.cached_veh_length + 1) / 2 + flip_offs;
this->bounds.extent.y = this->gcache.cached_veh_length;
this->bounds.offset.y = 1;
break;
/* Move northern corner of the bounding box down according to vehicle length
* and center the bounding box on the vehicle. */
case DIR_SW:
this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs;
this->x_extent = VEHICLE_LENGTH - 1;
this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
this->bounds.origin.x = -(this->gcache.cached_veh_length) / 2 - flip_offs;
this->bounds.extent.x = this->gcache.cached_veh_length;
this->bounds.offset.x = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
break;
case DIR_SE:
this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs;
this->y_extent = VEHICLE_LENGTH - 1;
this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
this->bounds.origin.y = -(this->gcache.cached_veh_length) / 2 - flip_offs;
this->bounds.extent.y = this->gcache.cached_veh_length;
this->bounds.offset.y = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
break;
default:

View File

@ -635,7 +635,7 @@ CommandCost CmdPlantTree(DoCommandFlags flags, TileIndex tile, TileIndex start_t
}
struct TreeListEnt : PalSpriteID {
uint8_t x, y;
int8_t x, y;
};
static void DrawTile_Trees(TileInfo *ti)
@ -699,7 +699,8 @@ static void DrawTile_Trees(TileInfo *ti)
}
}
AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x + te[mi].x, ti->y + te[mi].y, 16 - te[mi].x, 16 - te[mi].y, 0x30, z, IsTransparencySet(TO_TREES), -te[mi].x, -te[mi].y);
SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, 48}, {te[mi].x, te[mi].y, 0}};
AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x, ti->y, z, bounds, IsTransparencySet(TO_TREES));
/* replace the removed one with the last one */
te[mi] = te[trees - 1];

View File

@ -1017,10 +1017,10 @@ static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlags flags)
* @param h Bounding box size in Y direction
* @param subsprite Optional subsprite for drawing halfpillars
*/
static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, int w, int h, const SubSprite *subsprite)
static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
{
static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START; ///< Start offset of pillar wrt. bridge (downwards)
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, w, h, BB_HEIGHT_UNDER_BRIDGE - PILLAR_Z_OFFSET, z, IsTransparencySet(TO_BRIDGES), 0, 0, -PILLAR_Z_OFFSET, subsprite);
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, -PILLAR_Z_OFFSET}, {w, h, BB_HEIGHT_UNDER_BRIDGE}, {0, 0, PILLAR_Z_OFFSET}}, IsTransparencySet(TO_BRIDGES), subsprite);
}
/**
@ -1194,18 +1194,20 @@ static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int off
}
}
static const uint size_x[6] = { 1, 16, 16, 1, 16, 1 };
static const uint size_y[6] = { 16, 1, 1, 16, 1, 16 };
static const uint front_bb_offset_x[6] = { 15, 0, 0, 15, 0, 15 };
static const uint front_bb_offset_y[6] = { 0, 15, 15, 0, 15, 0 };
static constexpr SpriteBounds back_bounds[6] = {
{{}, {0, TILE_SIZE, 40}, {}},
{{}, {TILE_SIZE, 0, 40}, {}},
{{}, {TILE_SIZE, 0, 40}, {}},
{{}, {0, TILE_SIZE, 40}, {}},
{{}, {TILE_SIZE, 0, 40}, {}},
{{}, {0, TILE_SIZE, 40}, {}},
};
/* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called
* The bounding boxes here are the same as for bridge front/roof */
for (uint i = 0; i < lengthof(seq_back); ++i) {
if (seq_back[i] != 0) {
AddSortableSpriteToDraw(seq_back[i], PAL_NONE,
x, y, size_x[offset], size_y[offset], 0x28, z,
trans_back[i]);
AddSortableSpriteToDraw(seq_back[i], PAL_NONE, x, y, z, back_bounds[offset], trans_back[i]);
}
}
@ -1213,12 +1215,18 @@ static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int off
EndSpriteCombine();
StartSpriteCombine();
static constexpr SpriteBounds front_bounds[6] = {
{{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
{{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
{{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
{{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
{{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
{{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
};
for (uint i = 0; i < lengthof(seq_front); ++i) {
if (seq_front[i] != 0) {
AddSortableSpriteToDraw(seq_front[i], PAL_NONE,
x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z,
trans_front[i],
front_bb_offset_x[offset], front_bb_offset_y[offset]);
AddSortableSpriteToDraw(seq_front[i], PAL_NONE, x, y, z, front_bounds[offset], trans_front[i]);
}
}
}
@ -1251,15 +1259,35 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
*
*/
static const int _tunnel_BB[4][12] = {
/* tunnnel-roof | Z-separator | tram-catenary
* w h bb_x bb_y| x y w h |bb_x bb_y w h */
{ 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // NE
{ 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // SE
{ 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // SW
{ 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // NW
/* Tunnel sprites are positioned at 15,15, but the bounding box covers most of the tile. */
static constexpr SpriteBounds roof_bounds[DIAGDIR_END] = {
{{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // NE
{{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // SE
{{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // SW
{{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // NW
};
/* Catenary sprites are positioned at 0,0, with the same bounding box as above. */
static constexpr SpriteBounds catenary_bounds[DIAGDIR_END] = {
{{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // NE
{{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // SE
{{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // SW
{{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // NW
};
static constexpr SpriteBounds rear_sep[DIAGDIR_END] = {
{{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
{{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
{{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
{{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
};
static constexpr SpriteBounds front_sep[DIAGDIR_END] = {
{{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
{{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
{{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
{{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
};
const int *BB_data = _tunnel_BB[tunnelbridge_direction];
bool catenary = false;
@ -1332,7 +1360,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
if (catenary_sprite_base != 0) {
catenary = true;
StartSpriteCombine();
AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR);
AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, *ti, catenary_bounds[tunnelbridge_direction], IsTransparencySet(TO_CATENARY));
}
} else {
const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
@ -1364,15 +1392,15 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
if (railtype_overlay != 0 && !catenary) StartSpriteCombine();
AddSortableSpriteToDraw(image + 1, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR);
AddSortableSpriteToDraw(image + 1, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
/* Draw railtype tunnel portal overlay if defined. */
if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR);
if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
if (catenary || railtype_overlay != 0) EndSpriteCombine();
/* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */
AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x, ti->y, BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x + BB_data[4], ti->y + BB_data[5], BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, rear_sep[tunnelbridge_direction]);
AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, front_sep[tunnelbridge_direction]);
DrawBridgeMiddle(ti);
} else { // IsBridge(ti->tile)
@ -1423,7 +1451,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
* it doesn't disappear behind it
*/
/* Bridge heads are drawn solid no matter how invisibility/transparency is set */
AddSortableSpriteToDraw(psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z);
AddSortableSpriteToDraw(psid->sprite, psid->pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
if (transport_type == TRANSPORT_ROAD) {
uint offset = tunnelbridge_direction;
@ -1445,9 +1473,9 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_BRIDGE);
if (surface != 0) {
if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, ti->x, ti->y, 16, 16, 0, ti->z + 8);
AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
} else {
AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, 16, 16, 8, ti->z);
AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
}
}
/* Don't fallback to non-overlay sprite -- the spec states that
@ -1460,15 +1488,15 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
if (rti->UsesOverlay()) {
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8);
AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
} else {
AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z);
AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
}
} else {
if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8);
AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
} else {
AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z);
AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
}
}
}
@ -1578,7 +1606,7 @@ void DrawBridgeMiddle(const TileInfo *ti)
int z = bridge_z - BRIDGE_Z_START;
/* Add a bounding box that separates the bridge from things below it. */
AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, 16, 16, 1, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR);
AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR, {{}, {TILE_SIZE, TILE_SIZE, 1}, {}});
/* Draw Trambits as SpriteCombine */
if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
@ -1586,9 +1614,9 @@ void DrawBridgeMiddle(const TileInfo *ti)
/* Draw floor and far part of bridge*/
if (!IsInvisibilitySet(TO_BRIDGES)) {
if (axis == AXIS_X) {
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 1, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
} else {
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
}
}
@ -1602,16 +1630,16 @@ void DrawBridgeMiddle(const TileInfo *ti)
if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) {
SpriteID surface = GetCustomRailSprite(rti, rampsouth, RTSG_BRIDGE, TCX_ON_BRIDGE);
if (surface != 0) {
AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES));
}
}
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth)) {
if (rti->UsesOverlay()) {
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES));
} else {
AddSortableSpriteToDraw(axis == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
AddSortableSpriteToDraw(axis == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES));
}
}
@ -1626,10 +1654,10 @@ void DrawBridgeMiddle(const TileInfo *ti)
if (!IsInvisibilitySet(TO_BRIDGES)) {
if (axis == AXIS_X) {
y += 12;
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 4, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 3, BRIDGE_Z_START);
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 3, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, -3, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
} else {
x += 12;
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 4, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 3, 0, BRIDGE_Z_START);
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{3, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {-3, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
}
}

View File

@ -1109,8 +1109,7 @@ static void DoDrawVehicle(const Vehicle *v)
for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) {
PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal;
if (!pal2 || v->vehstatus.Test(VehState::Crashed)) pal2 = pal;
AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos, v->y_pos, v->z_pos, v->bounds, shadowed);
}
EndSpriteCombine();
}
@ -1674,12 +1673,24 @@ void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const
Rect new_coord;
this->sprite_cache.sprite_seq.GetBounds(&new_coord);
Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
/* z-bounds are not used. */
Point pt = RemapCoords(this->x_pos + this->bounds.origin.x + this->bounds.offset.x, this->y_pos + this->bounds.origin.y + this->bounds.offset.y, this->z_pos);
new_coord.left += pt.x;
new_coord.top += pt.y;
new_coord.right += pt.x + 2 * ZOOM_BASE;
new_coord.bottom += pt.y + 2 * ZOOM_BASE;
extern bool _draw_bounding_boxes;
if (_draw_bounding_boxes) {
int x = this->x_pos + this->bounds.origin.x;
int y = this->y_pos + this->bounds.origin.y;
int z = this->z_pos + this->bounds.origin.z;
new_coord.left = std::min(new_coord.left, RemapCoords(x + bounds.extent.x, y, z).x);
new_coord.right = std::max(new_coord.right, RemapCoords(x, y + bounds.extent.y, z).x + 1);
new_coord.top = std::min(new_coord.top, RemapCoords(x, y, z + bounds.extent.z).y);
new_coord.bottom = std::max(new_coord.bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1);
}
if (update_cache) {
/*
* If the old coordinates are invalid, set the cache to the new coordinates for correct

View File

@ -10,6 +10,7 @@
#ifndef VEHICLE_BASE_H
#define VEHICLE_BASE_H
#include "sprite.h"
#include "track_type.h"
#include "command_type.h"
#include "order_base.h"
@ -293,13 +294,7 @@ public:
* 0xff == reserved for another custom sprite
*/
uint8_t spritenum = 0;
uint8_t x_extent = 0; ///< x-extent of vehicle bounding box
uint8_t y_extent = 0; ///< y-extent of vehicle bounding box
uint8_t z_extent = 0; ///< z-extent of vehicle bounding box
int8_t x_bb_offs = 0; ///< x offset of vehicle bounding box
int8_t y_bb_offs = 0; ///< y offset of vehicle bounding box
int8_t x_offs = 0; ///< x offset for vehicle sprite
int8_t y_offs = 0; ///< y offset for vehicle sprite
SpriteBounds bounds{}; ///< Bounding box of vehicle.
EngineID engine_type = EngineID::Invalid(); ///< The type of engine used for this vehicle.
TextEffectID fill_percent_te_id = INVALID_TE_ID; ///< a text-effect id to a loading indicator object

View File

@ -1080,9 +1080,9 @@ void OpenGLBackend::DrawMouseCursor()
const OpenGLSprite *spr = this->cursor_cache.Get(cs.image.sprite).get();
this->RenderOglSprite(spr, cs.image.pal,
this->cursor_pos.x + cs.pos.x + UnScaleByZoom(spr->x_offs, ZOOM_LVL_GUI),
this->cursor_pos.y + cs.pos.y + UnScaleByZoom(spr->y_offs, ZOOM_LVL_GUI),
ZOOM_LVL_GUI);
this->cursor_pos.x + cs.pos.x + UnScaleByZoom(spr->x_offs, _gui_zoom),
this->cursor_pos.y + cs.pos.y + UnScaleByZoom(spr->y_offs, _gui_zoom),
_gui_zoom);
}
}
}

View File

@ -660,12 +660,17 @@ static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z
* @param bb_offset_z bounding box extent towards negative Z (world)
* @param sub Only draw a part of the sprite.
*/
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
{
int32_t left, right, top, bottom;
assert((image & SPRITE_MASK) < MAX_SPRITES);
/* Move to bounding box. */
x += bounds.origin.x;
y += bounds.origin.y;
z += bounds.origin.z;
/* make the sprites transparent with the right palette */
if (transparent) {
SetBit(image, PALETTE_MODIFIER_TRANSPARENT);
@ -673,21 +678,21 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w,
}
if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) {
AddCombinedSprite(image, pal, x, y, z, sub);
AddCombinedSprite(image, pal, x + bounds.offset.x, y + bounds.offset.y, z + bounds.offset.z, sub);
return;
}
_vd.last_child = LAST_CHILD_NONE;
Point pt = RemapCoords(x, y, z);
Point pt = RemapCoords(x + bounds.offset.x, y + bounds.offset.y, z + bounds.offset.z);
int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y;
/* Compute screen extents of sprite */
if (image == SPR_EMPTY_BOUNDING_BOX) {
left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x;
right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1;
top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y;
bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1;
left = tmp_left = RemapCoords(x + bounds.extent.x, y, z).x;
right = RemapCoords(x, y + bounds.extent.y, z).x + 1;
top = tmp_top = RemapCoords(x, y, z + bounds.extent.z).y;
bottom = RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1;
} else {
const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal);
left = tmp_left = (pt.x += spr->x_offs);
@ -698,10 +703,10 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w,
if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) {
/* Compute maximal extents of sprite and its bounding box */
left = std::min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x);
right = std::max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1);
top = std::min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y);
bottom = std::max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1);
left = std::min(left , RemapCoords(x + bounds.extent.x, y, z).x);
right = std::max(right , RemapCoords(x, y + bounds.extent.y, z).x + 1);
top = std::min(top , RemapCoords(x, y, z + bounds.extent.z).y);
bottom = std::max(bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1);
}
/* Do not add the sprite to the viewport, if it is outside */
@ -722,14 +727,14 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w,
ps.image = image;
ps.pal = pal;
ps.sub = sub;
ps.xmin = x + bb_offset_x;
ps.xmax = x + std::max(bb_offset_x, w) - 1;
ps.xmin = x;
ps.xmax = x + bounds.extent.x - 1;
ps.ymin = y + bb_offset_y;
ps.ymax = y + std::max(bb_offset_y, h) - 1;
ps.ymin = y;
ps.ymax = y + bounds.extent.y - 1;
ps.zmin = z + bb_offset_z;
ps.zmax = z + std::max(bb_offset_z, dz) - 1;
ps.zmin = z;
ps.zmax = z + bounds.extent.z - 1;
ps.first_child = LAST_CHILD_NONE;

View File

@ -11,6 +11,7 @@
#define VIEWPORT_FUNC_H
#include "gfx_type.h"
#include "sprite.h"
#include "viewport_type.h"
#include "window_type.h"
#include "tile_map.h"
@ -51,10 +52,14 @@ void OffsetGroundSprite(int x, int y);
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0);
void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32_t x, int32_t y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0);
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = nullptr);
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent = false, const SubSprite *sub = nullptr);
void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent = false, const SubSprite *sub = nullptr, bool scale = true, bool relative = true);
std::string *ViewportAddString(const DrawPixelInfo *dpi, const ViewportSign *sign, ViewportStringFlags flags, Colours colour);
inline void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, const PointXyz<int32_t> &world, const SpriteBounds &bounds, bool transparent = false, const SubSprite *sub = nullptr)
{
AddSortableSpriteToDraw(image, pal, world.x, world.y, world.z, bounds, transparent, sub);
}
void StartSpriteCombine();
void EndSpriteCombine();

View File

@ -89,8 +89,8 @@ enum ZoomStateChange : uint8_t {
* z=6 reserved, currently unused.
* z=7 Z separator between bridge/tunnel and the things under/above it.
*/
static const uint BB_HEIGHT_UNDER_BRIDGE = 6; ///< Everything that can be built under low bridges, must not exceed this Z height.
static const uint BB_Z_SEPARATOR = 7; ///< Separates the bridge/tunnel from the things under/above it.
static constexpr int BB_HEIGHT_UNDER_BRIDGE = 6; ///< Everything that can be built under low bridges, must not exceed this Z height.
static constexpr int BB_Z_SEPARATOR = 7; ///< Separates the bridge/tunnel from the things under/above it.
/** Viewport place method (type of highlighted area and placed objects) */
enum ViewportPlaceMethod : uint8_t {

View File

@ -806,11 +806,7 @@ static void DrawWaterTileStruct(const TileInfo *ti, std::span<const DrawTileSeqS
for (const DrawTileSeqStruct &dtss : seq) {
uint tile_offs = offset + dtss.image.sprite;
if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs);
AddSortableSpriteToDraw(base + tile_offs, palette,
ti->x + dtss.delta_x, ti->y + dtss.delta_y,
dtss.size_x, dtss.size_y,
dtss.size_z, ti->z + dtss.delta_z,
IsTransparencySet(TO_BUILDINGS));
AddSortableSpriteToDraw(base + tile_offs, palette, *ti, dtss, IsTransparencySet(TO_BUILDINGS));
}
}

View File

@ -44,7 +44,7 @@ static std::string GetStringForWidget(const Window *w, const NWidgetCore *nwid,
/**
* Scale a RectPadding to GUI zoom level.
* @param r RectPadding at ZOOM_BASE (traditional "normal" interface size).
* @return RectPadding at #ZOOM_LVL_GUI (current interface size).
* @return RectPadding at current interface size.
*/
static inline RectPadding ScaleGUITrad(const RectPadding &r)
{
@ -54,7 +54,7 @@ static inline RectPadding ScaleGUITrad(const RectPadding &r)
/**
* Scale a Dimension to GUI zoom level.
* @param d Dimension at ZOOM_BASE (traditional "normal" interface size).
* @return Dimension at #ZOOM_LVL_GUI (current interface size).
* @return Dimension at current interface size.
*/
static inline Dimension ScaleGUITrad(const Dimension &dim)
{

View File

@ -72,11 +72,11 @@ inline int UnScaleByZoomLower(int value, ZoomLevel zoom)
/**
* Short-hand to apply GUI zoom level.
* @param value Pixel amount at #ZoomLevel::Min (full zoom in).
* @return Pixel amount at #ZOOM_LVL_GUI (current interface size).
* @return Pixel amount at current interface size.
*/
inline int UnScaleGUI(int value)
{
return UnScaleByZoom(value, ZOOM_LVL_GUI);
return UnScaleByZoom(value, _gui_zoom);
}
/**
@ -86,7 +86,7 @@ inline int UnScaleGUI(int value)
*/
inline ZoomLevel ScaleZoomGUI(ZoomLevel value)
{
return std::clamp(value + (ZOOM_LVL_GUI - ZoomLevel::Normal), ZoomLevel::Min, ZoomLevel::Max);
return std::clamp(value + (_gui_zoom - ZoomLevel::Normal), ZoomLevel::Min, ZoomLevel::Max);
}
/**
@ -96,13 +96,13 @@ inline ZoomLevel ScaleZoomGUI(ZoomLevel value)
*/
inline ZoomLevel UnScaleZoomGUI(ZoomLevel value)
{
return std::clamp(value - (ZOOM_LVL_GUI - ZoomLevel::Normal), ZoomLevel::Min, ZoomLevel::Max);
return std::clamp(value - (_gui_zoom - ZoomLevel::Normal), ZoomLevel::Min, ZoomLevel::Max);
}
/**
* Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
* @param value Pixel amount at #ZOOM_BASE (traditional "normal" interface size).
* @return Pixel amount at #ZOOM_LVL_GUI (current interface size).
* @return Pixel amount at current interface size.
*/
inline int ScaleSpriteTrad(int value)
{
@ -112,7 +112,7 @@ inline int ScaleSpriteTrad(int value)
/**
* Scale traditional pixel dimensions to GUI zoom level.
* @param value Pixel amount at #ZOOM_BASE (traditional "normal" interface size).
* @return Pixel amount at #ZOOM_LVL_GUI (current interface size).
* @return Pixel amount at current interface size.
*/
inline int ScaleGUITrad(int value)
{

View File

@ -52,7 +52,6 @@ extern int _gui_scale_cfg;
extern ZoomLevel _gui_zoom;
extern ZoomLevel _font_zoom;
#define ZOOM_LVL_GUI (_gui_zoom)
static const int MIN_INTERFACE_SCALE = 100;
static const int MAX_INTERFACE_SCALE = 500;