Merge branch 'master' into jgrpp

# Conflicts:
#	CMakeLists.txt
#	COMPILING.md
#	src/console.cpp
#	src/console_cmds.cpp
#	src/console_internal.h
#	src/rev.cpp.in
This commit is contained in:
Jonathan G Rennison
2021-04-25 02:14:29 +01:00
85 changed files with 2756 additions and 809 deletions

View File

@@ -201,7 +201,7 @@ struct AIListWindow : public Window {
{
switch (widget) {
case WID_AIL_LIST: { // Select one of the AIs
int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_AIL_LIST, 0, this->line_height) - 1;
int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_AIL_LIST) - 1;
if (sel < (int)this->info_list->size()) {
this->selected = sel;
this->SetDirty();
@@ -795,6 +795,7 @@ struct AIConfigWindow : public Window {
case WID_AIC_LIST:
this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
resize->height = this->line_height;
size->height = 8 * this->line_height;
break;
@@ -906,7 +907,7 @@ struct AIConfigWindow : public Window {
}
case WID_AIC_LIST: { // Select a slot
this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height);
this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
this->InvalidateData();
if (click_count > 1 && this->selected_slot != INVALID_COMPANY) ShowAIListWindow((CompanyID)this->selected_slot);
break;

View File

@@ -11,6 +11,7 @@
#include "command_func.h"
#include "group.h"
#include "autoreplace_base.h"
#include "core/bitmath_func.hpp"
#include "core/pool_func.hpp"
#include "safeguards.h"
@@ -64,7 +65,7 @@ void RemoveAllEngineReplacement(EngineRenewList *erl)
EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old)
{
const EngineRenew *er = GetEngineReplacement(erl, engine, group);
if (er == nullptr && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !Group::Get(group)->replace_protection))) {
if (er == nullptr && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !HasBit(Group::Get(group)->flags, GroupFlags::GF_REPLACE_PROTECTION)))) {
/* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */
er = GetEngineReplacement(erl, engine, ALL_GROUP);
}

View File

@@ -760,6 +760,9 @@ CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1
bool wagon_removal = c->settings.renew_keep_length;
bool same_type_only = HasBit(p2, 0);
const Group *g = Group::GetIfValid(v->group_id);
if (g != nullptr) wagon_removal = HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL);
/* Test whether any replacement is set, before issuing a whole lot of commands that would end in nothing changed */
Vehicle *w = v;
bool any_replacements = false;

View File

@@ -375,8 +375,15 @@ public:
break;
case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: {
const Company *c = Company::Get(_local_company);
SetDParam(0, c->settings.renew_keep_length ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
bool remove_wagon;
const Group *g = Group::GetIfValid(this->sel_group);
if (g != nullptr) {
remove_wagon = HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL);
} else {
const Company *c = Company::Get(_local_company);
remove_wagon = c->settings.renew_keep_length;
}
SetDParam(0, remove_wagon ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
break;
}
@@ -528,9 +535,16 @@ public:
}
break;
case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length
DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING);
case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: {
const Group *g = Group::GetIfValid(this->sel_group);
if (g != nullptr) {
DoCommandP(0, this->sel_group | (GroupFlags::GF_REPLACE_WAGON_REMOVAL << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL) ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_FLAG);
} else {
// toggle renew_keep_length
DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING);
}
break;
}
case WID_RV_START_REPLACE: { // Start replacing
if (this->GetWidget<NWidgetLeaf>(widget)->ButtonHit(pt)) {

View File

@@ -228,7 +228,7 @@ CommandProc CmdCreateGroupFromList;
CommandProc CmdAddVehicleGroup;
CommandProc CmdAddSharedVehicleGroup;
CommandProc CmdRemoveAllVehiclesGroup;
CommandProc CmdSetGroupReplaceProtection;
CommandProc CmdSetGroupFlag;
CommandProc CmdSetGroupLivery;
CommandProc CmdMoveOrder;
@@ -462,7 +462,7 @@ static const Command _command_proc_table[] = {
DEF_CMD(CmdAddVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_VEHICLE_GROUP
DEF_CMD(CmdAddSharedVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_SHARE_VEHICLE_GROUP
DEF_CMD(CmdRemoveAllVehiclesGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_REMOVE_ALL_VEHICLES_GROUP
DEF_CMD(CmdSetGroupReplaceProtection, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_REPLACE_PROTECTION
DEF_CMD(CmdSetGroupFlag, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_FLAG
DEF_CMD(CmdSetGroupLivery, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_LIVERY
DEF_CMD(CmdMoveOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MOVE_ORDER
DEF_CMD(CmdReverseOrderList, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_REVERSE_ORDER_LIST

View File

@@ -410,7 +410,7 @@ enum Commands {
CMD_ADD_VEHICLE_GROUP, ///< add a vehicle to a group
CMD_ADD_SHARED_VEHICLE_GROUP, ///< add all other shared vehicles to a group which are missing
CMD_REMOVE_ALL_VEHICLES_GROUP, ///< remove all vehicles from a group
CMD_SET_GROUP_REPLACE_PROTECTION, ///< set the autoreplace-protection for a group
CMD_SET_GROUP_FLAG, ///< set/clear a flag for a group
CMD_SET_GROUP_LIVERY, ///< set the livery for a group
CMD_MOVE_ORDER, ///< move an order

View File

@@ -246,10 +246,10 @@ static const NWidgetPart _nested_company_finances_widgets[] = {
EndContainer(),
NWidget(NWID_SPACER), SetFill(0, 0), SetMinimalSize(30, 0),
NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_NULL, STR_NULL),
NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_NULL, STR_NULL),
NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_LOAN_LINE), SetMinimalSize(0, 2), SetFill(1, 0),
NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_TOTAL_VALUE), SetDataTip(STR_NULL, STR_NULL),
NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_TOTAL_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_MAXLOAN),
NWidget(NWID_HORIZONTAL),
@@ -299,6 +299,24 @@ struct CompanyFinancesWindow : Window {
SetDParam(1, (CompanyID)this->window_number);
break;
case WID_CF_BALANCE_VALUE: {
const Company *c = Company::Get((CompanyID)this->window_number);
SetDParam(0, c->money);
break;
}
case WID_CF_LOAN_VALUE: {
const Company *c = Company::Get((CompanyID)this->window_number);
SetDParam(0, c->current_loan);
break;
}
case WID_CF_TOTAL_VALUE: {
const Company *c = Company::Get((CompanyID)this->window_number);
SetDParam(0, c->money - c->current_loan);
break;
}
case WID_CF_MAXLOAN_VALUE:
SetDParam(0, _economy.max_loan);
break;
@@ -357,27 +375,6 @@ struct CompanyFinancesWindow : Window {
break;
}
case WID_CF_BALANCE_VALUE: {
const Company *c = Company::Get((CompanyID)this->window_number);
SetDParam(0, c->money);
DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
break;
}
case WID_CF_LOAN_VALUE: {
const Company *c = Company::Get((CompanyID)this->window_number);
SetDParam(0, c->current_loan);
DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
break;
}
case WID_CF_TOTAL_VALUE: {
const Company *c = Company::Get((CompanyID)this->window_number);
SetDParam(0, c->money - c->current_loan);
DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
break;
}
case WID_CF_LOAN_LINE:
GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK);
break;
@@ -1018,7 +1015,7 @@ public:
break;
case WID_SCL_MATRIX: {
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SCL_MATRIX, 0, this->line_height);
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SCL_MATRIX);
if (row >= this->rows) return;
if (this->livery_class < LC_GROUP_RAIL) {
@@ -1262,70 +1259,82 @@ static const NWidgetPart _nested_select_company_manager_face_widgets[] = {
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 4),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_HAIR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EYEBROWS, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_NOSE, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_MOUSTACHE, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_CHIN, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_JACKET, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_COLLAR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0),
NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT),
SetDataTip(STR_FACE_EARRING, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP),
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
@@ -1356,9 +1365,6 @@ class SelectCompanyManagerFaceWindow : public Window
Dimension yesno_dim; ///< Dimension of a yes/no button of a part in the advanced face window.
Dimension number_dim; ///< Dimension of a number widget of a part in the advanced face window.
static const StringID PART_TEXTS_IS_FEMALE[]; ///< Strings depending on #is_female, used to describe parts (2 entries for a part).
static const StringID PART_TEXTS[]; ///< Fixed strings to describe parts of the face.
/**
* Draw dynamic a label to the left of the button and a value in the button
*
@@ -1391,6 +1397,10 @@ class SelectCompanyManagerFaceWindow : public Window
this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
this->GetWidget<NWidgetCore>(WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT)->widget_data = this->is_female ? STR_FACE_EARRING : STR_FACE_MOUSTACHE;
this->GetWidget<NWidgetCore>(WID_SCMF_TIE_EARRING_TEXT)->widget_data = this->is_female ? STR_FACE_EARRING : STR_FACE_TIE;
this->GetWidget<NWidgetCore>(WID_SCMF_LIPS_MOUSTACHE_TEXT)->widget_data = this->is_moust_male ? STR_FACE_MOUSTACHE : STR_FACE_LIPS;
}
public:
@@ -1452,6 +1462,21 @@ public:
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
{
switch (widget) {
case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
*size = maxdim(*size, GetStringBoundingBox(STR_FACE_EARRING));
*size = maxdim(*size, GetStringBoundingBox(STR_FACE_MOUSTACHE));
break;
case WID_SCMF_TIE_EARRING_TEXT:
*size = maxdim(*size, GetStringBoundingBox(STR_FACE_EARRING));
*size = maxdim(*size, GetStringBoundingBox(STR_FACE_TIE));
break;
case WID_SCMF_LIPS_MOUSTACHE_TEXT:
*size = maxdim(*size, GetStringBoundingBox(STR_FACE_LIPS));
*size = maxdim(*size, GetStringBoundingBox(STR_FACE_MOUSTACHE));
break;
case WID_SCMF_FACE: {
Dimension face_size = GetSpriteSize(SPR_GRADIENT);
size->width = std::max(size->width, face_size.width);
@@ -1459,35 +1484,6 @@ public:
break;
}
case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
case WID_SCMF_TIE_EARRING_TEXT: {
int offset = (widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2;
*size = maxdim(GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset]), GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset + 1]));
size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
break;
}
case WID_SCMF_LIPS_MOUSTACHE_TEXT:
*size = maxdim(GetStringBoundingBox(STR_FACE_LIPS), GetStringBoundingBox(STR_FACE_MOUSTACHE));
size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
break;
case WID_SCMF_HAS_GLASSES_TEXT:
case WID_SCMF_HAIR_TEXT:
case WID_SCMF_EYEBROWS_TEXT:
case WID_SCMF_EYECOLOUR_TEXT:
case WID_SCMF_GLASSES_TEXT:
case WID_SCMF_NOSE_TEXT:
case WID_SCMF_CHIN_TEXT:
case WID_SCMF_JACKET_TEXT:
case WID_SCMF_COLLAR_TEXT:
*size = GetStringBoundingBox(PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT]);
size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
break;
case WID_SCMF_HAS_MOUSTACHE_EARRING:
case WID_SCMF_HAS_GLASSES:
*size = this->yesno_dim;
@@ -1572,30 +1568,6 @@ public:
void DrawWidget(const Rect &r, int widget) const override
{
switch (widget) {
case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
case WID_SCMF_TIE_EARRING_TEXT: {
StringID str = PART_TEXTS_IS_FEMALE[(widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female];
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_GOLD, SA_RIGHT);
break;
}
case WID_SCMF_LIPS_MOUSTACHE_TEXT:
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, (this->is_moust_male) ? STR_FACE_MOUSTACHE : STR_FACE_LIPS, TC_GOLD, SA_RIGHT);
break;
case WID_SCMF_HAS_GLASSES_TEXT:
case WID_SCMF_HAIR_TEXT:
case WID_SCMF_EYEBROWS_TEXT:
case WID_SCMF_EYECOLOUR_TEXT:
case WID_SCMF_GLASSES_TEXT:
case WID_SCMF_NOSE_TEXT:
case WID_SCMF_CHIN_TEXT:
case WID_SCMF_JACKET_TEXT:
case WID_SCMF_COLLAR_TEXT:
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT], TC_GOLD, SA_RIGHT);
break;
case WID_SCMF_HAS_MOUSTACHE_EARRING:
if (this->is_female) { // Only for female faces
this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
@@ -1783,25 +1755,6 @@ public:
}
};
/** Both text values of parts of the face that depend on the #is_female boolean value. */
const StringID SelectCompanyManagerFaceWindow::PART_TEXTS_IS_FEMALE[] = {
STR_FACE_MOUSTACHE, STR_FACE_EARRING, // WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT
STR_FACE_TIE, STR_FACE_EARRING, // WID_SCMF_TIE_EARRING_TEXT
};
/** Textual names for parts of the face. */
const StringID SelectCompanyManagerFaceWindow::PART_TEXTS[] = {
STR_FACE_GLASSES, // WID_SCMF_HAS_GLASSES_TEXT
STR_FACE_HAIR, // WID_SCMF_HAIR_TEXT
STR_FACE_EYEBROWS, // WID_SCMF_EYEBROWS_TEXT
STR_FACE_EYECOLOUR, // WID_SCMF_EYECOLOUR_TEXT
STR_FACE_GLASSES, // WID_SCMF_GLASSES_TEXT
STR_FACE_NOSE, // WID_SCMF_NOSE_TEXT
STR_FACE_CHIN, // WID_SCMF_CHIN_TEXT
STR_FACE_JACKET, // WID_SCMF_JACKET_TEXT
STR_FACE_COLLAR, // WID_SCMF_COLLAR_TEXT
};
/** Company manager face selection window description */
static WindowDesc _select_company_manager_face_desc(
WDP_AUTO, "company_face", 0, 0,

View File

@@ -24,8 +24,17 @@ static const uint ICON_TOKEN_COUNT = 20; ///< Maximum number of tokens in on
static const uint ICON_MAX_RECURSE = 10; ///< Maximum number of recursion
/* console parser */
IConsoleCmd *_iconsole_cmds; ///< list of registered commands
IConsoleAlias *_iconsole_aliases; ///< list of registered aliases
/* static */ IConsole::CommandList &IConsole::Commands()
{
static IConsole::CommandList cmds;
return cmds;
}
/* static */ IConsole::AliasList &IConsole::Aliases()
{
static IConsole::AliasList aliases;
return aliases;
}
FILE *_iconsole_output_file;
@@ -195,49 +204,13 @@ bool GetArgumentInteger(uint32 *value, const char *arg)
}
/**
* Add an item to an alphabetically sorted list.
* @param base first item of the list
* @param item_new the item to add
* Creates a copy of a string with underscores removed from it
* @param name String to remove the underscores from.
* @return A copy of \a name, without underscores.
*/
template<class T>
void IConsoleAddSorted(T **base, T *item_new)
std::string RemoveUnderscores(std::string name)
{
if (*base == nullptr) {
*base = item_new;
return;
}
T *item_before = nullptr;
T *item = *base;
/* The list is alphabetically sorted, insert the new item at the correct location */
while (item != nullptr) {
if (strcmp(item->name, item_new->name) > 0) break; // insert here
item_before = item;
item = item->next;
}
if (item_before == nullptr) {
*base = item_new;
} else {
item_before->next = item_new;
}
item_new->next = item;
}
/**
* Remove underscores from a string; the string will be modified!
* @param[in,out] name String to remove the underscores from.
* @return \a name, with its contents modified.
*/
char *RemoveUnderscores(char *name)
{
char *q = name;
for (const char *p = name; *p != '\0'; p++) {
if (*p != '_') *q++ = *p;
}
*q = '\0';
name.erase(std::remove(name.begin(), name.end(), '_'), name.end());
return name;
}
@@ -246,16 +219,9 @@ char *RemoveUnderscores(char *name)
* @param name name of the command that will be used
* @param proc function that will be called upon execution of command
*/
void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook, bool unlisted)
/* static */ void IConsole::CmdRegister(const std::string &name, IConsoleCmdProc *proc, IConsoleHook *hook, bool unlisted)
{
IConsoleCmd *item_new = MallocT<IConsoleCmd>(1);
item_new->name = RemoveUnderscores(stredup(name));
item_new->next = nullptr;
item_new->proc = proc;
item_new->hook = hook;
item_new->unlisted = unlisted;
IConsoleAddSorted(&_iconsole_cmds, item_new);
IConsole::Commands().try_emplace(RemoveUnderscores(name), name, proc, hook, unlisted);
}
/**
@@ -263,13 +229,10 @@ void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *
* @param name command to be found
* @return return Cmdstruct of the found command, or nullptr on failure
*/
IConsoleCmd *IConsoleCmdGet(const char *name)
/* static */ IConsoleCmd *IConsole::CmdGet(const std::string &name)
{
IConsoleCmd *item;
for (item = _iconsole_cmds; item != nullptr; item = item->next) {
if (strcmp(item->name, name) == 0) return item;
}
auto item = IConsole::Commands().find(RemoveUnderscores(name));
if (item != IConsole::Commands().end()) return &item->second;
return nullptr;
}
@@ -278,22 +241,10 @@ IConsoleCmd *IConsoleCmdGet(const char *name)
* @param name name of the alias that will be used
* @param cmd name of the command that 'name' will be alias of
*/
void IConsoleAliasRegister(const char *name, const char *cmd)
/* static */ void IConsole::AliasRegister(const std::string &name, const std::string &cmd)
{
if (IConsoleAliasGet(name) != nullptr) {
IConsoleError("an alias with this name already exists; insertion aborted");
return;
}
char *new_alias = RemoveUnderscores(stredup(name));
char *cmd_aliased = stredup(cmd);
IConsoleAlias *item_new = MallocT<IConsoleAlias>(1);
item_new->next = nullptr;
item_new->cmdline = cmd_aliased;
item_new->name = new_alias;
IConsoleAddSorted(&_iconsole_aliases, item_new);
auto result = IConsole::Aliases().try_emplace(RemoveUnderscores(name), name, cmd);
if (!result.second) IConsoleError("an alias with this name already exists; insertion aborted");
}
/**
@@ -301,16 +252,13 @@ void IConsoleAliasRegister(const char *name, const char *cmd)
* @param name alias to be found
* @return return Aliasstruct of the found alias, or nullptr on failure
*/
IConsoleAlias *IConsoleAliasGet(const char *name)
/* static */ IConsoleAlias *IConsole::AliasGet(const std::string &name)
{
IConsoleAlias *item;
for (item = _iconsole_aliases; item != nullptr; item = item->next) {
if (strcmp(item->name, name) == 0) return item;
}
auto item = IConsole::Aliases().find(RemoveUnderscores(name));
if (item != IConsole::Aliases().end()) return &item->second;
return nullptr;
}
/**
* An alias is just another name for a command, or for more commands
* Execute it as well.
@@ -330,7 +278,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
return;
}
for (const char *cmdptr = alias->cmdline; *cmdptr != '\0'; cmdptr++) {
for (const char *cmdptr = alias->cmdline.c_str(); *cmdptr != '\0'; cmdptr++) {
switch (*cmdptr) {
case '\'': // ' will double for ""
alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer));
@@ -373,7 +321,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
if (param < 0 || param >= tokencount) {
IConsoleError("too many or wrong amount of parameters passed to alias, aborting");
IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline);
IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name.c_str(), alias->cmdline.c_str());
return;
}
@@ -501,8 +449,7 @@ void IConsoleCmdExecTokens(uint token_count, char *tokens[], const uint recurse_
* First try commands, then aliases. Execute
* the found action taking into account its hooking code
*/
RemoveUnderscores(tokens[0]);
IConsoleCmd *cmd = IConsoleCmdGet(tokens[0]);
IConsoleCmd *cmd = IConsole::CmdGet(tokens[0]);
if (cmd != nullptr) {
ConsoleHookResult chr = (cmd->hook == nullptr ? CHR_ALLOW : cmd->hook(true));
switch (chr) {
@@ -518,7 +465,7 @@ void IConsoleCmdExecTokens(uint token_count, char *tokens[], const uint recurse_
}
token_count--;
IConsoleAlias *alias = IConsoleAliasGet(tokens[0]);
IConsoleAlias *alias = IConsole::AliasGet(tokens[0]);
if (alias != nullptr) {
IConsoleAliasExec(alias, token_count, &tokens[1], recurse_count + 1);
return;

View File

@@ -792,7 +792,14 @@ DEF_CONSOLE_CMD(ConClientNickChange)
return true;
}
if (!NetworkServerChangeClientName(client_id, argv[2])) {
char *client_name = argv[2];
StrTrimInPlace(client_name);
if (!NetworkIsValidClientName(client_name)) {
IConsoleError("Cannot give a client an empty name");
return true;
}
if (!NetworkServerChangeClientName(client_id, client_name)) {
IConsoleError("Cannot give a client a duplicate name");
}
@@ -1477,12 +1484,11 @@ DEF_CONSOLE_CMD(ConAlias)
if (argc < 3) return false;
alias = IConsoleAliasGet(argv[1]);
alias = IConsole::AliasGet(argv[1]);
if (alias == nullptr) {
IConsoleAliasRegister(argv[1], argv[2]);
IConsole::AliasRegister(argv[1], argv[2]);
} else {
free(alias->cmdline);
alias->cmdline = stredup(argv[2]);
alias->cmdline = argv[2];
}
return true;
}
@@ -1603,13 +1609,13 @@ DEF_CONSOLE_CMD(ConInfoCmd)
if (argc < 2) return false;
const IConsoleCmd *cmd = IConsoleCmdGet(argv[1]);
const IConsoleCmd *cmd = IConsole::CmdGet(argv[1]);
if (cmd == nullptr) {
IConsoleError("the given command was not found");
return true;
}
IConsolePrintF(CC_DEFAULT, "command name: %s", cmd->name);
IConsolePrintF(CC_DEFAULT, "command name: %s", cmd->name.c_str());
IConsolePrintF(CC_DEFAULT, "command proc: %p", cmd->proc);
if (cmd->hook != nullptr) IConsoleWarning("command is hooked");
@@ -1668,21 +1674,20 @@ DEF_CONSOLE_CMD(ConHelp)
const IConsoleCmd *cmd;
const IConsoleAlias *alias;
RemoveUnderscores(argv[1]);
cmd = IConsoleCmdGet(argv[1]);
cmd = IConsole::CmdGet(argv[1]);
if (cmd != nullptr) {
cmd->proc(0, nullptr);
return true;
}
alias = IConsoleAliasGet(argv[1]);
alias = IConsole::AliasGet(argv[1]);
if (alias != nullptr) {
cmd = IConsoleCmdGet(alias->cmdline);
cmd = IConsole::CmdGet(alias->cmdline);
if (cmd != nullptr) {
cmd->proc(0, nullptr);
return true;
}
IConsolePrintF(CC_ERROR, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline);
IConsolePrintF(CC_ERROR, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline.c_str());
return true;
}
@@ -1709,9 +1714,10 @@ DEF_CONSOLE_CMD(ConListCommands)
return true;
}
for (const IConsoleCmd *cmd = _iconsole_cmds; cmd != nullptr; cmd = cmd->next) {
if (argv[1] == nullptr || strstr(cmd->name, argv[1]) != nullptr) {
if ((_settings_client.gui.console_show_unlisted || !cmd->unlisted) && (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE)) IConsolePrintF(CC_DEFAULT, "%s", cmd->name);
for (auto &it : IConsole::Commands()) {
const IConsoleCmd *cmd = &it.second;
if (argv[1] == nullptr || cmd->name.find(argv[1]) != std::string::npos) {
if ((_settings_client.gui.console_show_unlisted || !cmd->unlisted) && (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE)) IConsolePrintF(CC_DEFAULT, "%s", cmd->name.c_str());
}
}
@@ -1725,9 +1731,10 @@ DEF_CONSOLE_CMD(ConListAliases)
return true;
}
for (const IConsoleAlias *alias = _iconsole_aliases; alias != nullptr; alias = alias->next) {
if (argv[1] == nullptr || strstr(alias->name, argv[1]) != nullptr) {
IConsolePrintF(CC_DEFAULT, "%s => %s", alias->name, alias->cmdline);
for (auto &it : IConsole::Aliases()) {
const IConsoleAlias *alias = &it.second;
if (argv[1] == nullptr || alias->name.find(argv[1]) != std::string::npos) {
IConsolePrintF(CC_DEFAULT, "%s => %s", alias->name.c_str(), alias->cmdline.c_str());
}
}
@@ -3185,9 +3192,9 @@ DEF_CONSOLE_CMD(ConIfHourMinute)
static void IConsoleDebugLibRegister()
{
IConsoleCmdRegister("resettile", ConResetTile);
IConsoleAliasRegister("dbg_echo", "echo %A; echo %B");
IConsoleAliasRegister("dbg_echo2", "echo %!");
IConsole::CmdRegister("resettile", ConResetTile);
IConsole::AliasRegister("dbg_echo", "echo %A; echo %B");
IConsole::AliasRegister("dbg_echo2", "echo %!");
}
#endif
@@ -3284,199 +3291,199 @@ DEF_CONSOLE_CMD(ConDumpInfo)
void IConsoleStdLibRegister()
{
IConsoleCmdRegister("debug_level", ConDebugLevel);
IConsoleCmdRegister("echo", ConEcho);
IConsoleCmdRegister("echoc", ConEchoC);
IConsoleCmdRegister("exec", ConExec);
IConsoleCmdRegister("exit", ConExit);
IConsoleCmdRegister("part", ConPart);
IConsoleCmdRegister("help", ConHelp);
IConsoleCmdRegister("info_cmd", ConInfoCmd);
IConsoleCmdRegister("list_cmds", ConListCommands);
IConsoleCmdRegister("list_aliases", ConListAliases);
IConsoleCmdRegister("newgame", ConNewGame);
IConsoleCmdRegister("restart", ConRestart);
IConsoleCmdRegister("reload", ConReload);
IConsoleCmdRegister("getseed", ConGetSeed);
IConsoleCmdRegister("getdate", ConGetDate);
IConsoleCmdRegister("getsysdate", ConGetSysDate);
IConsoleCmdRegister("quit", ConExit);
IConsoleCmdRegister("resetengines", ConResetEngines, ConHookNoNetwork);
IConsoleCmdRegister("reset_enginepool", ConResetEnginePool, ConHookNoNetwork);
IConsoleCmdRegister("return", ConReturn);
IConsoleCmdRegister("screenshot", ConScreenShot);
IConsoleCmdRegister("minimap", ConMinimap);
IConsoleCmdRegister("script", ConScript);
IConsoleCmdRegister("scrollto", ConScrollToTile);
IConsoleCmdRegister("highlight_tile", ConHighlightTile);
IConsoleAliasRegister("scrollto_highlight", "scrollto %+; highlight_tile %+");
IConsoleCmdRegister("alias", ConAlias);
IConsoleCmdRegister("load", ConLoad);
IConsoleCmdRegister("rm", ConRemove);
IConsoleCmdRegister("save", ConSave);
IConsoleCmdRegister("saveconfig", ConSaveConfig);
IConsoleCmdRegister("ls", ConListFiles);
IConsoleCmdRegister("cd", ConChangeDirectory);
IConsoleCmdRegister("pwd", ConPrintWorkingDirectory);
IConsoleCmdRegister("clear", ConClearBuffer);
IConsoleCmdRegister("setting", ConSetting);
IConsoleCmdRegister("setting_newgame", ConSettingNewgame);
IConsoleCmdRegister("list_settings",ConListSettings);
IConsoleCmdRegister("gamelog", ConGamelogPrint);
IConsoleCmdRegister("rescan_newgrf", ConRescanNewGRF);
IConsole::CmdRegister("debug_level", ConDebugLevel);
IConsole::CmdRegister("echo", ConEcho);
IConsole::CmdRegister("echoc", ConEchoC);
IConsole::CmdRegister("exec", ConExec);
IConsole::CmdRegister("exit", ConExit);
IConsole::CmdRegister("part", ConPart);
IConsole::CmdRegister("help", ConHelp);
IConsole::CmdRegister("info_cmd", ConInfoCmd);
IConsole::CmdRegister("list_cmds", ConListCommands);
IConsole::CmdRegister("list_aliases", ConListAliases);
IConsole::CmdRegister("newgame", ConNewGame);
IConsole::CmdRegister("restart", ConRestart);
IConsole::CmdRegister("reload", ConReload);
IConsole::CmdRegister("getseed", ConGetSeed);
IConsole::CmdRegister("getdate", ConGetDate);
IConsole::CmdRegister("getsysdate", ConGetSysDate);
IConsole::CmdRegister("quit", ConExit);
IConsole::CmdRegister("resetengines", ConResetEngines, ConHookNoNetwork);
IConsole::CmdRegister("reset_enginepool", ConResetEnginePool, ConHookNoNetwork);
IConsole::CmdRegister("return", ConReturn);
IConsole::CmdRegister("screenshot", ConScreenShot);
IConsole::CmdRegister("minimap", ConMinimap);
IConsole::CmdRegister("script", ConScript);
IConsole::CmdRegister("scrollto", ConScrollToTile);
IConsole::CmdRegister("highlight_tile", ConHighlightTile);
IConsole::AliasRegister("scrollto_highlight", "scrollto %+; highlight_tile %+");
IConsole::CmdRegister("alias", ConAlias);
IConsole::CmdRegister("load", ConLoad);
IConsole::CmdRegister("rm", ConRemove);
IConsole::CmdRegister("save", ConSave);
IConsole::CmdRegister("saveconfig", ConSaveConfig);
IConsole::CmdRegister("ls", ConListFiles);
IConsole::CmdRegister("cd", ConChangeDirectory);
IConsole::CmdRegister("pwd", ConPrintWorkingDirectory);
IConsole::CmdRegister("clear", ConClearBuffer);
IConsole::CmdRegister("setting", ConSetting);
IConsole::CmdRegister("setting_newgame", ConSettingNewgame);
IConsole::CmdRegister("list_settings", ConListSettings);
IConsole::CmdRegister("gamelog", ConGamelogPrint);
IConsole::CmdRegister("rescan_newgrf", ConRescanNewGRF);
IConsoleAliasRegister("dir", "ls");
IConsoleAliasRegister("del", "rm %+");
IConsoleAliasRegister("newmap", "newgame");
IConsoleAliasRegister("patch", "setting %+");
IConsoleAliasRegister("set", "setting %+");
IConsoleAliasRegister("set_newgame", "setting_newgame %+");
IConsoleAliasRegister("list_patches", "list_settings %+");
IConsoleAliasRegister("developer", "setting developer %+");
IConsole::AliasRegister("dir", "ls");
IConsole::AliasRegister("del", "rm %+");
IConsole::AliasRegister("newmap", "newgame");
IConsole::AliasRegister("patch", "setting %+");
IConsole::AliasRegister("set", "setting %+");
IConsole::AliasRegister("set_newgame", "setting_newgame %+");
IConsole::AliasRegister("list_patches", "list_settings %+");
IConsole::AliasRegister("developer", "setting developer %+");
IConsoleCmdRegister("list_ai_libs", ConListAILibs);
IConsoleCmdRegister("list_ai", ConListAI);
IConsoleCmdRegister("reload_ai", ConReloadAI);
IConsoleCmdRegister("rescan_ai", ConRescanAI);
IConsoleCmdRegister("start_ai", ConStartAI);
IConsoleCmdRegister("stop_ai", ConStopAI);
IConsole::CmdRegister("list_ai_libs", ConListAILibs);
IConsole::CmdRegister("list_ai", ConListAI);
IConsole::CmdRegister("reload_ai", ConReloadAI);
IConsole::CmdRegister("rescan_ai", ConRescanAI);
IConsole::CmdRegister("start_ai", ConStartAI);
IConsole::CmdRegister("stop_ai", ConStopAI);
IConsoleCmdRegister("list_game", ConListGame);
IConsoleCmdRegister("list_game_libs", ConListGameLibs);
IConsoleCmdRegister("rescan_game", ConRescanGame);
IConsole::CmdRegister("list_game", ConListGame);
IConsole::CmdRegister("list_game_libs", ConListGameLibs);
IConsole::CmdRegister("rescan_game", ConRescanGame);
IConsoleCmdRegister("companies", ConCompanies);
IConsoleAliasRegister("players", "companies");
IConsole::CmdRegister("companies", ConCompanies);
IConsole::AliasRegister("players", "companies");
/* networking functions */
/* Content downloading is only available with ZLIB */
#if defined(WITH_ZLIB)
IConsoleCmdRegister("content", ConContent);
IConsole::CmdRegister("content", ConContent);
#endif /* defined(WITH_ZLIB) */
/*** Networking commands ***/
IConsoleCmdRegister("say", ConSay, ConHookNeedNetwork);
IConsoleCmdRegister("say_company", ConSayCompany, ConHookNeedNetwork);
IConsoleAliasRegister("say_player", "say_company %+");
IConsoleCmdRegister("say_client", ConSayClient, ConHookNeedNetwork);
IConsole::CmdRegister("say", ConSay, ConHookNeedNetwork);
IConsole::CmdRegister("say_company", ConSayCompany, ConHookNeedNetwork);
IConsole::AliasRegister("say_player", "say_company %+");
IConsole::CmdRegister("say_client", ConSayClient, ConHookNeedNetwork);
IConsoleCmdRegister("connect", ConNetworkConnect, ConHookClientOnly);
IConsoleCmdRegister("clients", ConNetworkClients, ConHookNeedNetwork);
IConsoleCmdRegister("status", ConStatus, ConHookServerOnly);
IConsoleCmdRegister("server_info", ConServerInfo, ConHookServerOnly);
IConsoleAliasRegister("info", "server_info");
IConsoleCmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly);
IConsoleCmdRegister("rcon", ConRcon, ConHookNeedNetwork);
IConsoleCmdRegister("settings_access", ConSettingsAccess, ConHookNeedNetwork);
IConsole::CmdRegister("connect", ConNetworkConnect, ConHookClientOnly);
IConsole::CmdRegister("clients", ConNetworkClients, ConHookNeedNetwork);
IConsole::CmdRegister("status", ConStatus, ConHookServerOnly);
IConsole::CmdRegister("server_info", ConServerInfo, ConHookServerOnly);
IConsole::AliasRegister("info", "server_info");
IConsole::CmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly);
IConsole::CmdRegister("rcon", ConRcon, ConHookNeedNetwork);
IConsole::CmdRegister("settings_access", ConSettingsAccess, ConHookNeedNetwork);
IConsoleCmdRegister("join", ConJoinCompany, ConHookNeedNetwork);
IConsoleAliasRegister("spectate", "join 255");
IConsoleCmdRegister("move", ConMoveClient, ConHookServerOnly);
IConsoleCmdRegister("reset_company", ConResetCompany, ConHookServerOnly);
IConsoleAliasRegister("clean_company", "reset_company %A");
IConsoleCmdRegister("client_name", ConClientNickChange, ConHookServerOnly);
IConsoleCmdRegister("kick", ConKick, ConHookServerOnly);
IConsoleCmdRegister("ban", ConBan, ConHookServerOnly);
IConsoleCmdRegister("unban", ConUnBan, ConHookServerOnly);
IConsoleCmdRegister("banlist", ConBanList, ConHookServerOnly);
IConsole::CmdRegister("join", ConJoinCompany, ConHookNeedNetwork);
IConsole::AliasRegister("spectate", "join 255");
IConsole::CmdRegister("move", ConMoveClient, ConHookServerOnly);
IConsole::CmdRegister("reset_company", ConResetCompany, ConHookServerOnly);
IConsole::AliasRegister("clean_company", "reset_company %A");
IConsole::CmdRegister("client_name", ConClientNickChange, ConHookServerOnly);
IConsole::CmdRegister("kick", ConKick, ConHookServerOnly);
IConsole::CmdRegister("ban", ConBan, ConHookServerOnly);
IConsole::CmdRegister("unban", ConUnBan, ConHookServerOnly);
IConsole::CmdRegister("banlist", ConBanList, ConHookServerOnly);
IConsoleCmdRegister("pause", ConPauseGame, ConHookServerOnly);
IConsoleCmdRegister("unpause", ConUnpauseGame, ConHookServerOnly);
IConsole::CmdRegister("pause", ConPauseGame, ConHookServerOnly);
IConsole::CmdRegister("unpause", ConUnpauseGame, ConHookServerOnly);
IConsoleCmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork);
IConsoleAliasRegister("company_password", "company_pw %+");
IConsoleCmdRegister("company_pw_hash", ConCompanyPasswordHash, ConHookServerOnly);
IConsoleAliasRegister("company_password_hash", "company_pw %+");
IConsoleCmdRegister("company_pw_hashes", ConCompanyPasswordHashes, ConHookServerOnly);
IConsoleAliasRegister("company_password_hashes", "company_pw_hashes");
IConsole::CmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork);
IConsole::AliasRegister("company_password", "company_pw %+");
IConsole::CmdRegister("company_pw_hash", ConCompanyPasswordHash, ConHookServerOnly);
IConsole::AliasRegister("company_password_hash", "company_pw %+");
IConsole::CmdRegister("company_pw_hashes", ConCompanyPasswordHashes, ConHookServerOnly);
IConsole::AliasRegister("company_password_hashes", "company_pw_hashes");
IConsoleAliasRegister("net_frame_freq", "setting frame_freq %+");
IConsoleAliasRegister("net_sync_freq", "setting sync_freq %+");
IConsoleAliasRegister("server_pw", "setting server_password %+");
IConsoleAliasRegister("server_password", "setting server_password %+");
IConsoleAliasRegister("rcon_pw", "setting rcon_password %+");
IConsoleAliasRegister("rcon_password", "setting rcon_password %+");
IConsoleAliasRegister("settings_pw", "setting settings_password %+");
IConsoleAliasRegister("settings_password", "setting settings_password %+");
IConsoleAliasRegister("name", "setting client_name %+");
IConsoleAliasRegister("server_name", "setting server_name %+");
IConsoleAliasRegister("server_port", "setting server_port %+");
IConsoleAliasRegister("server_advertise", "setting server_advertise %+");
IConsoleAliasRegister("max_clients", "setting max_clients %+");
IConsoleAliasRegister("max_companies", "setting max_companies %+");
IConsoleAliasRegister("max_spectators", "setting max_spectators %+");
IConsoleAliasRegister("max_join_time", "setting max_join_time %+");
IConsoleAliasRegister("pause_on_join", "setting pause_on_join %+");
IConsoleAliasRegister("autoclean_companies", "setting autoclean_companies %+");
IConsoleAliasRegister("autoclean_protected", "setting autoclean_protected %+");
IConsoleAliasRegister("autoclean_unprotected", "setting autoclean_unprotected %+");
IConsoleAliasRegister("restart_game_year", "setting restart_game_year %+");
IConsoleAliasRegister("min_players", "setting min_active_clients %+");
IConsoleAliasRegister("reload_cfg", "setting reload_cfg %+");
IConsole::AliasRegister("net_frame_freq", "setting frame_freq %+");
IConsole::AliasRegister("net_sync_freq", "setting sync_freq %+");
IConsole::AliasRegister("server_pw", "setting server_password %+");
IConsole::AliasRegister("server_password", "setting server_password %+");
IConsole::AliasRegister("rcon_pw", "setting rcon_password %+");
IConsole::AliasRegister("rcon_password", "setting rcon_password %+");
IConsole::AliasRegister("settings_pw", "setting settings_password %+");
IConsole::AliasRegister("settings_password", "setting settings_password %+");
IConsole::AliasRegister("name", "setting client_name %+");
IConsole::AliasRegister("server_name", "setting server_name %+");
IConsole::AliasRegister("server_port", "setting server_port %+");
IConsole::AliasRegister("server_advertise", "setting server_advertise %+");
IConsole::AliasRegister("max_clients", "setting max_clients %+");
IConsole::AliasRegister("max_companies", "setting max_companies %+");
IConsole::AliasRegister("max_spectators", "setting max_spectators %+");
IConsole::AliasRegister("max_join_time", "setting max_join_time %+");
IConsole::AliasRegister("pause_on_join", "setting pause_on_join %+");
IConsole::AliasRegister("autoclean_companies", "setting autoclean_companies %+");
IConsole::AliasRegister("autoclean_protected", "setting autoclean_protected %+");
IConsole::AliasRegister("autoclean_unprotected", "setting autoclean_unprotected %+");
IConsole::AliasRegister("restart_game_year", "setting restart_game_year %+");
IConsole::AliasRegister("min_players", "setting min_active_clients %+");
IConsole::AliasRegister("reload_cfg", "setting reload_cfg %+");
/* conditionals */
IConsoleCmdRegister("if_year", ConIfYear);
IConsoleCmdRegister("if_month", ConIfMonth);
IConsoleCmdRegister("if_day", ConIfDay);
IConsoleCmdRegister("if_hour", ConIfHour);
IConsoleCmdRegister("if_minute", ConIfMinute);
IConsoleCmdRegister("if_hour_minute", ConIfHourMinute);
IConsole::CmdRegister("if_year", ConIfYear);
IConsole::CmdRegister("if_month", ConIfMonth);
IConsole::CmdRegister("if_day", ConIfDay);
IConsole::CmdRegister("if_hour", ConIfHour);
IConsole::CmdRegister("if_minute", ConIfMinute);
IConsole::CmdRegister("if_hour_minute", ConIfHourMinute);
/* debugging stuff */
#ifdef _DEBUG
IConsoleDebugLibRegister();
#endif
IConsoleCmdRegister("fps", ConFramerate);
IConsoleCmdRegister("fps_wnd", ConFramerateWindow);
IConsole::CmdRegister("fps", ConFramerate);
IConsole::CmdRegister("fps_wnd", ConFramerateWindow);
IConsoleCmdRegister("find_non_realistic_braking_signal", ConFindNonRealisticBrakingSignal);
IConsole::CmdRegister("find_non_realistic_braking_signal", ConFindNonRealisticBrakingSignal);
IConsoleCmdRegister("getfulldate", ConGetFullDate, nullptr, true);
IConsoleCmdRegister("dump_command_log", ConDumpCommandLog, nullptr, true);
IConsoleCmdRegister("dump_desync_msgs", ConDumpDesyncMsgLog, nullptr, true);
IConsoleCmdRegister("dump_inflation", ConDumpInflation, nullptr, true);
IConsoleCmdRegister("dump_cpdp_stats", ConDumpCpdpStats, nullptr, true);
IConsoleCmdRegister("dump_veh_stats", ConVehicleStats, nullptr, true);
IConsoleCmdRegister("dump_map_stats", ConMapStats, nullptr, true);
IConsoleCmdRegister("dump_st_flow_stats", ConStFlowStats, nullptr, true);
IConsoleCmdRegister("dump_game_events", ConDumpGameEvents, nullptr, true);
IConsoleCmdRegister("dump_load_debug_log", ConDumpLoadDebugLog, nullptr, true);
IConsoleCmdRegister("dump_load_debug_config", ConDumpLoadDebugConfig, nullptr, true);
IConsoleCmdRegister("dump_linkgraph_jobs", ConDumpLinkgraphJobs, nullptr, true);
IConsoleCmdRegister("dump_road_types", ConDumpRoadTypes, nullptr, true);
IConsoleCmdRegister("dump_rail_types", ConDumpRailTypes, nullptr, true);
IConsoleCmdRegister("dump_bridge_types", ConDumpBridgeTypes, nullptr, true);
IConsoleCmdRegister("dump_cargo_types", ConDumpCargoTypes, nullptr, true);
IConsoleCmdRegister("dump_tile", ConDumpTile, nullptr, true);
IConsoleCmdRegister("check_caches", ConCheckCaches, nullptr, true);
IConsoleCmdRegister("show_town_window", ConShowTownWindow, nullptr, true);
IConsoleCmdRegister("show_station_window", ConShowStationWindow, nullptr, true);
IConsoleCmdRegister("show_industry_window", ConShowIndustryWindow, nullptr, true);
IConsoleCmdRegister("viewport_debug", ConViewportDebug, nullptr, true);
IConsoleCmdRegister("viewport_mark_dirty", ConViewportMarkDirty, nullptr, true);
IConsoleCmdRegister("viewport_mark_dirty_st_overlay", ConViewportMarkStationOverlayDirty, nullptr, true);
IConsoleCmdRegister("gfx_debug", ConGfxDebug, nullptr, true);
IConsoleCmdRegister("csleep", ConCSleep, nullptr, true);
IConsoleCmdRegister("recalculate_road_cached_one_way_states", ConRecalculateRoadCachedOneWayStates, ConHookNoNetwork, true);
IConsoleCmdRegister("misc_debug", ConMiscDebug, nullptr, true);
IConsole::CmdRegister("getfulldate", ConGetFullDate, nullptr, true);
IConsole::CmdRegister("dump_command_log", ConDumpCommandLog, nullptr, true);
IConsole::CmdRegister("dump_desync_msgs", ConDumpDesyncMsgLog, nullptr, true);
IConsole::CmdRegister("dump_inflation", ConDumpInflation, nullptr, true);
IConsole::CmdRegister("dump_cpdp_stats", ConDumpCpdpStats, nullptr, true);
IConsole::CmdRegister("dump_veh_stats", ConVehicleStats, nullptr, true);
IConsole::CmdRegister("dump_map_stats", ConMapStats, nullptr, true);
IConsole::CmdRegister("dump_st_flow_stats", ConStFlowStats, nullptr, true);
IConsole::CmdRegister("dump_game_events", ConDumpGameEvents, nullptr, true);
IConsole::CmdRegister("dump_load_debug_log", ConDumpLoadDebugLog, nullptr, true);
IConsole::CmdRegister("dump_load_debug_config", ConDumpLoadDebugConfig, nullptr, true);
IConsole::CmdRegister("dump_linkgraph_jobs", ConDumpLinkgraphJobs, nullptr, true);
IConsole::CmdRegister("dump_road_types", ConDumpRoadTypes, nullptr, true);
IConsole::CmdRegister("dump_rail_types", ConDumpRailTypes, nullptr, true);
IConsole::CmdRegister("dump_bridge_types", ConDumpBridgeTypes, nullptr, true);
IConsole::CmdRegister("dump_cargo_types", ConDumpCargoTypes, nullptr, true);
IConsole::CmdRegister("dump_tile", ConDumpTile, nullptr, true);
IConsole::CmdRegister("check_caches", ConCheckCaches, nullptr, true);
IConsole::CmdRegister("show_town_window", ConShowTownWindow, nullptr, true);
IConsole::CmdRegister("show_station_window", ConShowStationWindow, nullptr, true);
IConsole::CmdRegister("show_industry_window", ConShowIndustryWindow, nullptr, true);
IConsole::CmdRegister("viewport_debug", ConViewportDebug, nullptr, true);
IConsole::CmdRegister("viewport_mark_dirty", ConViewportMarkDirty, nullptr, true);
IConsole::CmdRegister("viewport_mark_dirty_st_overlay", ConViewportMarkStationOverlayDirty, nullptr, true);
IConsole::CmdRegister("gfx_debug", ConGfxDebug, nullptr, true);
IConsole::CmdRegister("csleep", ConCSleep, nullptr, true);
IConsole::CmdRegister("recalculate_road_cached_one_way_states", ConRecalculateRoadCachedOneWayStates, ConHookNoNetwork, true);
IConsole::CmdRegister("misc_debug", ConMiscDebug, nullptr, true);
/* NewGRF development stuff */
IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool);
IConsoleCmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool);
IConsoleCmdRegister("dump_info", ConDumpInfo);
IConsoleCmdRegister("do_disaster", ConDoDisaster, ConHookNewGRFDeveloperTool, true);
IConsoleCmdRegister("bankrupt_company", ConBankruptCompany, ConHookNewGRFDeveloperTool, true);
IConsoleCmdRegister("delete_company", ConDeleteCompany, ConHookNewGRFDeveloperTool, true);
IConsoleCmdRegister("road_type_flag_ctl", ConRoadTypeFlagCtl, ConHookNewGRFDeveloperTool, true);
IConsoleCmdRegister("rail_type_map_colour_ctl", ConRailTypeMapColourCtl, ConHookNewGRFDeveloperTool, true);
IConsoleCmdRegister("switch_baseset", ConSwitchBaseset, ConHookNewGRFDeveloperTool, true);
IConsole::CmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool);
IConsole::CmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool);
IConsole::CmdRegister("dump_info", ConDumpInfo);
IConsole::CmdRegister("do_disaster", ConDoDisaster, ConHookNewGRFDeveloperTool, true);
IConsole::CmdRegister("bankrupt_company", ConBankruptCompany, ConHookNewGRFDeveloperTool, true);
IConsole::CmdRegister("delete_company", ConDeleteCompany, ConHookNewGRFDeveloperTool, true);
IConsole::CmdRegister("road_type_flag_ctl", ConRoadTypeFlagCtl, ConHookNewGRFDeveloperTool, true);
IConsole::CmdRegister("rail_type_map_colour_ctl", ConRailTypeMapColourCtl, ConHookNewGRFDeveloperTool, true);
IConsole::CmdRegister("switch_baseset", ConSwitchBaseset, ConHookNewGRFDeveloperTool, true);
/* Bug workarounds */
IConsoleCmdRegister("jgrpp_bug_workaround_unblock_heliports", ConResetBlockedHeliports, ConHookNoNetwork, true);
IConsoleCmdRegister("merge_linkgraph_jobs_asap", ConMergeLinkgraphJobsAsap, ConHookNoNetwork, true);
IConsole::CmdRegister("jgrpp_bug_workaround_unblock_heliports", ConResetBlockedHeliports, ConHookNoNetwork, true);
IConsole::CmdRegister("merge_linkgraph_jobs_asap", ConMergeLinkgraphJobsAsap, ConHookNoNetwork, true);
#ifdef _DEBUG
IConsoleCmdRegister("delete_vehicle_id", ConDeleteVehicleID, ConHookNoNetwork, true);
IConsole::CmdRegister("delete_vehicle_id", ConDeleteVehicleID, ConHookNoNetwork, true);
#endif
}

View File

@@ -524,11 +524,9 @@ static void IConsoleTabCompletion()
return;
}
}
size_t length = cmdptr - input;
char *prefix = (char*)alloca(length + 1);
strecpy(prefix, input, prefix + length);
RemoveUnderscores(prefix);
size_t prefix_length = strlen(prefix);
extern std::string RemoveUnderscores(std::string name);
std::string prefix = RemoveUnderscores(std::string(input, cmdptr - input));
size_t prefix_length = prefix.size();
if (prefix_length == 0) return;
@@ -536,26 +534,28 @@ static void IConsoleTabCompletion()
char *b = buffer;
uint matches = 0;
std::string common_prefix;
for (const IConsoleCmd *cmd = _iconsole_cmds; cmd != nullptr; cmd = cmd->next) {
if (strncmp(cmd->name, prefix, prefix_length) == 0) {
for (auto &it : IConsole::Commands()) {
const char *cmd_name = it.first.c_str();
const IConsoleCmd *cmd = &it.second;
if (strncmp(cmd_name, prefix.c_str(), prefix_length) == 0) {
if ((_settings_client.gui.console_show_unlisted || !cmd->unlisted) && (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE)) {
if (matches == 0) {
common_prefix = cmd->name;
common_prefix = it.first;
} else {
const char *cp = common_prefix.c_str();
const char *cmdp = cmd->name;
const char *cmdp = cmd_name;
while (true) {
const char *end = cmdp;
WChar a = Utf8Consume(cp);
WChar b = Utf8Consume(cmdp);
if (a == 0 || b == 0 || a != b) {
common_prefix.resize(end - cmd->name);
common_prefix.resize(end - cmd_name);
break;
}
}
}
matches++;
b += seprintf(b, lastof(buffer), "%s ", cmd->name);
b += seprintf(b, lastof(buffer), "%s ", cmd_name);
}
}
}

View File

@@ -11,6 +11,7 @@
#define CONSOLE_INTERNAL_H
#include "gfx_type.h"
#include <map>
static const uint ICON_CMDLN_SIZE = 1024; ///< maximum length of a typed in command
static const uint ICON_MAX_STREAMSIZE = 2048; ///< maximum length of a totally expanded command
@@ -33,9 +34,9 @@ enum ConsoleHookResult {
typedef bool IConsoleCmdProc(byte argc, char *argv[]);
typedef ConsoleHookResult IConsoleHook(bool echo);
struct IConsoleCmd {
char *name; ///< name of command
IConsoleCmd *next; ///< next command in list
IConsoleCmd(const std::string &name, IConsoleCmdProc *proc, IConsoleHook *hook, bool unlisted) : name(name), proc(proc), hook(hook), unlisted(unlisted) {}
std::string name; ///< name of command
IConsoleCmdProc *proc; ///< process executed when command is typed
IConsoleHook *hook; ///< any special trigger action that needs executing
bool unlisted;
@@ -54,25 +55,31 @@ struct IConsoleCmd {
* - ";" allows for combining commands (see example 'ng')
*/
struct IConsoleAlias {
char *name; ///< name of the alias
IConsoleAlias *next; ///< next alias in list
IConsoleAlias(const std::string &name, const std::string &cmdline) : name(name), cmdline(cmdline) {}
char *cmdline; ///< command(s) that is/are being aliased
std::string name; ///< name of the alias
std::string cmdline; ///< command(s) that is/are being aliased
};
/* console parser */
extern IConsoleCmd *_iconsole_cmds; ///< List of registered commands.
extern IConsoleAlias *_iconsole_aliases; ///< List of registered aliases.
struct IConsole
{
typedef std::map<std::string, IConsoleCmd> CommandList;
typedef std::map<std::string, IConsoleAlias> AliasList;
/* console parser */
static CommandList &Commands();
static AliasList &Aliases();
/* Commands */
static void CmdRegister(const std::string &name, IConsoleCmdProc *proc, IConsoleHook *hook = nullptr, bool unlisted = false);
static IConsoleCmd *CmdGet(const std::string &name);
static void AliasRegister(const std::string &name, const std::string &cmd);
static IConsoleAlias *AliasGet(const std::string &name);
};
/* console functions */
void IConsoleClearBuffer();
/* Commands */
void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook = nullptr, bool unlisted = false);
void IConsoleAliasRegister(const char *name, const char *cmd);
IConsoleCmd *IConsoleCmdGet(const char *name);
IConsoleAlias *IConsoleAliasGet(const char *name);
/* console std lib (register ingame commands/aliases) */
void IConsoleStdLibRegister();
@@ -82,6 +89,5 @@ bool GetArgumentInteger(uint32 *value, const char *arg);
void IConsoleGUIInit();
void IConsoleGUIFree();
void IConsoleGUIPrint(TextColour colour_code, char *string);
char *RemoveUnderscores(char *name);
#endif /* CONSOLE_INTERNAL_H */

View File

@@ -80,10 +80,4 @@ struct PointDimension {
int height;
};
/** A pair of two integers */
struct Pair {
int a;
int b;
};
#endif /* GEOMETRY_TYPE_HPP */

View File

@@ -682,7 +682,7 @@ struct FramerateWindow : Window {
case WID_FRW_TIMES_AVERAGE: {
/* Open time graph windows when clicking detail measurement lines */
const Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR);
int line = sb->GetScrolledRowFromWidget(pt.y - FONT_HEIGHT_NORMAL - VSPACING, this, widget, VSPACING, FONT_HEIGHT_NORMAL);
int line = sb->GetScrolledRowFromWidget(pt.y, this, widget, VSPACING + FONT_HEIGHT_NORMAL);
if (line != INT_MAX) {
line++;
/* Find the visible line that was clicked */

View File

@@ -92,24 +92,6 @@ Dimension GetSpriteSize(SpriteID sprid, Point *offset = nullptr, ZoomLevel zoom
void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr);
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
/** How to align the to-be drawn text. */
enum StringAlignment {
SA_LEFT = 0 << 0, ///< Left align the text.
SA_HOR_CENTER = 1 << 0, ///< Horizontally center the text.
SA_RIGHT = 2 << 0, ///< Right align the text (must be a single bit).
SA_HOR_MASK = 3 << 0, ///< Mask for horizontal alignment.
SA_TOP = 0 << 2, ///< Top align the text.
SA_VERT_CENTER = 1 << 2, ///< Vertically center the text.
SA_BOTTOM = 2 << 2, ///< Bottom align the text.
SA_VERT_MASK = 3 << 2, ///< Mask for vertical alignment.
SA_CENTER = SA_HOR_CENTER | SA_VERT_CENTER, ///< Center both horizontally and vertically.
SA_FORCE = 1 << 4, ///< Force the alignment, i.e. don't swap for RTL languages.
};
DECLARE_ENUM_AS_BIT_SET(StringAlignment)
int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL);

View File

@@ -324,4 +324,22 @@ enum Support8bpp {
S8BPP_HARDWARE, ///< Full 8bpp support by OS and hardware.
};
/** How to align the to-be drawn text. */
enum StringAlignment {
SA_LEFT = 0 << 0, ///< Left align the text.
SA_HOR_CENTER = 1 << 0, ///< Horizontally center the text.
SA_RIGHT = 2 << 0, ///< Right align the text (must be a single bit).
SA_HOR_MASK = 3 << 0, ///< Mask for horizontal alignment.
SA_TOP = 0 << 2, ///< Top align the text.
SA_VERT_CENTER = 1 << 2, ///< Vertically center the text.
SA_BOTTOM = 2 << 2, ///< Bottom align the text.
SA_VERT_MASK = 3 << 2, ///< Mask for vertical alignment.
SA_CENTER = SA_HOR_CENTER | SA_VERT_CENTER, ///< Center both horizontally and vertically.
SA_FORCE = 1 << 4, ///< Force the alignment, i.e. don't swap for RTL languages.
};
DECLARE_ENUM_AS_BIT_SET(StringAlignment)
#endif /* GFX_TYPE_H */

View File

@@ -992,7 +992,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow {
}
case WID_CPR_MATRIX: {
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX, 0, this->line_height);
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX);
if (row >= this->vscroll->GetCount()) return;
const CargoSpec *cs;

View File

@@ -62,13 +62,19 @@ struct GroupStatistics {
static void UpdateAutoreplace(CompanyID company);
};
enum GroupFlags : uint8 {
GF_REPLACE_PROTECTION, ///< If set to true, the global autoreplace has no effect on the group
GF_REPLACE_WAGON_REMOVAL, ///< If set, autoreplace will perform wagon removal on vehicles in this group.
GF_END,
};
/** Group data. */
struct Group : GroupPool::PoolItem<&_group_pool> {
std::string name; ///< Group Name
Owner owner; ///< Group Owner
VehicleType vehicle_type; ///< Vehicle type of the group
bool replace_protection; ///< If set to true, the global autoreplace have no effect on the group
uint8 flags; ///< Group flags
Livery livery; ///< Custom colour scheme for vehicles in this group
GroupStatistics statistics; ///< NOSAVE: Statistics and caches on the vehicles in the group.

View File

@@ -324,7 +324,6 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (flags & DC_EXEC) {
Group *g = new Group(_current_company);
g->replace_protection = false;
g->vehicle_type = vt;
g->parent = INVALID_GROUP;
@@ -332,10 +331,12 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
const Company *c = Company::Get(_current_company);
g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
if (c->settings.renew_keep_length) SetBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL);
} else {
g->parent = pg->index;
g->livery.colour1 = pg->livery.colour1;
g->livery.colour2 = pg->livery.colour2;
g->flags = pg->flags;
}
_new_group_id = g->index;
@@ -728,42 +729,50 @@ CommandCost CmdSetGroupLivery(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
}
/**
* Set replace protection for a group and its sub-groups.
* Set group flag for a group and its sub-groups.
* @param g initial group.
* @param protect 1 to set or 0 to clear protection.
* @param set 1 to set or 0 to clear protection.
*/
static void SetGroupReplaceProtection(Group *g, bool protect)
static void SetGroupFlag(Group *g, GroupFlags flag, bool set, bool children)
{
g->replace_protection = protect;
if (set) {
SetBit(g->flags, flag);
} else {
ClrBit(g->flags, flag);
}
if (!children) return;
for (Group *pg : Group::Iterate()) {
if (pg->parent == g->index) SetGroupReplaceProtection(pg, protect);
if (pg->parent == g->index) SetGroupFlag(pg, flag, set, true);
}
}
/**
* (Un)set global replace protection from a group
* (Un)set group flag from a group
* @param tile unused
* @param flags type of operation
* @param p1 index of group array
* - p1 bit 0-15 : GroupID
* - p1 bit 0-15 : GroupID
* - p1 bit 16-18 : Flag to set, by value not bit.
* @param p2
* - p2 bit 0 : 1 to set or 0 to clear protection.
* - p2 bit 1 : 1 to apply to sub-groups.
* @param text unused
* @return the cost of this operation or an error
*/
CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
CommandCost CmdSetGroupFlag(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
Group *g = Group::GetIfValid(p1);
Group *g = Group::GetIfValid(GB(p1, 0, 16));
if (g == nullptr || g->owner != _current_company) return CMD_ERROR;
/* GroupFlags are stored in as an 8 bit bitfield but passed here by value,
* so 3 bits is sufficient to cover each possible value. */
GroupFlags flag = (GroupFlags)GB(p1, 16, 3);
if (flag >= GroupFlags::GF_END) return CMD_ERROR;
if (flags & DC_EXEC) {
if (HasBit(p2, 1)) {
SetGroupReplaceProtection(g, HasBit(p2, 0));
} else {
g->replace_protection = HasBit(p2, 0);
}
SetGroupFlag(g, flag, HasBit(p2, 0), HasBit(p2, 1));
SetWindowDirty(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);

View File

@@ -618,7 +618,7 @@ public:
/* If not a default group and the group has replace protection, show an enabled replace sprite. */
uint16 protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN;
if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && Group::Get(this->vli.index)->replace_protection) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN;
if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && HasBit(Group::Get(this->vli.index)->flags, GroupFlags::GF_REPLACE_PROTECTION)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN;
this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype;
/* Set text of "group by" dropdown widget. */
@@ -675,7 +675,7 @@ public:
assert(g->owner == this->owner);
DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * LEVEL_WIDTH, g->replace_protection, g->folded || (i + 1 < (int)this->groups.size() && indents[i + 1] > this->indents[i]));
DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * LEVEL_WIDTH, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (i + 1 < (int)this->groups.size() && indents[i + 1] > this->indents[i]));
y1 += this->tiny_step_height;
}
@@ -755,7 +755,7 @@ public:
break;
case WID_GL_LIST_GROUP: { // Matrix Group
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height);
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
if (id_g >= this->groups.size()) return;
if (groups[id_g]->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) {
@@ -891,7 +891,7 @@ public:
case WID_GL_REPLACE_PROTECTION: {
const Group *g = Group::GetIfValid(this->vli.index);
if (g != nullptr) {
DoCommandP(0, this->vli.index, (g->replace_protection ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_REPLACE_PROTECTION);
DoCommandP(0, this->vli.index | (GroupFlags::GF_REPLACE_PROTECTION << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION) ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_FLAG);
}
break;
}
@@ -921,7 +921,7 @@ public:
break;
case WID_GL_LIST_GROUP: { // Matrix group
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height);
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
GroupID new_g = id_g >= this->groups.size() ? INVALID_GROUP : this->groups[id_g]->index;
if (this->group_sel != new_g && g->parent != new_g) {
@@ -954,7 +954,7 @@ public:
this->group_over = INVALID_GROUP;
this->SetDirty();
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height);
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;
DoCommandP(0, new_g, vindex | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr);
@@ -1124,7 +1124,7 @@ public:
break;
case WID_GL_LIST_GROUP: { // ... the list of custom groups.
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height);
uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP);
new_group_over = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index;
break;
}

View File

@@ -11,6 +11,7 @@ set(LANG_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/brazilian_portuguese.txt
${CMAKE_CURRENT_SOURCE_DIR}/bulgarian.txt
${CMAKE_CURRENT_SOURCE_DIR}/catalan.txt
${CMAKE_CURRENT_SOURCE_DIR}/chuvash.txt
${CMAKE_CURRENT_SOURCE_DIR}/croatian.txt
${CMAKE_CURRENT_SOURCE_DIR}/czech.txt
${CMAKE_CURRENT_SOURCE_DIR}/danish.txt
@@ -22,13 +23,16 @@ set(LANG_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/faroese.txt
${CMAKE_CURRENT_SOURCE_DIR}/finnish.txt
${CMAKE_CURRENT_SOURCE_DIR}/french.txt
${CMAKE_CURRENT_SOURCE_DIR}/frisian.txt
${CMAKE_CURRENT_SOURCE_DIR}/gaelic.txt
${CMAKE_CURRENT_SOURCE_DIR}/galician.txt
${CMAKE_CURRENT_SOURCE_DIR}/german.txt
${CMAKE_CURRENT_SOURCE_DIR}/greek.txt
${CMAKE_CURRENT_SOURCE_DIR}/hebrew.txt
${CMAKE_CURRENT_SOURCE_DIR}/hindi.txt
${CMAKE_CURRENT_SOURCE_DIR}/hungarian.txt
${CMAKE_CURRENT_SOURCE_DIR}/icelandic.txt
${CMAKE_CURRENT_SOURCE_DIR}/ido.txt
${CMAKE_CURRENT_SOURCE_DIR}/indonesian.txt
${CMAKE_CURRENT_SOURCE_DIR}/irish.txt
${CMAKE_CURRENT_SOURCE_DIR}/italian.txt
@@ -38,9 +42,13 @@ set(LANG_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/latvian.txt
${CMAKE_CURRENT_SOURCE_DIR}/lithuanian.txt
${CMAKE_CURRENT_SOURCE_DIR}/luxembourgish.txt
${CMAKE_CURRENT_SOURCE_DIR}/macedonian.txt
${CMAKE_CURRENT_SOURCE_DIR}/malay.txt
${CMAKE_CURRENT_SOURCE_DIR}/maltese.txt
${CMAKE_CURRENT_SOURCE_DIR}/marathi.txt
${CMAKE_CURRENT_SOURCE_DIR}/norwegian_bokmal.txt
${CMAKE_CURRENT_SOURCE_DIR}/norwegian_nynorsk.txt
${CMAKE_CURRENT_SOURCE_DIR}/persian.txt
${CMAKE_CURRENT_SOURCE_DIR}/polish.txt
${CMAKE_CURRENT_SOURCE_DIR}/portuguese.txt
${CMAKE_CURRENT_SOURCE_DIR}/romanian.txt
@@ -56,6 +64,7 @@ set(LANG_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/thai.txt
${CMAKE_CURRENT_SOURCE_DIR}/traditional_chinese.txt
${CMAKE_CURRENT_SOURCE_DIR}/turkish.txt
${CMAKE_CURRENT_SOURCE_DIR}/urdu.txt
${CMAKE_CURRENT_SOURCE_DIR}/ukrainian.txt
${CMAKE_CURRENT_SOURCE_DIR}/vietnamese.txt
${CMAKE_CURRENT_SOURCE_DIR}/welsh.txt

View File

@@ -1007,6 +1007,8 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardware
STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Selecteer dit vakje om OpenTTD hardwareversnelling te laten gebruiken. De gewijzigde instelling wordt pas van kracht nadat het spel opnieuw is gestart.
STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}De instelling wordt pas van kracht als het spel opnieuw is gestart
STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync
STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Selecteer dit vakje om het scherm verticaal te synchroniseren. De wijziging gaat pas in nadat je het spel opnieuw hebt opgestart. Werkt alleen als hardwareversnelling is ingeschakeld
STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Menupuntgrootte
STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Kiest de grootte van bedieningselementen
@@ -1140,6 +1142,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Instelli
STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtertekst:
STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Alles uitvouwen
STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Alles inklappen
STR_CONFIG_SETTING_RESET_ALL :{BLACK}Alle waarden terugstellen
STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(geen uitleg beschikbaar)
STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standaardwaarde: {ORANGE}{STRING}
STR_CONFIG_SETTING_TYPE :{LTBLUE}Instellingstype: {ORANGE}{STRING}
@@ -1148,6 +1151,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Spelinstellinge
STR_CONFIG_SETTING_TYPE_GAME_INGAME :Spelinstellingen (opgeslagen in bestand; alleen van invloed op huidig spel)
STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Bedrijfsinstellingen (opgeslagen in bestand; alleen van invloed op nieuwe spellen)
STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Bedrijfsinstellingen (opgeslagen in bestand; alleen van invloed op huidig bedrijf)
STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Voorzichtig!
STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Met deze actie herstel je alle spelinstellingen naar hun standaardwaarden.{}Weet je zeker dat je wilt doorgaan?
STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categorie:
STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type:
@@ -2493,7 +2498,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Haven bo
STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Boei plaatsen, deze kan gebruikt worden voor extra tussenstops. Shift schakelt tussen bouwen/inschatting van de kosten
STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Aquaduct bouwen. Shift schakelt tussen bouwen/inschatting van de kosten.
STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Hiermee plaats je watermassa's.{}Maakt een kanaal, tenzij je Ctrl vasthoudt op zeeniveau, dan overstroomt de omgeving.
STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Hiermee maak je rivieren
STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Hiermee maak je rivieren. Ctrl selecteert het gebied diagonaal
# Ship depot construction window
STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Richting van dok

View File

@@ -1006,6 +1006,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Every 12 months
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Language
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Select the interface language to use
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{RAW_STRING} ({NUM}% completed)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullscreen
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Check this box to play OpenTTD fullscreen mode
@@ -2553,6 +2554,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Could no
STR_NETWORK_ERROR_CLIENT_START :{WHITE}Could not connect
STR_NETWORK_ERROR_TIMEOUT :{WHITE}Connection #{NUM} timed out
STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}A protocol error was detected and the connection was closed
STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Your player name has not been set. The name can be set at the top of the Multiplayer window
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision
STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full
@@ -2565,6 +2567,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took
STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your computer is too slow to keep up with the server
STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map
STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server
STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Your player name is not valid
############ Leave those lines in this order!!
STR_NETWORK_ERROR_CLIENT_GENERAL :general error
@@ -2587,6 +2590,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :received no pas
STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :general timeout
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloading map took too long
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :processing map took too long
STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :invalid client name
############ End of leave-in-this-order
STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss

View File

@@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Every 12 months
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Language
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Select the interface language to use
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completed)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullscreen
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Check this box to play OpenTTD fullscreen mode

View File

@@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Kerran vuodessa
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Kieli
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Valitse käyttöliittymän kieli
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}{NBSP}% valmiina)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Koko näyttö
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Valitse tämä pelataksesi kokoruututilassa

1057
src/lang/hindi.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1006,6 +1006,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :12개월마다
STR_GAME_OPTIONS_LANGUAGE :{BLACK}언어
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}사용할 언어를 선택하세요
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% 번역됨)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}전체화면
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}OpenTTD를 전체화면으로 플레이하려면 클릭하세요.
@@ -1298,7 +1299,7 @@ STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :일반적으로
STR_CONFIG_SETTING_SIGNALSIDE :신호기 보이기: {STRING}
STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :선로의 어느 쪽에 신호기를 설치할 지 선택합니다.
STR_CONFIG_SETTING_SIGNALSIDE_LEFT :왼쪽에
STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :행 방향에
STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :자동차 통행 방향에
STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :오른쪽에
STR_CONFIG_SETTING_SHOWFINANCES :연말에 자동으로 재정 창을 띄우기: {STRING}
STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :이 설정을 켜면. 회사의 재정 상태를 확인하기 쉽도록 매년 말에 재정 창이 자동으로 뜹니다.

View File

@@ -1374,6 +1374,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Co 12 miesięcy
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Język
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Wybierz język interfejsu
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} (ukończono {NUM}%)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pełny ekran
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Zaznacz, jeśli chcesz grać w OpenTTD w trybie pełnoekranowym

View File

@@ -1140,6 +1140,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Каждый г
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Язык
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Язык пользовательского интерфейса
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% перевед{P ён ено ено})
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Полноэкранный режим
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Включить/выключить полноэкранный режим
@@ -1150,11 +1151,11 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :Другое
STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM}
STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Аппаратное ускорение
STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Нажмите здесь, чтобы включить/выключить аппаратное ускорение в OpenTTD. После этого игру потребуется перезапустить.
STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Включить/выключить аппаратное ускорение. После этого игру потребуется перезапустить.
STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Эта настройка будет применена только после перезапуска игры
STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}Вертикальная синхронизация
STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Нажмите здесь, чтобы включить/выключить вертикальную синхронизацию. После этого игру потребуется перезапустить. Работает только при включённом аппаратном ускорении.
STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Включить/выключить вертикальную синхронизацию. После этого игру потребуется перезапустить. Работает только при включённом аппаратном ускорении.
STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Размер элементов интерфейса
STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Выберите размер элементов интерфейса

View File

@@ -995,6 +995,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 meses
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Selecciona el idioma a emplear en interfaz del juego
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completo)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pantalla completa
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Marca esta opción para jugar OpenTTD a pantalla completa

View File

@@ -995,6 +995,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 meses
STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma
STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Elegir el idioma de la interfaz
STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completado)
STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pantalla completa
STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Jugar OpenTTD en pantalla completa
@@ -1008,6 +1009,8 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Acelerac
STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Activar esta casilla para intentar emplear la aceleración por hardware. Este cambio solo tiene efecto tras reiniciar el juego
STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Esta configuración solo tendrá efecto después de reiniciar el juego
STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync
STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Activar esta casilla para realizar sincronización vertical de pantalla (VSync). Este cambio solo tiene efecto tras reiniciar el juego y si la aceleración por hardware está activada.
STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Tamaño de la interfaz
STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Elegir el tamaño de los elementos de la interfaz

View File

@@ -58,6 +58,7 @@ struct LanguagePackHeader {
char cases[MAX_NUM_CASES][CASE_GENDER_LEN]; ///< the cases used by this translation
bool IsValid() const;
bool IsReasonablyFinished() const;
/**
* Get the index for the given gender.

View File

@@ -483,7 +483,6 @@ static const char * const _credits[] = {
u8" Ingo von Borstel (planetmaker) - General, Support (since 1.1)",
u8" Remko Bijker (Rubidium) - Lead coder and way more (since 0.4.5)",
u8" Jos\u00e9 Soler (Terkhen) - General coding (since 1.0)",
u8" Leif Linse (Zuu) - AI/Game Script (since 1.2)",
u8"",
u8"Inactive Developers:",
u8" Jean-Fran\u00e7ois Claeys (Belugas) - GUI, NewGRF and more (0.4.5 - 1.0)",
@@ -496,6 +495,7 @@ static const char * const _credits[] = {
u8" Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5)",
u8" Patric Stout (TrueBrain) - NoAI, NoGo, Network (0.3 - 1.2), sys op (active)",
u8" Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3)",
u8" Leif Linse (Zuu) - AI/Game Script (1.2 - 1.6)",
u8"",
u8"Retired Developers:",
u8" Tam\u00e1s Farag\u00f3 (Darkvater) - Ex-Lead coder (0.3 - 0.5)",

View File

@@ -1142,7 +1142,7 @@ static void RegisterConsoleMidiCommands()
{
static bool registered = false;
if (!registered) {
IConsoleCmdRegister("dumpsmf", CmdDumpSMF);
IConsole::CmdRegister("dumpsmf", CmdDumpSMF);
registered = true;
}
}

View File

@@ -340,6 +340,7 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err)
STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER,
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP,
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN,
STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME,
};
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
@@ -722,6 +723,8 @@ void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const c
if (address.GetPort() == 0) return;
if (!NetworkValidateClientName()) return;
strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host));
_settings_client.network.last_port = address.GetPort();
_network_join_as = join_as;

View File

@@ -282,7 +282,6 @@ static void SendChat(const char *buf, DestType type, int dest)
/** Window to enter the chat message in. */
struct NetworkChatWindow : public Window {
DestType dtype; ///< The type of destination.
StringID dest_string; ///< String representation of the destination.
int dest; ///< The identifier of the destination.
QueryString message_editbox; ///< Message editbox.
@@ -307,9 +306,10 @@ struct NetworkChatWindow : public Window {
STR_NULL,
};
assert((uint)this->dtype < lengthof(chat_captions));
this->dest_string = chat_captions[this->dtype];
this->InitNested(type);
this->CreateNestedTree();
this->GetWidget<NWidgetCore>(WID_NC_DESTINATION)->widget_data = chat_captions[this->dtype];
this->FinishInitNested(type);
this->SetFocusedWidget(WID_NC_TEXTBOX);
InvalidateWindowData(WC_NEWS_WINDOW, 0, this->height);
@@ -464,27 +464,13 @@ struct NetworkChatWindow : public Window {
return pt;
}
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
void SetStringParameters(int widget) const override
{
if (widget != WID_NC_DESTINATION) return;
if (this->dtype == DESTTYPE_CLIENT) {
SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name);
}
Dimension d = GetStringBoundingBox(this->dest_string);
d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
*size = maxdim(*size, d);
}
void DrawWidget(const Rect &r, int widget) const override
{
if (widget != WID_NC_DESTINATION) return;
if (this->dtype == DESTTYPE_CLIENT) {
SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name);
}
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, this->dest_string, TC_BLACK, SA_RIGHT);
}
void OnClick(Point pt, int widget, int click_count) override
@@ -532,7 +518,7 @@ static const NWidgetPart _nested_chat_window_widgets[] = {
NWidget(WWT_CLOSEBOX, COLOUR_GREY, WID_NC_CLOSE),
NWidget(WWT_PANEL, COLOUR_GREY, WID_NC_BACKGROUND),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXT, COLOUR_GREY, WID_NC_DESTINATION), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetDataTip(STR_NULL, STR_NULL),
NWidget(WWT_TEXT, COLOUR_GREY, WID_NC_DESTINATION), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetTextColour(TC_BLACK), SetAlignment(SA_TOP | SA_RIGHT), SetDataTip(STR_NULL, STR_NULL),
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NC_TEXTBOX), SetMinimalSize(100, 12), SetPadding(1, 0, 1, 0), SetResize(1, 0),
SetDataTip(STR_NETWORK_CHAT_OSKTITLE, STR_NULL),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NC_SENDBUTTON), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetDataTip(STR_NETWORK_CHAT_SEND, STR_NULL),

View File

@@ -736,6 +736,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
/* The server validates the name when receiving it from clients, so when it is wrong
* here something went really wrong. In the best case the packet got malformed on its
* way too us, in the worst case the server is broken or compromised. */
if (!NetworkIsValidClientName(name)) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
ci = NetworkClientInfo::GetByClientID(client_id);
if (ci != nullptr) {
@@ -781,26 +785,27 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p)
{
static const StringID network_error_strings[] = {
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_GENERAL
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_DESYNC
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_SAVEGAME_FAILED
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_CONNECTION_LOST
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_ILLEGAL_PACKET
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NEWGRF_MISMATCH
STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_AUTHORIZED
STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_EXPECTED
STR_NETWORK_ERROR_WRONG_REVISION, // NETWORK_ERROR_WRONG_REVISION
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NAME_IN_USE
STR_NETWORK_ERROR_WRONG_PASSWORD, // NETWORK_ERROR_WRONG_PASSWORD
STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_COMPANY_MISMATCH
STR_NETWORK_ERROR_KICKED, // NETWORK_ERROR_KICKED
STR_NETWORK_ERROR_CHEATER, // NETWORK_ERROR_CHEATER
STR_NETWORK_ERROR_SERVER_FULL, // NETWORK_ERROR_FULL
STR_NETWORK_ERROR_TOO_MANY_COMMANDS, // NETWORK_ERROR_TOO_MANY_COMMANDS
STR_NETWORK_ERROR_TIMEOUT_PASSWORD, // NETWORK_ERROR_TIMEOUT_PASSWORD
STR_NETWORK_ERROR_TIMEOUT_COMPUTER, // NETWORK_ERROR_TIMEOUT_COMPUTER
STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP
STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_GENERAL
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_DESYNC
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_SAVEGAME_FAILED
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_CONNECTION_LOST
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_ILLEGAL_PACKET
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NEWGRF_MISMATCH
STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_AUTHORIZED
STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_EXPECTED
STR_NETWORK_ERROR_WRONG_REVISION, // NETWORK_ERROR_WRONG_REVISION
STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NAME_IN_USE
STR_NETWORK_ERROR_WRONG_PASSWORD, // NETWORK_ERROR_WRONG_PASSWORD
STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_COMPANY_MISMATCH
STR_NETWORK_ERROR_KICKED, // NETWORK_ERROR_KICKED
STR_NETWORK_ERROR_CHEATER, // NETWORK_ERROR_CHEATER
STR_NETWORK_ERROR_SERVER_FULL, // NETWORK_ERROR_FULL
STR_NETWORK_ERROR_TOO_MANY_COMMANDS, // NETWORK_ERROR_TOO_MANY_COMMANDS
STR_NETWORK_ERROR_TIMEOUT_PASSWORD, // NETWORK_ERROR_TIMEOUT_PASSWORD
STR_NETWORK_ERROR_TIMEOUT_COMPUTER, // NETWORK_ERROR_TIMEOUT_COMPUTER
STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP
STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN
STR_NETWORK_ERROR_INVALID_CLIENT_NAME, // NETWORK_ERROR_INVALID_CLIENT_NAME
};
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
@@ -1414,6 +1419,56 @@ void NetworkClientsToSpectators(CompanyID cid)
cur_company.Restore();
}
/**
* Check whether the given client name is deemed valid for use in network games.
* An empty name (null or '') is not valid as that is essentially no name at all.
* A name starting with white space is not valid for tab completion purposes.
* @param client_name The client name to check for validity.
* @return True iff the name is valid.
*/
bool NetworkIsValidClientName(const char *client_name)
{
if (StrEmpty(client_name)) return false;
if (*client_name == ' ') return false;
return true;
}
/**
* Trim the given client name in place, i.e. remove leading and trailing spaces.
* After the trim check whether the client name is valid. A client name is valid
* whenever the name is not empty and does not start with spaces. This check is
* done via \c NetworkIsValidClientName.
* When the client name is valid, this function returns true.
* When the client name is not valid a GUI error message is shown telling the
* user to set the client name and this function returns false.
*
* This function is not suitable for ensuring a valid client name at the server
* as the error message will then be shown to the host instead of the client.
* @param client_name The client name to validate. It will be trimmed of leading
* and trailing spaces.
* @return True iff the client name is valid.
*/
bool NetworkValidateClientName(char *client_name)
{
StrTrimInPlace(client_name);
if (NetworkIsValidClientName(client_name)) return true;
ShowErrorMessage(STR_NETWORK_ERROR_BAD_PLAYER_NAME, INVALID_STRING_ID, WL_ERROR);
return false;
}
/**
* Convenience method for NetworkValidateClientName on _settings_client.network.client_name.
* It trims the client name and checks whether it is empty. When it is empty
* an error message is shown to the GUI user.
* See \c NetworkValidateClientName(char*) for details about the functionality.
* @return True iff the client name is valid.
*/
bool NetworkValidateClientName()
{
return NetworkValidateClientName(_settings_client.network.client_name);
}
/**
* Send the server our name.
*/
@@ -1422,6 +1477,11 @@ void NetworkUpdateClientName()
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(_network_own_client_id);
if (ci == nullptr) return;
/* There is no validation on string settings, it is actually a post change callback.
* This method is called from that post change callback. So, when the client name is
* changed via the console there is no easy way to prevent an invalid name. Though,
* we can prevent it getting sent here. */
if (!NetworkValidateClientName()) return;
/* Don't change the name if it is the same as the old name */
if (strcmp(ci->client_name, _settings_client.network.client_name) != 0) {

View File

@@ -863,55 +863,31 @@ public:
EventState OnKeyPress(WChar key, uint16 keycode) override
{
switch (keycode) {
case WKC_UP:
/* scroll up by one */
if (this->list_pos > 0) this->list_pos--;
break;
case WKC_DOWN:
/* scroll down by one */
if (this->list_pos < (int)this->content.size() - 1) this->list_pos++;
break;
case WKC_PAGEUP:
/* scroll up a page */
this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity();
break;
case WKC_PAGEDOWN:
/* scroll down a page */
this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.size() - 1);
break;
case WKC_HOME:
/* jump to beginning */
this->list_pos = 0;
break;
case WKC_END:
/* jump to end */
this->list_pos = (int)this->content.size() - 1;
break;
case WKC_SPACE:
case WKC_RETURN:
if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) {
if (this->selected != nullptr) {
_network_content_client.ToggleSelectedState(this->selected);
this->content.ForceResort();
this->InvalidateData();
if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_NOT_HANDLED) {
switch (keycode) {
case WKC_SPACE:
case WKC_RETURN:
if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) {
if (this->selected != nullptr) {
_network_content_client.ToggleSelectedState(this->selected);
this->content.ForceResort();
this->InvalidateData();
}
if (this->filter_data.types.any()) {
this->content.ForceRebuild();
this->InvalidateData();
}
return ES_HANDLED;
}
if (this->filter_data.types.any()) {
this->content.ForceRebuild();
this->InvalidateData();
}
return ES_HANDLED;
}
/* space is pressed and filter is focused. */
FALLTHROUGH;
/* space is pressed and filter is focused. */
FALLTHROUGH;
default:
return ES_NOT_HANDLED;
default:
return ES_NOT_HANDLED;
}
}
if (this->content.size() == 0) {
this->list_pos = 0; // above stuff may result in "-1".
if (this->UpdateFilterState()) {
this->content.ForceRebuild();
this->InvalidateData();

View File

@@ -36,6 +36,9 @@ extern StringList _network_host_list;
extern StringList _network_ban_list;
byte NetworkSpectatorCount();
bool NetworkIsValidClientName(const char *client_name);
bool NetworkValidateClientName();
bool NetworkValidateClientName(char *client_name);
void NetworkUpdateClientName();
bool NetworkCompanyHasClients(CompanyID company);
const char *NetworkChangeCompanyPassword(CompanyID company_id, const char *password);

View File

@@ -68,8 +68,8 @@ void UpdateNetworkGameWindow()
}
typedef GUIList<NetworkGameList*, StringFilter&> GUIGameServerList;
typedef uint16 ServerListPosition;
static const ServerListPosition SLP_INVALID = 0xFFFF;
typedef int ServerListPosition;
static const ServerListPosition SLP_INVALID = -1;
/** Full blown container to make it behave exactly as we want :) */
class NWidgetServerListHeader : public NWidgetContainer {
@@ -786,39 +786,8 @@ public:
EventState state = ES_NOT_HANDLED;
/* handle up, down, pageup, pagedown, home and end */
if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) {
if (this->servers.size() == 0) return ES_HANDLED;
switch (keycode) {
case WKC_UP:
/* scroll up by one */
if (this->list_pos == SLP_INVALID) return ES_HANDLED;
if (this->list_pos > 0) this->list_pos--;
break;
case WKC_DOWN:
/* scroll down by one */
if (this->list_pos == SLP_INVALID) return ES_HANDLED;
if (this->list_pos < this->servers.size() - 1) this->list_pos++;
break;
case WKC_PAGEUP:
/* scroll up a page */
if (this->list_pos == SLP_INVALID) return ES_HANDLED;
this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity();
break;
case WKC_PAGEDOWN:
/* scroll down a page */
if (this->list_pos == SLP_INVALID) return ES_HANDLED;
this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1);
break;
case WKC_HOME:
/* jump to beginning */
this->list_pos = 0;
break;
case WKC_END:
/* jump to end */
this->list_pos = (ServerListPosition)this->servers.size() - 1;
break;
default: NOT_REACHED();
}
if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) {
if (this->list_pos == SLP_INVALID) return ES_HANDLED;
this->server = this->servers[this->list_pos];
@@ -854,12 +823,9 @@ public:
}
case WID_NG_CLIENT:
/* Make sure the name does not start with a space, so TAB completion works */
if (!StrEmpty(this->name_editbox.text.buf) && this->name_editbox.text.buf[0] != ' ') {
strecpy(_settings_client.network.client_name, this->name_editbox.text.buf, lastof(_settings_client.network.client_name));
} else {
strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name));
}
/* Validation of the name will happen once the user tries to join or start a game, as getting
* error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */
strecpy(_settings_client.network.client_name, this->name_editbox.text.buf, lastof(_settings_client.network.client_name));
break;
}
}
@@ -1292,6 +1258,8 @@ static WindowDesc _network_start_server_window_desc(
static void ShowNetworkStartServerWindow()
{
if (!NetworkValidateClientName()) return;
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY);
@@ -1584,6 +1552,8 @@ static WindowDesc _network_lobby_window_desc(
*/
static void ShowNetworkLobbyWindow(NetworkGameList *ngl)
{
if (!NetworkValidateClientName()) return;
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START);
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);

View File

@@ -987,8 +987,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p)
break;
}
/* We need a valid name.. make it Player */
if (StrEmpty(name)) strecpy(name, "Player", lastof(name));
if (!NetworkIsValidClientName(name)) {
/* An invalid client name was given. However, the client ensures the name
* is valid before it is sent over the network, so something went horribly
* wrong. This is probably someone trying to troll us. */
return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
}
if (!NetworkFindName(name, lastof(name))) { // Change name if duplicate
/* We could not create a name for this client */
@@ -1558,6 +1562,13 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
if (ci != nullptr) {
if (!NetworkIsValidClientName(client_name)) {
/* An invalid client name was given. However, the client ensures the name
* is valid before it is sent over the network, so something went horribly
* wrong. This is probably someone trying to troll us. */
return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME);
}
/* Display change */
if (NetworkFindName(client_name, lastof(client_name))) {
NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name);

View File

@@ -133,6 +133,7 @@ enum NetworkErrorCode {
NETWORK_ERROR_TIMEOUT_COMPUTER,
NETWORK_ERROR_TIMEOUT_MAP,
NETWORK_ERROR_TIMEOUT_JOIN,
NETWORK_ERROR_INVALID_CLIENT_NAME,
NETWORK_ERROR_END,
};

View File

@@ -1327,42 +1327,8 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
{
if (!this->editable) return ES_NOT_HANDLED;
switch (keycode) {
case WKC_UP:
/* scroll up by one */
if (this->avail_pos > 0) this->avail_pos--;
break;
if (this->vscroll2->UpdateListPositionOnKeyPress(this->avail_pos, keycode) == ES_NOT_HANDLED) return ES_NOT_HANDLED;
case WKC_DOWN:
/* scroll down by one */
if (this->avail_pos < (int)this->avails.size() - 1) this->avail_pos++;
break;
case WKC_PAGEUP:
/* scroll up a page */
this->avail_pos = (this->avail_pos < this->vscroll2->GetCapacity()) ? 0 : this->avail_pos - this->vscroll2->GetCapacity();
break;
case WKC_PAGEDOWN:
/* scroll down a page */
this->avail_pos = std::min(this->avail_pos + this->vscroll2->GetCapacity(), (int)this->avails.size() - 1);
break;
case WKC_HOME:
/* jump to beginning */
this->avail_pos = 0;
break;
case WKC_END:
/* jump to end */
this->avail_pos = (uint)this->avails.size() - 1;
break;
default:
return ES_NOT_HANDLED;
}
if (this->avails.size() == 0) this->avail_pos = -1;
if (this->avail_pos >= 0) {
this->active_sel = nullptr;
DeleteWindowByClass(WC_GRF_PARAMETERS);

View File

@@ -422,7 +422,7 @@ struct NewsWindow : Window {
{
switch (widget) {
case WID_N_CAPTION:
DrawCaption(r, COLOUR_LIGHT_BLUE, this->owner, STR_NEWS_MESSAGE_CAPTION);
DrawCaption(r, COLOUR_LIGHT_BLUE, this->owner, TC_FROMSTRING, STR_NEWS_MESSAGE_CAPTION, SA_HOR_CENTER);
break;
case WID_N_PANEL:
@@ -1205,7 +1205,7 @@ struct MessageHistoryWindow : Window {
NewsItem *ni = _latest_news;
if (ni == nullptr) return;
for (int n = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_MH_BACKGROUND, WD_FRAMERECT_TOP, this->line_height); n > 0; n--) {
for (int n = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_MH_BACKGROUND, WD_FRAMERECT_TOP); n > 0; n--) {
ni = ni->prev;
if (ni == nullptr) return;
}

View File

@@ -77,8 +77,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,11,0,${REV_ISODATE}
PRODUCTVERSION 1,11,0,${REV_ISODATE}
FILEVERSION ${REV_MAJOR},${REV_MINOR},${REV_BUILD},${REV_ISODATE}
PRODUCTVERSION ${REV_MAJOR},${REV_MINOR},${REV_BUILD},${REV_ISODATE}
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L

View File

@@ -1578,7 +1578,7 @@ public:
break;
case WID_BRAS_NEWST_LIST: {
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST, 0, this->line_height);
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST);
if (y >= (int)this->station_classes.size()) return;
StationClassID station_class_id = this->station_classes[y];
if (_railstation.station_class != station_class_id) {

View File

@@ -91,4 +91,4 @@ const byte _openttd_revision_tagged = ${REV_ISTAG};
* version, thus making comparisons on specific revisions easy.
*/
/** ${REV_ISSTABLETAG} removed */
const uint32 _openttd_newgrf_version = 1 << 28 | 12 << 24 | 0 << 20 | 0 << 19 | 28004;
const uint32 _openttd_newgrf_version = ${REV_MAJOR} << 28 | ${REV_MINOR} << 24 | ${REV_BUILD} << 20 | 0 << 19 | 28004;

View File

@@ -3743,6 +3743,23 @@ bool AfterLoadGame()
}
}
if (IsSavegameVersionBefore(SLV_GROUP_REPLACE_WAGON_REMOVAL)) {
/* Propagate wagon removal flag for compatibility */
/* Temporary bitmask of company wagon removal setting */
uint16 wagon_removal = 0;
for (const Company *c : Company::Iterate()) {
if (c->settings.renew_keep_length) SetBit(wagon_removal, c->index);
}
for (Group *g : Group::Iterate()) {
if (g->flags != 0) {
/* Convert old replace_protection value to flag. */
g->flags = 0;
SetBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION);
}
if (HasBit(wagon_removal, g->owner)) SetBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL);
}
}
/* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */
Station::RecomputeCatchmentForAll();

View File

@@ -21,7 +21,7 @@ static const SaveLoad _group_desc[] = {
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164), // num_vehicle
SLE_VAR(Group, owner, SLE_UINT8),
SLE_VAR(Group, vehicle_type, SLE_UINT8),
SLE_VAR(Group, replace_protection, SLE_BOOL),
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),

View File

@@ -329,6 +329,7 @@ enum SaveLoadVersion : uint16 {
SLV_VEH_MOTION_COUNTER, ///< 288 PR#8591 Desync safe motion counter
SLV_INDUSTRY_TEXT, ///< 289 PR#8576 v1.11.0-RC1 Additional GS text for industries.
SLV_MAPGEN_SETTINGS_REVAMP, ///< 290 PR#8891 v1.11 Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type).
SLV_GROUP_REPLACE_WAGON_REMOVAL, ///< 291 PR#7441 Per-group wagon removal flag.
SL_MAX_VERSION, ///< Highest possible saveload version

View File

@@ -89,14 +89,14 @@
{
EnforcePrecondition(false, IsValidGroup(group_id));
return ScriptObject::DoCommand(0, group_id, enable ? 1 : 0, CMD_SET_GROUP_REPLACE_PROTECTION);
return ScriptObject::DoCommand(0, group_id | GroupFlags::GF_REPLACE_PROTECTION, enable ? 1 : 0, CMD_SET_GROUP_FLAG);
}
/* static */ bool ScriptGroup::GetAutoReplaceProtection(GroupID group_id)
{
if (!IsValidGroup(group_id)) return false;
return ::Group::Get(group_id)->replace_protection;
return HasBit(::Group::Get(group_id)->flags, GroupFlags::GF_REPLACE_PROTECTION);
}
/* static */ int32 ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id)

View File

@@ -36,6 +36,7 @@
#include "querystring_gui.h"
#include "fontcache.h"
#include "zoom_func.h"
#include "rev.h"
#include "video/video_driver.hpp"
#include "music/music_driver.hpp"
@@ -220,7 +221,10 @@ struct GameOptionsWindow : Window {
case WID_GO_LANG_DROPDOWN: { // Setup interface language dropdown
for (uint i = 0; i < _languages.size(); i++) {
auto item = new DropDownListParamStringItem(STR_JUST_RAW_STRING, i, false);
bool hide_language = IsReleasedVersion() && !_languages[i].IsReasonablyFinished();
if (hide_language) continue;
bool hide_percentage = IsReleasedVersion() || _languages[i].missing < _settings_client.gui.missing_strings_threshold;
auto item = new DropDownListParamStringItem(hide_percentage ? STR_JUST_RAW_STRING : STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE, i, false);
if (&_languages[i] == _current_language) {
*selected_index = i;
item->SetParamStr(0, _languages[i].own_name);
@@ -232,6 +236,7 @@ struct GameOptionsWindow : Window {
* entries in the dropdown list. */
item->SetParamStr(0, _languages[i].name);
}
item->SetParam(1, (LANGUAGE_TOTAL_STRINGS - _languages[i].missing) * 100 / LANGUAGE_TOTAL_STRINGS);
list.emplace_back(item);
}
std::sort(list.begin(), list.end(), DropDownListStringItem::NatSortFunc);

View File

@@ -156,9 +156,6 @@ void CheckRedrawStationCoverage(Window *w)
* @param type Cargo type
* @param amount Cargo amount
* @param rating ratings data for that particular cargo
*
* @note Each cargo-bar is 16 pixels wide and 6 pixels high
* @note Each rating 14 pixels wide and 1 pixel high and is 1 pixel below the cargo-bar
*/
static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating)
{
@@ -168,32 +165,33 @@ static void StationsWndShowStationRating(int left, int right, int y, CargoID typ
const CargoSpec *cs = CargoSpec::Get(type);
if (!cs->IsValid()) return;
int padding = ScaleFontTrad(1);
int width = right - left;
int colour = cs->rating_colour;
TextColour tc = GetContrastColour(colour);
uint w = (std::min(amount, units_full) + 5) / 36;
uint w = std::min(amount + 5, units_full) * width / units_full;
int height = GetCharacterHeight(FS_SMALL);
int height = GetCharacterHeight(FS_SMALL) + padding - 1;
/* Draw total cargo (limited) on station (fits into 16 pixels) */
if (w != 0) GfxFillRect(left, y, left + w - 1, y + height, colour);
/* Draw a one pixel-wide bar of additional cargo meter, useful
* for stations with only a small amount (<=30) */
if (w == 0) {
uint rest = amount / 5;
if (amount > 30) {
/* Draw total cargo (limited) on station */
GfxFillRect(left, y, left + w - 1, y + height, colour);
} else {
/* Draw a (scaled) one pixel-wide bar of additional cargo meter, useful
* for stations with only a small amount (<=30) */
uint rest = ScaleFontTrad(amount) / 5;
if (rest != 0) {
w += left;
GfxFillRect(w, y + height - rest, w, y + height, colour);
GfxFillRect(left, y + height - rest, left + padding - 1, y + height, colour);
}
}
DrawString(left + 1, right, y, cs->abbrev, tc);
DrawString(left + padding, right, y, cs->abbrev, tc);
/* Draw green/red ratings bar (fits into 14 pixels) */
y += height + 2;
GfxFillRect(left + 1, y, left + 14, y, PC_RED);
rating = std::min<uint>(rating, rating_full) / 16;
if (rating != 0) GfxFillRect(left + 1, y, left + rating, y, PC_GREEN);
/* Draw green/red ratings bar (fits under the waiting bar) */
y += height + padding + 1;
GfxFillRect(left + padding, y, right - padding - 1, y + padding - 1, PC_RED);
w = std::min<uint>(rating, rating_full) * (width - padding - padding) / rating_full;
if (w != 0) GfxFillRect(left + padding, y, left + w - 1, y + padding - 1, PC_GREEN);
}
typedef GUIList<const Station*> GUIStationList;
@@ -217,6 +215,7 @@ protected:
GUIStationList stations;
Scrollbar *vscroll;
uint rating_width;
/**
* (Re)Build station list
@@ -395,16 +394,17 @@ public:
}
case WID_STL_LIST:
resize->height = FONT_HEIGHT_NORMAL;
resize->height = std::max(FONT_HEIGHT_NORMAL, FONT_HEIGHT_SMALL + ScaleFontTrad(3));
size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM;
break;
case WID_STL_TRAIN:
case WID_STL_TRUCK:
case WID_STL_BUS:
case WID_STL_AIRPLANE:
case WID_STL_SHIP:
size->height = std::max<uint>(FONT_HEIGHT_SMALL, 10) + padding.height;
/* Determine appropriate width for mini station rating graph */
this->rating_width = 0;
const CargoSpec *cs;
FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
this->rating_width = std::max(this->rating_width, GetStringBoundingBox(cs->abbrev).width);
}
/* Approximately match original 16 pixel wide rating bars by multiplying string width by 1.6 */
this->rating_width = this->rating_width * 16 / 10;
break;
case WID_STL_CARGOALL:
@@ -448,6 +448,12 @@ public:
bool rtl = _current_text_dir == TD_RTL;
int max = std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.size());
int y = r.top + WD_FRAMERECT_TOP;
uint line_height = this->GetWidget<NWidgetBase>(widget)->resize_y;
/* Spacing between station name and first rating graph. */
int text_spacing = ScaleFontTrad(5);
/* Spacing between additional rating graphs. */
int rating_spacing = ScaleFontTrad(4);
for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner
const Station *st = this->stations[i];
assert(st->xy != INVALID_TILE);
@@ -458,8 +464,8 @@ public:
SetDParam(0, st->index);
SetDParam(1, st->facilities);
int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION);
x += rtl ? -5 : 5;
int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + (line_height - FONT_HEIGHT_NORMAL) / 2, STR_STATION_LIST_STATION);
x += rtl ? -text_spacing : text_spacing;
/* show cargo waiting and station ratings */
for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) {
@@ -470,17 +476,17 @@ public:
* instead of drawing to the left and then incrementing
* the space. */
if (rtl) {
x -= 20;
x -= rating_width + rating_spacing;
if (x < r.left + WD_FRAMERECT_LEFT) break;
}
StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating);
StationsWndShowStationRating(x, x + rating_width, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating);
if (!rtl) {
x += 20;
x += rating_width + rating_spacing;
if (x > r.right - WD_FRAMERECT_RIGHT) break;
}
}
}
y += FONT_HEIGHT_NORMAL;
y += line_height;
}
if (this->vscroll->GetCount() == 0) { // company has no stations
@@ -491,30 +497,30 @@ public:
}
case WID_STL_NOCARGOWAITING: {
int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER);
int cg_ofst = this->IsWidgetLowered(widget) ? 1 : 0;
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER);
break;
}
case WID_STL_CARGOALL: {
int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
int cg_ofst = this->IsWidgetLowered(widget) ? 1 : 0;
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
break;
}
case WID_STL_FACILALL: {
int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1;
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
int cg_ofst = this->IsWidgetLowered(widget) ? 1 : 0;
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER);
break;
}
default:
if (widget >= WID_STL_CARGOSTART) {
const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART];
int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1;
GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour);
int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 1 : 0;
GfxFillRect(r.left + cg_ofst + 1, r.top + cg_ofst + 1, r.right - 1 + cg_ofst, r.bottom - 1 + cg_ofst, cs->rating_colour);
TextColour tc = GetContrastColour(cs->rating_colour);
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER);
DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER);
}
break;
}
@@ -532,7 +538,7 @@ public:
{
switch (widget) {
case WID_STL_LIST: {
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL);
uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST);
if (id_v >= this->stations.size()) return; // click out of list bound
const Station *st = this->stations[id_v];
@@ -723,7 +729,8 @@ static NWidgetBase *CargoWidgets(int *biggest_index)
for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) {
NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
panel->SetMinimalSize(14, 11);
panel->SetMinimalSize(14, 0);
panel->SetMinimalTextLines(1, 0, FS_NORMAL);
panel->SetResize(0, 0);
panel->SetFill(0, 1);
panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
@@ -742,16 +749,16 @@ static const NWidgetPart _nested_company_stations_widgets[] = {
NWidget(WWT_STICKYBOX, COLOUR_GREY),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 11), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 11), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 11), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 11), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 11), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1),
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1),
NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1),
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 0), SetFill(0, 1), EndContainer(),
NWidgetFunction(CargoWidgets),
NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(),
NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1),
NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(),
NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1),
NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL),
@@ -1922,7 +1929,7 @@ struct StationViewWindow : public Window {
{
switch (widget) {
case WID_SV_WAITING:
this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition());
this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP) - this->vscroll->GetPosition());
break;
case WID_SV_CATCHMENT:

View File

@@ -273,13 +273,14 @@ struct HeaderFileWriter : HeaderWriter, FileWriter {
const char *real_filename;
/** The previous string ID that was printed. */
int prev;
uint total_strings;
/**
* Open a file to write to.
* @param filename The file to open.
*/
HeaderFileWriter(const char *filename) : FileWriter("tmp.xxx"),
real_filename(stredup(filename)), prev(0)
real_filename(stredup(filename)), prev(0), total_strings(0)
{
fprintf(this->fh, "/* This file is automatically generated. Do not modify */\n\n");
fprintf(this->fh, "#ifndef TABLE_STRINGS_H\n");
@@ -297,6 +298,7 @@ struct HeaderFileWriter : HeaderWriter, FileWriter {
if (prev + 1 != stringid) fprintf(this->fh, "\n");
fprintf(this->fh, "static const StringID %s = 0x%X;\n", name, stringid);
prev = stringid;
total_strings++;
}
void Finalise(const StringData &data)
@@ -311,8 +313,10 @@ struct HeaderFileWriter : HeaderWriter, FileWriter {
"\n"
"static const uint LANGUAGE_PACK_VERSION = 0x%X;\n"
"static const uint LANGUAGE_MAX_PLURAL = %u;\n"
"static const uint LANGUAGE_MAX_PLURAL_FORMS = %d;\n\n",
(uint)data.Version(), (uint)lengthof(_plural_forms), max_plural_forms
"static const uint LANGUAGE_MAX_PLURAL_FORMS = %d;\n"
"static const uint LANGUAGE_TOTAL_STRINGS = %u;\n"
"\n",
(uint)data.Version(), (uint)lengthof(_plural_forms), max_plural_forms, total_strings
);
fprintf(this->fh, "#endif /* TABLE_STRINGS_H */\n");

View File

@@ -334,6 +334,66 @@ bool StrValid(const char *str, const char *last)
return *str == '\0';
}
/**
* Trim the spaces from the begin of given string in place, i.e. the string buffer
* that is passed will be modified whenever spaces exist in the given string.
* When there are spaces at the begin, the whole string is moved forward.
* @param str The string to perform the in place left trimming on.
*/
static void StrLeftTrimInPlace(char *str)
{
if (StrEmpty(str)) return;
char *first_non_space = str;
while (*first_non_space == ' ') first_non_space++;
if (first_non_space == str) return;
/* The source will reach '\0' first, but set the '\0' on the destination afterwards. */
char *dst = str;
for (char *src = first_non_space; *src != '\0'; dst++, src++) *dst = *src;
*dst = '\0';
}
/**
* Trim the spaces from the end of given string in place, i.e. the string buffer
* that is passed will be modified whenever spaces exist in the given string.
* When there are spaces at the end, the '\0' will be moved forward.
* @param str The string to perform the in place left trimming on.
*/
static void StrRightTrimInPlace(char *str)
{
if (StrEmpty(str)) return;
char *end = str;
while (*end != '\0') end++;
char *last_non_space = end - 1;
while (last_non_space >= str && *last_non_space == ' ') last_non_space--;
/* The last non space points to the last character of the string that is not
* a space. For a string with only spaces or an empty string this would be
* the position before the begin of the string. The previous search ensures
* that this location before the string is not read.
* In any case, the character after the last non space character will be
* either a space or the existing termination, so it can be set to '\0'.
*/
last_non_space[1] = '\0';
}
/**
* Trim the spaces from given string in place, i.e. the string buffer that
* is passed will be modified whenever spaces exist in the given string.
* When there are spaces at the begin, the whole string is moved forward
* and when there are spaces at the back the '\0' termination is moved.
* @param str The string to perform the in place trimming on.
*/
void StrTrimInPlace(char *str)
{
StrLeftTrimInPlace(str);
StrRightTrimInPlace(str);
}
/** Scans the string for colour codes and strips them */
void str_strip_colours(char *str)
{

View File

@@ -54,6 +54,7 @@ bool strtolower(char *str);
bool strtolower(std::string &str, std::string::size_type offs = 0);
bool StrValid(const char *str, const char *last);
void StrTrimInPlace(char *str);
/**
* Check if a string buffer is empty.

View File

@@ -2058,6 +2058,15 @@ bool LanguagePackHeader::IsValid() const
StrValid(this->digit_decimal_separator, lastof(this->digit_decimal_separator));
}
/**
* Check whether a translation is sufficiently finished to offer it to the public.
*/
bool LanguagePackHeader::IsReasonablyFinished() const
{
/* "Less than 25% missing" is "sufficiently finished". */
return 4 * this->missing < LANGUAGE_TOTAL_STRINGS;
}
/**
* Read a particular language.
* @param lang The metadata about the language.
@@ -2312,6 +2321,10 @@ void InitializeLanguagePacks()
}
if (strcmp (lng.isocode, "en_GB") == 0) en_GB_fallback = &lng;
/* Only auto-pick finished translations */
if (!lng.IsReasonablyFinished()) continue;
if (strncmp(lng.isocode, lang, 5) == 0) chosen_language = &lng;
if (strncmp(lng.isocode, lang, 2) == 0) language_fallback = &lng;
}

View File

@@ -50,14 +50,14 @@ void Subsidy::AwardTo(CompanyID company)
char *cn = stredup(company_name);
/* Add a news item */
Pair reftype = SetupSubsidyDecodeParam(this, false);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(this, false);
InjectDParam(1);
SetDParamStr(0, cn);
AddNewsItem(
STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier,
NT_SUBSIDIES, NF_NORMAL,
(NewsReferenceType)reftype.a, this->src, (NewsReferenceType)reftype.b, this->dst,
reftype.first, this->src, reftype.second, this->dst,
cn
);
AI::BroadcastNewEvent(new ScriptEventSubsidyAwarded(this->index));
@@ -72,7 +72,7 @@ void Subsidy::AwardTo(CompanyID company)
* @param mode Unit of cargo used, \c true means general name, \c false means singular form.
* @return Reference of the subsidy in the news system.
*/
Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
{
NewsReferenceType reftype1 = NR_NONE;
NewsReferenceType reftype2 = NR_NONE;
@@ -107,10 +107,7 @@ Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode)
}
SetDParam(5, s->dst);
Pair p;
p.a = reftype1;
p.b = reftype2;
return p;
return std::pair<NewsReferenceType, NewsReferenceType>(reftype1, reftype2);
}
/**
@@ -219,8 +216,8 @@ void CreateSubsidy(CargoID cid, SourceType src_type, SourceID src, SourceType ds
s->remaining = SUBSIDY_OFFER_MONTHS;
s->awarded = INVALID_COMPANY;
Pair reftype = SetupSubsidyDecodeParam(s, false);
AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, false);
AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC);
SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST);
AI::BroadcastNewEvent(new ScriptEventSubsidyOffer(s->index));
@@ -494,14 +491,14 @@ void SubsidyMonthlyLoop()
for (Subsidy *s : Subsidy::Iterate()) {
if (--s->remaining == 0) {
if (!s->IsAwarded()) {
Pair reftype = SetupSubsidyDecodeParam(s, true);
AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, true);
AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
AI::BroadcastNewEvent(new ScriptEventSubsidyOfferExpired(s->index));
Game::NewEvent(new ScriptEventSubsidyOfferExpired(s->index));
} else {
if (s->awarded == _local_company) {
Pair reftype = SetupSubsidyDecodeParam(s, true);
AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst);
std::pair<NewsReferenceType, NewsReferenceType> reftype = SetupSubsidyDecodeParam(s, true);
AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst);
}
AI::BroadcastNewEvent(new ScriptEventSubsidyExpired(s->index));
Game::NewEvent(new ScriptEventSubsidyExpired(s->index));

View File

@@ -14,8 +14,9 @@
#include "station_type.h"
#include "company_type.h"
#include "cargo_type.h"
#include "news_type.h"
Pair SetupSubsidyDecodeParam(const struct Subsidy *s, bool mode);
std::pair<NewsReferenceType, NewsReferenceType> SetupSubsidyDecodeParam(const struct Subsidy *s, bool mode);
void DeleteSubsidyWith(SourceType type, SourceID index);
bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st);
void RebuildSubsidisedSourceAndDestinationCache();

View File

@@ -3458,7 +3458,7 @@ public:
break;
case WID_TRSL_LIST_SLOTS: { // Matrix Slot
uint id_s = this->slot_sb->GetScrolledRowFromWidget(pt.y, this, WID_TRSL_LIST_SLOTS, 0, this->tiny_step_height);
uint id_s = this->slot_sb->GetScrolledRowFromWidget(pt.y, this, WID_TRSL_LIST_SLOTS, 0);
if (id_s >= this->slots.size()) return;
this->slot_sel = this->vli.index = this->slots[id_s]->index;
@@ -3526,7 +3526,7 @@ public:
this->slot_over = INVALID_GROUP;
this->SetDirty();
uint id_s = this->slot_sb->GetScrolledRowFromWidget(pt.y, this, WID_TRSL_LIST_SLOTS, 0, this->tiny_step_height);
uint id_s = this->slot_sb->GetScrolledRowFromWidget(pt.y, this, WID_TRSL_LIST_SLOTS, 0);
if (id_s >= this->slots.size()) return; // click out of list bound
if (_ctrl_pressed) {
@@ -3627,7 +3627,7 @@ public:
break;
case WID_TRSL_LIST_SLOTS: { // ... the list of slots.
uint id_s = this->slot_sb->GetScrolledRowFromWidget(pt.y, this, WID_TRSL_LIST_SLOTS, 0, this->tiny_step_height);
uint id_s = this->slot_sb->GetScrolledRowFromWidget(pt.y, this, WID_TRSL_LIST_SLOTS, 0);
if (id_s < this->slots.size()) new_slot_over = this->slots[id_s]->index;
break;
}
@@ -3959,7 +3959,7 @@ public:
{
switch (widget) {
case WID_TRCL_LIST_COUNTERS: { // Matrix
uint id_s = this->sb->GetScrolledRowFromWidget(pt.y, this, WID_TRCL_LIST_COUNTERS, 0, this->tiny_step_height);
uint id_s = this->sb->GetScrolledRowFromWidget(pt.y, this, WID_TRCL_LIST_COUNTERS, 0);
if (id_s >= this->ctrs.size()) return;
this->selected = this->ctrs[id_s]->index;

View File

@@ -254,7 +254,7 @@ const char *VideoDriver_CocoaOpenGL::AllocateContext(bool allow_software)
CGLSetCurrentContext(this->gl_context);
return OpenGLBackend::Create(&GetOGLProcAddressCallback);
return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize());
}
NSView *VideoDriver_CocoaOpenGL::AllocateDrawView()

View File

@@ -464,16 +464,17 @@ void SetupDebugOutput()
/**
* Create and initialize the singleton back-end class.
* @param get_proc Callback to get an OpenGL function from the OS driver.
* @param screen_res Current display resolution.
* @return nullptr on success, error message otherwise.
*/
/* static */ const char *OpenGLBackend::Create(GetOGLProcAddressProc get_proc)
/* static */ const char *OpenGLBackend::Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res)
{
if (OpenGLBackend::instance != nullptr) OpenGLBackend::Destroy();
GetOGLProcAddress = get_proc;
OpenGLBackend::instance = new OpenGLBackend();
return OpenGLBackend::instance->Init();
return OpenGLBackend::instance->Init(screen_res);
}
/**
@@ -521,9 +522,10 @@ OpenGLBackend::~OpenGLBackend()
/**
* Check for the needed OpenGL functionality and allocate all resources.
* @param screen_res Current display resolution.
* @return Error string or nullptr if successful.
*/
const char *OpenGLBackend::Init()
const char *OpenGLBackend::Init(const Dimension &screen_res)
{
if (!BindBasicInfoProcs()) return "OpenGL not supported";
@@ -546,6 +548,12 @@ const char *OpenGLBackend::Init()
_gl_major_ver = atoi(ver);
_gl_minor_ver = minor != nullptr ? atoi(minor + 1) : 0;
#ifdef _WIN32
/* Old drivers on Windows (especially if made by Intel) seem to be
* unstable, so cull the oldest stuff here. */
if (!IsOpenGLVersionAtLeast(3, 2)) return "Need at least OpenGL version 3.2 on Windows";
#endif
if (!BindBasicOpenGLProcs()) return "Failed to bind basic OpenGL functions.";
SetupDebugOutput();
@@ -581,6 +589,11 @@ const char *OpenGLBackend::Init()
}
if (this->persistent_mapping_supported) DEBUG(driver, 3, "OpenGL: Using persistent buffer mapping");
/* Check maximum texture size against screen resolution. */
GLint max_tex_size = 0;
_glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
if (std::max(screen_res.width, screen_res.height) > (uint)max_tex_size) return "Max supported texture size is too small";
/* Check available texture units. */
GLint max_tex_units = 0;
_glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_tex_units);

View File

@@ -74,7 +74,7 @@ private:
OpenGLBackend();
~OpenGLBackend();
const char *Init();
const char *Init(const Dimension &screen_res);
bool InitShaders();
void InternalClearCursorCache();
@@ -87,7 +87,7 @@ public:
{
return OpenGLBackend::instance;
}
static const char *Create(GetOGLProcAddressProc get_proc);
static const char *Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res);
static void Destroy();
void PrepareContext();

View File

@@ -121,7 +121,7 @@ const char *VideoDriver_SDL_OpenGL::AllocateContext()
ToggleVsync(_video_vsync);
return OpenGLBackend::Create(&GetOGLProcAddressCallback);
return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize());
}
void VideoDriver_SDL_OpenGL::PopulateSystemSprites()

View File

@@ -1368,14 +1368,22 @@ const char *VideoDriver_Win32OpenGL::AllocateContext()
/* Create OpenGL device context. Try to get an 3.2+ context if possible. */
if (_wglCreateContextAttribsARB != nullptr) {
/* Try for OpenGL 4.5 first. */
int attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
WGL_CONTEXT_MINOR_VERSION_ARB, 5,
WGL_CONTEXT_FLAGS_ARB, _debug_driver_level >= 8 ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
_hasWGLARBCreateContextProfile ? WGL_CONTEXT_PROFILE_MASK_ARB : 0, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, // Terminate list if WGL_ARB_create_context_profile isn't supported.
0
};
rc = _wglCreateContextAttribsARB(this->dc, nullptr, attribs);
if (rc == nullptr) {
/* Try again for a 3.2 context. */
attribs[1] = 3;
attribs[3] = 2;
rc = _wglCreateContextAttribsARB(this->dc, nullptr, attribs);
}
}
if (rc == nullptr) {
@@ -1388,7 +1396,7 @@ const char *VideoDriver_Win32OpenGL::AllocateContext()
this->ToggleVsync(_video_vsync);
this->gl_rc = rc;
return OpenGLBackend::Create(&GetOGLProcAddressCallback);
return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize());
}
bool VideoDriver_Win32OpenGL::ToggleFullscreen(bool full_screen)

View File

@@ -24,6 +24,33 @@
#include "safeguards.h"
/**
* Calculate x and y coordinates for an aligned object within a window.
* @param r Rectangle of the widget to be drawn in.
* @param d Dimension of the object to be drawn.
* @param align Alignment of the object.
* @return A point containing the position at which to draw.
*/
static inline Point GetAlignedPosition(const Rect &r, const Dimension &d, StringAlignment align)
{
Point p;
/* In case we have a RTL language we swap the alignment. */
if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT;
switch (align & SA_HOR_MASK) {
case SA_LEFT: p.x = r.left; break;
case SA_HOR_CENTER: p.x = CenterBounds(r.left, r.right, d.width); break;
case SA_RIGHT: p.x = r.right - d.width; break;
default: NOT_REACHED();
}
switch (align & SA_VERT_MASK) {
case SA_TOP: p.y = r.top; break;
case SA_VERT_CENTER: p.y = CenterBounds(r.top, r.bottom, d.height); break;
case SA_BOTTOM: p.y = r.bottom - d.height; break;
default: NOT_REACHED();
}
return p;
}
/**
* Compute the vertical position of the draggable part of scrollbar
* @param sb Scrollbar list data
@@ -212,15 +239,17 @@ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, Fra
* @param colour Colour of the button.
* @param clicked Button is lowered.
* @param img Sprite to draw.
* @param align Alignment of the sprite.
*/
static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img)
static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img, StringAlignment align)
{
assert(img != 0);
DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE);
if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; // Show different image when clicked for #WWT_IMGBTN_2.
Dimension d = GetSpriteSize(img);
DrawSprite(img, PAL_NONE, CenterBounds(r.left, r.right, d.width) + clicked, CenterBounds(r.top, r.bottom, d.height) + clicked);
Point p = GetAlignedPosition(r, d, align);
DrawSprite(img, PAL_NONE, p.x + clicked, p.y + clicked);
}
/**
@@ -228,15 +257,17 @@ static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colo
* @param r Rectangle of the label background.
* @param type Widget type (#WWT_TEXTBTN, #WWT_TEXTBTN_2, or #WWT_LABEL).
* @param clicked Label is rendered lowered.
* @param colour Colour of the text.
* @param str Text to draw.
* @param align Alignment of the text.
*/
static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, StringID str)
static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, TextColour colour, StringID str, StringAlignment align)
{
if (str == STR_NULL) return;
if ((type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++;
Dimension d = GetStringBoundingBox(str);
int offset = std::max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered
DrawString(r.left + clicked, r.right + clicked, r.top + offset + clicked, str, TC_FROMSTRING, SA_HOR_CENTER);
Point p = GetAlignedPosition(r, d, align);
DrawString(r.left + clicked, r.right + clicked, p.y + clicked, str, colour, align);
}
/**
@@ -244,24 +275,27 @@ static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, Strin
* @param r Rectangle of the background.
* @param colour Colour of the text.
* @param str Text to draw.
* @param align Alignment of the text.
*/
static inline void DrawText(const Rect &r, TextColour colour, StringID str)
static inline void DrawText(const Rect &r, TextColour colour, StringID str, StringAlignment align)
{
Dimension d = GetStringBoundingBox(str);
int offset = std::max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered
if (str != STR_NULL) DrawString(r.left, r.right, r.top + offset, str, colour);
Point p = GetAlignedPosition(r, d, align);
if (str != STR_NULL) DrawString(r.left, r.right, p.y, str, colour, align);
}
/**
* Draw an inset widget.
* @param r Rectangle of the background.
* @param colour Colour of the inset.
* @param str Text to draw.
* @param r Rectangle of the background.
* @param colour Colour of the inset.
* @param text_colour Colour of the text.
* @param str Text to draw.
* @param align Alignment of the text.
*/
static inline void DrawInset(const Rect &r, Colours colour, StringID str)
static inline void DrawInset(const Rect &r, Colours colour, TextColour text_colour, StringID str, StringAlignment align)
{
DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_LOWERED | FR_DARKENED);
if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str);
if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str, text_colour, align);
}
/**
@@ -402,15 +436,17 @@ static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool l
/**
* Draw a frame widget.
* @param r Rectangle of the frame.
* @param colour Colour of the frame.
* @param str Text of the frame.
* @param r Rectangle of the frame.
* @param colour Colour of the frame.
* @param text_colour Colour of the text.
* @param str Text of the frame.
* @param align Alignment of the text in the frame.
*/
static inline void DrawFrame(const Rect &r, Colours colour, StringID str)
static inline void DrawFrame(const Rect &r, Colours colour, TextColour text_colour, StringID str, StringAlignment align)
{
int x2 = r.left; // by default the left side is the left side of the widget
if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str);
if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str, text_colour, align);
int c1 = _colour_gradient[colour][3];
int c2 = _colour_gradient[colour][7];
@@ -458,7 +494,7 @@ static inline void DrawFrame(const Rect &r, Colours colour, StringID str)
*/
static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked)
{
DrawImageButtons(r, WWT_SHADEBOX, colour, clicked, clicked ? SPR_WINDOW_SHADE: SPR_WINDOW_UNSHADE);
DrawImageButtons(r, WWT_SHADEBOX, colour, clicked, clicked ? SPR_WINDOW_SHADE: SPR_WINDOW_UNSHADE, SA_CENTER);
}
/**
@@ -469,7 +505,7 @@ static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked)
*/
static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked)
{
DrawImageButtons(r, WWT_STICKYBOX, colour, clicked, clicked ? SPR_PIN_UP : SPR_PIN_DOWN);
DrawImageButtons(r, WWT_STICKYBOX, colour, clicked, clicked ? SPR_PIN_UP : SPR_PIN_DOWN, SA_CENTER);
}
/**
@@ -480,7 +516,7 @@ static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked)
*/
static inline void DrawDefSizeBox(const Rect &r, Colours colour, bool clicked)
{
DrawImageButtons(r, WWT_DEFSIZEBOX, colour, clicked, SPR_WINDOW_DEFSIZE);
DrawImageButtons(r, WWT_DEFSIZEBOX, colour, clicked, SPR_WINDOW_DEFSIZE, SA_CENTER);
}
/**
@@ -491,7 +527,7 @@ static inline void DrawDefSizeBox(const Rect &r, Colours colour, bool clicked)
*/
static inline void DrawDebugBox(const Rect &r, Colours colour, bool clicked)
{
DrawImageButtons(r, WWT_DEBUGBOX, colour, clicked, SPR_WINDOW_DEBUG);
DrawImageButtons(r, WWT_DEBUGBOX, colour, clicked, SPR_WINDOW_DEBUG, SA_CENTER);
}
/**
@@ -530,12 +566,14 @@ static inline void DrawCloseBox(const Rect &r, Colours colour)
/**
* Draw a caption bar.
* @param r Rectangle of the bar.
* @param colour Colour of the window.
* @param owner 'Owner' of the window.
* @param str Text to draw in the bar.
* @param r Rectangle of the bar.
* @param colour Colour of the window.
* @param owner 'Owner' of the window.
* @param text_colour Colour of the text.
* @param str Text to draw in the bar.
* @param align Alignment of the text.
*/
void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str)
void DrawCaption(const Rect &r, Colours colour, Owner owner, TextColour text_colour, StringID str, StringAlignment align)
{
bool company_owned = owner < MAX_COMPANIES;
@@ -548,8 +586,8 @@ void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str)
if (str != STR_NULL) {
Dimension d = GetStringBoundingBox(str);
int offset = std::max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered
DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, r.top + offset, str, TC_FROMSTRING, SA_HOR_CENTER);
Point p = GetAlignedPosition(r, d, align);
DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, p.y, str, text_colour, align);
}
}
@@ -560,10 +598,11 @@ void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str)
* @param clicked_button The button-part is lowered.
* @param clicked_dropdown The drop-down part is lowered.
* @param str Text of the button.
* @param align Alignment of the text within the dropdown.
*
* @note Magic constants are also used in #NWidgetLeaf::ButtonHit.
*/
static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str)
static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str, StringAlignment align)
{
int text_offset = std::max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered
@@ -575,12 +614,12 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke
DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE);
DrawFrameRect(r.right + 1 - dd_width, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE);
DrawSprite(SPR_ARROW_DOWN, PAL_NONE, r.right - (dd_width - 2) + clicked_dropdown, r.top + image_offset + clicked_dropdown);
if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK);
if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK, align);
} else {
DrawFrameRect(r.left + dd_width, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE);
DrawFrameRect(r.left, r.top, r.left + dd_width - 1, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE);
DrawSprite(SPR_ARROW_DOWN, PAL_NONE, r.left + 1 + clicked_dropdown, r.top + image_offset + clicked_dropdown);
if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK);
if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK, align);
}
}
@@ -590,10 +629,11 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke
* @param colour Background colour of the widget.
* @param clicked The widget is lowered.
* @param str Text of the button.
* @param align Alignment of the text.
*/
static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str)
static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str, StringAlignment align)
{
DrawButtonDropdown(r, colour, false, clicked, str);
DrawButtonDropdown(r, colour, false, clicked, str, align);
}
/**
@@ -871,6 +911,8 @@ NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y
this->widget_data = widget_data;
this->tool_tip = tool_tip;
this->scrollbar_index = -1;
this->text_colour = TC_FROMSTRING;
this->align = SA_CENTER;
}
/**
@@ -894,6 +936,15 @@ void NWidgetCore::SetDataTip(uint32 widget_data, StringID tool_tip)
this->tool_tip = tool_tip;
}
/**
* Set the text colour of the nested widget.
* @param colour TextColour to use.
*/
void NWidgetCore::SetTextColour(TextColour colour)
{
this->text_colour = colour;
}
/**
* Set the tool tip of the nested widget.
* @param tool_tip Tool tip string to use.
@@ -903,6 +954,15 @@ void NWidgetCore::SetToolTip(StringID tool_tip)
this->tool_tip = tool_tip;
}
/**
* Set the text/image alignment of the nested widget.
* @param align Alignment to use.
*/
void NWidgetCore::SetAlignment(StringAlignment align)
{
this->align = align;
}
void NWidgetCore::FillNestedArray(NWidgetBase **array, uint length)
{
if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this;
@@ -1774,6 +1834,7 @@ NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, N
assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME);
if (index >= 0) this->SetIndex(index);
this->child = child;
this->SetAlignment(SA_TOP | SA_LEFT);
}
NWidgetBackground::~NWidgetBackground()
@@ -1910,12 +1971,12 @@ void NWidgetBackground::Draw(const Window *w)
case WWT_FRAME:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawFrame(r, this->colour, this->widget_data);
DrawFrame(r, this->colour, this->text_colour, this->widget_data, this->align);
break;
case WWT_INSET:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawInset(r, this->colour, this->widget_data);
DrawInset(r, this->colour, this->text_colour, this->widget_data, this->align);
break;
default:
@@ -2030,16 +2091,75 @@ void NWidgetViewport::UpdateViewportCoordinates(Window *w)
* @param w The window the click was in.
* @param widget Widget number of the widget clicked in.
* @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0.
* @param line_height Height of a single row. A negative value means using the vertical resize step of the widget.
* @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned.
*/
int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const
int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding) const
{
uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height);
uint pos = w->GetRowFromWidget(clickpos, widget, padding, -1);
if (pos != INT_MAX) pos += this->GetPosition();
return (pos >= this->GetCount()) ? INT_MAX : pos;
}
/**
* Update the given list position as if it were on this scroll bar when the given keycode was pressed.
* This does not update the actual position of this scroll bar, that is left to the caller. It does,
* however use the capacity and count of the scroll bar for the bounds and amount to scroll.
*
* When the count is 0 or the return is ES_NOT_HANDLED, then the position is not updated.
* With WKC_UP and WKC_DOWN the position goes one up or down respectively.
* With WKC_PAGEUP and WKC_PAGEDOWN the position goes one capacity up or down respectively.
* With WKC_HOME the first position is selected and with WKC_END the last position is selected.
* This function ensures that pos is in the range [0..count).
* @param list_position The current position in the list.
* @param key_code The pressed key code.
* @return ES_NOT_HANDLED when another key than the 6 specific keys was pressed, otherwise ES_HANDLED.
*/
EventState Scrollbar::UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const
{
int new_pos = list_position;
switch (keycode) {
case WKC_UP:
/* scroll up by one */
new_pos--;
break;
case WKC_DOWN:
/* scroll down by one */
new_pos++;
break;
case WKC_PAGEUP:
/* scroll up a page */
new_pos -= this->GetCapacity();
break;
case WKC_PAGEDOWN:
/* scroll down a page */
new_pos += this->GetCapacity();
break;
case WKC_HOME:
/* jump to beginning */
new_pos = 0;
break;
case WKC_END:
/* jump to end */
new_pos = this->GetCount() - 1;
break;
default:
return ES_NOT_HANDLED;
}
/* If there are no elements, there is nothing to scroll/update. */
if (this->GetCount() != 0) {
list_position = Clamp(new_pos, 0, this->GetCount() - 1);
}
return ES_HANDLED;
}
/**
* Set capacity of visible elements from the size and resize properties of a widget.
* @param w Window.
@@ -2202,6 +2322,11 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data,
case WWT_EMPTY:
break;
case WWT_TEXT:
this->SetFill(0, 0);
this->SetAlignment(SA_LEFT | SA_VERT_CENTER);
break;
case WWT_PUSHBTN:
case WWT_IMGBTN:
case WWT_PUSHIMGBTN:
@@ -2210,7 +2335,6 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data,
case WWT_PUSHTXTBTN:
case WWT_TEXTBTN_2:
case WWT_LABEL:
case WWT_TEXT:
case WWT_MATRIX:
case NWID_BUTTON_DROPDOWN:
case NWID_PUSHBUTTON_DROPDOWN:
@@ -2269,6 +2393,7 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data,
case WWT_DROPDOWN:
this->SetFill(0, 0);
this->min_y = WD_DROPDOWN_HEIGHT;
this->SetAlignment(SA_TOP | SA_LEFT);
break;
default:
@@ -2506,7 +2631,7 @@ void NWidgetLeaf::Draw(const Window *w)
case WWT_IMGBTN:
case WWT_PUSHIMGBTN:
case WWT_IMGBTN_2:
DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data);
DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data, this->align);
break;
case WWT_TEXTBTN:
@@ -2514,7 +2639,7 @@ void NWidgetLeaf::Draw(const Window *w)
case WWT_TEXTBTN_2:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE);
DrawLabel(r, this->type, clicked, this->widget_data);
DrawLabel(r, this->type, clicked, this->text_colour, this->widget_data, this->align);
break;
case WWT_ARROWBTN:
@@ -2527,18 +2652,18 @@ void NWidgetLeaf::Draw(const Window *w)
case AWV_RIGHT: sprite = SPR_ARROW_RIGHT; break;
default: NOT_REACHED();
}
DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite);
DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite, this->align);
break;
}
case WWT_LABEL:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawLabel(r, this->type, clicked, this->widget_data);
DrawLabel(r, this->type, clicked, this->text_colour, this->widget_data, this->align);
break;
case WWT_TEXT:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawText(r, (TextColour)this->colour, this->widget_data);
DrawText(r, this->text_colour, this->widget_data, this->align);
break;
case WWT_MATRIX:
@@ -2553,7 +2678,7 @@ void NWidgetLeaf::Draw(const Window *w)
case WWT_CAPTION:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawCaption(r, this->colour, w->owner, this->widget_data);
DrawCaption(r, this->colour, w->owner, this->text_colour, this->widget_data, this->align);
break;
case WWT_SHADEBOX:
@@ -2586,13 +2711,13 @@ void NWidgetLeaf::Draw(const Window *w)
case WWT_DROPDOWN:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawDropdown(r, this->colour, clicked, this->widget_data);
DrawDropdown(r, this->colour, clicked, this->widget_data, this->align);
break;
case NWID_BUTTON_DROPDOWN:
case NWID_PUSHBUTTON_DROPDOWN:
if (this->index >= 0) w->SetStringParameters(this->index);
DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data);
DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data, this->align);
break;
default:
@@ -2731,6 +2856,22 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest,
break;
}
case WPT_TEXTCOLOUR: {
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
if (nwc != nullptr) {
nwc->SetTextColour(parts->u.colour.colour);
}
break;
}
case WPT_ALIGNMENT: {
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
if (nwc != nullptr) {
nwc->SetAlignment(parts->u.align.align);
}
break;
}
case WPT_FILL: {
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
if (nwrb != nullptr) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y);

View File

@@ -92,6 +92,8 @@ enum WidgetType : uint8 {
WPT_DATATIP, ///< Widget part for specifying data and tooltip.
WPT_PADDING, ///< Widget part for specifying a padding.
WPT_PIPSPACE, ///< Widget part for specifying pre/inter/post space for containers.
WPT_TEXTCOLOUR, ///< Widget part for specifying text colour.
WPT_ALIGNMENT, ///< Widget part for specifying text/image alignment.
WPT_ENDCONTAINER, ///< Widget part to denote end of a container.
WPT_FUNCTION, ///< Widget part for calling a user function.
WPT_SCROLLBAR, ///< Widget part for attaching a scrollbar.
@@ -316,6 +318,8 @@ public:
void SetIndex(int index);
void SetDataTip(uint32 widget_data, StringID tool_tip);
void SetToolTip(StringID tool_tip);
void SetTextColour(TextColour colour);
void SetAlignment(StringAlignment align);
inline void SetLowered(bool lowered);
inline bool IsLowered() const;
@@ -336,6 +340,8 @@ public:
StringID tool_tip; ///< Tooltip of the widget. @see Widget::tootips
int scrollbar_index; ///< Index of an attached scrollbar.
TextColour highlight_colour; ///< Colour of highlight.
TextColour text_colour; ///< Colour of text within widget.
StringAlignment align; ///< Alignment of text/image within widget.
};
/**
@@ -774,7 +780,8 @@ public:
}
}
int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const;
int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0) const;
EventState UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const;
};
/**
@@ -930,6 +937,22 @@ struct NWidgetPartTextLines {
FontSize size; ///< Font size of text lines.
};
/**
* Widget part for storing text colour.
* @ingroup NestedWidgetParts
*/
struct NWidgetPartTextColour {
TextColour colour; ///< TextColour for DrawString.
};
/**
* Widget part for setting text/image alignment within a widget.
* @ingroup NestedWidgetParts
*/
struct NWidgetPartAlignment {
StringAlignment align; ///< Alignment of text/image.
};
/**
* Pointer to function returning a nested widget.
* @param biggest_index Pointer to storage for collecting the biggest index used in the nested widget.
@@ -951,6 +974,8 @@ struct NWidgetPart {
NWidgetPartPaddings padding; ///< Part with paddings.
NWidgetPartPIP pip; ///< Part with pre/inter/post spaces.
NWidgetPartTextLines text_lines; ///< Part with text line data.
NWidgetPartTextColour colour; ///< Part with text colour data.
NWidgetPartAlignment align; ///< Part with internal alignment.
NWidgetFunctionType *func_ptr; ///< Part with a function call.
NWidContainerFlags cont_flags; ///< Part with container flags.
} u;
@@ -1009,6 +1034,36 @@ static inline NWidgetPart SetMinimalTextLines(uint8 lines, uint8 spacing, FontSi
return part;
}
/**
* Widget part function for setting the text colour.
* @param colour Colour to draw string within widget.
* @ingroup NestedWidgetParts
*/
static inline NWidgetPart SetTextColour(TextColour colour)
{
NWidgetPart part;
part.type = WPT_TEXTCOLOUR;
part.u.colour.colour = colour;
return part;
}
/**
* Widget part function for setting the alignment of text/images.
* @param align Alignment of text/image within widget.
* @ingroup NestedWidgetParts
*/
static inline NWidgetPart SetAlignment(StringAlignment align)
{
NWidgetPart part;
part.type = WPT_ALIGNMENT;
part.u.align.align = align;
return part;
}
/**
* Widget part function for setting filling.
* @param fill_x Horizontal filling step from minimal size.

View File

@@ -140,7 +140,7 @@ enum WidgetDrawDistances {
/* widget.cpp */
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags);
void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str);
void DrawCaption(const Rect &r, Colours colour, Owner owner, TextColour text_colour, StringID str, StringAlignment align);
/* window.cpp */
extern WindowBase *_z_front_window;