1
0
Fork 0

Compare commits

...

11 Commits

66 changed files with 1489 additions and 359 deletions

View File

@ -509,7 +509,7 @@ public:
this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage);
this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage);
this->SetDirty();
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->UpdateSelectSize();
SetViewportCatchmentStation(nullptr, true);
break;

View File

@ -36,7 +36,8 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left;
uint16_t *anim = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
const uint8_t *remap = bp->remap; // store so we don't have to access it via bp every time
const uint8_t *remap = bp->remap->GetPaletteRemap(); // store so we don't have to access it via bp every time
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
for (int y = 0; y < bp->height; y++) {
Colour *dst_ln = dst + bp->pitch;
@ -135,6 +136,43 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
}
break;
case BlitterMode::RGBAColourRemap:
if (src_px->a == 255) {
do {
uint m = *src_n;
/* In case the m-channel is zero, do not remap this pixel in any way */
if (m == 0) {
*dst = src_px->data;
*anim = 0;
} else {
const Colour &c = remap_rgba[GB(m, 0, 8)];
*anim = 0;
*dst = AdjustBrightness(c, GB(m, 8, 8));
}
anim++;
dst++;
src_px++;
src_n++;
} while (--n != 0);
} else {
do {
uint m = *src_n;
if (m == 0) {
*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
*anim = 0;
} else {
const Colour &c = remap_rgba[GB(m, 0, 8)];
*anim = 0;
*dst = ComposeColourPANoCheck(AdjustBrightness(c, GB(m, 8, 8)), c.a * src_px->a / 255, *dst);
}
anim++;
dst++;
src_px++;
src_n++;
} while (--n != 0);
}
break;
case BlitterMode::CrashRemap:
if (src_px->a == 255) {
do {
@ -273,6 +311,7 @@ void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
default: NOT_REACHED();
case BlitterMode::Normal: Draw<BlitterMode::Normal>(bp, zoom); return;
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap>(bp, zoom); return;
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap>(bp, zoom); return;
case BlitterMode::Transparent: Draw<BlitterMode::Transparent>(bp, zoom); return;
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap>(bp, zoom); return;
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap>(bp, zoom); return;
@ -323,7 +362,7 @@ void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height,
void Blitter_32bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
{
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
*((Colour *)video + x + y * _screen.pitch) = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
/* Set the colour in the anim-buffer too, if we are rendering to the screen */
if (_screen_disable_anim) return;
@ -333,7 +372,7 @@ void Blitter_32bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
{
const Colour c = LookupColourInPalette(colour.p);
const Colour c = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
if (_screen_disable_anim) {
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
@ -357,7 +396,7 @@ void Blitter_32bppAnim::DrawRect(void *video, int width, int height, PixelColour
return;
}
Colour colour32 = LookupColourInPalette(colour.p);
Colour colour32 = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
uint16_t *anim_line = this->ScreenToAnimOffset((uint32_t *)video) + this->anim_buf;
do {

View File

@ -33,7 +33,7 @@ template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bpp
GNU_TARGET("sse4.1")
inline void Blitter_32bppSSE4_Anim::Draw(const BlitterParams *bp, ZoomLevel zoom)
{
const uint8_t * const remap = bp->remap;
const uint8_t * const remap = bp->remap->GetPaletteRemap();
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
uint16_t *anim_line = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
int effective_width = bp->width;

View File

@ -20,12 +20,13 @@ void *Blitter_32bppBase::MoveTo(void *video, int x, int y)
void Blitter_32bppBase::SetPixel(void *video, int x, int y, PixelColour colour)
{
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour.p);
const Colour c = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
*((Colour *)video + x + y * _screen.pitch) = c;
}
void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, PixelColour colour, int width, int dash)
{
const Colour c = LookupColourInPalette(colour.p);
const Colour c = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = c;
});
@ -33,7 +34,7 @@ void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int
void Blitter_32bppBase::DrawRect(void *video, int width, int height, PixelColour colour)
{
Colour colour32 = LookupColourInPalette(colour.p);
Colour colour32 = colour.HasRGB() ? colour.ToColour() : LookupColourInPalette(colour.p);
do {
Colour *dst = (Colour *)video;

View File

@ -48,7 +48,8 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL
Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left;
/* store so we don't have to access it via bp every time (compiler assumes pointer aliasing) */
const uint8_t *remap = bp->remap;
const uint8_t *remap = bp->remap->GetPaletteRemap();
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
for (int y = 0; y < bp->height; y++) {
/* next dst line begins here */
@ -142,6 +143,37 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL
}
break;
case BlitterMode::RGBAColourRemap:
if (src_px->a == 255) {
do {
uint m = *src_n;
/* In case the m-channel is zero, do not remap this pixel in any way */
if (m == 0) {
*dst = src_px->data;
} else {
const Colour c = remap_rgba[GB(m, 0, 8)];
*dst = AdjustBrightness(c, GB(m, 8, 8));
}
dst++;
src_px++;
src_n++;
} while (--n != 0);
} else {
do {
uint m = *src_n;
if (m == 0) {
*dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
} else {
const Colour c = remap_rgba[GB(m, 0, 8)];
*dst = ComposeColourPANoCheck(AdjustBrightness(c, GB(m, 8, 8)), src_px->a, *dst);
}
dst++;
src_px++;
src_n++;
} while (--n != 0);
}
break;
case BlitterMode::CrashRemap:
if (src_px->a == 255) {
do {
@ -263,6 +295,7 @@ void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode,
default: NOT_REACHED();
case BlitterMode::Normal: Draw<BlitterMode::Normal, Tpal_to_rgb>(bp, zoom); return;
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap, Tpal_to_rgb>(bp, zoom); return;
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap, Tpal_to_rgb>(bp, zoom); return;
case BlitterMode::Transparent: Draw<BlitterMode::Transparent, Tpal_to_rgb>(bp, zoom); return;
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap, Tpal_to_rgb>(bp, zoom); return;
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap, Tpal_to_rgb>(bp, zoom); return;

View File

@ -23,6 +23,8 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
{
const Blitter_32bppSimple::Pixel *src, *src_line;
Colour *dst, *dst_line;
const uint8_t *remap = bp->remap->GetPaletteRemap();
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
/* Find where to start reading in the source sprite */
src_line = (const Blitter_32bppSimple::Pixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom);
@ -42,7 +44,19 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
if (src->m == 0) {
if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst);
} else {
if (bp->remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst);
if (remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(remap[src->m]), src->v), src->a, *dst);
}
break;
case BlitterMode::RGBAColourRemap:
/* In case the m-channel is zero, do not remap this pixel in any way */
if (src->m == 0) {
if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst);
} else {
const Colour &c = remap_rgba[src->m];
if (c.a != 0) {
*dst = ComposeColourPA(AdjustBrightness(c, src->v), src->a, *dst);
}
}
break;
@ -53,7 +67,7 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
*dst = ComposeColourRGBA(g, g, g, src->a, *dst);
}
} else {
if (bp->remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst);
if (remap[src->m] != 0) *dst = ComposeColourPA(AdjustBrightness(this->LookupColourInPalette(remap[src->m]), src->v), src->a, *dst);
}
break;
@ -73,7 +87,7 @@ void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoo
case BlitterMode::TransparentRemap:
/* Apply custom transparency remap. */
if (src->a != 0) {
*dst = this->LookupColourInPalette(bp->remap[GetNearestColourIndex(*dst)]);
*dst = this->LookupColourInPalette(remap[GetNearestColourIndex(*dst)]);
}
break;

View File

@ -221,7 +221,7 @@ inline void Blitter_32bppSSSE3::Draw(const Blitter::BlitterParams *bp, ZoomLevel
inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
#endif
{
const uint8_t * const remap = bp->remap;
const uint8_t * const remap = bp->remap->GetPaletteRemap();
Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
int effective_width = bp->width;

View File

@ -32,10 +32,14 @@ void Blitter_40bppAnim::SetPixel(void *video, int x, int y, PixelColour colour)
if (_screen_disable_anim) {
Blitter_32bppOptimized::SetPixel(video, x, y, colour);
} else {
size_t y_offset = static_cast<size_t>(y) * _screen.pitch;
*((Colour *)video + x + y_offset) = _black_colour;
bool has_rgb = colour.HasRGB();
const Colour colour32 = has_rgb ? colour.ToColour() : _black_colour;
const uint8_t colour8 = has_rgb ? 0 : colour.p;
VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour.p;
size_t y_offset = static_cast<size_t>(y) * _screen.pitch;
*((Colour *)video + x + y_offset) = colour32;
VideoDriver::GetInstance()->GetAnimBuffer()[((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + x + y_offset] = colour8;
}
}
@ -47,6 +51,10 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, PixelColour
return;
}
bool has_rgb = colour.HasRGB();
const Colour colour32 = has_rgb ? colour.ToColour() : _black_colour;
const uint8_t colour8 = has_rgb ? 0 : colour.p;
assert(VideoDriver::GetInstance()->GetAnimBuffer() != nullptr);
uint8_t *anim_line = ((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + VideoDriver::GetInstance()->GetAnimBuffer();
@ -55,8 +63,8 @@ void Blitter_40bppAnim::DrawRect(void *video, int width, int height, PixelColour
uint8_t *anim = anim_line;
for (int i = width; i > 0; i--) {
*dst = _black_colour;
*anim = colour.p;
*dst = colour32;
*anim = colour8;
dst++;
anim++;
}
@ -73,12 +81,16 @@ void Blitter_40bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int
return;
}
bool has_rgb = colour.HasRGB();
const Colour colour32 = has_rgb ? colour.ToColour() : _black_colour;
const uint8_t colour8 = has_rgb ? 0 : colour.p;
assert(VideoDriver::GetInstance()->GetAnimBuffer() != nullptr);
uint8_t *anim = ((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + VideoDriver::GetInstance()->GetAnimBuffer();
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = _black_colour;
*(anim + x + y * _screen.pitch) = colour.p;
*((Colour *)video + x + y * _screen.pitch) = colour32;
*(anim + x + y * _screen.pitch) = colour8;
});
}
@ -114,7 +126,8 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
uint8_t *anim = VideoDriver::GetInstance()->GetAnimBuffer() + ((uint32_t *)bp->dst - (uint32_t *)_screen.dst_ptr) + bp->top * bp->pitch + bp->left;
/* store so we don't have to access it via bp every time (compiler assumes pointer aliasing) */
const uint8_t *remap = bp->remap;
const uint8_t *remap = bp->remap->GetPaletteRemap();
const Colour *remap_rgba = mode == BlitterMode::RGBAColourRemap ? bp->remap->GetRGBARemap() : nullptr;
for (int y = 0; y < bp->height; y++) {
/* next dst line begins here */
@ -225,6 +238,49 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
}
break;
case BlitterMode::RGBAColourRemap:
if (src_px->a == 255) {
do {
uint8_t m = GB(*src_n, 0, 8);
/* In case the m-channel is zero, only apply the crash remap by darkening the RGB colour. */
if (m == 0) {
*dst = *src_px;
*anim = 0;
} else {
const Colour &c = remap_rgba[GB(m, 0, 8)];
if (c.a != 0) {
*dst = ComposeColourRGBANoCheck(c.r, c.g, c.b, c.a, *dst);
*anim = 0;
}
}
anim++;
dst++;
src_px++;
src_n++;
} while (--n != 0);
} else {
do {
uint8_t m = GB(*src_n, 0, 8);
Colour b = this->RealizeBlendedColour(*anim, *dst);
if (m == 0) {
Colour c = *src_px;
*dst = this->ComposeColourRGBANoCheck(c.r, c.g, c.b, src_px->a / 255, b);
*anim = 0;
} else {
const Colour &c = remap_rgba[m];
if (c.a != 0) {
*dst = this->ComposeColourPANoCheck(c, c.a * src_px->a / 255, b);
*anim = 0; // Animation colours don't work with alpha-blending.
}
}
anim++;
dst++;
src_px++;
src_n++;
} while (--n != 0);
}
break;
case BlitterMode::BlackRemap:
do {
*anim++ = 0;
@ -341,6 +397,7 @@ void Blitter_40bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomL
default: NOT_REACHED();
case BlitterMode::Normal: Draw<BlitterMode::Normal>(bp, zoom); return;
case BlitterMode::ColourRemap: Draw<BlitterMode::ColourRemap>(bp, zoom); return;
case BlitterMode::RGBAColourRemap: Draw<BlitterMode::RGBAColourRemap>(bp, zoom); return;
case BlitterMode::Transparent: Draw<BlitterMode::Transparent>(bp, zoom); return;
case BlitterMode::TransparentRemap: Draw<BlitterMode::TransparentRemap>(bp, zoom); return;
case BlitterMode::CrashRemap: Draw<BlitterMode::CrashRemap>(bp, zoom); return;
@ -374,7 +431,8 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
anim = anim - width + _screen.pitch;
} while (--height);
} else if (pal == PALETTE_NEWSPAPER) {
const uint8_t *remap = GetNonSprite(pal, SpriteType::Recolour) + 1;
const RecolourSprite *rs = GetRecolourSprite(pal);
const uint8_t *remap = rs->GetPaletteRemap();
do {
for (int i = 0; i != width; i++) {
if (*anim == 0) {
@ -389,7 +447,8 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
anim = anim - width + _screen.pitch;
} while (--height);
} else {
const uint8_t *remap = GetNonSprite(pal, SpriteType::Recolour) + 1;
const RecolourSprite *rs = GetRecolourSprite(pal);
const uint8_t *remap = rs->GetPaletteRemap();
do {
for (int i = 0; i != width; i++) {
if (*anim != 0) *anim = remap[*anim];

View File

@ -16,7 +16,7 @@
void Blitter_8bppBase::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal)
{
const uint8_t *ctab = GetNonSprite(pal, SpriteType::Recolour) + 1;
const uint8_t *ctab = GetRecolourSprite(pal)->GetPaletteRemap();
do {
for (int i = 0; i != width; i++) *((uint8_t *)dst + i) = ctab[((uint8_t *)dst)[i]];

View File

@ -85,7 +85,7 @@ void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Z
switch (mode) {
case BlitterMode::ColourRemap:
case BlitterMode::CrashRemap: {
const uint8_t *remap = bp->remap;
const uint8_t *remap = bp->remap->GetPaletteRemap();
do {
uint m = remap[*src];
if (m != 0) *dst = m;
@ -101,7 +101,7 @@ void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Z
case BlitterMode::Transparent:
case BlitterMode::TransparentRemap: {
const uint8_t *remap = bp->remap;
const uint8_t *remap = bp->remap->GetPaletteRemap();
src += pixels;
do {
*dst = remap[*dst];

View File

@ -20,6 +20,7 @@ void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoom
{
const uint8_t *src, *src_line;
uint8_t *dst, *dst_line;
const uint8_t *remap = bp->remap->GetPaletteRemap();
/* Find where to start reading in the source sprite */
src_line = (const uint8_t *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom);
@ -38,12 +39,12 @@ void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoom
switch (mode) {
case BlitterMode::ColourRemap:
case BlitterMode::CrashRemap:
colour = bp->remap[*src];
colour = remap[*src];
break;
case BlitterMode::Transparent:
case BlitterMode::TransparentRemap:
if (*src != 0) colour = bp->remap[*dst];
if (*src != 0) colour = remap[*dst];
break;
case BlitterMode::BlackRemap:

View File

@ -17,6 +17,7 @@
enum class BlitterMode : uint8_t {
Normal, ///< Perform the simple blitting.
ColourRemap, ///< Perform a colour remapping.
RGBAColourRemap, ///< Perform a colour remapping.
Transparent, ///< Perform transparency darkening remapping.
TransparentRemap, ///< Perform transparency colour remapping.
CrashRemap, ///< Perform a crash remapping.
@ -31,7 +32,7 @@ public:
/** Parameters related to blitting. */
struct BlitterParams {
const void *sprite; ///< Pointer to the sprite how ever the encoder stored it
const uint8_t *remap; ///< XXX -- Temporary storage for remap array
const RecolourSprite *remap; ///< Pointer to the RecolourSprite to use with remapping.
int skip_left; ///< How much pixels of the source to skip on the left (based on zoom of dst)
int skip_top; ///< How much pixels of the source to skip on the top (based on zoom of dst)

View File

@ -35,6 +35,7 @@
#include "smallmap_gui.h"
#include "game/game.hpp"
#include "goal_base.h"
#include "spritecache.h"
#include "story_base.h"
#include "company_cmd.h"
#include "timer/timer.h"
@ -55,6 +56,7 @@ void UpdateObjectColours(const Company *c);
CompanyID _local_company; ///< Company controlled by the human player at this client. Can also be #COMPANY_SPECTATOR.
CompanyID _current_company; ///< Company currently doing an action.
TypedIndexContainer<std::array<Colours, MAX_COMPANIES>, CompanyID> _company_colours; ///< NOSAVE: can be determined from company structs.
TypedIndexContainer<std::array<PaletteID, MAX_COMPANIES>, CompanyID> _company_palettes; ///< NOSAVE: can be determined from company structs.
std::string _company_manager_face; ///< for company manager face storage in openttd.cfg
uint _cur_company_tick_index; ///< used to generate a name for one company that doesn't have a name yet per tick
@ -163,7 +165,7 @@ TextColour GetDrawStringCompanyColour(CompanyID company)
*/
PaletteID GetCompanyPalette(CompanyID company)
{
return GetColourPalette(_company_colours[company]);
return _company_palettes[company];
}
/**
@ -513,7 +515,7 @@ static Colours GenerateCompanyColour()
/* Move the colours that look similar to each company's colour to the side */
for (const Company *c : Company::Iterate()) {
Colours pcolour = c->colour;
Colours pcolour = Colours(c->colour & 0xF);
for (uint i = 0; i < COLOUR_END; i++) {
if (colours[i] == pcolour) {
@ -566,6 +568,40 @@ restart:;
}
}
void ClearLivery(Livery &livery)
{
DeallocateDynamicSprite(livery.cached_pal_1cc);
DeallocateDynamicSprite(livery.cached_pal_2cc);
DeallocateDynamicSprite(livery.cached_pal_2cr);
livery.cached_pal_1cc = PALETTE_RECOLOUR_START + GB(livery.colour1, 0, 4);
livery.cached_pal_2cc = SPR_2CCMAP_BASE + GB(livery.colour1, 0, 4) + GB(livery.colour2, 0, 4) * 16;
livery.cached_pal_2cr = SPR_2CCMAP_BASE + GB(livery.colour2, 0, 4) + GB(livery.colour1, 0, 4) * 16;
}
/**
* Update cached palettes for a livery.
* @param livery Livery to update.
* @param always_update Always update instead of clearing livery (for LS_DEFAULT which is always needed).
*/
void UpdateLivery(Livery &livery, bool always_update)
{
if ((always_update || livery.in_use != 0) && (ColoursPacker(livery.colour1).IsCustom() || ColoursPacker(livery.colour2).IsCustom())) {
PaletteID pal_1cc = PALETTE_RECOLOUR_START + GB(livery.colour1, 0, 4);
livery.cached_pal_1cc = CreateCompanyColourRemap(livery.colour1, livery.colour1, false, pal_1cc, livery.cached_pal_1cc);
if (_loaded_newgrf_features.has_2CC) {
PaletteID pal_2cc = SPR_2CCMAP_BASE + GB(livery.colour1, 0, 4) + GB(livery.colour2, 0, 4) * 16;
livery.cached_pal_2cc = CreateCompanyColourRemap(livery.colour1, livery.colour2, true, pal_2cc, livery.cached_pal_2cc);
PaletteID pal_2cr = SPR_2CCMAP_BASE + GB(livery.colour2, 0, 4) + GB(livery.colour1, 0, 4) * 16;
livery.cached_pal_2cr = CreateCompanyColourRemap(livery.colour2, livery.colour1, true, pal_2cr, livery.cached_pal_2cr);
}
} else {
ClearLivery(livery);
}
}
/**
* Reset the livery schemes to the company's primary colour.
* This is used on loading games without livery information and on new company start up.
@ -577,6 +613,7 @@ void ResetCompanyLivery(Company *c)
c->livery[scheme].in_use = 0;
c->livery[scheme].colour1 = c->colour;
c->livery[scheme].colour2 = c->colour;
UpdateLivery(c->livery[scheme], scheme == LS_DEFAULT);
}
for (Group *g : Group::Iterate()) {
@ -584,8 +621,12 @@ void ResetCompanyLivery(Company *c)
g->livery.in_use = 0;
g->livery.colour1 = c->colour;
g->livery.colour2 = c->colour;
UpdateLivery(g->livery, false);
}
}
_company_colours[c->index] = c->livery[LS_DEFAULT].colour1;
_company_palettes[c->index] = c->livery[LS_DEFAULT].cached_pal_1cc;
}
/**
@ -613,7 +654,6 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = CompanyID::Invalid(
c->colour = colour;
ResetCompanyLivery(c);
_company_colours[c->index] = c->colour;
/* Scale the initial loan based on the inflation rounded down to the loan interval. The maximum loan has already been inflation adjusted. */
c->money = c->current_loan = std::min<int64_t>((INITIAL_LOAN * _economy.inflation_prices >> 16) / LOAN_INTERVAL * LOAN_INTERVAL, _economy.max_loan);
@ -1076,11 +1116,16 @@ CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint32_t bits, uint s
*/
void UpdateCompanyLiveries(Company *c)
{
UpdateLivery(c->livery[LS_DEFAULT], true);
for (int i = 1; i < LS_END; i++) {
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
UpdateLivery(c->livery[i], false);
}
UpdateCompanyGroupLiveries(c);
_company_colours[c->index] = c->livery[LS_DEFAULT].colour1;
_company_palettes[c->index] = c->livery[LS_DEFAULT].cached_pal_1cc;
}
/**
@ -1093,7 +1138,7 @@ void UpdateCompanyLiveries(Company *c)
*/
CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool primary, Colours colour)
{
if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR;
if (scheme >= LS_END) return CMD_ERROR;
/* Default scheme can't be reset to invalid. */
if (scheme == LS_DEFAULT && colour == INVALID_COLOUR) return CMD_ERROR;
@ -1117,9 +1162,11 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
* original and cached company colours too. */
if (scheme == LS_DEFAULT) {
UpdateCompanyLiveries(c);
_company_colours[_current_company] = colour;
/* Update cached colour/palette for company */
c->colour = colour;
CompanyAdminUpdate(c);
} else {
UpdateLivery(c->livery[scheme], false);
}
} else {
if (scheme != LS_DEFAULT) AssignBit(c->livery[scheme].in_use, 1, colour != INVALID_COLOUR);
@ -1128,6 +1175,8 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
if (scheme == LS_DEFAULT) {
UpdateCompanyLiveries(c);
} else {
UpdateLivery(c->livery[scheme], false);
}
}

View File

@ -15,7 +15,7 @@
#include "livery.h"
enum ClientID : uint32_t;
enum Colours : uint8_t;
enum Colours : uint32_t;
CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id);
CommandCost CmdCompanyAllowListCtrl(DoCommandFlags flags, CompanyAllowListCtrlAction action, const std::string &public_key);

View File

@ -14,6 +14,7 @@
#include "company_type.h"
#include "gfx_type.h"
#include "vehicle_type.h"
#include "livery.h"
bool CheckTakeoverVehicleLimit(CompanyID cbig, CompanyID small);
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner);
@ -24,6 +25,8 @@ void CompanyAdminUpdate(const Company *company);
void CompanyAdminBankrupt(CompanyID company_id);
void UpdateLandscapingLimits();
void UpdateCompanyLiveries(Company *c);
void ClearLivery(Livery &livery);
void UpdateLivery(Livery &livery, bool always_update);
Money GetAvailableMoney(CompanyID company);
Money GetAvailableMoneyForCommand();
@ -37,7 +40,9 @@ extern CompanyID _local_company;
extern CompanyID _current_company;
extern TypedIndexContainer<std::array<Colours, MAX_COMPANIES>, CompanyID> _company_colours;
extern TypedIndexContainer<std::array<PaletteID, MAX_COMPANIES>, CompanyID> _company_palettes;
extern std::string _company_manager_face;
PaletteID GetCompanyPalette(CompanyID company);
/**

View File

@ -7,6 +7,7 @@
/** @file company_gui.cpp %Company related GUIs. */
#include "palette_func.h"
#include "stdafx.h"
#include "currency.h"
#include "error.h"
@ -47,6 +48,7 @@
#include "timer/timer.h"
#include "timer/timer_window.h"
#include "core/string_consumer.hpp"
#include "blitter/factory.hpp"
#include "widgets/company_widget.h"
@ -584,6 +586,13 @@ static const LiveryClass _livery_class[LS_END] = {
LC_ROAD, LC_ROAD,
};
StringID GetColourString(Colours colour)
{
if (ColoursPacker(colour).IsCustom()) return STR_COLOUR_CUSTOM;
if (colour == INVALID_COLOUR) return STR_COLOUR_DEFAULT;
return STR_COLOUR_DARK_BLUE + colour;
}
/**
* Colour selection list item, with icon and string components.
* @tparam TSprite Recolourable sprite to draw as icon.
@ -591,12 +600,372 @@ static const LiveryClass _livery_class[LS_END] = {
template <SpriteID TSprite = SPR_SQUARE>
class DropDownListColourItem : public DropDownIcon<DropDownString<DropDownListItem>> {
public:
DropDownListColourItem(int colour, bool masked) :
DropDownIcon<DropDownString<DropDownListItem>>(TSprite, GetColourPalette(static_cast<Colours>(colour % COLOUR_END)), GetString(colour < COLOUR_END ? (STR_COLOUR_DARK_BLUE + colour) : STR_COLOUR_DEFAULT), colour, masked)
DropDownListColourItem(PaletteID pal, StringID str, int value, bool masked) :
DropDownIcon<DropDownString<DropDownListItem>>(TSprite, pal, GetString(str), value, masked)
{
}
};
class SelectCustomColourWindow : public Window {
/* Preserved values from parent window when this window was opened. */
uint32_t sel;
LiveryClass lc;
bool ctrl_pressed;
bool primary;
bool group;
Scrollbar *hue, *sat, *val, *con;
Colours current;
HsvColour current_hsv;
uint8_t contrast;
static inline const int BUTTON_SIZE = 10;
static inline const int CON_MAX = UINT8_MAX;
void SetPresetColours()
{
for (uint i = 0; i < std::size(_settings_client.gui.preset_colours); ++i) {
this->GetWidget<NWidgetCore>(WID_SCC_PRESETS + i)->colour = _settings_client.gui.preset_colours[i];
}
}
Colour AdjustBrightness(const Colour &rgb, ColourShade shade, int contrast) const
{
int level = (shade - SHADE_NORMAL) * contrast / (SHADE_END / 2);
return {
ClampTo<uint8_t>(std::max(1, rgb.r + level)),
ClampTo<uint8_t>(std::max(1, rgb.g + level)),
ClampTo<uint8_t>(std::max(1, rgb.b + level))
};
}
bool SetScrollbarPositions()
{
bool changed = false;
changed |= this->hue->SetPosition(HsvColour::HUE_MAX - this->current_hsv.h);
changed |= this->sat->SetPosition(this->current_hsv.s);
changed |= this->val->SetPosition(HsvColour::VAL_MAX - this->current_hsv.v);
changed |= this->con->SetPosition(CON_MAX - this->contrast);
return changed;
}
public:
SelectCustomColourWindow(WindowDesc &desc, int window_number, CompanyID company, Colours colour, uint32_t sel, LiveryClass lc, bool ctrl, bool primary, bool group) :
Window(desc), sel(sel), lc(lc), ctrl_pressed(ctrl), primary(primary), group(group)
{
this->InitNested(window_number);
this->owner = (Owner)company;
this->current = colour;
ColoursPacker colourp(colour);
if ((colourp.GetHue() | colourp.GetSaturation() | colourp.GetValue()) == 0) {
auto [rgba, contrast] = GetCompanyColourRGB(colour);
this->current_hsv = ConvertRgbToHsv(rgba);
this->contrast = contrast;
} else {
this->current_hsv = colourp.Hsv();
this->contrast = colourp.GetContrast();
}
this->hue = this->GetScrollbar(WID_SCC_SCROLLBAR_HUE);
this->hue->SetCapacity(HsvColour::HUE_MAX / BUTTON_SIZE);
this->hue->SetCount(HsvColour::HUE_MAX + HsvColour::HUE_MAX / BUTTON_SIZE);
this->sat = this->GetScrollbar(WID_SCC_SCROLLBAR_SAT);
this->sat->SetCapacity(HsvColour::SAT_MAX / BUTTON_SIZE);
this->sat->SetCount(HsvColour::SAT_MAX + HsvColour::SAT_MAX / BUTTON_SIZE);
this->val = this->GetScrollbar(WID_SCC_SCROLLBAR_VAL);
this->val->SetCapacity(HsvColour::VAL_MAX / BUTTON_SIZE);
this->val->SetCount(HsvColour::VAL_MAX + HsvColour::VAL_MAX / BUTTON_SIZE);
this->con = this->GetScrollbar(WID_SCC_SCROLLBAR_CON);
this->con->SetCapacity(CON_MAX / BUTTON_SIZE);
this->con->SetCount(CON_MAX + CON_MAX / BUTTON_SIZE);
this->SetScrollbarPositions();
this->SetPresetColours();
}
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
{
switch (widget) {
case WID_SCC_CAPTION:
return GetString(stringid, this->owner);
default:
return this->Window::GetWidgetString(widget, stringid);
}
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
HsvColour hsv = this->current_hsv;
switch (widget) {
case WID_SCC_HUE: {
int range = r.Height() - 1;
int mid = CentreBounds(r.left, r.right, 0);
hsv.s = HsvColour::SAT_MAX;
for (int i = 0; i <= range; i++) {
hsv.h = HsvColour::HUE_MAX * i / range;
hsv.v = HsvColour::VAL_MAX;
GfxFillRect(r.left, r.bottom - i, mid - 1, r.bottom - i, ConvertHsvToRgb(hsv), FILLRECT_OPAQUE);
hsv.v = HsvColour::VAL_MAX * 3 / 4;
GfxFillRect(mid, r.bottom - i, r.right, r.bottom - i, ConvertHsvToRgb(hsv), FILLRECT_OPAQUE);
}
/* Mark current value. */
GfxDrawLine(r.left, r.bottom - this->current_hsv.h * range / HsvColour::HUE_MAX, r.right, r.bottom - this->current_hsv.h * range / HsvColour::HUE_MAX, PC_WHITE, 1, 1);
break;
}
case WID_SCC_SAT: {
int width = r.Width() - 1;
int height = r.Height() - 1;
for (int x = 0; x <= width; x++) {
hsv.s = HsvColour::SAT_MAX * x / width;
for (int y = 0; y <= height; y++) {
hsv.v = HsvColour::VAL_MAX * y / height;
GfxFillRect(r.left + x, r.bottom - y, r.left + x, r.bottom - y, ConvertHsvToRgb(hsv), FILLRECT_OPAQUE);
}
}
/* Mark current value. */
GfxDrawLine(r.left + this->current_hsv.s * width / HsvColour::SAT_MAX, r.top, r.left + this->current_hsv.s * width / HsvColour::SAT_MAX, r.bottom, PC_WHITE, 1, 1);
GfxDrawLine(r.left, r.bottom - this->current_hsv.v * height / HsvColour::VAL_MAX, r.right, r.bottom - this->current_hsv.v * height / HsvColour::VAL_MAX, PC_WHITE, 1, 1);
break;
}
case WID_SCC_CON: {
int range = r.Height() - 1;
int mid = CentreBounds(r.left, r.right, 0);
Colour rgb = ConvertHsvToRgb(HsvColour{0, 0, HsvColour::VAL_MAX / 2});
for (int i = 0; i <= range; i++) {
int contrast = i * CON_MAX / width;
GfxFillRect(r.left, r.bottom - i, mid - 1, r.bottom - i, AdjustBrightness(rgb, SHADE_LIGHTEST, contrast), FILLRECT_OPAQUE);
GfxFillRect(mid, r.bottom - i, r.right, r.bottom - i, AdjustBrightness(rgb, SHADE_DARKEST, contrast), FILLRECT_OPAQUE);
}
/* Mark current value. */
GfxDrawLine(r.left, r.bottom - this->contrast * range / CON_MAX, r.right, r.bottom - this->contrast * range / CON_MAX, PC_WHITE, 1, 1);
break;
}
case WID_SCC_OUTPUT: {
int range = r.Height();
/* Pack and unpack to colours, to produce the result. */
Colours colour = this->PackColour();
ColoursPacker colourp(colour);
HsvColour hsv = colourp.Hsv();
uint8_t con = colourp.GetContrast();
for (ColourShade shade = SHADE_BEGIN; shade != SHADE_END; ++shade) {
Colour c = ConvertHsvToRgb(AdjustHsvColourBrightness(hsv, shade, con));
GfxFillRect(r.left, r.bottom - (shade + 1) * range / SHADE_END + 1, r.right, r.bottom - shade * range / SHADE_END, c, FILLRECT_OPAQUE);
}
break;
}
}
}
void OnClick(Point pt, int widget, int click_count) override
{
bool changed = false;
if (widget >= WID_SCC_DEFAULT && widget <= WID_SCC_DEFAULT_LAST && !_ctrl_pressed) {
/* Select colour from default preset. */
this->current = this->GetWidget<NWidgetCore>(widget)->colour;
auto [rgba, contrast] = GetCompanyColourRGB(this->current);
this->current_hsv = ConvertRgbToHsv(rgba);
this->contrast = contrast;
changed = this->SetScrollbarPositions();
}
if (widget >= WID_SCC_PRESETS && widget <= WID_SCC_PRESETS_LAST) {
if (_ctrl_pressed) {
/* Save colour to preset. */
_settings_client.gui.preset_colours[widget - WID_SCC_PRESETS] = this->PackColour();
this->SetPresetColours();
} else {
/* Select colour from preset. */
ColoursPacker cp(_settings_client.gui.preset_colours[widget - WID_SCC_PRESETS]);
this->current_hsv = cp.Hsv();
this->contrast = cp.GetContrast();
changed = this->SetScrollbarPositions();
}
}
if (widget == WID_SCC_HUE) {
/* Click and drag on hue widget */
const NWidgetCore *wi = this->GetWidget<NWidgetCore>(widget);
this->current_hsv.h = std::clamp<int>(HsvColour::HUE_MAX - (pt.y - wi->pos_y) * HsvColour::HUE_MAX / (int)wi->current_y, 0, HsvColour::HUE_MAX);
this->contrast = CON_MAX - this->con->GetPosition();
changed = this->SetScrollbarPositions();
if (click_count > 0) this->mouse_capture_widget = widget;
}
if (widget == WID_SCC_SAT) {
/* Click and drag on saturation/value widget */
const NWidgetCore *wi = this->GetWidget<NWidgetCore>(widget);
this->current_hsv.s = std::clamp<int>((pt.x - wi->pos_x) * HsvColour::SAT_MAX / (int)wi->current_x, 0, HsvColour::SAT_MAX);
this->current_hsv.v = std::clamp<int>(HsvColour::VAL_MAX - (pt.y - wi->pos_y) * HsvColour::VAL_MAX / (int)wi->current_y, 0, HsvColour::VAL_MAX);
this->contrast = CON_MAX - this->con->GetPosition();
changed = this->SetScrollbarPositions();
if (click_count > 0) this->mouse_capture_widget = widget;
}
if (widget == WID_SCC_CON) {
/* Click and drag on contrast widget */
const NWidgetCore *wi = this->GetWidget<NWidgetCore>(widget);
this->contrast = std::clamp<int>(CON_MAX - (pt.y - wi->pos_y) * CON_MAX / (int)wi->current_y, 0, CON_MAX);
changed = this->SetScrollbarPositions();
if (click_count > 0) this->mouse_capture_widget = widget;
}
if (!changed) return;
this->SetDirty();
this->SetTimeout();
}
void OnScrollbarScroll(WidgetID) override
{
/* Update colour from new scrollbar positions. */
this->current_hsv.h = HsvColour::HUE_MAX - this->hue->GetPosition();
this->current_hsv.s = this->sat->GetPosition();
this->current_hsv.v = HsvColour::VAL_MAX - this->val->GetPosition();
this->contrast = CON_MAX - this->con->GetPosition();
this->SetTimeout();
}
Colours PackColour() const
{
Colours colour;
ColoursPacker cp(colour);
cp.SetIndex(this->current);
cp.SetCustom(true);
cp.SetHue(this->current_hsv.h);
cp.SetSaturation(this->current_hsv.s);
cp.SetValue(this->current_hsv.v);
cp.SetContrast(this->contrast);
return colour;
}
void OnTimeout() override
{
Colours colour = this->PackColour();
if (colour != this->current) {
this->current = colour;
if (this->group) {
Command<CMD_SET_GROUP_LIVERY>::Post((GroupID)this->sel, primary, this->current);
} else {
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
/* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
if (HasBit(this->sel, scheme) || (this->ctrl_pressed && _livery_class[scheme] == this->lc && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
Command<CMD_SET_COMPANY_COLOUR>::Post(scheme, primary, this->current);
}
}
}
}
}
};
static constexpr NWidgetPart _nested_select_custom_colour_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCC_CAPTION), SetStringTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1),
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), SetPadding(WidgetDimensions::unscaled.frametext),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_BLUE, WID_SCC_DEFAULT + 0), SetFill(1, 1), SetMinimalSize(16, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_PALE_GREEN, WID_SCC_DEFAULT + 1), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_PINK, WID_SCC_DEFAULT + 2), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_SCC_DEFAULT + 3), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_RED, WID_SCC_DEFAULT + 4), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_SCC_DEFAULT + 5), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_SCC_DEFAULT + 6), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_GREEN, WID_SCC_DEFAULT + 7), SetFill(1, 1),
EndContainer(),
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
NWidget(WWT_PUSHTXTBTN, COLOUR_BLUE, WID_SCC_DEFAULT + 8), SetFill(1, 1), SetMinimalSize(16, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_SCC_DEFAULT + 9), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCC_DEFAULT + 10), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_PURPLE, WID_SCC_DEFAULT + 11), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SCC_DEFAULT + 12), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SCC_DEFAULT + 13), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCC_DEFAULT + 14), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_SCC_DEFAULT + 15), SetFill(1, 1),
EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_BLUE, WID_SCC_PRESETS + 0), SetFill(1, 1), SetMinimalSize(16, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_PALE_GREEN, WID_SCC_PRESETS + 1), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_PINK, WID_SCC_PRESETS + 2), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_SCC_PRESETS + 3), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_RED, WID_SCC_PRESETS + 4), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_SCC_PRESETS + 5), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_SCC_PRESETS + 6), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_DARK_GREEN, WID_SCC_PRESETS + 7), SetFill(1, 1),
EndContainer(),
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
NWidget(WWT_PUSHTXTBTN, COLOUR_BLUE, WID_SCC_PRESETS + 8), SetFill(1, 1), SetMinimalSize(16, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_SCC_PRESETS + 9), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_SCC_PRESETS + 10), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_PURPLE, WID_SCC_PRESETS + 11), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SCC_PRESETS + 12), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SCC_PRESETS + 13), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCC_PRESETS + 14), SetFill(1, 1),
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_SCC_PRESETS + 15), SetFill(1, 1),
EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_INSET, COLOUR_GREY),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_HUE), SetMinimalSize(16, 0),
EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_HUE),
EndContainer(),
NWidget(NWID_VERTICAL),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_INSET, COLOUR_GREY),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_SAT), SetMinimalSize(160, 160),
EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_VAL),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_SAT),
NWidget(NWID_SPACER), SetMinimalSize(11, 11),
EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_INSET, COLOUR_GREY),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_CON), SetMinimalSize(16, 0),
EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCC_SCROLLBAR_CON),
EndContainer(),
NWidget(WWT_INSET, COLOUR_GREY),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCC_OUTPUT), SetFill(1, 1), SetMinimalSize(16, 0),
EndContainer(),
EndContainer(),
EndContainer(),
};
static WindowDesc _select_custom_colour_desc(
WDP_AUTO, {}, 0, 0,
WC_CUSTOM_COLOUR, WC_NONE,
{},
_nested_select_custom_colour_widgets
);
/** Company livery colour scheme window. */
struct SelectCompanyLiveryWindow : public Window {
private:
@ -608,57 +977,86 @@ private:
GUIGroupList groups{};
Scrollbar *vscroll = nullptr;
void ShowColourDropDownMenu(uint32_t widget)
/**
* Get the first selected livery.
*/
const Livery *GetSelectedLivery() const
{
uint32_t used_colours = 0;
const Livery *livery, *default_livery = nullptr;
bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
uint8_t default_col = 0;
/* Disallow other company colours for the primary colour */
if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
for (const Company *c : Company::Iterate()) {
if (c->index != _local_company) SetBit(used_colours, c->colour);
}
}
const Company *c = Company::Get(this->window_number);
if (this->livery_class < LC_GROUP_RAIL) {
/* Get the first selected livery to use as the default dropdown item */
LiveryScheme scheme;
for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
if (HasBit(this->sel, scheme)) break;
}
if (scheme == LS_END) scheme = LS_DEFAULT;
livery = &c->livery[scheme];
if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT];
const Company *c = Company::Get((CompanyID)this->window_number);
return &c->livery[scheme];
} else {
const Group *g = Group::Get(this->sel);
return &g->livery;
}
}
/**
* Get the default selected livery.
*/
const Livery *GetDefaultLivery() const
{
const Company *c = Company::Get((CompanyID)this->window_number);
if (this->livery_class < LC_GROUP_RAIL) {
if (!HasBit(this->sel, LS_DEFAULT)) return &c->livery[LS_DEFAULT];
} else {
const Group *g = Group::Get(this->sel);
livery = &g->livery;
if (g->parent == GroupID::Invalid()) {
default_livery = &c->livery[LS_DEFAULT];
return &c->livery[LS_DEFAULT];
} else {
const Group *pg = Group::Get(g->parent);
default_livery = &pg->livery;
return &pg->livery;
}
}
return nullptr;
}
void ShowColourDropDownMenu(uint32_t widget)
{
uint32_t used_colours = 0;
bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
/* Disallow other company colours for the primary colour */
if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
for (const Company *c : Company::Iterate()) {
if (c->index != _local_company) SetBit(used_colours, c->colour & 0xF);
}
}
/* Get the first selected livery to use as the default dropdown item */
const Livery *livery = GetSelectedLivery();
const Livery *default_livery = GetDefaultLivery();
DropDownList list;
if (default_livery != nullptr) {
/* Add COLOUR_END to put the colour out of range, but also allow us to show what the default is */
default_col = (primary ? default_livery->colour1 : default_livery->colour2) + COLOUR_END;
list.push_back(std::make_unique<DropDownListColourItem<>>(default_col, false));
list.push_back(std::make_unique<DropDownListColourItem<>>(primary ? default_livery->cached_pal_1cc : default_livery->cached_pal_2cr, STR_COLOUR_DEFAULT, INVALID_COLOUR, false));
}
for (Colours colour = COLOUR_BEGIN; colour != COLOUR_END; colour++) {
list.push_back(std::make_unique<DropDownListColourItem<>>(colour, HasBit(used_colours, colour)));
list.push_back(std::make_unique<DropDownListColourItem<>>(GetColourPalette(colour), GetColourString(colour), colour, HasBit(used_colours, colour)));
}
list.push_back(std::make_unique<DropDownListColourItem<>>(primary ? livery->cached_pal_1cc : livery->cached_pal_2cr, STR_COLOUR_CUSTOM, 0xFF, BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32));
uint8_t sel;
int sel;
if (default_livery == nullptr || HasBit(livery->in_use, primary ? 0 : 1)) {
sel = primary ? livery->colour1 : livery->colour2;
Colours col = primary ? livery->colour1 : livery->colour2;
if (ColoursPacker(col).IsCustom()) {
sel = 0xFF;
} else {
sel = default_col;
sel = ColoursPacker(col).GetIndex();
}
} else {
sel = INVALID_COLOUR;
}
ShowDropDownList(this, std::move(list), sel, widget);
}
@ -820,7 +1218,7 @@ public:
if (scheme == LS_END) scheme = LS_DEFAULT;
const Livery *livery = &c->livery[scheme];
if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) {
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
colour = GetColourString(primary ? livery->colour1 : livery->colour2);
}
}
} else {
@ -828,7 +1226,7 @@ public:
const Group *g = Group::Get(this->sel);
const Livery *livery = &g->livery;
if (HasBit(livery->in_use, primary ? 0 : 1)) {
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
colour = GetColourString(primary ? livery->colour1 : livery->colour2);
}
}
}
@ -868,26 +1266,26 @@ public:
int y = ir.top;
const Company *c = Company::Get((CompanyID)this->window_number);
/* Helper function to draw livery info. */
auto draw_livery = [&](std::string_view str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
/* Livery Label. */
DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
/* Text below the first dropdown. */
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
DrawSprite(SPR_SQUARE, HasBit(livery.in_use, 0) ? livery.cached_pal_1cc : c->livery[LS_DEFAULT].cached_pal_1cc, pri_squ.left, y + square_offs);
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? GetColourString(livery.colour1) : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
/* Text below the second dropdown. */
if (sec.right > sec.left) { // Second dropdown has non-zero size.
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
DrawSprite(SPR_SQUARE, HasBit(livery.in_use, 1) ? livery.cached_pal_2cr : c->livery[LS_DEFAULT].cached_pal_2cr, sec_squ.left, y + square_offs);
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? GetColourString(livery.colour2) : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
}
y += this->line_height;
};
const Company *c = Company::Get(this->window_number);
if (livery_class < LC_GROUP_RAIL) {
int pos = this->vscroll->GetPosition();
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
@ -998,6 +1396,16 @@ public:
bool local = this->window_number == _local_company;
if (!local) return;
if (index == 0xFF) {
/* Special case for 'Custom...' option */
int number = ((widget == WID_SCL_PRI_COL_DROPDOWN) ? 1 : 0) | (this->window_number << 1);
if (BringWindowToFrontById(WC_CUSTOM_COLOUR, number)) return;
const Livery *livery = GetSelectedLivery();
new SelectCustomColourWindow(_select_custom_colour_desc, number, (CompanyID)this->window_number, (widget == WID_SCL_PRI_COL_DROPDOWN) ? livery->colour1 : livery->colour2, this->sel, this->livery_class, _ctrl_pressed, widget == WID_SCL_PRI_COL_DROPDOWN, this->livery_class >= LC_GROUP_RAIL);
return;
}
Colours colour = static_cast<Colours>(index);
if (colour >= COLOUR_END) colour = INVALID_COLOUR;
@ -1114,10 +1522,10 @@ void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
/**
* Draws the face of a company manager's face.
* @param cmf the company manager's face
* @param colour the (background) colour of the gradient
* @param palette the (background) colour of the gradient
* @param r position to draw the face
*/
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r)
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, PaletteID palette, const Rect &r)
{
/* Determine offset from centre of drawing rect. */
Dimension d = GetSpriteSize(SPR_GRADIENT);
@ -1148,7 +1556,7 @@ void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const
}
/* Draw the gradient (background) */
DrawSprite(SPR_GRADIENT, GetColourPalette(colour), x, y);
DrawSprite(SPR_GRADIENT, palette, x, y);
/* Thirdly, draw sprites. */
for (auto var : SetBitIterator(active_vars)) {
@ -2105,7 +2513,7 @@ struct CompanyWindow : Window
const Company *c = Company::Get(this->window_number);
switch (widget) {
case WID_C_FACE:
DrawCompanyManagerFace(c->face, c->colour, r);
DrawCompanyManagerFace(c->face, GetCompanyPalette(c->index), r);
break;
case WID_C_FACE_TITLE:
@ -2359,8 +2767,8 @@ struct BuyCompanyWindow : Window {
{
switch (widget) {
case WID_BC_FACE: {
const Company *c = Company::Get(this->window_number);
DrawCompanyManagerFace(c->face, c->colour, r);
const Company *c = Company::Get((CompanyID)this->window_number);
DrawCompanyManagerFace(c->face, GetCompanyPalette(c->index), r);
break;
}

View File

@ -180,6 +180,6 @@ uint32_t MaskCompanyManagerFaceBits(const CompanyManagerFace &cmf, FaceVars vars
std::string FormatCompanyManagerFaceCode(const CompanyManagerFace &cmf);
std::optional<CompanyManagerFace> ParseCompanyManagerFaceCode(std::string_view str);
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r);
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, PaletteID palette, const Rect &r);
#endif /* COMPANY_MANAGER_FACE_H */

View File

@ -1949,7 +1949,7 @@ static bool ConCompanies(std::span<std::string_view> argv)
/* Grab the company name */
std::string company_name = GetString(STR_COMPANY_NAME, c->index);
std::string colour = GetString(STR_COLOUR_DARK_BLUE + _company_colours[c->index]);
std::string colour = GetString(STR_COLOUR_DARK_BLUE + _company_colours[c->index] & 0xF);
IConsolePrint(CC_INFO, "#:{}({}) Company Name: '{}' Year Founded: {} Money: {} Loan: {} Value: {} (T:{}, R:{}, P:{}, S:{}) {}",
c->index + 1, colour, company_name,
c->inaugurated_year, (int64_t)c->money, (int64_t)c->current_loan, (int64_t)CalculateCompanyValue(c),

View File

@ -469,7 +469,7 @@ public:
this->RaiseWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
_settings_client.gui.station_show_coverage = (widget != BDSW_LT_OFF);
this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
SetViewportCatchmentStation(nullptr, true);
break;
@ -580,7 +580,7 @@ public:
this->RaiseWidget(WID_BDD_X + _ship_depot_direction);
_ship_depot_direction = (widget == WID_BDD_X ? AXIS_X : AXIS_Y);
this->LowerWidget(WID_BDD_X + _ship_depot_direction);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
UpdateDocksDirection();
this->SetDirty();
break;

View File

@ -18,6 +18,7 @@
#include "company_base.h"
#include "company_func.h"
#include "company_manager_face.h"
#include "sprite.h"
#include "strings_func.h"
#include "zoom_func.h"
#include "window_func.h"
@ -188,7 +189,7 @@ public:
switch (widget) {
case WID_EM_FACE: {
const Company *c = Company::Get(this->company);
DrawCompanyManagerFace(c->face, c->colour, r);
DrawCompanyManagerFace(c->face, GetCompanyPalette(c->index), r);
break;
}

View File

@ -323,7 +323,7 @@ static void StartGeneratingLandscape(GenerateLandscapeWindowMode mode)
MakeNewgameSettingsLive();
ResetGRFConfig(true);
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
SndConfirmBeep();
switch (mode) {
case GLWM_GENERATE: _switch_mode = (_game_mode == GM_EDITOR) ? SM_GENRANDLAND : SM_NEWGAME; break;
case GLWM_HEIGHTMAP: _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_HEIGHTMAP : SM_START_HEIGHTMAP; break;

View File

@ -72,8 +72,8 @@ int _gui_scale_cfg; ///< GUI scale in config.
* @ingroup dirty
*/
static Rect _invalid_rect;
static const uint8_t *_colour_remap_ptr;
static uint8_t _string_colourremap[3]; ///< Recoloursprite for stringdrawing. The grf loader ensures that #SpriteType::Font sprites only use colours 0 to 2.
static const RecolourSprite *_colour_remap_ptr;
static RecolourSpriteRGBA _string_colourremap; ///< RecolourSprite for string drawing.
static const uint DIRTY_BLOCK_HEIGHT = 8;
static const uint DIRTY_BLOCK_WIDTH = 64;
@ -470,19 +470,32 @@ void DrawRectOutline(const Rect &r, PixelColour colour, int width, int dash)
* Set the colour remap to be for the given colour.
* @param colour the new colour of the remap.
*/
static void SetColourRemap(TextColour colour)
static BlitterMode SetColourRemap(TextColour colour)
{
if (colour == TC_INVALID) return;
if (colour == TC_INVALID) return BlitterMode::ColourRemap;
/* Black strings have no shading ever; the shading is black, so it
* would be invisible at best, but it actually makes it illegible. */
bool no_shade = (colour & TC_NO_SHADE) != 0 || colour == TC_BLACK;
if ((colour & TC_IS_RGB_COLOUR) && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32) {
/* Unpack RGB TextColour */
TextColourPacker tcp(colour);
_string_colourremap.rgba[1] = tcp.ToColour();
_string_colourremap.rgba[2] = _cur_palette.palette[no_shade ? 0 : PC_BLACK.p];
_colour_remap_ptr = &_string_colourremap;
return BlitterMode::RGBAColourRemap;
}
bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0;
colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR | TC_FORCED);
_string_colourremap[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour].p;
_string_colourremap[2] = no_shade ? 0 : 1;
_colour_remap_ptr = _string_colourremap;
_string_colourremap.palette[1] = raw_colour ? (uint8_t)colour : _string_colourmap[colour].p;
_string_colourremap.palette[2] = no_shade ? 0 : PC_BLACK.p;
_colour_remap_ptr = &_string_colourremap;
return BlitterMode::ColourRemap;
}
/**
@ -602,7 +615,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
/* Update the last colour for the truncation ellipsis. */
last_colour = colour;
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
SetColourRemap(do_shadow ? TC_BLACK : colour);
BlitterMode bm = SetColourRemap(do_shadow ? TC_BLACK : colour); // the last run also sets the colour for the truncation dots
for (int i = 0; i < run.GetGlyphCount(); i++) {
GlyphID glyph = glyphs[i];
@ -623,7 +636,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
if (do_shadow && (glyph & SPRITE_GLYPH) != 0) continue;
GfxMainBlitter(sprite, begin_x + (do_shadow ? shadow_offset : 0), top + (do_shadow ? shadow_offset : 0), BlitterMode::ColourRemap);
GfxMainBlitter(sprite, begin_x + (do_shadow ? shadow_offset : 0), top + (do_shadow ? shadow_offset : 0), bm);
}
}
return last_colour;
@ -640,7 +653,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
}
if (underline) {
GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, PixelColour{_string_colourremap[1]});
GfxFillRect(left, y + h, right, y + h + WidgetDimensions::scaled.bevel.top - 1, PixelColour{_string_colourremap.GetPaletteRemap()[1]});
}
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;
@ -948,11 +961,11 @@ Dimension GetStringListBoundingBox(std::span<const StringID> list, FontSize font
*/
void DrawCharCentered(char32_t c, const Rect &r, TextColour colour)
{
SetColourRemap(colour);
BlitterMode bm = SetColourRemap(colour);
GfxMainBlitter(GetGlyph(FS_NORMAL, c),
CentreBounds(r.left, r.right, GetCharacterWidth(FS_NORMAL, c)),
CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)),
BlitterMode::ColourRemap);
bm);
}
/**
@ -983,13 +996,13 @@ Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
* @param pal The palette to get the blitter mode for.
* @return The blitter mode associated with the palette.
*/
static BlitterMode GetBlitterMode(PaletteID pal)
static BlitterMode GetBlitterMode(PaletteID pal, const RecolourSprite &recolour)
{
switch (pal) {
case PAL_NONE: return BlitterMode::Normal;
case PALETTE_CRASH: return BlitterMode::CrashRemap;
case PALETTE_ALL_BLACK: return BlitterMode::BlackRemap;
default: return BlitterMode::ColourRemap;
default: return recolour.IsRGB() && BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 32 ? BlitterMode::RGBAColourRemap : BlitterMode::ColourRemap;
}
}
@ -1006,15 +1019,17 @@ void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSpri
SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH);
if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
pal = GB(pal, 0, PALETTE_WIDTH);
_colour_remap_ptr = GetNonSprite(pal, SpriteType::Recolour) + 1;
_colour_remap_ptr = GetRecolourSprite(pal);
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, pal == PALETTE_TO_TRANSPARENT ? BlitterMode::Transparent : BlitterMode::TransparentRemap, sub, real_sprite);
} else if (pal != PAL_NONE) {
BlitterMode bm;
if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) {
SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
bm = SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
} else {
_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1;
_colour_remap_ptr = GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH));
bm = GetBlitterMode(pal, *_colour_remap_ptr);
}
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal), sub, real_sprite);
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, bm, sub, real_sprite);
} else {
GfxMainBlitterViewport(GetSprite(real_sprite, SpriteType::Normal), x, y, BlitterMode::Normal, sub, real_sprite);
}
@ -1034,15 +1049,17 @@ void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub,
SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH);
if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) {
pal = GB(pal, 0, PALETTE_WIDTH);
_colour_remap_ptr = GetNonSprite(pal, SpriteType::Recolour) + 1;
_colour_remap_ptr = GetRecolourSprite(pal);
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, pal == PALETTE_TO_TRANSPARENT ? BlitterMode::Transparent : BlitterMode::TransparentRemap, sub, real_sprite, zoom);
} else if (pal != PAL_NONE) {
BlitterMode bm;
if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) {
SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
bm = SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH));
} else {
_colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1;
_colour_remap_ptr = GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH));
bm = GetBlitterMode(pal, *_colour_remap_ptr);
}
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, GetBlitterMode(pal), sub, real_sprite, zoom);
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, bm, sub, real_sprite, zoom);
} else {
GfxMainBlitter(GetSprite(real_sprite, SpriteType::Normal), x, y, BlitterMode::Normal, sub, real_sprite, zoom);
}

View File

@ -280,7 +280,7 @@ struct SubSprite {
int left, top, right, bottom;
};
enum Colours : uint8_t {
enum Colours : uint32_t {
COLOUR_BEGIN,
COLOUR_DARK_BLUE = COLOUR_BEGIN,
COLOUR_PALE_GREEN,
@ -299,13 +299,14 @@ enum Colours : uint8_t {
COLOUR_GREY,
COLOUR_WHITE,
COLOUR_END,
INVALID_COLOUR = 0xFF,
INVALID_COLOUR = UINT32_MAX,
};
DECLARE_INCREMENT_DECREMENT_OPERATORS(Colours)
DECLARE_ENUM_AS_ADDABLE(Colours)
DECLARE_ENUM_AS_BIT_SET(Colours)
/** Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palette.png */
enum TextColour : uint16_t {
enum TextColour : uint32_t {
TC_BEGIN = 0x00,
TC_FROMSTRING = 0x00,
TC_BLUE = 0x00,
@ -331,9 +332,10 @@ enum TextColour : uint16_t {
TC_IS_PALETTE_COLOUR = 0x100, ///< Colour value is already a real palette colour index, not an index of a StringColour.
TC_NO_SHADE = 0x200, ///< Do not add shading to this text colour.
TC_FORCED = 0x400, ///< Ignore colour changes from strings.
TC_IS_RGB_COLOUR = 0x800, ///< Colour includes RGB component.
TC_COLOUR_MASK = 0xFF, ///< Mask to test if TextColour (without flags) is within limits.
TC_FLAGS_MASK = 0x700, ///< Mask to test if TextColour (with flags) is within limits.
TC_FLAGS_MASK = 0xF00, ///< Mask to test if TextColour (with flags) is within limits.
};
DECLARE_ENUM_AS_BIT_SET(TextColour)
@ -404,12 +406,30 @@ DECLARE_ENUM_AS_BIT_SET(StringAlignment)
/** Colour for pixel/line drawing. */
struct PixelColour {
uint8_t p; ///< Palette index.
uint8_t p = 0; ///< Palette index.
uint8_t r = 0; ///< Red component.
uint8_t g = 0; ///< Green component.
uint8_t b = 0; ///< Blue component.
constexpr PixelColour() : p(0) {}
constexpr PixelColour() {}
explicit constexpr PixelColour(uint8_t p) : p(p) {}
constexpr PixelColour(uint8_t p, Colour colour) : p(p), r(colour.r), g(colour.g), b(colour.b) {}
PixelColour(Colour colour);
constexpr inline TextColour ToTextColour() const { return static_cast<TextColour>(this->p) | TC_IS_PALETTE_COLOUR; }
constexpr inline bool HasRGB() const { return (this->r | this->g | this->b) != 0; }
constexpr inline Colour ToColour() const { return {this->r, this->g, this->b}; }
TextColour ToTextColour() const;
};
struct HsvColour {
static constexpr int HUE_MAX = 360 * 128; ///< Maximum value for hue.
static constexpr int SAT_MAX = UINT8_MAX; ///< Maximum value for saturation.
static constexpr int VAL_MAX = UINT8_MAX; ///< Maximum value for value.
static constexpr int HUE_RGN = HUE_MAX / 6;
uint16_t h; ///< Hue ranging from 0 to HUE_MAX.
uint8_t s; ///< Saturation ranging from 0 to SAT_MAX.
uint8_t v; ///< Value (brightness) ranging from 0 to VAL_MAX.
};
#endif /* GFX_TYPE_H */

View File

@ -87,6 +87,7 @@ struct Group : GroupPool::PoolItem<&_group_pool> {
Group() {}
Group(CompanyID owner, VehicleType vehicle_type) : owner(owner), vehicle_type(vehicle_type) {}
~Group();
};

View File

@ -19,6 +19,7 @@
#include "core/pool_func.hpp"
#include "order_backup.h"
#include "group_cmd.h"
#include "spritecache.h"
#include "table/strings.h"
@ -308,6 +309,7 @@ static void PropagateChildLivery(const Group *g, bool reset_cache)
Group *cg = Group::Get(childgroup);
if (!HasBit(cg->livery.in_use, 0)) cg->livery.colour1 = g->livery.colour1;
if (!HasBit(cg->livery.in_use, 1)) cg->livery.colour2 = g->livery.colour2;
UpdateLivery(cg->livery, false);
PropagateChildLivery(cg, reset_cache);
}
}
@ -323,11 +325,20 @@ void UpdateCompanyGroupLiveries(const Company *c)
if (g->owner == c->index && g->parent == GroupID::Invalid()) {
if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
UpdateLivery(g->livery, false);
PropagateChildLivery(g, false);
}
}
}
Group::~Group()
{
if (CleaningPool()) return;
DeallocateDynamicSprite(this->livery.cached_pal_1cc);
DeallocateDynamicSprite(this->livery.cached_pal_2cc);
DeallocateDynamicSprite(this->livery.cached_pal_2cr);
}
/**
* Create a new vehicle group.
@ -483,8 +494,9 @@ CommandCost CmdAlterGroup(DoCommandFlags flags, AlterGroupMode mode, GroupID gro
if (!HasBit(g->livery.in_use, 0) || !HasBit(g->livery.in_use, 1)) {
/* Update livery with new parent's colours if either colour is default. */
const Livery *livery = GetParentLivery(g);
if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = livery->colour1;
if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = livery->colour2;
if (!HasBit(g->livery.in_use, 0)) if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = livery->colour1;
if (!HasBit(g->livery.in_use, 1)) if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = livery->colour2;
UpdateLivery(g->livery, false);
PropagateChildLivery(g, true);
MarkWholeScreenDirty();
@ -680,8 +692,6 @@ CommandCost CmdSetGroupLivery(DoCommandFlags flags, GroupID group_id, bool prima
if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
if (colour >= COLOUR_END && colour != INVALID_COLOUR) return CMD_ERROR;
if (flags.Test(DoCommandFlag::Execute)) {
if (primary) {
AssignBit(g->livery.in_use, 0, colour != INVALID_COLOUR);
@ -692,6 +702,7 @@ CommandCost CmdSetGroupLivery(DoCommandFlags flags, GroupID group_id, bool prima
if (colour == INVALID_COLOUR) colour = GetParentLivery(g)->colour2;
g->livery.colour2 = colour;
}
UpdateLivery(g->livery, false);
PropagateChildLivery(g, true);
MarkWholeScreenDirty();

View File

@ -16,7 +16,7 @@
#include "vehiclelist.h"
#include "vehiclelist_cmd.h"
enum Colours : uint8_t;
enum Colours : uint32_t;
enum class GroupFlag : uint8_t;
/** Action for \c CmdAlterGroup. */

View File

@ -3076,7 +3076,7 @@ struct IndustryCargoesWindow : public Window {
case WID_IC_NOTIFY:
this->ToggleWidgetLoweredState(WID_IC_NOTIFY);
this->SetWidgetDirty(WID_IC_NOTIFY);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
if (this->IsWidgetLowered(WID_IC_NOTIFY)) {
if (FindWindowByClass(WC_SMALLMAP) == nullptr) ShowSmallMap();

View File

@ -170,6 +170,7 @@ STR_ITEMS :{COMMA}{NBSP}it
STR_CRATES :{COMMA}{NBSP}crate{P "" s}
STR_COLOUR_DEFAULT :Default
STR_COLOUR_CUSTOM :Custom...
###length 17
STR_COLOUR_DARK_BLUE :Dark Blue
STR_COLOUR_PALE_GREEN :Pale Green
@ -2325,6 +2326,11 @@ STR_LIVERY_LARGE_PLANE :Large Aeroplane
STR_LIVERY_PASSENGER_TRAM :Passenger Tram
STR_LIVERY_FREIGHT_TRAM :Freight Tram
STR_LIVERY_HUE :{BLACK}Hue
STR_LIVERY_SATURATION :{BLACK}Saturation
STR_LIVERY_LIGHTNESS :{BLACK}Lightness
STR_LIVERY_CONTRAST :{BLACK}Contrast
# Face selection window
STR_FACE_CAPTION :{WHITE}Face Selection
STR_FACE_CANCEL_TOOLTIP :{BLACK}Cancel new face selection

View File

@ -79,6 +79,10 @@ struct Livery {
uint8_t in_use = 0; ///< Bit 0 set if this livery should override the default livery first colour, Bit 1 for the second colour.
Colours colour1 = COLOUR_BEGIN; ///< First colour, for all vehicles.
Colours colour2 = COLOUR_BEGIN; ///< Second colour, for vehicles with 2CC support.
PaletteID cached_pal_1cc = 0; ///< NOSAVE: cached 1CC palette.
PaletteID cached_pal_2cc = 0; ///< NOSAVE: cached 2CC palette.
PaletteID cached_pal_2cr = 0; ///< NOSAVE: cached reversed 2CC palette.
};
void ResetCompanyLivery(Company *c);

View File

@ -64,7 +64,7 @@ bool HandlePlacePushButton(Window *w, WidgetID widget, CursorID cursor, HighLigh
{
if (w->IsWidgetDisabled(widget)) return false;
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
w->SetDirty();
if (w->IsWidgetLowered(widget)) {
@ -553,10 +553,19 @@ void ShowSelectGameWindow();
void SetupColoursAndInitialWindow()
{
for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
const uint8_t *b = GetNonSprite(GetColourPalette(i), SpriteType::Recolour) + 1;
assert(b != nullptr);
const RecolourSprite *rs = GetRecolourSprite(GetColourPalette(i));
assert(rs != nullptr);
const uint8_t *remap = rs->GetPaletteRemap();
if (rs->IsRGB()) {
const Colour *rgba_remap = rs->GetRGBARemap();
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
SetColourGradient(i, j, PixelColour{b[0xC6 + j]});
const Colour &c = rgba_remap[j];
SetColourGradient(i, j, PixelColour{remap[0xC6 + j], c});
}
} else {
for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
SetColourGradient(i, j, PixelColour{remap[0xC6 + j]});
}
}
}

View File

@ -325,7 +325,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company
p->Send_uint8 (c->index);
p->Send_string(GetString(STR_COMPANY_NAME, c->index));
p->Send_string(GetString(STR_PRESIDENT_NAME, c->index));
p->Send_uint8 (c->colour);
p->Send_uint8 (c->colour & 0xF);
p->Send_bool (true);
p->Send_uint32(c->inaugurated_year.base());
p->Send_bool (c->is_ai);
@ -348,7 +348,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Compa
p->Send_uint8 (c->index);
p->Send_string(GetString(STR_COMPANY_NAME, c->index));
p->Send_string(GetString(STR_PRESIDENT_NAME, c->index));
p->Send_uint8 (c->colour);
p->Send_uint8 (c->colour & 0xF);
p->Send_bool (true);
p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy

View File

@ -1678,6 +1678,9 @@ static void AfterLoadGRFs()
InitRailTypes();
InitRoadTypes();
/* Force cached palettes to be refreshed */
ResetVehicleColourMap();
for (Engine *e : Engine::IterateType(VEH_ROAD)) {
if (_gted[e->index].rv_max_speed != 0) {
/* Set RV maximum speed from the mph/0.8 unit value */
@ -1855,6 +1858,9 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset)
/* Pseudo sprite processing is finished; free temporary stuff */
_cur_gps.ClearDataForNextFile();
/* Make note of last sprite ID loaded for dynamic sprite management */
ClearDynamicSprites();
/* Call any functions that should be run after GRFs have been loaded. */
AfterLoadGRFs();

View File

@ -17,6 +17,7 @@
#include "water.h"
#include "landscape.h"
#include "company_base.h"
#include "company_func.h"
#include "town.h"
#include "newgrf_animation_base.h"
@ -241,7 +242,7 @@ static uint16_t GetAirportTileCallback(CallbackID callback, uint32_t param1, uin
return object.ResolveCallback(regs100);
}
static void AirportDrawTileLayout(const TileInfo *ti, const DrawTileSpriteSpan &dts, Colours colour)
static void AirportDrawTileLayout(const TileInfo *ti, const DrawTileSpriteSpan &dts, PaletteID cc_pal)
{
SpriteID image = dts.ground.sprite;
SpriteID pal = dts.ground.pal;
@ -250,11 +251,11 @@ static void AirportDrawTileLayout(const TileInfo *ti, const DrawTileSpriteSpan &
if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
DrawWaterClassGround(ti);
} else {
DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, GetColourPalette(colour)));
DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, cc_pal));
}
}
DrawNewGRFTileSeq(ti, &dts, TO_BUILDINGS, 0, GetColourPalette(colour));
DrawNewGRFTileSeq(ti, &dts, TO_BUILDINGS, 0, cc_pal);
}
bool DrawNewAirportTile(TileInfo *ti, Station *st, const AirportTileSpec *airts)
@ -278,7 +279,7 @@ bool DrawNewAirportTile(TileInfo *ti, Station *st, const AirportTileSpec *airts)
auto processor = group->ProcessRegisters(object, nullptr);
auto dts = processor.GetLayout();
AirportDrawTileLayout(ti, dts, Company::Get(st->owner)->colour);
AirportDrawTileLayout(ti, dts, GetCompanyPalette(st->owner));
return true;
}

View File

@ -528,7 +528,7 @@ struct NewsWindow : Window {
case WID_N_MGR_FACE: {
const CompanyNewsInformation *cni = static_cast<const CompanyNewsInformation*>(this->ni->data.get());
DrawCompanyManagerFace(cni->face, cni->colour, r);
DrawCompanyManagerFace(cni->face, cni->colour, r); // XXX TODO this should be a palette
GfxFillRect(r, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR);
break;
}

View File

@ -319,7 +319,7 @@ public:
if (_object_gui.sel_type != std::numeric_limits<uint16_t>::max()) {
_object_gui.sel_view = this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement();
this->InvalidateData(PickerInvalidation::Position);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
}
break;

View File

@ -15,6 +15,7 @@
#include "landscape_type.h"
#include "palette_func.h"
#include "settings_type.h"
#include "sprite.h"
#include "thread.h"
#include "table/palettes.h"
@ -84,6 +85,7 @@ static uint CalculateColourDistance(const Colour &col1, int r2, int g2, int b2)
/* Palette indexes for conversion. See docs/palettes/palette_key.png */
const uint8_t PALETTE_INDEX_CC_START = 198; ///< Palette index of start of company colour remap area.
const uint8_t PALETTE_INDEX_CC_END = PALETTE_INDEX_CC_START + 8; ///< Palette index of end of company colour remap area.
const uint8_t PALETTE_INDEX_CC2_START = 80; ///< Palette index of start of second company colour remap area.
const uint8_t PALETTE_INDEX_START = 1; ///< Palette index of start of defined palette.
const uint8_t PALETTE_INDEX_END = 215; ///< Palette index of end of defined palette.
@ -368,6 +370,81 @@ TextColour GetContrastColour(PixelColour background, uint8_t threshold)
return sq1000_brightness < ((uint) threshold) * ((uint) threshold) * 1000 ? TC_WHITE : TC_BLACK;
}
HsvColour ConvertRgbToHsv(Colour rgb)
{
HsvColour hsv;
uint8_t rgbmin = std::min({rgb.r, rgb.g, rgb.b});
uint8_t rgbmax = std::max({rgb.r, rgb.g, rgb.b});
hsv.v = rgbmax;
if (hsv.v == 0) {
hsv.h = 0;
hsv.s = 0;
return hsv;
}
int d = rgbmax - rgbmin;
hsv.s = HsvColour::SAT_MAX * d / rgbmax;
if (hsv.s == 0) {
hsv.h = 0;
return hsv;
}
int hue;
if (rgbmax == rgb.r) {
hue = HsvColour::HUE_RGN * 0 + HsvColour::HUE_RGN * ((int)rgb.g - (int)rgb.b) / d;
} else if (rgbmax == rgb.g) {
hue = HsvColour::HUE_RGN * 2 + HsvColour::HUE_RGN * ((int)rgb.b - (int)rgb.r) / d;
} else {
hue = HsvColour::HUE_RGN * 4 + HsvColour::HUE_RGN * ((int)rgb.r - (int)rgb.g) / d;
}
if (hue > HsvColour::HUE_MAX) hue -= HsvColour::HUE_MAX;
if (hue < 0) hue += HsvColour::HUE_MAX;
hsv.h = hue;
return hsv;
}
Colour ConvertHsvToRgb(HsvColour hsv)
{
if (hsv.s == 0) return Colour(hsv.v, hsv.v, hsv.v);
if (hsv.h >= HsvColour::HUE_MAX) hsv.h = 0;
int region = hsv.h / HsvColour::HUE_RGN;
int remainder = (hsv.h - (region * HsvColour::HUE_RGN)) * 6;
int p = (hsv.v * (HsvColour::SAT_MAX - hsv.s)) / HsvColour::SAT_MAX;
int q = (hsv.v * (HsvColour::SAT_MAX - ((hsv.s * remainder) / HsvColour::HUE_MAX))) / HsvColour::SAT_MAX;
int t = (hsv.v * (HsvColour::SAT_MAX - ((hsv.s * (HsvColour::HUE_MAX - remainder)) / HsvColour::HUE_MAX))) / HsvColour::SAT_MAX;
switch (region) {
case 0: return Colour(hsv.v, t, p);
case 1: return Colour(q, hsv.v, p);
case 2: return Colour(p, hsv.v, t);
case 3: return Colour(p, q, hsv.v);
case 4: return Colour(t, p, hsv.v);
default: return Colour(hsv.v, p, q);
}
}
/**
* Adjust brightness of an HSV colour.
* @param hsv colour to adjust.
* @param shade shade to apply.
* @param contrast contrast of shade.
* @returns Adjusted HSV colour.
**/
HsvColour AdjustHsvColourBrightness(HsvColour hsv, ColourShade shade, int contrast)
{
HsvColour r = hsv;
int amt = (shade - SHADE_NORMAL) * (16 + contrast) / 8;
int overflow = (hsv.v + amt) - HsvColour::VAL_MAX;
r.v = ClampTo<uint8_t>(hsv.v + amt);
r.s = ClampTo<uint8_t>(hsv.s - std::max(0, overflow));
return r;
}
/**
* Lookup table of colour shades for all 16 colour gradients.
* 8 colours per gradient from darkest (0) to lightest (7)
@ -387,6 +464,10 @@ struct ColourGradients
*/
PixelColour GetColourGradient(Colours colour, ColourShade shade)
{
ColoursPacker cp(colour);
if (cp.IsCustom()) {
return ConvertHsvToRgb(AdjustHsvColourBrightness(cp.Hsv(), shade, cp.GetContrast()));
}
return ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END];
}
@ -402,3 +483,61 @@ void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_in
assert(shade < SHADE_END);
ColourGradients::gradient[colour % COLOUR_END][shade % SHADE_END] = palette_index;
}
PixelColour::PixelColour(Colour colour) : r(colour.r), g(colour.g), b(colour.b)
{
this->p = GetNearestColourIndex(colour);
}
TextColour PixelColour::ToTextColour() const
{
TextColour tc = static_cast<TextColour>(this->p) | TC_IS_PALETTE_COLOUR;
if (this->HasRGB()) {
tc |= TC_IS_RGB_COLOUR;
TextColourPacker tcp(tc);
tcp.SetR(this->r);
tcp.SetG(this->g);
tcp.SetB(this->b);
}
return tc;
}
std::pair<Colour, uint8_t> GetCompanyColourRGB(Colours colour)
{
static constexpr uint8_t CC_PALETTE_CONTRAST = 90;
PaletteID pal = GetColourPalette(colour);
const RecolourSprite *map = GetRecolourSprite(pal);
Colour rgb = _palette.palette[map->palette[PALETTE_INDEX_CC_START + SHADE_NORMAL]];
return {rgb, CC_PALETTE_CONTRAST};
}
PaletteID CreateCompanyColourRemap(Colours colour1, Colours colour2, bool twocc, PaletteID basemap, PaletteID hint)
{
DeallocateDynamicSprite(hint);
PaletteID pal = AllocateDynamicSprite();
const RecolourSprite *base = GetRecolourSprite(basemap);
RecolourSpriteRGBA *p = new (InjectSprite(SpriteType::Recolour, pal, sizeof(RecolourSpriteRGBA)).data()) RecolourSpriteRGBA();
/* Copy base remap */
p->palette = base->palette;
std::ranges::transform(p->palette, p->rgba.begin(), [](const uint8_t &col) { return _palette.palette[col]; });
auto apply_colour = [](RecolourSpriteRGBA &remap, uint8_t index, Colours colour) {
ColoursPacker cp{colour};
if (!cp.IsCustom()) return;
HsvColour hsv = cp.Hsv();
uint8_t con = cp.GetContrast();
for (ColourShade shade = SHADE_BEGIN; shade != SHADE_END; ++shade) {
remap.rgba[index + shade] = ConvertHsvToRgb(AdjustHsvColourBrightness(hsv, shade, con));
}
};
apply_colour(*p, PALETTE_INDEX_CC_START, colour1);
if (twocc) apply_colour(*p, PALETTE_INDEX_CC2_START, colour2);
return pal;
}

View File

@ -83,9 +83,16 @@ enum ColourShade : uint8_t {
};
DECLARE_INCREMENT_DECREMENT_OPERATORS(ColourShade)
HsvColour ConvertRgbToHsv(Colour rgb);
Colour ConvertHsvToRgb(HsvColour hsv);
HsvColour AdjustHsvColourBrightness(HsvColour hsv, ColourShade shade, int contrast);
PixelColour GetColourGradient(Colours colour, ColourShade shade);
void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_colour);
std::pair<Colour, uint8_t> GetCompanyColourRGB(Colours colour);
PaletteID CreateCompanyColourRemap(Colours rgb1, Colours rgb2, bool twocc, PaletteID basemap, PaletteID hint);
/**
* Return the colour for a particular greyscale level.
* @param level Intensity, 0 = black, 15 = white
@ -124,4 +131,84 @@ static constexpr PixelColour PC_FIELDS {0x25}; ///< Light
static constexpr PixelColour PC_TREES {0x57}; ///< Green palette colour for trees.
static constexpr PixelColour PC_WATER {0xC9}; ///< Dark blue palette colour for water.
/**
* Stretch TNumBits to fill 8 bits.
* The most-significant digits are repeated as least-significant digits so that the full 8 bit range is used, e.g.:
* 000000 -> 00000000, 111100 -> 11110011, 111111 -> 11111111
* @param v Value of TNumBits to stretch.
* @returns 8 bit stretched value.
*/
template <uint TNumBits>
inline constexpr uint8_t StretchBits(uint8_t v)
{
return (v << (8 - TNumBits)) | (v >> (8 - (8 - TNumBits) * 2));
}
struct ColoursPacker
{
Colours &c;
explicit constexpr ColoursPacker(Colours &c) : c(c) { }
/*
* Constants for the bit packing used by Colours.
*/
static constexpr const uint IS_CUSTOM_BIT = 4;
static constexpr const uint INDEX_START = 0; ///< Packed start of index component
static constexpr const uint INDEX_SIZE = 4; ///< Packed size of index component
static constexpr const uint HUE_START = 7; ///< Packed start of hue component
static constexpr const uint HUE_SIZE = 9; ///< Packed size of hue component
static constexpr const uint SAT_START = 16; ///< Packed start of saturation component
static constexpr const uint SAT_SIZE = 6; ///< Packed size of saturation component
static constexpr const uint VAL_START = 22; ///< Packed start of value component
static constexpr const uint VAL_SIZE = 6; ///< Packed size of value component
static constexpr const uint CON_START = 28; ///< Packed start of contrast component
static constexpr const uint CON_SIZE = 4; ///< Packed size of contrast component
/* Colours is considered unused and blank if only the I component is set. */
inline constexpr bool IsCustom() const { return HasBit(this->c, IS_CUSTOM_BIT); }
inline constexpr uint8_t GetIndex() const { return GB(this->c, INDEX_START, INDEX_SIZE); }
inline constexpr uint16_t GetHue() const { return GB(this->c, HUE_START, HUE_SIZE) * HsvColour::HUE_MAX / (1U << 9); }
inline constexpr uint8_t GetSaturation() const { return StretchBits<SAT_SIZE>(GB(this->c, SAT_START, SAT_SIZE)); }
inline constexpr uint8_t GetValue() const { return StretchBits<VAL_SIZE>(GB(this->c, VAL_START, VAL_SIZE)); }
inline constexpr uint8_t GetContrast() const { return StretchBits<CON_SIZE>(GB(this->c, CON_START, CON_SIZE)); }
inline void SetCustom(bool v) { SB(this->c, IS_CUSTOM_BIT, 1, v); }
inline void SetIndex(uint8_t v) { SB(this->c, INDEX_START, INDEX_SIZE, v); }
inline void SetHue(uint16_t v) { SB(this->c, HUE_START, HUE_SIZE, v * (1U << HUE_SIZE) / HsvColour::HUE_MAX); }
inline void SetSaturation(uint8_t v) { SB(this->c, SAT_START, SAT_SIZE, v >> (8 - SAT_SIZE)); }
inline void SetValue(uint8_t v) { SB(this->c, VAL_START, VAL_SIZE, v >> (8 - VAL_SIZE)); }
inline void SetContrast(uint8_t v) { SB(this->c, CON_START, CON_SIZE, v >> (8 - CON_SIZE)); }
inline constexpr HsvColour Hsv() const { return {this->GetHue(), this->GetSaturation(), this->GetValue()}; }
};
struct TextColourPacker
{
TextColour &tc;
constexpr TextColourPacker(TextColour &tc) : tc(tc) { }
static constexpr uint8_t R_START = 12; ///< Packed start of red component
static constexpr uint8_t R_SIZE = 6; ///< Packed size of red component
static constexpr uint8_t G_START = 18; ///< Packed start of green component
static constexpr uint8_t G_SIZE = 6; ///< Packed size of green component
static constexpr uint8_t B_START = 24; ///< Packed start of blue component
static constexpr uint8_t B_SIZE = 6; ///< Packed size of blue component
inline constexpr uint8_t GetR() const { return StretchBits<R_SIZE>(GB(this->tc, R_START, R_SIZE)); }
inline constexpr uint8_t GetG() const { return StretchBits<G_SIZE>(GB(this->tc, G_START, G_SIZE)); }
inline constexpr uint8_t GetB() const { return StretchBits<B_SIZE>(GB(this->tc, B_START, B_SIZE)); }
inline constexpr void SetR(uint8_t v) { SB(this->tc, R_START, R_SIZE, v >> (8 - R_SIZE)); }
inline constexpr void SetG(uint8_t v) { SB(this->tc, G_START, G_SIZE, v >> (8 - G_SIZE)); }
inline constexpr void SetB(uint8_t v) { SB(this->tc, B_START, B_SIZE, v >> (8 - B_SIZE)); }
inline constexpr Colour ToColour() const { return Colour(this->GetR(), this->GetG(), this->GetB()); }
};
#endif /* PALETTE_FUNC_H */

View File

@ -384,7 +384,7 @@ void PickerWindow::OnClick(Point pt, WidgetID widget, int)
this->callbacks.SetSelectedClass(*it);
this->InvalidateData({PickerInvalidation::Type, PickerInvalidation::Position, PickerInvalidation::Validate});
}
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
CloseWindowById(WC_SELECT_STATION, 0);
break;
}
@ -434,7 +434,7 @@ void PickerWindow::OnClick(Point pt, WidgetID widget, int)
this->callbacks.SetSelectedType(item.index);
this->InvalidateData(PickerInvalidation::Position);
}
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
CloseWindowById(WC_SELECT_STATION, 0);
break;
}

View File

@ -357,7 +357,7 @@ static void BuildRailClick_Remove(Window *w)
{
if (w->IsWidgetDisabled(WID_RAT_REMOVE)) return;
ToggleRailButton_Remove(w);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
/* handle station builder */
if (w->IsWidgetLowered(WID_RAT_BUILD_STATION)) {
@ -1239,7 +1239,7 @@ public:
this->RaiseWidget(WID_BRAS_PLATFORM_DIR_X + _station_gui.axis);
_station_gui.axis = (Axis)(widget - WID_BRAS_PLATFORM_DIR_X);
this->LowerWidget(WID_BRAS_PLATFORM_DIR_X + _station_gui.axis);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
CloseWindowById(WC_SELECT_STATION, 0);
break;
@ -1271,7 +1271,7 @@ public:
this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN);
this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
CloseWindowById(WC_SELECT_STATION, 0);
break;
@ -1304,7 +1304,7 @@ public:
this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN);
this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
CloseWindowById(WC_SELECT_STATION, 0);
break;
@ -1338,7 +1338,7 @@ public:
this->SetWidgetLoweredState(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN, !_settings_client.gui.station_dragdrop);
this->SetWidgetLoweredState(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN, !_settings_client.gui.station_dragdrop);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
CloseWindowById(WC_SELECT_STATION, 0);
break;
@ -1350,7 +1350,7 @@ public:
this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage);
this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
SetViewportCatchmentStation(nullptr, true);
break;
@ -1743,7 +1743,7 @@ struct BuildRailDepotWindow : public PickerWindowBase {
this->RaiseWidget(WID_BRAD_DEPOT_NE + _build_depot_direction);
_build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE);
this->LowerWidget(WID_BRAD_DEPOT_NE + _build_depot_direction);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
break;
}

View File

@ -582,7 +582,7 @@ struct BuildRoadToolbarWindow : Window {
CloseWindowById(WC_SELECT_STATION, 0);
ToggleRoadButton_Remove(this);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
break;
case WID_ROT_CONVERT_ROAD:
@ -1145,7 +1145,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase {
this->RaiseWidget(WID_BROD_DEPOT_NE + _road_depot_orientation);
_road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE);
this->LowerWidget(WID_BROD_DEPOT_NE + _road_depot_orientation);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
break;
@ -1477,7 +1477,7 @@ public:
this->RaiseWidget(WID_BROS_STATION_NE + _roadstop_gui.orientation);
_roadstop_gui.orientation = (DiagDirection)(widget - WID_BROS_STATION_NE);
this->LowerWidget(WID_BROS_STATION_NE + _roadstop_gui.orientation);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
CloseWindowById(WC_SELECT_STATION, 0);
break;
@ -1487,7 +1487,7 @@ public:
this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
_settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF);
this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
SetViewportCatchmentStation(nullptr, true);
break;

View File

@ -3383,6 +3383,8 @@ bool AfterLoadGame()
}
for (Company *c : Company::Iterate()) {
UpdateLivery(c->livery[LS_DEFAULT], true);
_company_palettes[c->index] = c->livery[LS_DEFAULT].cached_pal_1cc;
UpdateCompanyLiveries(c);
}

View File

@ -411,8 +411,10 @@ class SlCompanyLiveries : public DefaultSaveLoadHandler<SlCompanyLiveries, Compa
public:
static inline const SaveLoad description[] = {
SLE_CONDVAR(Livery, in_use, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour1, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour2, SLE_UINT8, SLV_34, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour1, SLE_FILE_U8 | SLE_VAR_U32, SLV_34, SLV_CUSTOM_COMPANY_COLOURS),
SLE_CONDVAR(Livery, colour2, SLE_FILE_U8 | SLE_VAR_U32, SLV_34, SLV_CUSTOM_COMPANY_COLOURS),
SLE_CONDVAR(Livery, colour1, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
SLE_CONDVAR(Livery, colour2, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
};
static inline const SaveLoadCompatTable compat_description = _company_liveries_compat;
@ -511,7 +513,8 @@ static const SaveLoad _company_desc[] = {
SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, max_loan, SLE_INT64, SLV_MAX_LOAN_FOR_COMPANY, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, colour, SLE_UINT8),
SLE_CONDVAR(CompanyProperties, colour, SLE_FILE_U8 | SLE_VAR_U32, SL_MIN_VERSION, SLV_CUSTOM_COMPANY_COLOURS),
SLE_CONDVAR(CompanyProperties, colour, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8),
SLE_VAR(CompanyProperties, block_preview, SLE_UINT8),

View File

@ -23,8 +23,10 @@ static const SaveLoad _group_desc[] = {
SLE_VAR(Group, vehicle_type, SLE_UINT8),
SLE_VAR(Group, flags, SLE_UINT8),
SLE_CONDVAR(Group, livery.in_use, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION),
SLE_CONDVAR(Group, livery.colour1, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION),
SLE_CONDVAR(Group, livery.colour2, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION),
SLE_CONDVAR(Group, livery.colour1, SLE_FILE_U8 | SLE_VAR_U32, SLV_GROUP_LIVERIES, SLV_CUSTOM_COMPANY_COLOURS),
SLE_CONDVAR(Group, livery.colour2, SLE_FILE_U8 | SLE_VAR_U32, SLV_GROUP_LIVERIES, SLV_CUSTOM_COMPANY_COLOURS),
SLE_CONDVAR(Group, livery.colour1, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
SLE_CONDVAR(Group, livery.colour2, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
SLE_CONDVAR(Group, parent, SLE_UINT16, SLV_189, SL_MAX_VERSION),
SLE_CONDVAR(Group, number, SLE_UINT16, SLV_GROUP_NUMBERS, SL_MAX_VERSION),
};

View File

@ -179,7 +179,8 @@ static const SaveLoad _industry_desc[] = {
SLE_VAR(Industry, type, SLE_UINT8),
SLE_VAR(Industry, owner, SLE_UINT8),
SLE_VAR(Industry, random_colour, SLE_UINT8),
SLE_CONDVAR(Industry, random_colour, SLE_FILE_U8 | SLE_VAR_U32, SL_MIN_VERSION, SLV_CUSTOM_COMPANY_COLOURS),
SLE_CONDVAR(Industry, random_colour, SLE_UINT32, SLV_CUSTOM_COMPANY_COLOURS, SL_MAX_VERSION),
SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, SLV_31, SL_MAX_VERSION),
SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8),

View File

@ -406,6 +406,7 @@ enum SaveLoadVersion : uint16_t {
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.
SLV_INDUSTRY_ACCEPTED_HISTORY, ///< 357 PR#14321 Add per-industry history of cargo delivered and waiting.
SLV_CUSTOM_COMPANY_COLOURS, ///< 358 PR#11634 Custom company colours.
SL_MAX_VERSION, ///< Highest possible saveload version
};

View File

@ -210,6 +210,7 @@ struct GUISettings {
uint8_t osk_activation; ///< Mouse gesture to trigger the OSK.
Colours starting_colour; ///< default color scheme for the company to start a new game with
Colours starting_colour_secondary; ///< default secondary color scheme for the company to start a new game with
Colours preset_colours[16]; ///< custom colour presets.
bool show_newgrf_name; ///< Show the name of the NewGRF in the build vehicle window
bool show_cargo_in_vehicle_lists; ///< Show the cargoes the vehicles can carry in the list windows
bool auto_remove_signals; ///< automatically remove signals when in the way during rail construction

View File

@ -1717,7 +1717,7 @@ public:
const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
Point zoom_pt = { (int)wid->current_x / 2, (int)wid->current_y / 2};
this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &zoom_pt);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
break;
}
@ -1729,13 +1729,13 @@ public:
case WID_SM_VEGETATION: // Show vegetation
case WID_SM_OWNERS: // Show land owners
this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR));
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
break;
case WID_SM_CENTERMAP: // Center the smallmap again
this->SmallMapCenterOnCurrentPos();
this->HandleButtonClick(WID_SM_CENTERMAP);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
break;
case WID_SM_TOGGLETOWNNAME: // Toggle town names
@ -1743,7 +1743,7 @@ public:
this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns);
this->SetDirty();
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
break;
case WID_SM_SHOW_IND_NAMES: // Toggle industry names
@ -1751,7 +1751,7 @@ public:
this->SetWidgetLoweredState(WID_SM_SHOW_IND_NAMES, this->show_ind_names);
this->SetDirty();
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
break;
case WID_SM_LEGEND: // Legend

View File

@ -247,6 +247,22 @@ void SndPlayFx(SoundID sound)
StartSound(sound, 0.5, UINT8_MAX);
}
/**
* Play a beep sound for a click event if enabled in settings.
*/
void SndClickBeep()
{
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
}
/**
* Play a beep sound for a confirm event if enabled in settings.
*/
void SndConfirmBeep()
{
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
}
/** Names corresponding to the sound set's files */
static const std::string_view _sound_file_names[] = { "samples" };

View File

@ -21,4 +21,7 @@ void SndPlayVehicleFx(SoundID sound, const Vehicle *v);
void SndPlayFx(SoundID sound);
void SndCopyToPool();
void SndClickBeep();
void SndConfirmBeep();
#endif /* SOUND_FUNC_H */

View File

@ -185,6 +185,6 @@ inline PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, Pal
* @param colour Colour.
* @return Recolour palette.
*/
static inline PaletteID GetColourPalette(Colours colour) { return PALETTE_RECOLOUR_START + colour; }
static inline PaletteID GetColourPalette(Colours colour) { return PALETTE_RECOLOUR_START + (colour % COLOUR_END); }
#endif /* SPRITE_H */

View File

@ -406,6 +406,40 @@ static bool ResizeSprites(SpriteLoader::SpriteCollection &sprite, ZoomLevels spr
return true;
}
/**
* Read recolour sprite data.
* @param file SpriteFile to read from.
* @param entries Number of entries to read.
*/
void RecolourSprite::Read(SpriteFile &file, size_t entries)
{
assert(entries <= RecolourSprite::PALETTE_SIZE);
if (file.NeedsPaletteRemap()) {
/* Remapping from "Windows" to "DOS" requires a temporary buffer as entries are overwritten. */
std::array<uint8_t, RecolourSprite::PALETTE_SIZE> tmp{};
file.ReadBlock(tmp.data(), entries);
for (uint i = 0; i < entries; ++i) {
this->palette[i] = _palmap_w2d[tmp[_palmap_d2w[i]]];
}
} else {
file.ReadBlock(this->palette.data(), entries);
}
}
void RecolourSpriteRGBA::Read(SpriteFile &file, size_t entries)
{
this->RecolourSprite::Read(file, entries);
/* Colour is byte-arranged differently by platform, so read components individually. */
for (uint i = 0; i < entries; ++i) {
this->rgba[i].r = file.ReadByte();
this->rgba[i].g = file.ReadByte();
this->rgba[i].b = file.ReadByte();
this->rgba[i].a = file.ReadByte();
}
}
/**
* Load a recolour sprite into memory.
* @param file GRF we're reading from.
@ -416,31 +450,23 @@ static bool ResizeSprites(SpriteLoader::SpriteCollection &sprite, ZoomLevels spr
*/
static void *ReadRecolourSprite(SpriteFile &file, size_t file_pos, uint num, SpriteAllocator &allocator)
{
/* "Normal" recolour sprites are ALWAYS 257 bytes. Then there is a small
* number of recolour sprites that are 17 bytes that only exist in DOS
* GRFs which are the same as 257 byte recolour sprites, but with the last
* 240 bytes zeroed. */
static const uint RECOLOUR_SPRITE_SIZE = 257;
uint8_t *dest = allocator.Allocate<uint8_t>(std::max(RECOLOUR_SPRITE_SIZE, num));
file.SeekTo(file_pos, SEEK_SET);
if (file.NeedsPaletteRemap()) {
uint8_t *dest_tmp = new uint8_t[std::max(RECOLOUR_SPRITE_SIZE, num)];
/* Only a few recolour sprites are less than 257 bytes */
if (num < RECOLOUR_SPRITE_SIZE) std::fill_n(dest_tmp, RECOLOUR_SPRITE_SIZE, 0);
file.ReadBlock(dest_tmp, num);
/* The first byte of the recolour sprite records the number of entries, with
* the caveat that as this is a single byte 256 is recorded as 0. */
uint entries = file.ReadByte();
if (entries == 0) entries = 256;
--num;
/* The data of index 0 is never used; "literal 00" according to the (New)GRF specs. */
for (uint i = 1; i < RECOLOUR_SPRITE_SIZE; i++) {
dest[i] = _palmap_w2d[dest_tmp[_palmap_d2w[i - 1] + 1]];
}
delete[] dest_tmp;
} else {
file.ReadBlock(dest, num);
if (entries > num) {
Debug(grf, 1, "ReadRecolourSprite: Expected recolour sprite with {} entries but only {} present", entries, num);
entries = num;
}
return dest;
num -= entries;
RecolourSprite *rs = (num == entries * 4) ? allocator.New<RecolourSpriteRGBA>() : allocator.New<RecolourSprite>();
rs->Read(file, entries);
return rs;
}
/**
@ -733,7 +759,7 @@ static void DeleteEntriesFromSpriteCache(size_t to_remove)
SpriteID i = 0;
for (; i != static_cast<SpriteID>(_spritecache.size()) && candidate_bytes < to_remove; i++) {
const SpriteCache *sc = GetSpriteCache(i);
if (sc->ptr != nullptr) {
if (sc->ptr != nullptr && sc->file != nullptr) {
push({ sc->lru, i, sc->length });
if (candidate_bytes >= to_remove) break;
}
@ -742,7 +768,7 @@ static void DeleteEntriesFromSpriteCache(size_t to_remove)
* only sprites with LRU values <= the maximum (i.e. the top of the heap) need to be considered */
for (; i != static_cast<SpriteID>(_spritecache.size()); i++) {
const SpriteCache *sc = GetSpriteCache(i);
if (sc->ptr != nullptr && sc->lru <= candidates.front().lru) {
if (sc->ptr != nullptr && sc->file != nullptr && sc->lru <= candidates.front().lru) {
push({ sc->lru, i, sc->length });
while (!candidates.empty() && candidate_bytes - candidates.front().size >= to_remove) {
pop();
@ -784,6 +810,10 @@ void IncreaseSpriteLRU()
void SpriteCache::ClearSpriteData()
{
if (this->ptr == nullptr) return;
if (this->type == SpriteType::Recolour) reinterpret_cast<RecolourSprite *>(this->ptr.get())->~RecolourSprite();
_spritecache_bytes_used -= this->length;
this->ptr.reset();
}
@ -795,6 +825,32 @@ void *UniquePtrSpriteAllocator::AllocatePtr(size_t size)
return this->data.get();
}
/**
* Allocate and inject memory for a memory-based sprite.
*/
std::span<std::byte> InjectSprite(SpriteType type, SpriteID load_index, size_t len)
{
if (SpriteExists(load_index)) GetSpriteCache(load_index)->ClearSpriteData();
SpriteCache *sc = AllocateSpriteCache(load_index);
sc->file_pos = SIZE_MAX;
sc->file = nullptr;
sc->id = 0;
sc->lru = 0;
sc->type = type;
sc->warned = false;
sc->control_flags = {};
UniquePtrSpriteAllocator cache_allocator;
cache_allocator.Allocate<std::byte>(len);
sc->ptr = std::move(cache_allocator.data);
sc->length = static_cast<uint32_t>(cache_allocator.size);
_spritecache_bytes_used += sc->length;
return {sc->ptr.get(), sc->length};
}
/**
* Handles the case when a sprite of different type is requested than is present in the SpriteCache.
* For SpriteType::Font sprites, it is normal. In other cases, default sprite is loaded instead.
@ -928,3 +984,44 @@ void GfxClearFontSpriteCache()
}
/* static */ SpriteCollMap<ReusableBuffer<SpriteLoader::CommonPixel>> SpriteLoader::Sprite::buffer;
static SpriteID _sprites_end; ///< First usable free sprite ID.
static std::vector<uint32_t> _dynamic_sprites; ///< List of used/free custom sprite slots.
/**
* Clear custom sprites mapping and set first usable free sprite ID.
*/
void ClearDynamicSprites()
{
_dynamic_sprites.clear();
_sprites_end = _spritecache.size();
}
/**
* Allocate a custom sprite ID.
*/
SpriteID AllocateDynamicSprite()
{
/* Find first unused slot, or make one. */
auto it = std::ranges::find(_dynamic_sprites, 0);
if (it == std::end(_dynamic_sprites)) it = _dynamic_sprites.emplace(it, 0);
(*it)++;
return _sprites_end + std::distance(std::begin(_dynamic_sprites), it);
}
/**
* Mark a custom sprite ID as deallocated.
* The sprite slot is merely marked as reusable.
*/
void DeallocateDynamicSprite(SpriteID sprite)
{
if (sprite >= _sprites_end && sprite < _sprites_end + _dynamic_sprites.size()) {
assert(_dynamic_sprites[sprite - _sprites_end] > 0);
--_dynamic_sprites[sprite - _sprites_end];
if (_dynamic_sprites[sprite - _sprites_end] == 0) {
GetSpriteCache(sprite)->ClearSpriteData();
}
}
}

View File

@ -41,10 +41,9 @@ inline const Sprite *GetSprite(SpriteID sprite, SpriteType type)
return (Sprite*)GetRawSprite(sprite, type);
}
inline const uint8_t *GetNonSprite(SpriteID sprite, SpriteType type)
inline const RecolourSprite *GetRecolourSprite(SpriteID sprite)
{
assert(type == SpriteType::Recolour);
return (uint8_t*)GetRawSprite(sprite, type);
return static_cast<RecolourSprite *>(GetRawSprite(sprite, SpriteType::Recolour));
}
void GfxInitSpriteMem();
@ -60,5 +59,10 @@ size_t GetGRFSpriteOffset(uint32_t id);
bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id);
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num);
void DupSprite(SpriteID old_spr, SpriteID new_spr);
std::span<std::byte> InjectSprite(SpriteType type, SpriteID load_index, size_t len);
void ClearDynamicSprites();
SpriteID AllocateDynamicSprite();
void DeallocateDynamicSprite(SpriteID spite);
#endif /* SPRITECACHE_H */

View File

@ -11,6 +11,8 @@
#define SPRITECACHE_TYPE_H
#include "core/enum_type.hpp"
#include "gfx_type.h"
#include "spriteloader/sprite_file_type.hpp"
/** Data structure describing a sprite. */
struct Sprite {
@ -21,6 +23,29 @@ struct Sprite {
std::byte data[]; ///< Sprite data.
};
/** Data structure describing a palette remap. */
class RecolourSprite {
public:
static constexpr size_t PALETTE_SIZE = 256; ///< Number of entries in a recolour sprite.
virtual ~RecolourSprite() {}
virtual void Read(SpriteFile &file, size_t entries);
inline const uint8_t *GetPaletteRemap() const { return this->palette.data(); }
virtual bool IsRGB() const { return false; }
virtual const Colour *GetRGBARemap() const { return nullptr; }
std::array<uint8_t, PALETTE_SIZE> palette{}; ///< Palette index remap, mapping from one palette index to another.
};
class RecolourSpriteRGBA : public RecolourSprite {
public:
void Read(SpriteFile &file, size_t entries) override;
bool IsRGB() const override { return true; }
const Colour *GetRGBARemap() const override { return this->rgba.data(); }
std::array<Colour, PALETTE_SIZE> rgba{}; ///< RGBA remap, mapping from palette index to colour.
};
enum class SpriteCacheCtrlFlag : uint8_t {
AllowZoomMin1xPal, ///< Allow use of sprite min zoom setting at 1x in palette mode.
AllowZoomMin1x32bpp, ///< Allow use of sprite min zoom setting at 1x in 32bpp mode.

View File

@ -117,6 +117,18 @@ public:
return static_cast<T *>(this->AllocatePtr(size));
}
/**
* Allocate memory and construct an object in the sprite cache.
* @tparam T Type to construct.
* @tparam Targs The constructor parameter types.
* @param args Parameters for the constructor.
*/
template <typename T, typename... Targs>
T *New(Targs &&... args)
{
return new (this->Allocate<T>(sizeof(T))) T(std::forward<Targs &&>(args)...);
}
protected:
/**
* Allocate memory for a sprite.

View File

@ -47,7 +47,7 @@ static const PalSpriteID _aqueduct_sprite_table_heads[] = {
{SPR_AQUEDUCT_RAMP_SW, PAL_NONE}, {SPR_AQUEDUCT_RAMP_SE, PAL_NONE}, {SPR_AQUEDUCT_RAMP_NE, PAL_NONE}, {SPR_AQUEDUCT_RAMP_NW, PAL_NONE},
};
static const PalSpriteID _bridge_sprite_table_4_0[] = {
static const PalSpriteID _bridge_sprite_table_suspension_oxide_north[] = {
{ 0x9A9, PAL_NONE }, { 0x99F, PAL_NONE }, { 0x9B1, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9A5, PAL_NONE }, { 0x997, PAL_NONE }, { 0x9AD, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x99D, PAL_NONE }, { 0x99F, PAL_NONE }, { 0x9B1, PAL_NONE }, { 0x0, PAL_NONE },
@ -58,7 +58,7 @@ static const PalSpriteID _bridge_sprite_table_4_0[] = {
{ 0x1116, PAL_NONE }, { 0x997, PAL_NONE }, { 0x9AD, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_4_1[] = {
static const PalSpriteID _bridge_sprite_table_suspension_oxide_south[] = {
{ 0x9AA, PAL_NONE }, { 0x9A0, PAL_NONE }, { 0x9B2, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9A6, PAL_NONE }, { 0x998, PAL_NONE }, { 0x9AE, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x99E, PAL_NONE }, { 0x9A0, PAL_NONE }, { 0x9B2, PAL_NONE }, { 0x0, PAL_NONE },
@ -69,7 +69,7 @@ static const PalSpriteID _bridge_sprite_table_4_1[] = {
{ 0x1117, PAL_NONE }, { 0x998, PAL_NONE }, { 0x9AE, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_4_2[] = {
static const PalSpriteID _bridge_sprite_table_suspension_oxide_inner_north[] = {
{ 0x9AC, PAL_NONE }, { 0x9A4, PAL_NONE }, { 0x9B4, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9A8, PAL_NONE }, { 0x99C, PAL_NONE }, { 0x9B0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9A2, PAL_NONE }, { 0x9A4, PAL_NONE }, { 0x9B4, PAL_NONE }, { 0x0, PAL_NONE },
@ -80,7 +80,7 @@ static const PalSpriteID _bridge_sprite_table_4_2[] = {
{ 0x1119, PAL_NONE }, { 0x99C, PAL_NONE }, { 0x9B0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_4_3[] = {
static const PalSpriteID _bridge_sprite_table_suspension_oxide_inner_south[] = {
{ 0x9AB, PAL_NONE }, { 0x9A3, PAL_NONE }, { 0x9B3, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9A7, PAL_NONE }, { 0x99B, PAL_NONE }, { 0x9AF, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9A1, PAL_NONE }, { 0x9A3, PAL_NONE }, { 0x9B3, PAL_NONE }, { 0x0, PAL_NONE },
@ -91,7 +91,7 @@ static const PalSpriteID _bridge_sprite_table_4_3[] = {
{ 0x1118, PAL_NONE }, { 0x99B, PAL_NONE }, { 0x9AF, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_4_4[] = {
static const PalSpriteID _bridge_sprite_table_suspension_oxide_middle_odd[] = {
{ 0x9B6, PAL_NONE }, { 0x9BA, PAL_NONE }, { 0x9BC, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9B5, PAL_NONE }, { 0x9B9, PAL_NONE }, { 0x9BB, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9B8, PAL_NONE }, { 0x9BA, PAL_NONE }, { 0x9BC, PAL_NONE }, { 0x0, PAL_NONE },
@ -102,7 +102,7 @@ static const PalSpriteID _bridge_sprite_table_4_4[] = {
{ 0x111E, PAL_NONE }, { 0x9B9, PAL_NONE }, { 0x9BB, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_4_5[] = {
static const PalSpriteID _bridge_sprite_table_suspension_middle_even[] = {
{ 0x9BD, PAL_NONE }, { 0x9C1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9BE, PAL_NONE }, { 0x9C2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9BF, PAL_NONE }, { 0x9C1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -113,7 +113,7 @@ static const PalSpriteID _bridge_sprite_table_4_5[] = {
{ 0x1121, PAL_NONE }, { 0x9C2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_4_6[] = {
static const PalSpriteID _bridge_sprite_table_generic_oxide_heads[] = {
{ 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE },
{ 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE },
{ 0x98E, PAL_NONE }, { 0x990, PAL_NONE }, { 0x98D, PAL_NONE }, { 0x98F, PAL_NONE },
@ -124,7 +124,7 @@ static const PalSpriteID _bridge_sprite_table_4_6[] = {
{ 0x1113, PAL_NONE }, { 0x1115, PAL_NONE }, { 0x1112, PAL_NONE }, { 0x1114, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_5_0[] = {
static const PalSpriteID _bridge_sprite_table_suspension_yellow_north[] = {
{ 0x9A9, PALETTE_TO_STRUCT_YELLOW }, { 0x99F, PALETTE_TO_STRUCT_YELLOW }, { 0x9B1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9A5, PALETTE_TO_STRUCT_YELLOW }, { 0x997, PALETTE_TO_STRUCT_YELLOW }, { 0x9AD, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x99D, PALETTE_TO_STRUCT_YELLOW }, { 0x99F, PALETTE_TO_STRUCT_YELLOW }, { 0x9B1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
@ -135,7 +135,7 @@ static const PalSpriteID _bridge_sprite_table_5_0[] = {
{ 0x1116, PALETTE_TO_STRUCT_YELLOW }, { 0x997, PALETTE_TO_STRUCT_YELLOW }, { 0x9AD, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_5_1[] = {
static const PalSpriteID _bridge_sprite_table_suspension_yellow_south[] = {
{ 0x9AA, PALETTE_TO_STRUCT_YELLOW }, { 0x9A0, PALETTE_TO_STRUCT_YELLOW }, { 0x9B2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9A6, PALETTE_TO_STRUCT_YELLOW }, { 0x998, PALETTE_TO_STRUCT_YELLOW }, { 0x9AE, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x99E, PALETTE_TO_STRUCT_YELLOW }, { 0x9A0, PALETTE_TO_STRUCT_YELLOW }, { 0x9B2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
@ -146,7 +146,7 @@ static const PalSpriteID _bridge_sprite_table_5_1[] = {
{ 0x1117, PALETTE_TO_STRUCT_YELLOW }, { 0x998, PALETTE_TO_STRUCT_YELLOW }, { 0x9AE, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_5_2[] = {
static const PalSpriteID _bridge_sprite_table_suspension_yellow_inner_north[] = {
{ 0x9AC, PALETTE_TO_STRUCT_YELLOW }, { 0x9A4, PALETTE_TO_STRUCT_YELLOW }, { 0x9B4, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9A8, PALETTE_TO_STRUCT_YELLOW }, { 0x99C, PALETTE_TO_STRUCT_YELLOW }, { 0x9B0, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9A2, PALETTE_TO_STRUCT_YELLOW }, { 0x9A4, PALETTE_TO_STRUCT_YELLOW }, { 0x9B4, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
@ -157,7 +157,7 @@ static const PalSpriteID _bridge_sprite_table_5_2[] = {
{ 0x1119, PALETTE_TO_STRUCT_YELLOW }, { 0x99C, PALETTE_TO_STRUCT_YELLOW }, { 0x9B0, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_5_3[] = {
static const PalSpriteID _bridge_sprite_table_suspension_yellow_inner_south[] = {
{ 0x9AB, PALETTE_TO_STRUCT_YELLOW }, { 0x9A3, PALETTE_TO_STRUCT_YELLOW }, { 0x9B3, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9A7, PALETTE_TO_STRUCT_YELLOW }, { 0x99B, PALETTE_TO_STRUCT_YELLOW }, { 0x9AF, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9A1, PALETTE_TO_STRUCT_YELLOW }, { 0x9A3, PALETTE_TO_STRUCT_YELLOW }, { 0x9B3, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
@ -168,7 +168,7 @@ static const PalSpriteID _bridge_sprite_table_5_3[] = {
{ 0x1118, PALETTE_TO_STRUCT_YELLOW }, { 0x99B, PALETTE_TO_STRUCT_YELLOW }, { 0x9AF, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_5_4[] = {
static const PalSpriteID _bridge_sprite_table_suspension_yellow_middle_odd[] = {
{ 0x9B6, PALETTE_TO_STRUCT_YELLOW }, { 0x9BA, PALETTE_TO_STRUCT_YELLOW }, { 0x9BC, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9B5, PALETTE_TO_STRUCT_YELLOW }, { 0x9B9, PALETTE_TO_STRUCT_YELLOW }, { 0x9BB, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0x9B8, PALETTE_TO_STRUCT_YELLOW }, { 0x9BA, PALETTE_TO_STRUCT_YELLOW }, { 0x9BC, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
@ -179,7 +179,7 @@ static const PalSpriteID _bridge_sprite_table_5_4[] = {
{ 0x111E, PALETTE_TO_STRUCT_YELLOW }, { 0x9B9, PALETTE_TO_STRUCT_YELLOW }, { 0x9BB, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_5_5[] = {
static const PalSpriteID _bridge_sprite_table_suspension_yellow_middle_even[] = {
{ 0x9BD, PALETTE_TO_STRUCT_YELLOW }, { 0x9C1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9BE, PALETTE_TO_STRUCT_YELLOW }, { 0x9C2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9BF, PALETTE_TO_STRUCT_YELLOW }, { 0x9C1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -190,7 +190,7 @@ static const PalSpriteID _bridge_sprite_table_5_5[] = {
{ 0x1121, PALETTE_TO_STRUCT_YELLOW }, { 0x9C2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_5_6[] = {
static const PalSpriteID _bridge_sprite_table_generic_yellow_heads[] = {
{ 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE },
{ 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE },
{ 0x98E, PALETTE_TO_STRUCT_YELLOW }, { 0x990, PALETTE_TO_STRUCT_YELLOW }, { 0x98D, PALETTE_TO_STRUCT_YELLOW }, { 0x98F, PALETTE_TO_STRUCT_YELLOW },
@ -201,7 +201,7 @@ static const PalSpriteID _bridge_sprite_table_5_6[] = {
{ 0x1113, PALETTE_TO_STRUCT_YELLOW }, { 0x1115, PALETTE_TO_STRUCT_YELLOW }, { 0x1112, PALETTE_TO_STRUCT_YELLOW }, { 0x1114, PALETTE_TO_STRUCT_YELLOW },
};
static const PalSpriteID _bridge_sprite_table_6_0[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_oxide_north[] = {
{ 0x9CD, PAL_NONE }, { 0x9D9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9CE, PAL_NONE }, { 0x9DA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9D3, PAL_NONE }, { 0x9D9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -212,7 +212,7 @@ static const PalSpriteID _bridge_sprite_table_6_0[] = {
{ 0x1125, PAL_NONE }, { 0x9DA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_6_1[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_oxide_south[] = {
{ 0x9CB, PAL_NONE }, { 0x9D7, PAL_NONE }, { 0x9DD, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9D0, PAL_NONE }, { 0x9DC, PAL_NONE }, { 0x9E0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9D1, PAL_NONE }, { 0x9D7, PAL_NONE }, { 0x9DD, PAL_NONE }, { 0x0, PAL_NONE },
@ -223,7 +223,7 @@ static const PalSpriteID _bridge_sprite_table_6_1[] = {
{ 0x1127, PAL_NONE }, { 0x9DC, PAL_NONE }, { 0x9E0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_6_2[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_oxide_middle[] = {
{ 0x9CC, PAL_NONE }, { 0x9D8, PAL_NONE }, { 0x9DE, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9CF, PAL_NONE }, { 0x9DB, PAL_NONE }, { 0x9DF, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9D2, PAL_NONE }, { 0x9D8, PAL_NONE }, { 0x9DE, PAL_NONE }, { 0x0, PAL_NONE },
@ -234,7 +234,7 @@ static const PalSpriteID _bridge_sprite_table_6_2[] = {
{ 0x1126, PAL_NONE }, { 0x9DB, PAL_NONE }, { 0x9DF, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_6_3[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_oxide_heads[] = {
{ 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE },
{ 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE },
{ 0x98E, PAL_NONE }, { 0x990, PAL_NONE }, { 0x98D, PAL_NONE }, { 0x98F, PAL_NONE },
@ -245,7 +245,7 @@ static const PalSpriteID _bridge_sprite_table_6_3[] = {
{ 0x1113, PAL_NONE }, { 0x1115, PAL_NONE }, { 0x1112, PAL_NONE }, { 0x1114, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_7_0[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_brown_north[] = {
{ 0x9CD, PALETTE_TO_STRUCT_BROWN }, { 0x9D9, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9CE, PALETTE_TO_STRUCT_BROWN }, { 0x9DA, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9D3, PALETTE_TO_STRUCT_BROWN }, { 0x9D9, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -256,7 +256,7 @@ static const PalSpriteID _bridge_sprite_table_7_0[] = {
{ 0x1125, PALETTE_TO_STRUCT_BROWN }, { 0x9DA, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_7_1[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_brown_south[] = {
{ 0x9CB, PALETTE_TO_STRUCT_BROWN }, { 0x9D7, PALETTE_TO_STRUCT_BROWN }, { 0x9DD, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
{ 0x9D0, PALETTE_TO_STRUCT_BROWN }, { 0x9DC, PALETTE_TO_STRUCT_BROWN }, { 0x9E0, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
{ 0x9D1, PALETTE_TO_STRUCT_BROWN }, { 0x9D7, PALETTE_TO_STRUCT_BROWN }, { 0x9DD, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
@ -267,7 +267,7 @@ static const PalSpriteID _bridge_sprite_table_7_1[] = {
{ 0x1127, PALETTE_TO_STRUCT_BROWN }, { 0x9DC, PALETTE_TO_STRUCT_BROWN }, { 0x9E0, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_7_2[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_brown_middle[] = {
{ 0x9CC, PALETTE_TO_STRUCT_BROWN }, { 0x9D8, PALETTE_TO_STRUCT_BROWN }, { 0x9DE, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
{ 0x9CF, PALETTE_TO_STRUCT_BROWN }, { 0x9DB, PALETTE_TO_STRUCT_BROWN }, { 0x9DF, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
{ 0x9D2, PALETTE_TO_STRUCT_BROWN }, { 0x9D8, PALETTE_TO_STRUCT_BROWN }, { 0x9DE, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
@ -278,7 +278,7 @@ static const PalSpriteID _bridge_sprite_table_7_2[] = {
{ 0x1126, PALETTE_TO_STRUCT_BROWN }, { 0x9DB, PALETTE_TO_STRUCT_BROWN }, { 0x9DF, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_7_3[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_brown_heads[] = {
{ 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE },
{ 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE },
{ 0x98E, PALETTE_TO_STRUCT_BROWN }, { 0x990, PALETTE_TO_STRUCT_BROWN }, { 0x98D, PALETTE_TO_STRUCT_BROWN }, { 0x98F, PALETTE_TO_STRUCT_BROWN },
@ -289,7 +289,7 @@ static const PalSpriteID _bridge_sprite_table_7_3[] = {
{ 0x1113, PALETTE_TO_STRUCT_BROWN }, { 0x1115, PALETTE_TO_STRUCT_BROWN }, { 0x1112, PALETTE_TO_STRUCT_BROWN }, { 0x1114, PALETTE_TO_STRUCT_BROWN },
};
static const PalSpriteID _bridge_sprite_table_8_0[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_red_north[] = {
{ 0x9CD, PALETTE_TO_STRUCT_RED }, { 0x9D9, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9CE, PALETTE_TO_STRUCT_RED }, { 0x9DA, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9D3, PALETTE_TO_STRUCT_RED }, { 0x9D9, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -300,7 +300,7 @@ static const PalSpriteID _bridge_sprite_table_8_0[] = {
{ 0x1125, PALETTE_TO_STRUCT_RED }, { 0x9DA, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_8_1[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_red_south[] = {
{ 0x9CB, PALETTE_TO_STRUCT_RED }, { 0x9D7, PALETTE_TO_STRUCT_RED }, { 0x9DD, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
{ 0x9D0, PALETTE_TO_STRUCT_RED }, { 0x9DC, PALETTE_TO_STRUCT_RED }, { 0x9E0, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
{ 0x9D1, PALETTE_TO_STRUCT_RED }, { 0x9D7, PALETTE_TO_STRUCT_RED }, { 0x9DD, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
@ -311,7 +311,7 @@ static const PalSpriteID _bridge_sprite_table_8_1[] = {
{ 0x1127, PALETTE_TO_STRUCT_RED }, { 0x9DC, PALETTE_TO_STRUCT_RED }, { 0x9E0, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_8_2[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_red_middle[] = {
{ 0x9CC, PALETTE_TO_STRUCT_RED }, { 0x9D8, PALETTE_TO_STRUCT_RED }, { 0x9DE, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
{ 0x9CF, PALETTE_TO_STRUCT_RED }, { 0x9DB, PALETTE_TO_STRUCT_RED }, { 0x9DF, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
{ 0x9D2, PALETTE_TO_STRUCT_RED }, { 0x9D8, PALETTE_TO_STRUCT_RED }, { 0x9DE, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
@ -322,7 +322,7 @@ static const PalSpriteID _bridge_sprite_table_8_2[] = {
{ 0x1126, PALETTE_TO_STRUCT_RED }, { 0x9DB, PALETTE_TO_STRUCT_RED }, { 0x9DF, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_8_3[] = {
static const PalSpriteID _bridge_sprite_table_cantilever_red_heads[] = {
{ 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE },
{ 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE },
{ 0x98E, PALETTE_TO_STRUCT_RED }, { 0x990, PALETTE_TO_STRUCT_RED }, { 0x98D, PALETTE_TO_STRUCT_RED }, { 0x98F, PALETTE_TO_STRUCT_RED },
@ -399,7 +399,7 @@ static const PalSpriteID _bridge_sprite_table_archgirder_heads[] = {
MW( SPR_BTGEN_MGLV_RAMP_X_DOWN ), MW( SPR_BTGEN_MGLV_RAMP_Y_DOWN ), MW( SPR_BTGEN_MGLV_RAMP_X_UP ), MW( SPR_BTGEN_MGLV_RAMP_Y_UP ),
};
static const PalSpriteID _bridge_sprite_table_concrete_suspended_A[] = {
static const PalSpriteID _bridge_sprite_table_suspension_concrete_north[] = {
MC( SPR_BTSUS_RAIL_X_REAR_TILE_A ), MC( SPR_BTSUS_X_FRONT_TILE_A ), MC( SPR_BTSUS_X_PILLAR_TILE_A ), MN( 0x0 ),
MC( SPR_BTSUS_RAIL_Y_REAR_TILE_A ), MC( SPR_BTSUS_Y_FRONT_TILE_A ), MC( SPR_BTSUS_Y_PILLAR_TILE_A ), MN( 0x0 ),
MC( SPR_BTSUS_ROAD_X_REAR_TILE_A ), MC( SPR_BTSUS_X_FRONT_TILE_A ), MC( SPR_BTSUS_X_PILLAR_TILE_A ), MN( 0x0 ),
@ -410,7 +410,7 @@ static const PalSpriteID _bridge_sprite_table_concrete_suspended_A[] = {
MC( SPR_BTSUS_MGLV_Y_REAR_TILE_A ), MC( SPR_BTSUS_Y_FRONT_TILE_A ), MC( SPR_BTSUS_Y_PILLAR_TILE_A ), MN( 0x0 ),
};
static const PalSpriteID _bridge_sprite_table_concrete_suspended_B[] = {
static const PalSpriteID _bridge_sprite_table_suspension_concrete_south[] = {
MC( SPR_BTSUS_RAIL_X_REAR_TILE_B ), MC( SPR_BTSUS_X_FRONT_TILE_B ), MC( SPR_BTSUS_X_PILLAR_TILE_B ), MN( 0x0 ),
MC( SPR_BTSUS_RAIL_Y_REAR_TILE_B ), MC( SPR_BTSUS_Y_FRONT_TILE_B ), MC( SPR_BTSUS_Y_PILLAR_TILE_B ), MN( 0x0 ),
MC( SPR_BTSUS_ROAD_X_REAR_TILE_B ), MC( SPR_BTSUS_X_FRONT_TILE_B ), MC( SPR_BTSUS_X_PILLAR_TILE_B ), MN( 0x0 ),
@ -421,7 +421,7 @@ static const PalSpriteID _bridge_sprite_table_concrete_suspended_B[] = {
MC( SPR_BTSUS_MGLV_Y_REAR_TILE_B ), MC( SPR_BTSUS_Y_FRONT_TILE_B ), MC( SPR_BTSUS_Y_PILLAR_TILE_B ), MN( 0x0 ),
};
static const PalSpriteID _bridge_sprite_table_concrete_suspended_C[] = {
static const PalSpriteID _bridge_sprite_table_suspension_concrete_inner_north[] = {
MC( SPR_BTSUS_RAIL_X_REAR_TILE_C ), MC( SPR_BTSUS_X_FRONT_TILE_C ), MC( SPR_BTSUS_X_PILLAR_TILE_C ), MN( 0x0 ),
MC( SPR_BTSUS_RAIL_Y_REAR_TILE_C ), MC( SPR_BTSUS_Y_FRONT_TILE_C ), MC( SPR_BTSUS_Y_PILLAR_TILE_C ), MN( 0x0 ),
MC( SPR_BTSUS_ROAD_X_REAR_TILE_C ), MC( SPR_BTSUS_X_FRONT_TILE_C ), MC( SPR_BTSUS_X_PILLAR_TILE_C ), MN( 0x0 ),
@ -432,7 +432,7 @@ static const PalSpriteID _bridge_sprite_table_concrete_suspended_C[] = {
MC( SPR_BTSUS_MGLV_Y_REAR_TILE_C ), MC( SPR_BTSUS_Y_FRONT_TILE_C ), MC( SPR_BTSUS_Y_PILLAR_TILE_C ), MN( 0x0 ),
};
static const PalSpriteID _bridge_sprite_table_concrete_suspended_D[] = {
static const PalSpriteID _bridge_sprite_table_suspension_concrete_inner_south[] = {
MC( SPR_BTSUS_RAIL_X_REAR_TILE_D ), MC( SPR_BTSUS_X_FRONT_TILE_D ), MC( SPR_BTSUS_X_PILLAR_TILE_D ), MN( 0x0 ),
MC( SPR_BTSUS_RAIL_Y_REAR_TILE_D ), MC( SPR_BTSUS_Y_FRONT_TILE_D ), MC( SPR_BTSUS_Y_PILLAR_TILE_D ), MN( 0x0 ),
MC( SPR_BTSUS_ROAD_X_REAR_TILE_D ), MC( SPR_BTSUS_X_FRONT_TILE_D ), MC( SPR_BTSUS_X_PILLAR_TILE_D ), MN( 0x0 ),
@ -443,7 +443,7 @@ static const PalSpriteID _bridge_sprite_table_concrete_suspended_D[] = {
MC( SPR_BTSUS_MGLV_Y_REAR_TILE_D ), MC( SPR_BTSUS_Y_FRONT_TILE_D ), MC( SPR_BTSUS_Y_PILLAR_TILE_D ), MN( 0x0 ),
};
static const PalSpriteID _bridge_sprite_table_concrete_suspended_E[] = {
static const PalSpriteID _bridge_sprite_table_suspension_concrete_middle_odd[] = {
MC( SPR_BTSUS_RAIL_X_REAR_TILE_E ), MC( SPR_BTSUS_X_FRONT_TILE_E ), MC( SPR_BTSUS_X_PILLAR_TILE_E ), MN( 0x0 ),
MC( SPR_BTSUS_RAIL_Y_REAR_TILE_E ), MC( SPR_BTSUS_Y_FRONT_TILE_E ), MC( SPR_BTSUS_Y_PILLAR_TILE_E ), MN( 0x0 ),
MC( SPR_BTSUS_ROAD_X_REAR_TILE_E ), MC( SPR_BTSUS_X_FRONT_TILE_E ), MC( SPR_BTSUS_X_PILLAR_TILE_E ), MN( 0x0 ),
@ -454,7 +454,7 @@ static const PalSpriteID _bridge_sprite_table_concrete_suspended_E[] = {
MC( SPR_BTSUS_MGLV_Y_REAR_TILE_E ), MC( SPR_BTSUS_Y_FRONT_TILE_E ), MC( SPR_BTSUS_Y_PILLAR_TILE_E ), MN( 0x0 ),
};
static const PalSpriteID _bridge_sprite_table_concrete_suspended_F[] = {
static const PalSpriteID _bridge_sprite_table_suspension_concrete_middle_even[] = {
MC( SPR_BTSUS_RAIL_X_REAR_TILE_F ), MC( SPR_BTSUS_X_FRONT ), MN( 0x0 ), MN( 0x0 ),
MC( SPR_BTSUS_RAIL_Y_REAR_TILE_F ), MC( SPR_BTSUS_Y_FRONT ), MN( 0x0 ), MN( 0x0 ),
MC( SPR_BTSUS_ROAD_X_REAR_TILE_F ), MC( SPR_BTSUS_X_FRONT ), MN( 0x0 ), MN( 0x0 ),
@ -465,7 +465,7 @@ static const PalSpriteID _bridge_sprite_table_concrete_suspended_F[] = {
MC( SPR_BTSUS_MGLV_Y_REAR_TILE_F ), MC( SPR_BTSUS_Y_FRONT ), MN( 0x0 ), MN( 0x0 ),
};
static const PalSpriteID _bridge_sprite_table_concrete_suspended_heads[] = {
static const PalSpriteID _bridge_sprite_table_generic_concrete_heads[] = {
MN( SPR_BTGEN_RAIL_X_SLOPE_UP ), MN( SPR_BTGEN_RAIL_Y_SLOPE_UP ), MN( SPR_BTGEN_RAIL_X_SLOPE_DOWN ), MN( SPR_BTGEN_RAIL_Y_SLOPE_DOWN ),
MN( SPR_BTGEN_RAIL_RAMP_X_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_Y_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_X_UP ), MN( SPR_BTGEN_RAIL_RAMP_Y_UP ),
MC( SPR_BTGEN_ROAD_X_SLOPE_UP ), MC( SPR_BTGEN_ROAD_Y_SLOPE_UP ), MC( SPR_BTGEN_ROAD_X_SLOPE_DOWN ), MC( SPR_BTGEN_ROAD_Y_SLOPE_DOWN ),
@ -476,7 +476,7 @@ static const PalSpriteID _bridge_sprite_table_concrete_suspended_heads[] = {
MC( SPR_BTGEN_MGLV_RAMP_X_DOWN ), MC( SPR_BTGEN_MGLV_RAMP_Y_DOWN ), MC( SPR_BTGEN_MGLV_RAMP_X_UP ), MC( SPR_BTGEN_MGLV_RAMP_Y_UP ),
};
static const PalSpriteID _bridge_sprite_table_9_0[] = {
static const PalSpriteID _bridge_sprite_table_girder_middle[] = {
{ 0x9F9, PAL_NONE }, { 0x9FD, PAL_NONE }, { 0x9C9, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9FA, PAL_NONE }, { 0x9FE, PAL_NONE }, { 0x9CA, PAL_NONE }, { 0x0, PAL_NONE },
{ 0x9FB, PAL_NONE }, { 0x9FD, PAL_NONE }, { 0x9C9, PAL_NONE }, { 0x0, PAL_NONE },
@ -487,7 +487,7 @@ static const PalSpriteID _bridge_sprite_table_9_0[] = {
{ 0x1133, PAL_NONE }, { 0x9FE, PAL_NONE }, { 0x9CA, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_10_0[] = {
static const PalSpriteID _bridge_sprite_table_tubular_oxide_north[] = {
{ 0xA0B, PAL_NONE }, { 0xA01, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA0C, PAL_NONE }, { 0xA02, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA11, PAL_NONE }, { 0xA01, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -498,7 +498,7 @@ static const PalSpriteID _bridge_sprite_table_10_0[] = {
{ 0xA1E, PAL_NONE }, { 0xA02, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_10_1[] = {
static const PalSpriteID _bridge_sprite_table_tubular_oxide_south[] = {
{ 0xA09, PAL_NONE }, { 0x9FF, PAL_NONE }, { 0xA05, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA0E, PAL_NONE }, { 0xA04, PAL_NONE }, { 0xA08, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA0F, PAL_NONE }, { 0x9FF, PAL_NONE }, { 0xA05, PAL_NONE }, { 0x0, PAL_NONE },
@ -509,7 +509,7 @@ static const PalSpriteID _bridge_sprite_table_10_1[] = {
{ 0xA20, PAL_NONE }, { 0xA04, PAL_NONE }, { 0xA08, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_10_2[] = {
static const PalSpriteID _bridge_sprite_table_tubular_oxide_middle[] = {
{ 0xA0A, PAL_NONE }, { 0xA00, PAL_NONE }, { 0xA06, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA0D, PAL_NONE }, { 0xA03, PAL_NONE }, { 0xA07, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA10, PAL_NONE }, { 0xA00, PAL_NONE }, { 0xA06, PAL_NONE }, { 0x0, PAL_NONE },
@ -520,7 +520,7 @@ static const PalSpriteID _bridge_sprite_table_10_2[] = {
{ 0xA1F, PAL_NONE }, { 0xA03, PAL_NONE }, { 0xA07, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_11_0[] = {
static const PalSpriteID _bridge_sprite_table_tubular_yellow_north[] = {
{ 0xA0B, PALETTE_TO_STRUCT_YELLOW }, { 0xA01, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA0C, PALETTE_TO_STRUCT_YELLOW }, { 0xA02, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA11, PALETTE_TO_STRUCT_YELLOW }, { 0xA01, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -531,7 +531,7 @@ static const PalSpriteID _bridge_sprite_table_11_0[] = {
{ 0xA1E, PALETTE_TO_STRUCT_YELLOW }, { 0xA02, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_11_1[] = {
static const PalSpriteID _bridge_sprite_table_tubular_yellow_south[] = {
{ 0xA09, PALETTE_TO_STRUCT_YELLOW }, { 0x9FF, PALETTE_TO_STRUCT_YELLOW }, { 0xA05, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0xA0E, PALETTE_TO_STRUCT_YELLOW }, { 0xA04, PALETTE_TO_STRUCT_YELLOW }, { 0xA08, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0xA0F, PALETTE_TO_STRUCT_YELLOW }, { 0x9FF, PALETTE_TO_STRUCT_YELLOW }, { 0xA05, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
@ -542,7 +542,7 @@ static const PalSpriteID _bridge_sprite_table_11_1[] = {
{ 0xA20, PALETTE_TO_STRUCT_YELLOW }, { 0xA04, PALETTE_TO_STRUCT_YELLOW }, { 0xA08, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_11_2[] = {
static const PalSpriteID _bridge_sprite_table_tubular_yellow_middle[] = {
{ 0xA0A, PALETTE_TO_STRUCT_YELLOW }, { 0xA00, PALETTE_TO_STRUCT_YELLOW }, { 0xA06, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0xA0D, PALETTE_TO_STRUCT_YELLOW }, { 0xA03, PALETTE_TO_STRUCT_YELLOW }, { 0xA07, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
{ 0xA10, PALETTE_TO_STRUCT_YELLOW }, { 0xA00, PALETTE_TO_STRUCT_YELLOW }, { 0xA06, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
@ -553,7 +553,7 @@ static const PalSpriteID _bridge_sprite_table_11_2[] = {
{ 0xA1F, PALETTE_TO_STRUCT_YELLOW }, { 0xA03, PALETTE_TO_STRUCT_YELLOW }, { 0xA07, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_12_0[] = {
static const PalSpriteID _bridge_sprite_table_tubular_silicon_north[] = {
{ 0xA0B, PALETTE_TO_STRUCT_CONCRETE }, { 0xA01, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA0C, PALETTE_TO_STRUCT_CONCRETE }, { 0xA02, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
{ 0xA11, PALETTE_TO_STRUCT_CONCRETE }, { 0xA01, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
@ -564,7 +564,7 @@ static const PalSpriteID _bridge_sprite_table_12_0[] = {
{ 0xA1E, PALETTE_TO_STRUCT_CONCRETE }, { 0xA02, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_12_1[] = {
static const PalSpriteID _bridge_sprite_table_tubular_silicon_south[] = {
{ 0xA09, PALETTE_TO_STRUCT_CONCRETE }, { 0x9FF, PALETTE_TO_STRUCT_CONCRETE }, { 0xA05, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE },
{ 0xA0E, PALETTE_TO_STRUCT_CONCRETE }, { 0xA04, PALETTE_TO_STRUCT_CONCRETE }, { 0xA08, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE },
{ 0xA0F, PALETTE_TO_STRUCT_CONCRETE }, { 0x9FF, PALETTE_TO_STRUCT_CONCRETE }, { 0xA05, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE },
@ -575,7 +575,7 @@ static const PalSpriteID _bridge_sprite_table_12_1[] = {
{ 0xA20, PALETTE_TO_STRUCT_CONCRETE }, { 0xA04, PALETTE_TO_STRUCT_CONCRETE }, { 0xA08, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE },
};
static const PalSpriteID _bridge_sprite_table_12_2[] = {
static const PalSpriteID _bridge_sprite_table_tubular_silicon_middle[] = {
{ 0xA0A, PALETTE_TO_STRUCT_CONCRETE }, { 0xA00, PALETTE_TO_STRUCT_CONCRETE }, { 0xA06, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE },
{ 0xA0D, PALETTE_TO_STRUCT_CONCRETE }, { 0xA03, PALETTE_TO_STRUCT_CONCRETE }, { 0xA07, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE },
{ 0xA10, PALETTE_TO_STRUCT_CONCRETE }, { 0xA00, PALETTE_TO_STRUCT_CONCRETE }, { 0xA06, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE },
@ -596,64 +596,64 @@ static const std::span<const PalSpriteID> _bridge_sprite_table_archgirder[] = {
_bridge_sprite_table_archgirder_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_4[] = {
_bridge_sprite_table_4_0,
_bridge_sprite_table_4_1,
_bridge_sprite_table_4_2,
_bridge_sprite_table_4_3,
_bridge_sprite_table_4_4,
_bridge_sprite_table_4_5,
_bridge_sprite_table_4_6,
static const std::span<const PalSpriteID> _bridge_sprite_table_suspension_oxide[] = {
_bridge_sprite_table_suspension_oxide_north,
_bridge_sprite_table_suspension_oxide_south,
_bridge_sprite_table_suspension_oxide_inner_north,
_bridge_sprite_table_suspension_oxide_inner_south,
_bridge_sprite_table_suspension_oxide_middle_odd,
_bridge_sprite_table_suspension_middle_even,
_bridge_sprite_table_generic_oxide_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_5[] = {
_bridge_sprite_table_5_0,
_bridge_sprite_table_5_1,
_bridge_sprite_table_5_2,
_bridge_sprite_table_5_3,
_bridge_sprite_table_5_4,
_bridge_sprite_table_5_5,
_bridge_sprite_table_5_6,
static const std::span<const PalSpriteID> _bridge_sprite_table_suspension_yellow[] = {
_bridge_sprite_table_suspension_yellow_north,
_bridge_sprite_table_suspension_yellow_south,
_bridge_sprite_table_suspension_yellow_inner_north,
_bridge_sprite_table_suspension_yellow_inner_south,
_bridge_sprite_table_suspension_yellow_middle_odd,
_bridge_sprite_table_suspension_yellow_middle_even,
_bridge_sprite_table_generic_yellow_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_concrete_suspended[] = {
_bridge_sprite_table_concrete_suspended_A,
_bridge_sprite_table_concrete_suspended_B,
_bridge_sprite_table_concrete_suspended_C,
_bridge_sprite_table_concrete_suspended_D,
_bridge_sprite_table_concrete_suspended_E,
_bridge_sprite_table_concrete_suspended_F,
_bridge_sprite_table_concrete_suspended_heads,
static const std::span<const PalSpriteID> _bridge_sprite_table_suspension_concrete[] = {
_bridge_sprite_table_suspension_concrete_north,
_bridge_sprite_table_suspension_concrete_south,
_bridge_sprite_table_suspension_concrete_inner_north,
_bridge_sprite_table_suspension_concrete_inner_south,
_bridge_sprite_table_suspension_concrete_middle_odd,
_bridge_sprite_table_suspension_concrete_middle_even,
_bridge_sprite_table_generic_concrete_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_6[] = {
_bridge_sprite_table_6_0,
_bridge_sprite_table_6_1,
_bridge_sprite_table_6_2,
_bridge_sprite_table_6_2,
_bridge_sprite_table_6_2,
_bridge_sprite_table_6_2,
_bridge_sprite_table_6_3,
static const std::span<const PalSpriteID> _bridge_sprite_table_cantilever_oxide[] = {
_bridge_sprite_table_cantilever_oxide_north,
_bridge_sprite_table_cantilever_oxide_south,
_bridge_sprite_table_cantilever_oxide_middle,
_bridge_sprite_table_cantilever_oxide_middle,
_bridge_sprite_table_cantilever_oxide_middle,
_bridge_sprite_table_cantilever_oxide_middle,
_bridge_sprite_table_cantilever_oxide_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_7[] = {
_bridge_sprite_table_7_0,
_bridge_sprite_table_7_1,
_bridge_sprite_table_7_2,
_bridge_sprite_table_7_2,
_bridge_sprite_table_7_2,
_bridge_sprite_table_7_2,
_bridge_sprite_table_7_3,
static const std::span<const PalSpriteID> _bridge_sprite_table_cantilever_brown[] = {
_bridge_sprite_table_cantilever_brown_north,
_bridge_sprite_table_cantilever_brown_south,
_bridge_sprite_table_cantilever_brown_middle,
_bridge_sprite_table_cantilever_brown_middle,
_bridge_sprite_table_cantilever_brown_middle,
_bridge_sprite_table_cantilever_brown_middle,
_bridge_sprite_table_cantilever_brown_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_8[] = {
_bridge_sprite_table_8_0,
_bridge_sprite_table_8_1,
_bridge_sprite_table_8_2,
_bridge_sprite_table_8_2,
_bridge_sprite_table_8_2,
_bridge_sprite_table_8_2,
_bridge_sprite_table_8_3,
static const std::span<const PalSpriteID> _bridge_sprite_table_cantilever_red[] = {
_bridge_sprite_table_cantilever_red_north,
_bridge_sprite_table_cantilever_red_south,
_bridge_sprite_table_cantilever_red_middle,
_bridge_sprite_table_cantilever_red_middle,
_bridge_sprite_table_cantilever_red_middle,
_bridge_sprite_table_cantilever_red_middle,
_bridge_sprite_table_cantilever_red_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_wood[] = {
@ -676,60 +676,60 @@ static const std::span<const PalSpriteID> _bridge_sprite_table_concrete[] = {
_bridge_sprite_table_concrete_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_9[] = {
_bridge_sprite_table_9_0,
_bridge_sprite_table_9_0,
_bridge_sprite_table_9_0,
_bridge_sprite_table_9_0,
_bridge_sprite_table_9_0,
_bridge_sprite_table_9_0,
_bridge_sprite_table_4_6,
static const std::span<const PalSpriteID> _bridge_sprite_table_girder[] = {
_bridge_sprite_table_girder_middle,
_bridge_sprite_table_girder_middle,
_bridge_sprite_table_girder_middle,
_bridge_sprite_table_girder_middle,
_bridge_sprite_table_girder_middle,
_bridge_sprite_table_girder_middle,
_bridge_sprite_table_generic_oxide_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_10[] = {
_bridge_sprite_table_10_0,
_bridge_sprite_table_10_1,
_bridge_sprite_table_10_2,
_bridge_sprite_table_10_2,
_bridge_sprite_table_10_2,
_bridge_sprite_table_10_2,
_bridge_sprite_table_4_6,
static const std::span<const PalSpriteID> _bridge_sprite_table_tubular_oxide[] = {
_bridge_sprite_table_tubular_oxide_north,
_bridge_sprite_table_tubular_oxide_south,
_bridge_sprite_table_tubular_oxide_middle,
_bridge_sprite_table_tubular_oxide_middle,
_bridge_sprite_table_tubular_oxide_middle,
_bridge_sprite_table_tubular_oxide_middle,
_bridge_sprite_table_generic_oxide_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_11[] = {
_bridge_sprite_table_11_0,
_bridge_sprite_table_11_1,
_bridge_sprite_table_11_2,
_bridge_sprite_table_11_2,
_bridge_sprite_table_11_2,
_bridge_sprite_table_11_2,
_bridge_sprite_table_5_6,
static const std::span<const PalSpriteID> _bridge_sprite_table_tubular_yellow[] = {
_bridge_sprite_table_tubular_yellow_north,
_bridge_sprite_table_tubular_yellow_south,
_bridge_sprite_table_tubular_yellow_middle,
_bridge_sprite_table_tubular_yellow_middle,
_bridge_sprite_table_tubular_yellow_middle,
_bridge_sprite_table_tubular_yellow_middle,
_bridge_sprite_table_generic_yellow_heads,
};
static const std::span<const PalSpriteID> _bridge_sprite_table_12[] = {
_bridge_sprite_table_12_0,
_bridge_sprite_table_12_1,
_bridge_sprite_table_12_2,
_bridge_sprite_table_12_2,
_bridge_sprite_table_12_2,
_bridge_sprite_table_12_2,
_bridge_sprite_table_concrete_suspended_heads,
static const std::span<const PalSpriteID> _bridge_sprite_table_tubular_silicon[] = {
_bridge_sprite_table_tubular_silicon_north,
_bridge_sprite_table_tubular_silicon_south,
_bridge_sprite_table_tubular_silicon_middle,
_bridge_sprite_table_tubular_silicon_middle,
_bridge_sprite_table_tubular_silicon_middle,
_bridge_sprite_table_tubular_silicon_middle,
_bridge_sprite_table_generic_concrete_heads,
};
static const std::span<const std::span<const PalSpriteID>> _bridge_sprite_table[MAX_BRIDGES] = {
_bridge_sprite_table_wood,
_bridge_sprite_table_concrete,
_bridge_sprite_table_archgirder,
_bridge_sprite_table_concrete_suspended,
_bridge_sprite_table_4,
_bridge_sprite_table_5,
_bridge_sprite_table_6,
_bridge_sprite_table_7,
_bridge_sprite_table_8,
_bridge_sprite_table_9,
_bridge_sprite_table_10,
_bridge_sprite_table_11,
_bridge_sprite_table_12
_bridge_sprite_table_suspension_concrete,
_bridge_sprite_table_suspension_oxide,
_bridge_sprite_table_suspension_yellow,
_bridge_sprite_table_cantilever_oxide,
_bridge_sprite_table_cantilever_brown,
_bridge_sprite_table_cantilever_red,
_bridge_sprite_table_girder,
_bridge_sprite_table_tubular_oxide,
_bridge_sprite_table_tubular_yellow,
_bridge_sprite_table_tubular_silicon,
};
/**

View File

@ -26,6 +26,7 @@ static const SettingVariant _gui_settings_table[] = {
};
[templates]
SDTC_BOOL = SDTC_BOOL( $var, SettingFlags({$flags}), $def, $str, $strhelp, $strval, $pre_cb, $post_cb, $str_cb, $help_cb, $val_cb, $def_cb, $from, $to, $cat, $extra, $startup),
SDTC_LIST = SDTC_LIST( $var, $type, SettingFlags({$flags}), $def, $from, $to, $cat, $extra, $startup),
SDTC_OMANY = SDTC_OMANY( $var, $type, SettingFlags({$flags}), $def, $max, $full, $str, $strhelp, $strval, $pre_cb, $post_cb, $str_cb, $help_cb, $val_cb, $def_cb, $from, $to, $cat, $extra, $startup),
SDTC_VAR = SDTC_VAR( $var, $type, SettingFlags({$flags}), $def, $min, $max, $interval, $str, $strhelp, $strval, $pre_cb, $post_cb, $str_cb, $help_cb, $val_cb, $def_cb, $range_cb, $from, $to, $cat, $extra, $startup),
@ -348,7 +349,7 @@ post_cb = InvalidateCompanyLiveryWindow
[SDTC_VAR]
var = gui.starting_colour
type = SLE_UINT8
type = SLE_UINT32
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown
def = COLOUR_END
min = 0
@ -359,7 +360,7 @@ strval = STR_COLOUR_DARK_BLUE
[SDTC_VAR]
var = gui.starting_colour_secondary
type = SLE_UINT8
type = SLE_UINT32
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync, SettingFlag::GuiDropdown
def = COLOUR_END
min = 0
@ -368,6 +369,13 @@ str = STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_SECONDARY
strhelp = STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_SECONDARY_HELPTEXT
strval = STR_COLOUR_SECONDARY_DARK_BLUE
[SDTC_LIST]
var = gui.preset_colours
type = SLE_UINT32
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync
def = """"
cat = SC_BASIC
[SDTC_BOOL]
var = gui.auto_remove_signals
flags = SettingFlag::NotInSave, SettingFlag::NoNetworkSync

View File

@ -621,7 +621,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
if (!IsInsideMM(size, 1, 8 + 1)) return;
_terraform_size = size;
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
this->SetDirty();
break;
}

View File

@ -117,7 +117,7 @@ public:
static void PopupMainToolbarMenu(Window *w, WidgetID widget, DropDownList &&list, int def)
{
ShowDropDownList(w, std::move(list), def, widget, 0, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
}
/**
@ -204,7 +204,7 @@ static CallBackFunction ToolbarPauseClick(Window *)
if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
if (Command<CMD_PAUSE>::Post(PauseMode::Normal, _pause_mode.None())) {
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
SndConfirmBeep();
}
return CBF_NONE;
}
@ -220,7 +220,7 @@ static CallBackFunction ToolbarFastForwardClick(Window *)
ChangeGameSpeed(_game_speed == 100);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -291,7 +291,7 @@ static CallBackFunction ToolbarOptionsClick(Window *w)
list.push_back(MakeDropDownListCheckedItem(IsTransparencySet(TO_SIGNS), STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS));
ShowDropDownList(w, std::move(list), 0, WID_TN_SETTINGS, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -684,7 +684,7 @@ static CallBackFunction ToolbarGraphsClick(Window *w)
if (_toolbar_mode != TB_NORMAL) AddDropDownLeagueTableOptions(list);
ShowDropDownList(w, std::move(list), GRMN_OPERATING_PROFIT_GRAPH, WID_TN_GRAPHS, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -697,7 +697,7 @@ static CallBackFunction ToolbarLeagueClick(Window *w)
int selected = list[0]->result;
ShowDropDownList(w, std::move(list), selected, WID_TN_LEAGUE, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -857,7 +857,7 @@ static CallBackFunction ToolbarZoomInClick(Window *w)
{
if (DoZoomInOutWindow(ZOOM_IN, GetMainWindow())) {
w->HandleButtonClick((_game_mode == GM_EDITOR) ? (WidgetID)WID_TE_ZOOM_IN : (WidgetID)WID_TN_ZOOM_IN);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
}
return CBF_NONE;
}
@ -868,7 +868,7 @@ static CallBackFunction ToolbarZoomOutClick(Window *w)
{
if (DoZoomInOutWindow(ZOOM_OUT, GetMainWindow())) {
w->HandleButtonClick((_game_mode == GM_EDITOR) ? (WidgetID)WID_TE_ZOOM_OUT : (WidgetID)WID_TN_ZOOM_OUT);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
}
return CBF_NONE;
}
@ -878,7 +878,7 @@ static CallBackFunction ToolbarZoomOutClick(Window *w)
static CallBackFunction ToolbarBuildRailClick(Window *w)
{
ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -900,7 +900,7 @@ static CallBackFunction MenuClickBuildRail(int index)
static CallBackFunction ToolbarBuildRoadClick(Window *w)
{
ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TN_ROADS, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -922,7 +922,7 @@ static CallBackFunction MenuClickBuildRoad(int index)
static CallBackFunction ToolbarBuildTramClick(Window *w)
{
ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TN_TRAMS, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -946,7 +946,7 @@ static CallBackFunction ToolbarBuildWaterClick(Window *w)
DropDownList list;
list.push_back(MakeDropDownListIconItem(SPR_IMG_BUILD_CANAL, PAL_NONE, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 0));
ShowDropDownList(w, std::move(list), 0, WID_TN_WATER, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -968,7 +968,7 @@ static CallBackFunction ToolbarBuildAirClick(Window *w)
DropDownList list;
list.push_back(MakeDropDownListIconItem(SPR_IMG_AIRPORT, PAL_NONE, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 0));
ShowDropDownList(w, std::move(list), 0, WID_TN_AIR, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -992,7 +992,7 @@ static CallBackFunction ToolbarForestClick(Window *w)
list.push_back(MakeDropDownListIconItem(SPR_IMG_PLANTTREES, PAL_NONE, STR_LANDSCAPING_MENU_PLANT_TREES, 1));
list.push_back(MakeDropDownListIconItem(SPR_IMG_SIGN, PAL_NONE, STR_LANDSCAPING_MENU_PLACE_SIGN, 2));
ShowDropDownList(w, std::move(list), 0, WID_TN_LANDSCAPE, 100, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -1188,7 +1188,7 @@ static CallBackFunction ToolbarSwitchClick(Window *w)
w->ReInit();
w->SetWidgetLoweredState(_game_mode == GM_EDITOR ? (WidgetID)WID_TE_SWITCH_BAR : (WidgetID)WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -1232,7 +1232,7 @@ static CallBackFunction ToolbarScenDateForward(Window *w)
static CallBackFunction ToolbarScenGenLand(Window *w)
{
w->HandleButtonClick(WID_TE_LAND_GENERATE);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
ShowEditorTerraformToolbar();
return CBF_NONE;
@ -1256,7 +1256,7 @@ static CallBackFunction ToolbarScenGenTown(int index)
static CallBackFunction ToolbarScenGenIndustry(Window *w)
{
w->HandleButtonClick(WID_TE_INDUSTRY);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
ShowBuildIndustryWindow();
return CBF_NONE;
}
@ -1264,7 +1264,7 @@ static CallBackFunction ToolbarScenGenIndustry(Window *w)
static CallBackFunction ToolbarScenBuildRoadClick(Window *w)
{
ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TE_ROADS, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -1284,7 +1284,7 @@ static CallBackFunction ToolbarScenBuildRoad(int index)
static CallBackFunction ToolbarScenBuildTramClick(Window *w)
{
ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TE_TRAMS, 140, true);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return CBF_NONE;
}
@ -1304,7 +1304,7 @@ static CallBackFunction ToolbarScenBuildTram(int index)
static CallBackFunction ToolbarScenBuildDocks(Window *w)
{
w->HandleButtonClick(WID_TE_WATER);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
ShowBuildDocksScenToolbar();
return CBF_NONE;
}
@ -1312,7 +1312,7 @@ static CallBackFunction ToolbarScenBuildDocks(Window *w)
static CallBackFunction ToolbarScenPlantTrees(Window *w)
{
w->HandleButtonClick(WID_TE_TREES);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
ShowBuildTreesToolbar();
return CBF_NONE;
}
@ -1320,7 +1320,7 @@ static CallBackFunction ToolbarScenPlantTrees(Window *w)
static CallBackFunction ToolbarScenPlaceSign(Window *w)
{
w->HandleButtonClick(WID_TE_SIGNS);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
return SelectSignTool();
}
@ -2407,7 +2407,7 @@ struct ScenarioEditorToolbarWindow : Window {
{
CallBackFunction cbf = _scen_toolbar_dropdown_procs[widget](index);
if (cbf != CBF_NONE) _last_started_action = cbf;
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
}
EventState OnHotkey(int hotkey) override

View File

@ -1739,7 +1739,7 @@ struct BuildHouseWindow : public PickerWindow {
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);
SndClickBeep();
this->SetDirty();
break;

View File

@ -80,7 +80,7 @@ public:
} else {
/* toggle the bit of the transparencies variable and play a sound */
ToggleTransparency((TransparencyOption)(widget - WID_TT_BEGIN));
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
MarkWholeScreenDirty();
}
} else if (widget == WID_TT_BUTTONS) {
@ -94,7 +94,7 @@ public:
if (i == WID_TT_TEXT|| i == WID_TT_END) return;
ToggleInvisibility((TransparencyOption)(i - WID_TT_BEGIN));
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
/* Redraw whole screen only if transparency is set */
if (IsTransparencySet((TransparencyOption)(i - WID_TT_BEGIN))) {

View File

@ -102,7 +102,7 @@ class BuildTreesWindow : public Window
if (this->tree_to_plant >= 0) {
/* Activate placement */
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
SndConfirmBeep();
SetObjectToPlace(SPR_CURSOR_TREE, PAL_NONE, HT_RECT | HT_DIAGONAL, this->window_class, this->window_number);
this->tree_to_plant = current_tree; // SetObjectToPlace may call ResetObjectToPlace which may reset tree_to_plant to -1
} else {
@ -180,7 +180,7 @@ public:
break;
case WID_BT_MANY_RANDOM: // place trees randomly over the landscape
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
SndConfirmBeep();
PlaceTreesRandomly();
MarkWholeScreenDirty();
break;

View File

@ -2045,7 +2045,6 @@ LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_
const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, uint8_t livery_setting)
{
const Company *c = Company::Get(company);
LiveryScheme scheme = LS_DEFAULT;
if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) {
if (v != nullptr) {
@ -2063,11 +2062,12 @@ const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID
* whether any _other_ liveries are in use. */
if (c->livery[LS_DEFAULT].in_use != 0) {
/* Determine the livery scheme to use */
scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
LiveryScheme scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
if (c->livery[scheme].in_use != 0) return &c->livery[scheme];
}
}
return &c->livery[scheme];
return &c->livery[LS_DEFAULT];
}
@ -2080,6 +2080,15 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng
const Engine *e = Engine::Get(engine_type);
/* Default livery for spectators */
static const Livery default_livery = {
0, COLOUR_GREY, COLOUR_GREY,
PALETTE_RECOLOUR_START, SPR_2CCMAP_BASE, SPR_2CCMAP_BASE,
};
bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
const Livery *livery = Company::IsValidID(company) ? GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries) : &default_livery;
/* Check if we should use the colour map callback */
if (e->info.callback_mask.Test(VehicleCallbackMask::ColourRemap)) {
uint16_t callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
@ -2090,6 +2099,15 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng
/* If bit 14 is set, then the company colours are applied to the
* map else it's returned as-is. */
if (!HasBit(callback, 14)) {
/* Test if this is the standard remap/reversed remap */
if (map == PALETTE_RECOLOUR_START + (livery->colour1 & 0xF)) {
map = livery->cached_pal_1cc;
} else if (map == SPR_2CCMAP_BASE + (livery->colour1 & 0xF) + (livery->colour2 & 0xF) * 16) {
map = livery->cached_pal_2cc;
} else if (map == SPR_2CCMAP_BASE + (livery->colour2 & 0xF) + (livery->colour1 & 0xF) * 16) {
map = livery->cached_pal_2cr;
}
/* Update cache */
if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;
return map;
@ -2097,17 +2115,19 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng
}
}
bool twocc = e->info.misc_flags.Test(EngineMiscFlag::Uses2CC);
if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
/* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
if (!Company::IsValidID(company)) return map;
const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
if (map == PALETTE_RECOLOUR_START || map == SPR_2CCMAP_BASE) {
/* Use cached palette when using default remaps */
map = twocc ? livery->cached_pal_2cc : livery->cached_pal_1cc;
} else {
/* Add offsets for custom NewGRF remaps */
map += livery->colour1;
if (twocc) map += livery->colour2 * 16;
}
/* Update cache */
if (v != nullptr) const_cast<Vehicle *>(v)->colourmap = map;

View File

@ -1290,7 +1290,7 @@ void OpenGLBackend::RenderOglSprite(const OpenGLSprite *gl_sprite, PaletteID pal
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, OpenGLSprite::pal_pbo);
_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
_glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, 256, GetNonSprite(GB(pal, 0, PALETTE_WIDTH), SpriteType::Recolour) + 1);
_glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, 256, GetRecolourSprite(GB(pal, 0, PALETTE_WIDTH))->GetPaletteRemap());
_glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RED, GL_UNSIGNED_BYTE, nullptr);
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

View File

@ -300,8 +300,6 @@ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, Fra
if (flags.Test(FrameFlag::Transparent)) {
GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR);
} else {
assert(colour < COLOUR_END);
const PixelColour dark = GetColourGradient(colour, SHADE_DARK);
const PixelColour medium_dark = GetColourGradient(colour, SHADE_LIGHT);
const PixelColour medium_light = GetColourGradient(colour, SHADE_LIGHTER);

View File

@ -75,6 +75,25 @@ enum CompanyFinancesWidgets : WidgetID {
};
/** Widgets of the #SelectCustomColourWindow class. */
enum SelectCustomColourWidgets {
WID_SCC_CAPTION, ///< Caption of window.
WID_SCC_HUE,
WID_SCC_SCROLLBAR_HUE, ///< Hue scrollbar.
WID_SCC_SAT,
WID_SCC_SCROLLBAR_SAT, ///< Saturation scrollbar.
WID_SCC_VAL,
WID_SCC_SCROLLBAR_VAL, ///< Value scrollbar.
WID_SCC_CON,
WID_SCC_SCROLLBAR_CON, ///< Contrast scrollbar.
WID_SCC_OUTPUT,
WID_SCC_DEFAULT, ///< First default colour.
WID_SCC_DEFAULT_LAST = WID_SCC_DEFAULT + COLOUR_END - 1,
WID_SCC_PRESETS, ///< First preset colour.
WID_SCC_PRESETS_LAST = WID_SCC_PRESETS + COLOUR_END - 1,
};
/** Widgets of the #SelectCompanyLiveryWindow class. */
enum SelectCompanyLiveryWidgets : WidgetID {
WID_SCL_CAPTION, ///< Caption of window.

View File

@ -231,6 +231,12 @@ enum WindowClass : uint16_t {
*/
WC_COMPANY_COLOUR,
/**
* Custom colour selection; %Window numbers:
* - #CompanyID = #SelectCustomColourWidgets
*/
WC_CUSTOM_COLOUR,
/**
* Alter company face window; %Window numbers:
* - #CompanyID = #SelectCompanyManagerFaceWidgets