mirror of https://github.com/OpenTTD/OpenTTD
Change: Display more useful information in sprite aligner than sprite ID.
Sprite IDs are not useful information given they change don't refer to anything outside the loaded game. Instead, include the filename and nfo line at minimum, and include action A or action 5 sprite replacement information if applicable.pull/12439/head
parent
fbdf26800b
commit
b8df11ca68
|
@ -254,6 +254,7 @@ add_files(
|
|||
music_gui.cpp
|
||||
newgrf.cpp
|
||||
newgrf.h
|
||||
newgrf_act5.h
|
||||
newgrf_airport.cpp
|
||||
newgrf_airport.h
|
||||
newgrf_airporttiles.cpp
|
||||
|
|
|
@ -3488,7 +3488,9 @@ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_ROAD_TYPE :Road type
|
|||
STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal)
|
||||
|
||||
# Sprite aligner window
|
||||
STR_SPRITE_ALIGNER_CAPTION :{WHITE}Aligning sprite {COMMA} ({RAW_STRING})
|
||||
STR_SPRITE_ALIGNER_CAPTION_NO_ACTION :{WHITE}Aligning sprite: ({RAW_STRING}:{NUM})
|
||||
STR_SPRITE_ALIGNER_CAPTION_ACTIONA :{WHITE}Aligning sprite: Action 0xA, {COMMA} ({RAW_STRING}:{NUM})
|
||||
STR_SPRITE_ALIGNER_CAPTION_ACTION5 :{WHITE}Aligning sprite: Action 0x5, type {HEX}, {COMMA} ({RAW_STRING}:{NUM})
|
||||
STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Next sprite
|
||||
STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Proceed to the next normal sprite, skipping any pseudo/recolour/font sprites and wrapping around from the last sprite to the first
|
||||
STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Go to sprite
|
||||
|
@ -3497,6 +3499,7 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Previous
|
|||
STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Proceed to the previous normal sprite, skipping any pseudo/recolour/font sprites and wrapping around from the first sprite to the last
|
||||
STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representation of the currently selected sprite. The alignment is ignored when drawing this sprite
|
||||
STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Move the sprite around, changing the X and Y offsets. Ctrl+Click to move the sprite eight units at a time
|
||||
STR_SPRITE_ALIGNER_SPRITE :{RAW_STRING}:{NUM}
|
||||
|
||||
###length 2
|
||||
STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Offset centred
|
||||
|
@ -5833,6 +5836,7 @@ STR_JUST_DATE_ISO :{DATE_ISO}
|
|||
STR_JUST_STRING :{STRING}
|
||||
STR_JUST_STRING1 :{STRING1}
|
||||
STR_JUST_STRING2 :{STRING2}
|
||||
STR_JUST_STRING4 :{STRING4}
|
||||
STR_JUST_STRING_STRING :{STRING}{STRING}
|
||||
STR_JUST_RAW_STRING :{RAW_STRING}
|
||||
STR_JUST_BIG_RAW_STRING :{BIG_FONT}{RAW_STRING}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "newgrf_station.h"
|
||||
#include "industrytype.h"
|
||||
#include "industry_map.h"
|
||||
#include "newgrf_act5.h"
|
||||
#include "newgrf_canal.h"
|
||||
#include "newgrf_townname.h"
|
||||
#include "newgrf_industries.h"
|
||||
|
@ -6369,7 +6370,7 @@ static void FeatureNewName(ByteReader *buf)
|
|||
* @param name Used for error warnings.
|
||||
* @return The number of sprites that is going to be skipped.
|
||||
*/
|
||||
static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, const char *name)
|
||||
static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, const std::string_view name)
|
||||
{
|
||||
|
||||
if (offset >= max_sprites) {
|
||||
|
@ -6390,23 +6391,8 @@ static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_spr
|
|||
}
|
||||
|
||||
|
||||
/** The type of action 5 type. */
|
||||
enum Action5BlockType {
|
||||
A5BLOCK_FIXED, ///< Only allow replacing a whole block of sprites. (TTDP compatible)
|
||||
A5BLOCK_ALLOW_OFFSET, ///< Allow replacing any subset by specifiing an offset.
|
||||
A5BLOCK_INVALID, ///< unknown/not-implemented type
|
||||
};
|
||||
/** Information about a single action 5 type. */
|
||||
struct Action5Type {
|
||||
Action5BlockType block_type; ///< How is this Action5 type processed?
|
||||
SpriteID sprite_base; ///< Load the sprites starting from this sprite.
|
||||
uint16_t min_sprites; ///< If the Action5 contains less sprites, the whole block will be ignored.
|
||||
uint16_t max_sprites; ///< If the Action5 contains more sprites, only the first max_sprites sprites will be used.
|
||||
const char *name; ///< Name for error messages.
|
||||
};
|
||||
|
||||
/** The information about action 5 types. */
|
||||
static const Action5Type _action5_types[] = {
|
||||
static constexpr auto _action5_types = std::to_array<Action5Type>({
|
||||
/* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */
|
||||
/* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" },
|
||||
/* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" },
|
||||
|
@ -6433,7 +6419,16 @@ static const Action5Type _action5_types[] = {
|
|||
/* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, SPR_AIRPORT_PREVIEW_COUNT, "Airport preview graphics" },
|
||||
/* 0x17 */ { A5BLOCK_ALLOW_OFFSET, SPR_RAILTYPE_TUNNEL_BASE, 1, RAILTYPE_TUNNEL_BASE_COUNT, "Railtype tunnel base" },
|
||||
/* 0x18 */ { A5BLOCK_ALLOW_OFFSET, SPR_PALETTE_BASE, 1, PALETTE_SPRITE_COUNT, "Palette" },
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Get list of all action 5 types
|
||||
* @return Read-only span of action 5 type information.
|
||||
*/
|
||||
std::span<const Action5Type> GetAction5Types()
|
||||
{
|
||||
return _action5_types;
|
||||
}
|
||||
|
||||
/* Action 0x05 */
|
||||
static void GraphicsNew(ByteReader *buf)
|
||||
|
@ -6468,7 +6463,7 @@ static void GraphicsNew(ByteReader *buf)
|
|||
}
|
||||
|
||||
/* Supported type? */
|
||||
if ((type >= lengthof(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
|
||||
if ((type >= std::size(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
|
||||
GrfMsg(2, "GraphicsNew: Custom graphics (type 0x{:02X}) sprite block of length {} (unimplemented, ignoring)", type, num);
|
||||
_cur.skip_sprites = num;
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file newgrf_act5.h Information about NewGRF Action 5. */
|
||||
|
||||
#ifndef NEWGRF_ACT5_H
|
||||
#define NEWGRF_ACT5_H
|
||||
|
||||
/** The type of action 5 type. */
|
||||
enum Action5BlockType {
|
||||
A5BLOCK_FIXED, ///< Only allow replacing a whole block of sprites. (TTDP compatible)
|
||||
A5BLOCK_ALLOW_OFFSET, ///< Allow replacing any subset by specifiing an offset.
|
||||
A5BLOCK_INVALID, ///< unknown/not-implemented type
|
||||
};
|
||||
|
||||
/** Information about a single action 5 type. */
|
||||
struct Action5Type {
|
||||
Action5BlockType block_type; ///< How is this Action5 type processed?
|
||||
SpriteID sprite_base; ///< Load the sprites starting from this sprite.
|
||||
uint16_t min_sprites; ///< If the Action5 contains less sprites, the whole block will be ignored.
|
||||
uint16_t max_sprites; ///< If the Action5 contains more sprites, only the first max_sprites sprites will be used.
|
||||
const std::string_view name; ///< Name for error messages.
|
||||
};
|
||||
|
||||
std::span<const Action5Type> GetAction5Types();
|
||||
|
||||
#endif /* NEWGRF_ACT5_H */
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
#include "core/backup_type.hpp"
|
||||
#include "core/geometry_func.hpp"
|
||||
#include "window_gui.h"
|
||||
#include "window_func.h"
|
||||
#include "random_access_file_type.h"
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include "train.h"
|
||||
#include "roadveh.h"
|
||||
|
||||
#include "newgrf_act5.h"
|
||||
#include "newgrf_airport.h"
|
||||
#include "newgrf_airporttiles.h"
|
||||
#include "newgrf_debug.h"
|
||||
|
@ -808,7 +810,6 @@ GrfSpecFeature GetGrfSpecFeature(VehicleType type)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**** Sprite Aligner ****/
|
||||
|
||||
/** Window used for aligning sprites. */
|
||||
|
@ -822,6 +823,7 @@ struct SpriteAlignerWindow : Window {
|
|||
static inline ZoomLevel zoom = ZOOM_LVL_END;
|
||||
static bool centre;
|
||||
static bool crosshair;
|
||||
const Action5Type *act5_type = nullptr; ///< Sprite Area of current selected sprite.
|
||||
|
||||
SpriteAlignerWindow(WindowDesc *desc, WindowNumber wno) : Window(desc)
|
||||
{
|
||||
|
@ -829,6 +831,10 @@ struct SpriteAlignerWindow : Window {
|
|||
if (SpriteAlignerWindow::zoom == ZOOM_LVL_END) SpriteAlignerWindow::zoom = _gui_zoom;
|
||||
SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
|
||||
|
||||
/* Oh yes, we assume there is at least one normal sprite! */
|
||||
while (GetSpriteType(this->current_sprite) != SpriteType::Normal) this->current_sprite++;
|
||||
this->SelectAction5Type();
|
||||
|
||||
this->CreateNestedTree();
|
||||
this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
|
||||
this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
|
||||
|
@ -837,9 +843,6 @@ struct SpriteAlignerWindow : Window {
|
|||
this->SetWidgetLoweredState(WID_SA_CENTRE, SpriteAlignerWindow::centre);
|
||||
this->SetWidgetLoweredState(WID_SA_CROSSHAIR, SpriteAlignerWindow::crosshair);
|
||||
|
||||
/* Oh yes, we assume there is at least one normal sprite! */
|
||||
while (GetSpriteType(this->current_sprite) != SpriteType::Normal) this->current_sprite++;
|
||||
|
||||
this->InvalidateData(0, true);
|
||||
}
|
||||
|
||||
|
@ -848,8 +851,22 @@ struct SpriteAlignerWindow : Window {
|
|||
const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
|
||||
switch (widget) {
|
||||
case WID_SA_CAPTION:
|
||||
SetDParam(0, this->current_sprite);
|
||||
SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
|
||||
if (this->act5_type != nullptr) {
|
||||
SetDParam(0, STR_SPRITE_ALIGNER_CAPTION_ACTION5);
|
||||
SetDParam(1, this->act5_type - GetAction5Types().data());
|
||||
SetDParam(2, this->current_sprite - this->act5_type->sprite_base);
|
||||
SetDParamStr(3, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
|
||||
SetDParam(4, GetSpriteLocalID(this->current_sprite));
|
||||
} else if (this->current_sprite < SPR_OPENTTD_BASE) {
|
||||
SetDParam(0, STR_SPRITE_ALIGNER_CAPTION_ACTIONA);
|
||||
SetDParam(1, this->current_sprite);
|
||||
SetDParamStr(2, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
|
||||
SetDParam(3, GetSpriteLocalID(this->current_sprite));
|
||||
} else {
|
||||
SetDParam(0, STR_SPRITE_ALIGNER_CAPTION_NO_ACTION);
|
||||
SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
|
||||
SetDParam(2, GetSpriteLocalID(this->current_sprite));
|
||||
}
|
||||
break;
|
||||
|
||||
case WID_SA_OFFSETS_ABS:
|
||||
|
@ -883,13 +900,21 @@ struct SpriteAlignerWindow : Window {
|
|||
case WID_SA_SPRITE:
|
||||
size->height = ScaleGUITrad(200);
|
||||
break;
|
||||
case WID_SA_LIST:
|
||||
SetDParamMaxDigits(0, 6);
|
||||
size->width = GetStringBoundingBox(STR_JUST_COMMA).width + padding.width;
|
||||
|
||||
case WID_SA_LIST: {
|
||||
Dimension d = {};
|
||||
for (const auto &spritefile : GetCachedSpriteFiles()) {
|
||||
SetDParamStr(0, spritefile->GetSimplifiedFilename());
|
||||
SetDParamMaxDigits(1, 6);
|
||||
d = maxdim(d, GetStringBoundingBox(STR_SPRITE_ALIGNER_SPRITE));
|
||||
}
|
||||
size->width = d.width + padding.width;
|
||||
resize->height = GetCharacterHeight(FS_NORMAL) + padding.height;
|
||||
resize->width = 1;
|
||||
resize->width = 1;
|
||||
fill->height = resize->height;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -941,8 +966,15 @@ struct SpriteAlignerWindow : Window {
|
|||
Rect ir = r.Shrink(WidgetDimensions::scaled.matrix);
|
||||
auto [first, last] = this->vscroll->GetVisibleRangeIterators(list);
|
||||
for (auto it = first; it != last; ++it) {
|
||||
SetDParam(0, *it);
|
||||
DrawString(ir, STR_JUST_COMMA, *it == this->current_sprite ? TC_WHITE : TC_BLACK, SA_RIGHT | SA_FORCE);
|
||||
const SpriteFile *file = GetOriginFile(*it);
|
||||
if (file == nullptr) {
|
||||
SetDParam(0, *it);
|
||||
DrawString(ir, STR_JUST_COMMA, *it == this->current_sprite ? TC_WHITE : (TC_GREY | TC_NO_SHADE), SA_RIGHT | SA_FORCE);
|
||||
} else {
|
||||
SetDParamStr(0, file->GetSimplifiedFilename());
|
||||
SetDParam(1, GetSpriteLocalID(*it));
|
||||
DrawString(ir, STR_SPRITE_ALIGNER_SPRITE, *it == this->current_sprite ? TC_WHITE : TC_BLACK);
|
||||
}
|
||||
ir.top += step_size;
|
||||
}
|
||||
break;
|
||||
|
@ -957,6 +989,7 @@ struct SpriteAlignerWindow : Window {
|
|||
do {
|
||||
this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
|
||||
} while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
|
||||
this->SelectAction5Type();
|
||||
this->SetDirty();
|
||||
break;
|
||||
|
||||
|
@ -968,6 +1001,7 @@ struct SpriteAlignerWindow : Window {
|
|||
do {
|
||||
this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
|
||||
} while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
|
||||
this->SelectAction5Type();
|
||||
this->SetDirty();
|
||||
break;
|
||||
|
||||
|
@ -983,6 +1017,7 @@ struct SpriteAlignerWindow : Window {
|
|||
SpriteID spr = *it;
|
||||
if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr;
|
||||
}
|
||||
this->SelectAction5Type();
|
||||
this->SetDirty();
|
||||
break;
|
||||
}
|
||||
|
@ -1060,6 +1095,7 @@ struct SpriteAlignerWindow : Window {
|
|||
while (GetSpriteType(this->current_sprite) != SpriteType::Normal) {
|
||||
this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
|
||||
}
|
||||
this->SelectAction5Type();
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
|
@ -1088,6 +1124,19 @@ struct SpriteAlignerWindow : Window {
|
|||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
|
||||
}
|
||||
|
||||
private:
|
||||
void SelectAction5Type()
|
||||
{
|
||||
const auto act5types = GetAction5Types();
|
||||
for (auto it = std::begin(act5types); it != std::end(act5types); ++it) {
|
||||
if (it->sprite_base <= this->current_sprite && this->current_sprite < it->sprite_base + it->max_sprites) {
|
||||
this->act5_type = &*it;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->act5_type = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
bool SpriteAlignerWindow::centre = true;
|
||||
|
@ -1096,7 +1145,7 @@ bool SpriteAlignerWindow::crosshair = true;
|
|||
static constexpr NWidgetPart _nested_sprite_aligner_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_JUST_STRING4, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_SHADEBOX, COLOUR_GREY),
|
||||
NWidget(WWT_STICKYBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
|
|
|
@ -74,6 +74,15 @@ static SpriteFile *GetCachedSpriteFileByName(const std::string &filename)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of cached SpriteFiles.
|
||||
* @return Read-only list of cache SpriteFiles.
|
||||
*/
|
||||
std::span<const std::unique_ptr<SpriteFile>> GetCachedSpriteFiles()
|
||||
{
|
||||
return _sprite_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open/get the SpriteFile that is cached for use in the sprite cache.
|
||||
* @param filename Name of the file at the disk.
|
||||
|
|
|
@ -62,6 +62,7 @@ void GfxClearFontSpriteCache();
|
|||
void IncreaseSpriteLRU();
|
||||
|
||||
SpriteFile &OpenCachedSpriteFile(const std::string &filename, Subdirectory subdir, bool palette_remap);
|
||||
std::span<const std::unique_ptr<SpriteFile>> GetCachedSpriteFiles();
|
||||
|
||||
void ReadGRFSpriteOffsets(SpriteFile &file);
|
||||
size_t GetGRFSpriteOffset(uint32_t id);
|
||||
|
|
Loading…
Reference in New Issue