Merge branch 'cpp-11' into crashlog_improvements
# Conflicts: # Makefile.src.in # projects/determineversion.vbs # source.list # src/crashlog.cpp # src/misc.cpp # src/os/unix/crashlog_unix.cpp # src/os/windows/crashlog_win.cpp # src/rev.h # src/thread/thread.h # src/thread/thread_morphos.cpp # src/thread/thread_none.cpp # src/thread/thread_os2.cpp # src/thread/thread_pthread.cpp # src/thread/thread_win32.cpp
This commit is contained in:
@@ -32,7 +32,7 @@ public:
|
||||
START_NEXT_EASY = DAYS_IN_YEAR * 2,
|
||||
START_NEXT_MEDIUM = DAYS_IN_YEAR,
|
||||
START_NEXT_HARD = DAYS_IN_YEAR / 2,
|
||||
START_NEXT_MIN = 1,
|
||||
START_NEXT_MIN = 0,
|
||||
START_NEXT_MAX = 3600,
|
||||
START_NEXT_DEVIATION = 60,
|
||||
};
|
||||
@@ -164,11 +164,9 @@ public:
|
||||
/** Gets the ScriptScanner instance that is used to find AI Libraries */
|
||||
static AIScannerLibrary *GetScannerLibrary();
|
||||
|
||||
#if defined(ENABLE_NETWORK)
|
||||
/** Wrapper function for AIScanner::HasAI */
|
||||
static bool HasAI(const struct ContentInfo *ci, bool md5sum);
|
||||
static bool HasAILibrary(const ContentInfo *ci, bool md5sum);
|
||||
#endif
|
||||
private:
|
||||
static uint frame_counter; ///< Tick counter for the AI code
|
||||
static class AIScannerInfo *scanner_info; ///< ScriptScanner instance that is used to find AIs
|
||||
|
@@ -35,6 +35,15 @@ ScriptConfigItem _start_date_config = {
|
||||
false
|
||||
};
|
||||
|
||||
AIConfig::AIConfig(const AIConfig *config) : ScriptConfig(config)
|
||||
{
|
||||
/* Override start_date as per AIConfig::AddRandomDeviation().
|
||||
* This is necessary because the ScriptConfig constructor will instead call
|
||||
* ScriptConfig::AddRandomDeviation(). */
|
||||
int start_date = config->GetSetting("start_date");
|
||||
this->SetSetting("start_date", start_date != 0 ? max(1, this->GetSetting("start_date")) : 0);
|
||||
}
|
||||
|
||||
/* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source)
|
||||
{
|
||||
AIConfig **config;
|
||||
@@ -118,3 +127,14 @@ void AIConfig::SetSetting(const char *name, int value)
|
||||
|
||||
ScriptConfig::SetSetting(name, value);
|
||||
}
|
||||
|
||||
void AIConfig::AddRandomDeviation()
|
||||
{
|
||||
int start_date = this->GetSetting("start_date");
|
||||
|
||||
ScriptConfig::AddRandomDeviation();
|
||||
|
||||
/* start_date = 0 is a special case, where random deviation does not occur.
|
||||
* If start_date was not already 0, then a minimum value of 1 must apply. */
|
||||
this->SetSetting("start_date", start_date != 0 ? max(1, this->GetSetting("start_date")) : 0);
|
||||
}
|
||||
|
@@ -26,14 +26,13 @@ public:
|
||||
ScriptConfig()
|
||||
{}
|
||||
|
||||
AIConfig(const AIConfig *config) :
|
||||
ScriptConfig(config)
|
||||
{}
|
||||
AIConfig(const AIConfig *config);
|
||||
|
||||
class AIInfo *GetInfo() const;
|
||||
|
||||
/* virtual */ int GetSetting(const char *name) const;
|
||||
/* virtual */ void SetSetting(const char *name, int value);
|
||||
int GetSetting(const char *name) const override;
|
||||
void SetSetting(const char *name, int value) override;
|
||||
void AddRandomDeviation() override;
|
||||
|
||||
/**
|
||||
* When ever the AI Scanner is reloaded, all infos become invalid. This
|
||||
@@ -46,9 +45,9 @@ public:
|
||||
bool ResetInfo(bool force_exact_match);
|
||||
|
||||
protected:
|
||||
/* virtual */ void PushExtraConfigList();
|
||||
/* virtual */ void ClearConfigList();
|
||||
/* virtual */ ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match);
|
||||
void PushExtraConfigList() override;
|
||||
void ClearConfigList() override;
|
||||
ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override;
|
||||
};
|
||||
|
||||
#endif /* AI_CONFIG_HPP */
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "../company_func.h"
|
||||
#include "../network/network.h"
|
||||
#include "../window_func.h"
|
||||
#include "../framerate_type.h"
|
||||
#include "ai_scanner.hpp"
|
||||
#include "ai_instance.hpp"
|
||||
#include "ai_config.hpp"
|
||||
@@ -79,8 +80,11 @@
|
||||
const Company *c;
|
||||
FOR_ALL_COMPANIES(c) {
|
||||
if (c->is_ai) {
|
||||
PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index));
|
||||
cur_company.Change(c->index);
|
||||
c->ai_instance->GameLoop();
|
||||
} else {
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + c->index));
|
||||
}
|
||||
}
|
||||
cur_company.Restore();
|
||||
@@ -101,6 +105,7 @@
|
||||
/* static */ void AI::Stop(CompanyID company)
|
||||
{
|
||||
if (_networking && !_network_server) return;
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + company));
|
||||
|
||||
Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
|
||||
Company *c = Company::Get(company);
|
||||
@@ -357,8 +362,6 @@
|
||||
InvalidateWindowClassesData(WC_AI_SETTINGS);
|
||||
}
|
||||
|
||||
#if defined(ENABLE_NETWORK)
|
||||
|
||||
/**
|
||||
* Check whether we have an AI (library) with the exact characteristics as ci.
|
||||
* @param ci the characteristics to search on (shortname and md5sum)
|
||||
@@ -375,8 +378,6 @@
|
||||
return AI::scanner_library->HasScript(ci, md5sum);
|
||||
}
|
||||
|
||||
#endif /* defined(ENABLE_NETWORK) */
|
||||
|
||||
/* static */ AIScannerInfo *AI::GetScannerInfo()
|
||||
{
|
||||
return AI::scanner_info;
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "../widgets/dropdown_func.h"
|
||||
#include "../hotkeys.h"
|
||||
#include "../core/geometry_func.hpp"
|
||||
#include "../guitimer_func.h"
|
||||
|
||||
#include "ai.hpp"
|
||||
#include "ai_gui.hpp"
|
||||
@@ -97,7 +98,7 @@ struct AIListWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIL_CAPTION:
|
||||
@@ -106,7 +107,7 @@ struct AIListWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
if (widget == WID_AIL_LIST) {
|
||||
this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
|
||||
@@ -117,7 +118,7 @@ struct AIListWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIL_LIST: {
|
||||
@@ -182,7 +183,7 @@ struct AIListWindow : public Window {
|
||||
DeleteWindowByClass(WC_QUERY_STRING);
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIL_LIST: { // Select one of the AIs
|
||||
@@ -210,7 +211,7 @@ struct AIListWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_AIL_LIST);
|
||||
}
|
||||
@@ -220,7 +221,7 @@ struct AIListWindow : public Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot)) {
|
||||
delete this;
|
||||
@@ -286,7 +287,7 @@ struct AISettingsWindow : public Window {
|
||||
bool clicked_increase; ///< Whether we clicked the increase or decrease button.
|
||||
bool clicked_dropdown; ///< Whether the dropdown is open.
|
||||
bool closing_dropdown; ///< True, if the dropdown list is currently closing.
|
||||
int timeout; ///< Timeout for unclicking the button.
|
||||
GUITimer timeout; ///< Timeout for unclicking the button.
|
||||
int clicked_row; ///< The clicked row of settings.
|
||||
int line_height; ///< Height of a row in the matrix widget.
|
||||
Scrollbar *vscroll; ///< Cache of the vertical scrollbar.
|
||||
@@ -316,7 +317,7 @@ struct AISettingsWindow : public Window {
|
||||
this->RebuildVisibleSettings();
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIS_CAPTION:
|
||||
@@ -345,7 +346,7 @@ struct AISettingsWindow : public Window {
|
||||
this->vscroll->SetCount((int)this->visible_settings.size());
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
if (widget == WID_AIS_BACKGROUND) {
|
||||
this->line_height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
|
||||
@@ -356,7 +357,7 @@ struct AISettingsWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
if (widget != WID_AIS_BACKGROUND) return;
|
||||
|
||||
@@ -377,7 +378,7 @@ struct AISettingsWindow : public Window {
|
||||
for (; this->vscroll->IsVisible(i) && it != visible_settings.end(); i++, it++) {
|
||||
const ScriptConfigItem &config_item = **it;
|
||||
int current_value = config->GetSetting((config_item).name);
|
||||
bool editable = _game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot)) || (config_item.flags & SCRIPTCONFIG_INGAME) != 0;
|
||||
bool editable = this->IsEditableItem(config_item);
|
||||
|
||||
StringID str;
|
||||
TextColour colour;
|
||||
@@ -420,7 +421,7 @@ struct AISettingsWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
if (this->closing_dropdown) {
|
||||
this->closing_dropdown = false;
|
||||
@@ -429,7 +430,7 @@ struct AISettingsWindow : public Window {
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIS_BACKGROUND: {
|
||||
@@ -440,7 +441,7 @@ struct AISettingsWindow : public Window {
|
||||
VisibleSettingsList::const_iterator it = this->visible_settings.begin();
|
||||
for (int i = 0; i < num; i++) it++;
|
||||
const ScriptConfigItem config_item = **it;
|
||||
if (_game_mode == GM_NORMAL && ((this->slot == OWNER_DEITY) || Company::IsValidID(this->slot)) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return;
|
||||
if (!this->IsEditableItem(config_item)) return;
|
||||
|
||||
if (this->clicked_row != num) {
|
||||
DeleteChildWindows(WC_QUERY_STRING);
|
||||
@@ -480,7 +481,7 @@ struct AISettingsWindow : public Window {
|
||||
|
||||
DropDownList *list = new DropDownList();
|
||||
for (int i = config_item.min_value; i <= config_item.max_value; i++) {
|
||||
*list->Append() = new DropDownListCharStringItem(config_item.labels->Find(i)->second, i, false);
|
||||
list->push_back(new DropDownListCharStringItem(config_item.labels->Find(i)->second, i, false));
|
||||
}
|
||||
|
||||
ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true);
|
||||
@@ -505,7 +506,7 @@ struct AISettingsWindow : public Window {
|
||||
if (new_val != old_val) {
|
||||
this->ai_config->SetSetting(config_item.name, new_val);
|
||||
this->clicked_button = num;
|
||||
this->timeout = 5;
|
||||
this->timeout.SetInterval(150);
|
||||
}
|
||||
} else if (!bool_item && !config_item.complete_labels) {
|
||||
/* Display a query box so users can enter a custom value. */
|
||||
@@ -529,7 +530,7 @@ struct AISettingsWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnQueryTextFinished(char *str)
|
||||
void OnQueryTextFinished(char *str) override
|
||||
{
|
||||
if (StrEmpty(str)) return;
|
||||
VisibleSettingsList::const_iterator it = this->visible_settings.begin();
|
||||
@@ -541,7 +542,7 @@ struct AISettingsWindow : public Window {
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnDropdownSelect(int widget, int index)
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
assert(this->clicked_dropdown);
|
||||
VisibleSettingsList::const_iterator it = this->visible_settings.begin();
|
||||
@@ -552,7 +553,7 @@ struct AISettingsWindow : public Window {
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close)
|
||||
void OnDropdownClose(Point pt, int widget, int index, bool instant_close) override
|
||||
{
|
||||
/* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
|
||||
* the same dropdown button was clicked again, and then not open the dropdown again.
|
||||
@@ -563,14 +564,14 @@ struct AISettingsWindow : public Window {
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_AIS_BACKGROUND);
|
||||
}
|
||||
|
||||
virtual void OnTick()
|
||||
void OnRealtimeTick(uint delta_ms) override
|
||||
{
|
||||
if (--this->timeout == 0) {
|
||||
if (this->timeout.Elapsed(delta_ms)) {
|
||||
this->clicked_button = -1;
|
||||
this->SetDirty();
|
||||
}
|
||||
@@ -581,9 +582,17 @@ struct AISettingsWindow : public Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
this->RebuildVisibleSettings();
|
||||
HideDropDownMenu(this);
|
||||
DeleteChildWindows(WC_QUERY_STRING);
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsEditableItem(const ScriptConfigItem config_item) const
|
||||
{
|
||||
return _game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot)) || (config_item.flags & SCRIPTCONFIG_INGAME) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -637,7 +646,7 @@ struct ScriptTextfileWindow : public TextfileWindow {
|
||||
this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR);
|
||||
}
|
||||
|
||||
/* virtual */ void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
if (widget == WID_TF_CAPTION) {
|
||||
SetDParam(0, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI);
|
||||
@@ -653,7 +662,7 @@ struct ScriptTextfileWindow : public TextfileWindow {
|
||||
*/
|
||||
void ShowScriptTextfileWindow(TextfileType file_type, CompanyID slot)
|
||||
{
|
||||
DeleteWindowByClass(WC_TEXTFILE);
|
||||
DeleteWindowById(WC_TEXTFILE, file_type);
|
||||
new ScriptTextfileWindow(file_type, slot);
|
||||
}
|
||||
|
||||
@@ -734,7 +743,7 @@ struct AIConfigWindow : public Window {
|
||||
DeleteWindowByClass(WC_AI_SETTINGS);
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIC_NUMBER:
|
||||
@@ -758,7 +767,7 @@ struct AIConfigWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIC_GAMELIST:
|
||||
@@ -810,7 +819,7 @@ struct AIConfigWindow : public Window {
|
||||
return slot < max_slot;
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AIC_GAMELIST: {
|
||||
@@ -849,7 +858,7 @@ struct AIConfigWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_END) {
|
||||
if (this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot) == NULL) return;
|
||||
@@ -868,7 +877,6 @@ struct AIConfigWindow : public Window {
|
||||
new_value = min(MAX_COMPANIES - 1, GetGameSettings().difficulty.max_no_competitors + 1);
|
||||
}
|
||||
IConsoleSetSetting("difficulty.max_no_competitors", new_value);
|
||||
this->InvalidateData();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -920,9 +928,7 @@ struct AIConfigWindow : public Window {
|
||||
if (!_network_available) {
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
|
||||
} else {
|
||||
#if defined(ENABLE_NETWORK)
|
||||
ShowNetworkContentListWindow(NULL, CONTENT_TYPE_AI, CONTENT_TYPE_GAME);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -933,7 +939,7 @@ struct AIConfigWindow : public Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (!IsEditable(this->selected_slot)) {
|
||||
this->selected_slot = INVALID_COMPANY;
|
||||
@@ -1090,7 +1096,7 @@ struct AIDebugWindow : public Window {
|
||||
this->InvalidateData(-1);
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
if (widget == WID_AID_LOG_PANEL) {
|
||||
resize->height = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
|
||||
@@ -1098,7 +1104,7 @@ struct AIDebugWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
this->SelectValidDebugCompany();
|
||||
|
||||
@@ -1176,7 +1182,7 @@ struct AIDebugWindow : public Window {
|
||||
this->last_vscroll_pos = this->vscroll->GetPosition();
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AID_NAME_TEXT:
|
||||
@@ -1199,7 +1205,7 @@ struct AIDebugWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
if (ai_debug_company == INVALID_COMPANY) return;
|
||||
|
||||
@@ -1258,7 +1264,7 @@ struct AIDebugWindow : public Window {
|
||||
this->last_vscroll_pos = this->vscroll->GetPosition();
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
/* Also called for hotkeys, so check for disabledness */
|
||||
if (this->IsWidgetDisabled(widget)) return;
|
||||
@@ -1276,8 +1282,8 @@ struct AIDebugWindow : public Window {
|
||||
case WID_AID_RELOAD_TOGGLE:
|
||||
if (ai_debug_company == OWNER_DEITY) break;
|
||||
/* First kill the company of the AI, then start a new one. This should start the current AI again */
|
||||
DoCommandP(0, 2 | ai_debug_company << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, 1 | ai_debug_company << 16, 0, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, CCA_NEW_AI | ai_debug_company << 16, 0, CMD_COMPANY_CTRL);
|
||||
break;
|
||||
|
||||
case WID_AID_SETTINGS:
|
||||
@@ -1328,7 +1334,7 @@ struct AIDebugWindow : public Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnEditboxChanged(int wid)
|
||||
void OnEditboxChanged(int wid) override
|
||||
{
|
||||
if (wid == WID_AID_BREAK_STR_EDIT_BOX) {
|
||||
/* Save the current string to static member so it can be restored next time the window is opened. */
|
||||
@@ -1343,7 +1349,7 @@ struct AIDebugWindow : public Window {
|
||||
* This is the company ID of the AI/GS which wrote a new log message, or -1 in other cases.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
/* If the log message is related to the active company tab, check the break string.
|
||||
* This needs to be done in gameloop-scope, so the AI is suspended immediately. */
|
||||
@@ -1400,7 +1406,7 @@ struct AIDebugWindow : public Window {
|
||||
(ai_debug_company == OWNER_DEITY ? !Game::IsPaused() : !AI::IsPaused(ai_debug_company)));
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_AID_LOG_PANEL);
|
||||
}
|
||||
|
@@ -29,12 +29,12 @@ static bool CheckAPIVersion(const char *api_version)
|
||||
return strcmp(api_version, "0.7") == 0 || strcmp(api_version, "1.0") == 0 || strcmp(api_version, "1.1") == 0 ||
|
||||
strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 ||
|
||||
strcmp(api_version, "1.5") == 0 || strcmp(api_version, "1.6") == 0 || strcmp(api_version, "1.7") == 0 ||
|
||||
strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0;
|
||||
strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0;
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
#if defined(_WIN32)
|
||||
#undef GetClassName
|
||||
#endif /* WIN32 */
|
||||
#endif /* _WIN32 */
|
||||
template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
|
||||
|
||||
/* static */ void AIInfo::RegisterAPI(Squirrel *engine)
|
||||
|
@@ -25,14 +25,14 @@ public:
|
||||
*/
|
||||
void Initialize(class AIInfo *info);
|
||||
|
||||
/* virtual */ int GetSetting(const char *name);
|
||||
/* virtual */ ScriptInfo *FindLibrary(const char *library, int version);
|
||||
int GetSetting(const char *name) override;
|
||||
ScriptInfo *FindLibrary(const char *library, int version) override;
|
||||
|
||||
private:
|
||||
/* virtual */ void RegisterAPI();
|
||||
/* virtual */ void Died();
|
||||
/* virtual */ CommandCallback *GetDoCommandCallback();
|
||||
/* virtual */ void LoadDummyScript();
|
||||
void RegisterAPI() override;
|
||||
void Died() override;
|
||||
CommandCallback *GetDoCommandCallback() override;
|
||||
void LoadDummyScript() override;
|
||||
};
|
||||
|
||||
#endif /* AI_INSTANCE_HPP */
|
||||
|
@@ -19,7 +19,7 @@ public:
|
||||
AIScannerInfo();
|
||||
~AIScannerInfo();
|
||||
|
||||
/* virtual */ void Initialize();
|
||||
void Initialize() override;
|
||||
|
||||
/**
|
||||
* Select a random AI.
|
||||
@@ -42,11 +42,11 @@ public:
|
||||
void SetDummyAI(class AIInfo *info);
|
||||
|
||||
protected:
|
||||
/* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last);
|
||||
/* virtual */ const char *GetFileName() const { return PATHSEP "info.nut"; }
|
||||
/* virtual */ Subdirectory GetDirectory() const { return AI_DIR; }
|
||||
/* virtual */ const char *GetScannerName() const { return "AIs"; }
|
||||
/* virtual */ void RegisterAPI(class Squirrel *engine);
|
||||
void GetScriptName(ScriptInfo *info, char *name, const char *last) override;
|
||||
const char *GetFileName() const override { return PATHSEP "info.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_DIR; }
|
||||
const char *GetScannerName() const override { return "AIs"; }
|
||||
void RegisterAPI(class Squirrel *engine) override;
|
||||
|
||||
private:
|
||||
AIInfo *info_dummy; ///< The dummy AI.
|
||||
@@ -54,7 +54,7 @@ private:
|
||||
|
||||
class AIScannerLibrary : public ScriptScanner {
|
||||
public:
|
||||
/* virtual */ void Initialize();
|
||||
void Initialize() override;
|
||||
|
||||
/**
|
||||
* Find a library in the pool.
|
||||
@@ -65,11 +65,11 @@ public:
|
||||
class AILibrary *FindLibrary(const char *library, int version);
|
||||
|
||||
protected:
|
||||
/* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last);
|
||||
/* virtual */ const char *GetFileName() const { return PATHSEP "library.nut"; }
|
||||
/* virtual */ Subdirectory GetDirectory() const { return AI_LIBRARY_DIR; }
|
||||
/* virtual */ const char *GetScannerName() const { return "AI Libraries"; }
|
||||
/* virtual */ void RegisterAPI(class Squirrel *engine);
|
||||
void GetScriptName(ScriptInfo *info, char *name, const char *last) override;
|
||||
const char *GetFileName() const override { return PATHSEP "library.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_LIBRARY_DIR; }
|
||||
const char *GetScannerName() const override { return "AI Libraries"; }
|
||||
void RegisterAPI(class Squirrel *engine) override;
|
||||
};
|
||||
|
||||
#endif /* AI_SCANNER_HPP */
|
||||
|
@@ -45,6 +45,8 @@ enum AirVehicleFlags {
|
||||
* landscape at a fixed altitude. This only has effect when there are more than 15 height levels. */
|
||||
VAF_IN_MAX_HEIGHT_CORRECTION = 1, ///< The vehicle is currently lowering its altitude because it hit the upper bound.
|
||||
VAF_IN_MIN_HEIGHT_CORRECTION = 2, ///< The vehicle is currently raising its altitude because it hit the lower bound.
|
||||
|
||||
VAF_HELI_DIRECT_DESCENT = 3, ///< The helicopter is descending directly at its destination (helipad or in front of hangar)
|
||||
};
|
||||
|
||||
static const int ROTOR_Z_OFFSET = 5; ///< Z Offset between helicopter- and rotorsprite.
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "core/backup_type.hpp"
|
||||
#include "zoom_func.h"
|
||||
#include "disaster_vehicle.h"
|
||||
#include "newgrf_airporttiles.h"
|
||||
#include "framerate_type.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
@@ -127,16 +128,15 @@ static StationID FindNearestHangar(const Aircraft *v)
|
||||
const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
|
||||
|
||||
FOR_ALL_STATIONS(st) {
|
||||
if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT)) continue;
|
||||
if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT) || !st->airport.HasHangar()) continue;
|
||||
|
||||
const AirportFTAClass *afc = st->airport.GetFTA();
|
||||
if (!st->airport.HasHangar() || (
|
||||
/* don't crash the plane if we know it can't land at the airport */
|
||||
(afc->flags & AirportFTAClass::SHORT_STRIP) &&
|
||||
(avi->subtype & AIR_FAST) &&
|
||||
!_cheats.no_jetcrash.value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* don't crash the plane if we know it can't land at the airport */
|
||||
if ((afc->flags & AirportFTAClass::SHORT_STRIP) && (avi->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) continue;
|
||||
|
||||
/* the plane won't land at any helicopter station */
|
||||
if (!(afc->flags & AirportFTAClass::AIRPLANES) && (avi->subtype & AIR_CTOL)) continue;
|
||||
|
||||
/* v->tile can't be used here, when aircraft is flying v->tile is set to 0 */
|
||||
uint distance = DistanceSquare(vtile, st->airport.tile);
|
||||
@@ -248,7 +248,7 @@ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoff
|
||||
* @param flags type of operation.
|
||||
* @param e the engine to build.
|
||||
* @param data unused.
|
||||
* @param ret[out] the vehicle that has been built.
|
||||
* @param[out] ret the vehicle that has been built.
|
||||
* @return the cost of this operation or an error.
|
||||
*/
|
||||
CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret)
|
||||
@@ -379,7 +379,7 @@ bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination,
|
||||
{
|
||||
const Station *st = GetTargetAirportIfValid(this);
|
||||
/* If the station is not a valid airport or if it has no hangars */
|
||||
if (st == NULL || !st->airport.HasHangar()) {
|
||||
if (st == NULL || !CanVehicleUseStation(this, st) || !st->airport.HasHangar()) {
|
||||
/* the aircraft has to search for a hangar on its own */
|
||||
StationID station = FindNearestHangar(this);
|
||||
|
||||
@@ -635,6 +635,12 @@ static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE,
|
||||
* and take-off speeds being too low. */
|
||||
speed_limit *= _settings_game.vehicle.plane_speed;
|
||||
|
||||
/* adjust speed for broken vehicles */
|
||||
if (v->vehstatus & VS_AIRCRAFT_BROKEN) {
|
||||
if (SPEED_LIMIT_BROKEN < speed_limit) hard_limit = false;
|
||||
speed_limit = min(speed_limit, SPEED_LIMIT_BROKEN);
|
||||
}
|
||||
|
||||
if (v->vcache.cached_max_speed < speed_limit) {
|
||||
if (v->cur_speed < speed_limit) hard_limit = false;
|
||||
speed_limit = v->vcache.cached_max_speed;
|
||||
@@ -654,9 +660,6 @@ static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE,
|
||||
|
||||
spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit);
|
||||
|
||||
/* adjust speed for broken vehicles */
|
||||
if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, SPEED_LIMIT_BROKEN);
|
||||
|
||||
/* updates statusbar only if speed have changed to save CPU time */
|
||||
if (spd != v->cur_speed) {
|
||||
v->cur_speed = spd;
|
||||
@@ -694,9 +697,9 @@ int GetTileHeightBelowAircraft(const Vehicle *v)
|
||||
* When the maximum is reached the vehicle should consider descending.
|
||||
* When the minimum is reached the vehicle should consider ascending.
|
||||
*
|
||||
* @param v The vehicle to get the flight levels for.
|
||||
* @param [out] min_level The minimum bounds for flight level.
|
||||
* @param [out] max_level The maximum bounds for flight level.
|
||||
* @param v The vehicle to get the flight levels for.
|
||||
* @param[out] min_level The minimum bounds for flight level.
|
||||
* @param[out] max_level The maximum bounds for flight level.
|
||||
*/
|
||||
void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_level)
|
||||
{
|
||||
@@ -728,7 +731,7 @@ void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_lev
|
||||
|
||||
/**
|
||||
* Gets the maximum 'flight level' for the holding pattern of the aircraft,
|
||||
* in pixels 'z_pos' 0, depending on terrain below..
|
||||
* in pixels 'z_pos' 0, depending on terrain below.
|
||||
*
|
||||
* @param v The aircraft that may or may not need to decrease its altitude.
|
||||
* @return Maximal aircraft holding altitude, while in normal flight, in pixels.
|
||||
@@ -780,6 +783,7 @@ int GetAircraftFlightLevel(T *v, bool takeoff)
|
||||
}
|
||||
|
||||
template int GetAircraftFlightLevel(DisasterVehicle *v, bool takeoff);
|
||||
template int GetAircraftFlightLevel(Aircraft *v, bool takeoff);
|
||||
|
||||
/**
|
||||
* Find the entry point to an airport depending on direction which
|
||||
@@ -915,6 +919,8 @@ static bool AircraftController(Aircraft *v)
|
||||
|
||||
/* Helicopter landing. */
|
||||
if (amd.flag & AMED_HELI_LOWER) {
|
||||
SetBit(v->flags, VAF_HELI_DIRECT_DESCENT);
|
||||
|
||||
if (st == NULL) {
|
||||
/* FIXME - AircraftController -> if station no longer exists, do not land
|
||||
* helicopter will circle until sign disappears, then go to next order
|
||||
@@ -935,7 +941,10 @@ static bool AircraftController(Aircraft *v)
|
||||
Vehicle *u = v->Next()->Next();
|
||||
|
||||
/* Increase speed of rotors. When speed is 80, we've landed. */
|
||||
if (u->cur_speed >= 80) return true;
|
||||
if (u->cur_speed >= 80) {
|
||||
ClrBit(v->flags, VAF_HELI_DIRECT_DESCENT);
|
||||
return true;
|
||||
}
|
||||
u->cur_speed += 4;
|
||||
} else {
|
||||
count = UpdateAircraftSpeed(v);
|
||||
@@ -1301,18 +1310,17 @@ static void CrashAirplane(Aircraft *v)
|
||||
*/
|
||||
static void MaybeCrashAirplane(Aircraft *v)
|
||||
{
|
||||
if (_settings_game.vehicle.plane_crashes == 0) return;
|
||||
|
||||
Station *st = Station::Get(v->targetairport);
|
||||
|
||||
/* FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports */
|
||||
uint32 prob = (0x4000 << _settings_game.vehicle.plane_crashes);
|
||||
uint32 prob;
|
||||
if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
|
||||
(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
|
||||
!_cheats.no_jetcrash.value) {
|
||||
prob /= 20;
|
||||
prob = 3276;
|
||||
} else {
|
||||
prob /= 1500;
|
||||
if (_settings_game.vehicle.plane_crashes == 0) return;
|
||||
prob = (0x4000 << _settings_game.vehicle.plane_crashes) / 1500;
|
||||
}
|
||||
|
||||
if (GB(Random(), 0, 22) > prob) return;
|
||||
@@ -1362,8 +1370,14 @@ static void AircraftEntersTerminal(Aircraft *v)
|
||||
*/
|
||||
static void AircraftLandAirplane(Aircraft *v)
|
||||
{
|
||||
Station *st = Station::Get(v->targetairport);
|
||||
|
||||
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
|
||||
|
||||
v->UpdateDeltaXY();
|
||||
|
||||
AirportTileAnimationTrigger(st, vt, AAT_STATION_AIRPLANE_LAND);
|
||||
|
||||
if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) {
|
||||
SndPlayVehicleFx(SND_17_SKID_PLANE, v);
|
||||
}
|
||||
@@ -1531,7 +1545,7 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
|
||||
go_to_hangar = Station::Get(v->targetairport)->airport.HasHangar();
|
||||
}
|
||||
|
||||
if (go_to_hangar) {
|
||||
if (go_to_hangar && Station::Get(v->targetairport)->airport.HasHangar()) {
|
||||
v->state = HANGAR;
|
||||
} else {
|
||||
/* airplane goto state takeoff, helicopter to helitakeoff */
|
||||
@@ -1600,6 +1614,7 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
|
||||
uint16 tsubspeed = v->subspeed;
|
||||
if (!AirportHasBlock(v, current, apc)) {
|
||||
v->state = landingtype; // LANDING / HELILANDING
|
||||
if (v->state == HELILANDING) SetBit(v->flags, VAF_HELI_DIRECT_DESCENT);
|
||||
/* it's a bit dirty, but I need to set position to next position, otherwise
|
||||
* if there are multiple runways, plane won't know which one it took (because
|
||||
* they all have heading LANDING). And also occupy that block! */
|
||||
@@ -1889,7 +1904,7 @@ static bool FreeTerminal(Aircraft *v, byte i, byte last_terminal)
|
||||
|
||||
/**
|
||||
* Get the number of terminals at the airport.
|
||||
* @param afc Airport description.
|
||||
* @param apc Airport description.
|
||||
* @return Number of terminals.
|
||||
*/
|
||||
static uint GetNumTerminals(const AirportFTAClass *apc)
|
||||
@@ -2088,7 +2103,19 @@ void UpdateAirplanesOnNewStation(const Station *st)
|
||||
FOR_ALL_AIRCRAFT(v) {
|
||||
if (!v->IsNormalAircraft() || v->targetairport != st->index) continue;
|
||||
assert(v->state == FLYING);
|
||||
|
||||
Order *o = &v->current_order;
|
||||
/* The aircraft is heading to a hangar, but the new station doesn't have one,
|
||||
* or the aircraft can't land on the new station. Cancel current order. */
|
||||
if (o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && o->GetDestination() == st->index &&
|
||||
(!st->airport.HasHangar() || !CanVehicleUseStation(v, st))) {
|
||||
o->MakeDummy();
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
}
|
||||
v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation);
|
||||
UpdateAircraftCache(v);
|
||||
}
|
||||
|
||||
/* Heliports don't have a hangar. Invalidate all go to hangar orders from all aircraft. */
|
||||
if (!st->airport.HasHangar()) RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, st->index, true);
|
||||
}
|
||||
|
@@ -87,14 +87,14 @@ struct BuildAirToolbarWindow : Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
|
||||
if (!CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) delete this;
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AT_AIRPORT:
|
||||
@@ -114,7 +114,7 @@ struct BuildAirToolbarWindow : Window {
|
||||
}
|
||||
|
||||
|
||||
virtual void OnPlaceObject(Point pt, TileIndex tile)
|
||||
void OnPlaceObject(Point pt, TileIndex tile) override
|
||||
{
|
||||
switch (this->last_user_action) {
|
||||
case WID_AT_AIRPORT:
|
||||
@@ -129,19 +129,19 @@ struct BuildAirToolbarWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
|
||||
void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
|
||||
{
|
||||
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
|
||||
}
|
||||
|
||||
virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
|
||||
void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override
|
||||
{
|
||||
if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
|
||||
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPlaceObjectAbort()
|
||||
void OnPlaceObjectAbort() override
|
||||
{
|
||||
this->RaiseButtons();
|
||||
|
||||
@@ -219,7 +219,7 @@ class BuildAirportWindow : public PickerWindowBase {
|
||||
DropDownList *list = new DropDownList();
|
||||
|
||||
for (uint i = 0; i < AirportClass::GetClassCount(); i++) {
|
||||
*list->Append() = new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false);
|
||||
list->push_back(new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false));
|
||||
}
|
||||
|
||||
return list;
|
||||
@@ -268,7 +268,7 @@ public:
|
||||
DeleteWindowById(WC_SELECT_STATION, 0);
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_CLASS_DROPDOWN:
|
||||
@@ -293,7 +293,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_CLASS_DROPDOWN: {
|
||||
@@ -357,7 +357,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_AIRPORT_LIST: {
|
||||
@@ -394,7 +394,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
this->DrawWidgets();
|
||||
|
||||
@@ -462,7 +462,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_CLASS_DROPDOWN:
|
||||
@@ -535,7 +535,7 @@ public:
|
||||
this->SelectOtherAirport(-1);
|
||||
}
|
||||
|
||||
virtual void OnDropdownSelect(int widget, int index)
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
assert(widget == WID_AP_CLASS_DROPDOWN);
|
||||
_selected_airport_class = (AirportClassID)index;
|
||||
@@ -543,7 +543,7 @@ public:
|
||||
this->SelectFirstAvailableAirport(false);
|
||||
}
|
||||
|
||||
virtual void OnTick()
|
||||
void OnRealtimeTick(uint delta_ms) override
|
||||
{
|
||||
CheckRedrawStationCoverage(this);
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
#include "safeguards.h"
|
||||
|
||||
/** The table/list with animated tiles. */
|
||||
SmallVector<TileIndex, 256> _animated_tiles;
|
||||
std::vector<TileIndex> _animated_tiles;
|
||||
|
||||
/**
|
||||
* Removes the given tile from the animated tile table.
|
||||
@@ -27,10 +27,10 @@ SmallVector<TileIndex, 256> _animated_tiles;
|
||||
*/
|
||||
void DeleteAnimatedTile(TileIndex tile)
|
||||
{
|
||||
TileIndex *to_remove = _animated_tiles.Find(tile);
|
||||
if (to_remove != _animated_tiles.End()) {
|
||||
auto to_remove = std::find(_animated_tiles.begin(), _animated_tiles.end(), tile);
|
||||
if (to_remove != _animated_tiles.end()) {
|
||||
/* The order of the remaining elements must stay the same, otherwise the animation loop may miss a tile. */
|
||||
_animated_tiles.ErasePreservingOrder(to_remove);
|
||||
_animated_tiles.erase(to_remove);
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ void DeleteAnimatedTile(TileIndex tile)
|
||||
void AddAnimatedTile(TileIndex tile)
|
||||
{
|
||||
MarkTileDirtyByTile(tile);
|
||||
_animated_tiles.Include(tile);
|
||||
include(_animated_tiles, tile);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,8 +53,8 @@ void AnimateAnimatedTiles()
|
||||
{
|
||||
PerformanceAccumulator framerate(PFE_GL_LANDSCAPE);
|
||||
|
||||
const TileIndex *ti = _animated_tiles.Begin();
|
||||
while (ti < _animated_tiles.End()) {
|
||||
const TileIndex *ti = _animated_tiles.data();
|
||||
while (ti < _animated_tiles.data() + _animated_tiles.size()) {
|
||||
const TileIndex curr = *ti;
|
||||
AnimateTile(curr);
|
||||
/* During the AnimateTile call, DeleteAnimatedTile could have been called,
|
||||
@@ -75,5 +75,5 @@ void AnimateAnimatedTiles()
|
||||
*/
|
||||
void InitializeAnimatedTiles()
|
||||
{
|
||||
_animated_tiles.Clear();
|
||||
_animated_tiles.clear();
|
||||
}
|
||||
|
@@ -168,16 +168,16 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine)
|
||||
* @param engine Model to investigate.
|
||||
* @param[out] cargoes Total amount of units that can be transported, summed by cargo.
|
||||
* @param[out] refits Whether a (possibly partial) refit for each cargo is possible.
|
||||
* @param cargo_type Selected refitted cargo type
|
||||
* @param cargo_capacity Capacity of selected refitted cargo type
|
||||
*/
|
||||
void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits)
|
||||
void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint16 cargo_capacity)
|
||||
{
|
||||
cargoes->Clear();
|
||||
*refits = 0;
|
||||
|
||||
const Engine *e = Engine::Get(engine);
|
||||
|
||||
CargoID cargo_type;
|
||||
uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type);
|
||||
if (cargo_type < NUM_CARGO && cargo_capacity > 0) {
|
||||
(*cargoes)[cargo_type] += cargo_capacity;
|
||||
if (IsEngineRefittable(engine)) SetBit(*refits, cargo_type);
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "autoreplace_gui.h"
|
||||
#include "articulated_vehicles.h"
|
||||
#include "core/random_func.hpp"
|
||||
#include "vehiclelist.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -32,7 +33,6 @@ extern void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index);
|
||||
* Figure out if two engines got at least one type of cargo in common (refitting if needed)
|
||||
* @param engine_a one of the EngineIDs
|
||||
* @param engine_b the other EngineID
|
||||
* @param type the type of the engines
|
||||
* @return true if they can both carry the same type of cargo (or at least one of them got no capacity at all)
|
||||
*/
|
||||
static bool EnginesHaveCargoInCommon(EngineID engine_a, EngineID engine_b)
|
||||
@@ -237,7 +237,7 @@ static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool
|
||||
* @param v The vehicle to find a replacement for
|
||||
* @param c The vehicle's owner (it's faster to forward the pointer than refinding it)
|
||||
* @param always_replace Always replace, even if not old.
|
||||
* @param [out] e the EngineID of the replacement. INVALID_ENGINE if no replacement is found
|
||||
* @param[out] e the EngineID of the replacement. INVALID_ENGINE if no replacement is found
|
||||
* @return Error if the engine to build is not available
|
||||
*/
|
||||
static CommandCost GetNewEngineType(const Vehicle *v, const Company *c, bool always_replace, EngineID &e)
|
||||
@@ -294,7 +294,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
|
||||
if (refit_cargo == CT_INVALID) return CommandCost(); // incompatible cargoes
|
||||
|
||||
/* Build the new vehicle */
|
||||
cost = DoCommand(old_veh->tile, e, 0, DC_EXEC | DC_AUTOREPLACE, GetCmdBuildVeh(old_veh));
|
||||
cost = DoCommand(old_veh->tile, e | (CT_INVALID << 24), 0, DC_EXEC | DC_AUTOREPLACE, GetCmdBuildVeh(old_veh));
|
||||
if (cost.Failed()) return cost;
|
||||
|
||||
Vehicle *new_veh = Vehicle::Get(_new_vehicle_id);
|
||||
@@ -778,6 +778,9 @@ CommandCost CmdSetAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
|
||||
if (flags & DC_EXEC) {
|
||||
GroupStatistics::UpdateAutoreplace(_current_company);
|
||||
if (IsLocalCompany()) SetWindowDirty(WC_REPLACE_VEHICLE, Engine::Get(old_engine_type)->type);
|
||||
|
||||
const VehicleType vt = Engine::Get(old_engine_type)->type;
|
||||
SetWindowDirty(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
|
||||
}
|
||||
if ((flags & DC_EXEC) && IsLocalCompany()) InvalidateAutoreplaceWindow(old_engine_type, id_g);
|
||||
|
||||
|
@@ -81,7 +81,7 @@ class ReplaceVehicleWindow : public Window {
|
||||
EngineID sel_engine[2]; ///< Selected engine left and right.
|
||||
GUIEngineList engines[2]; ///< Left and right list of engines.
|
||||
bool replace_engines; ///< If \c true, engines are replaced, if \c false, wagons are replaced (only for trains).
|
||||
bool reset_sel_engine; ///< Also reset #sel_engine while updating left and/or right (#update_left and/or #update_right) and no valid engine selected.
|
||||
bool reset_sel_engine; ///< Also reset #sel_engine while updating left and/or right and no valid engine selected.
|
||||
GroupID sel_group; ///< Group selected to replace.
|
||||
int details_height; ///< Minimal needed height of the details panels (found so far).
|
||||
byte sort_criteria; ///< Criteria of sorting vehicles.
|
||||
@@ -123,7 +123,7 @@ class ReplaceVehicleWindow : public Window {
|
||||
byte side = draw_left ? 0 : 1;
|
||||
|
||||
GUIEngineList *list = &this->engines[side];
|
||||
list->Clear();
|
||||
list->clear();
|
||||
|
||||
const Engine *e;
|
||||
FOR_ALL_ENGINES_OF_TYPE(e, type) {
|
||||
@@ -140,7 +140,7 @@ class ReplaceVehicleWindow : public Window {
|
||||
if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue;
|
||||
}
|
||||
|
||||
*list->Append() = eid;
|
||||
list->push_back(eid);
|
||||
if (eid == this->sel_engine[side]) selected_engine = eid; // The selected engine is still in the list
|
||||
}
|
||||
this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore)
|
||||
@@ -160,8 +160,8 @@ class ReplaceVehicleWindow : public Window {
|
||||
if (this->engines[0].NeedRebuild()) {
|
||||
/* We need to rebuild the left engines list */
|
||||
this->GenerateReplaceVehList(true);
|
||||
this->vscroll[0]->SetCount(this->engines[0].Length());
|
||||
if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].Length() != 0) {
|
||||
this->vscroll[0]->SetCount((uint)this->engines[0].size());
|
||||
if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].size() != 0) {
|
||||
this->sel_engine[0] = this->engines[0][0];
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ class ReplaceVehicleWindow : public Window {
|
||||
/* Either we got a request to rebuild the right engines list, or the left engines list selected a different engine */
|
||||
if (this->sel_engine[0] == INVALID_ENGINE) {
|
||||
/* Always empty the right engines list when nothing is selected in the left engines list */
|
||||
this->engines[1].Clear();
|
||||
this->engines[1].clear();
|
||||
this->sel_engine[1] = INVALID_ENGINE;
|
||||
} else {
|
||||
if (this->reset_sel_engine && this->sel_engine[0] != INVALID_ENGINE) {
|
||||
@@ -180,11 +180,11 @@ class ReplaceVehicleWindow : public Window {
|
||||
}
|
||||
/* Regenerate the list on the right. Note: This resets sel_engine[1] to INVALID_ENGINE, if it is no longer available. */
|
||||
this->GenerateReplaceVehList(false);
|
||||
this->vscroll[1]->SetCount(this->engines[1].Length());
|
||||
this->vscroll[1]->SetCount((uint)this->engines[1].size());
|
||||
if (this->reset_sel_engine && this->sel_engine[1] != INVALID_ENGINE) {
|
||||
int position = 0;
|
||||
for (EngineID *it = this->engines[1].Begin(); it != this->engines[1].End(); ++it) {
|
||||
if (*it == this->sel_engine[1]) break;
|
||||
for (EngineID &eid : this->engines[1]) {
|
||||
if (eid == this->sel_engine[1]) break;
|
||||
++position;
|
||||
}
|
||||
this->vscroll[1]->ScrollTowards(position);
|
||||
@@ -237,7 +237,7 @@ public:
|
||||
this->sel_group = id_g;
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_ASCENDING_DESCENDING: {
|
||||
@@ -316,7 +316,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_CAPTION:
|
||||
@@ -353,7 +353,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_ASCENDING_DESCENDING:
|
||||
@@ -384,7 +384,7 @@ public:
|
||||
case WID_RV_RIGHT_MATRIX: {
|
||||
int side = (widget == WID_RV_LEFT_MATRIX) ? 0 : 1;
|
||||
EngineID start = this->vscroll[side]->GetPosition(); // what is the offset for the start (scrolling)
|
||||
EngineID end = min(this->vscroll[side]->GetCapacity() + start, this->engines[side].Length());
|
||||
EngineID end = min(this->vscroll[side]->GetCapacity() + start, (uint)this->engines[side].size());
|
||||
|
||||
/* Do the actual drawing */
|
||||
DrawEngineList((VehicleType)this->window_number, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP,
|
||||
@@ -394,7 +394,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists();
|
||||
|
||||
@@ -423,9 +423,16 @@ public:
|
||||
/* Draw details panels. */
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if (this->sel_engine[side] != INVALID_ENGINE) {
|
||||
/* Use default engine details without refitting */
|
||||
const Engine *e = Engine::Get(this->sel_engine[side]);
|
||||
TestedEngineDetails ted;
|
||||
ted.cost = 0;
|
||||
ted.cargo = e->GetDefaultCargoType();
|
||||
ted.capacity = e->GetDisplayDefaultCapacity(&ted.mail_capacity);
|
||||
|
||||
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS);
|
||||
int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT,
|
||||
nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side]);
|
||||
nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side], ted);
|
||||
needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM);
|
||||
}
|
||||
}
|
||||
@@ -437,7 +444,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_ASCENDING_DESCENDING:
|
||||
@@ -461,8 +468,8 @@ public:
|
||||
|
||||
case WID_RV_TRAIN_ENGINEWAGON_DROPDOWN: {
|
||||
DropDownList *list = new DropDownList();
|
||||
*list->Append() = new DropDownListStringItem(STR_REPLACE_ENGINES, 1, false);
|
||||
*list->Append() = new DropDownListStringItem(STR_REPLACE_WAGONS, 0, false);
|
||||
list->push_back(new DropDownListStringItem(STR_REPLACE_ENGINES, 1, false));
|
||||
list->push_back(new DropDownListStringItem(STR_REPLACE_WAGONS, 0, false));
|
||||
ShowDropDownList(this, list, this->replace_engines ? 1 : 0, WID_RV_TRAIN_ENGINEWAGON_DROPDOWN);
|
||||
break;
|
||||
}
|
||||
@@ -501,7 +508,7 @@ public:
|
||||
click_side = 1;
|
||||
}
|
||||
uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget);
|
||||
size_t engine_count = this->engines[click_side].Length();
|
||||
size_t engine_count = this->engines[click_side].size();
|
||||
|
||||
EngineID e = engine_count > i ? this->engines[click_side][i] : INVALID_ENGINE;
|
||||
if (e == this->sel_engine[click_side]) break; // we clicked the one we already selected
|
||||
@@ -516,7 +523,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnDropdownSelect(int widget, int index)
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_RV_SORT_DROPDOWN:
|
||||
@@ -557,7 +564,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll[0]->SetCapacityFromWidget(this, WID_RV_LEFT_MATRIX);
|
||||
this->vscroll[1]->SetCapacityFromWidget(this, WID_RV_RIGHT_MATRIX);
|
||||
@@ -568,7 +575,7 @@ public:
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (data != 0) {
|
||||
/* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
|
||||
|
@@ -76,9 +76,9 @@ struct BaseSet {
|
||||
{
|
||||
free(this->name);
|
||||
|
||||
for (TranslatedStrings::iterator iter = this->description.Begin(); iter != this->description.End(); iter++) {
|
||||
free(iter->first);
|
||||
free(iter->second);
|
||||
for (auto &pair : this->description) {
|
||||
free(pair.first);
|
||||
free(pair.second);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < NUM_FILES; i++) {
|
||||
@@ -122,16 +122,16 @@ struct BaseSet {
|
||||
{
|
||||
if (isocode != NULL) {
|
||||
/* First the full ISO code */
|
||||
for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) {
|
||||
if (strcmp(iter->first, isocode) == 0) return iter->second;
|
||||
for (const auto &pair : this->description) {
|
||||
if (strcmp(pair.first, isocode) == 0) return pair.second;
|
||||
}
|
||||
/* Then the first two characters */
|
||||
for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) {
|
||||
if (strncmp(iter->first, isocode, 2) == 0) return iter->second;
|
||||
for (const auto &pair : this->description) {
|
||||
if (strncmp(pair.first, isocode, 2) == 0) return pair.second;
|
||||
}
|
||||
}
|
||||
/* Then fall back */
|
||||
return this->description.Begin()->second;
|
||||
return this->description.front().second;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,7 +176,7 @@ protected:
|
||||
static Tbase_set *duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded.
|
||||
static const Tbase_set *used_set; ///< The currently used set
|
||||
|
||||
/* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename);
|
||||
bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override;
|
||||
|
||||
/**
|
||||
* Get the extension that is used to identify this set.
|
||||
|
@@ -277,7 +277,6 @@ template <class Tbase_set>
|
||||
return p;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_NETWORK)
|
||||
#include "network/network_content.h"
|
||||
|
||||
template <class Tbase_set> const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s)
|
||||
@@ -307,22 +306,6 @@ template <class Tbase_set>
|
||||
(TryGetBaseSetFile(ci, md5sum, BaseMedia<Tbase_set>::duplicate_sets) != NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class Tbase_set>
|
||||
const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <class Tbase_set>
|
||||
/* static */ bool BaseMedia<Tbase_set>::HasSet(const ContentInfo *ci, bool md5sum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
/**
|
||||
* Count the number of available graphics sets.
|
||||
* @return the number of sets
|
||||
|
@@ -110,6 +110,12 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
|
||||
*/
|
||||
virtual void UpdateVirtCoord() = 0;
|
||||
|
||||
virtual void MoveSign(TileIndex new_xy)
|
||||
{
|
||||
this->xy = new_xy;
|
||||
this->UpdateVirtCoord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tile area for a given station type.
|
||||
* @param ta tile area to fill.
|
||||
|
120
src/bitmap_type.h
Normal file
120
src/bitmap_type.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file bitmap_type.hpp Bitmap functions. */
|
||||
|
||||
#ifndef BITMAP_TYPE_HPP
|
||||
#define BITMAP_TYPE_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
/** Represents a tile area containing containing individually set tiles.
|
||||
* Each tile must be contained within the preallocated area.
|
||||
* A std::vector<bool> is used to mark which tiles are contained.
|
||||
*/
|
||||
class BitmapTileArea : public TileArea {
|
||||
protected:
|
||||
std::vector<bool> data;
|
||||
|
||||
inline uint Index(uint x, uint y) const { return y * this->w + x; }
|
||||
|
||||
inline uint Index(TileIndex tile) const { return Index(TileX(tile) - TileX(this->tile), TileY(tile) - TileY(this->tile)); }
|
||||
|
||||
public:
|
||||
BitmapTileArea()
|
||||
{
|
||||
this->tile = INVALID_TILE;
|
||||
this->w = 0;
|
||||
this->h = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset and clear the BitmapTileArea.
|
||||
*/
|
||||
void Reset()
|
||||
{
|
||||
this->tile = INVALID_TILE;
|
||||
this->w = 0;
|
||||
this->h = 0;
|
||||
this->data.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the BitmapTileArea with the specified Rect.
|
||||
* @param rect Rect to use.
|
||||
*/
|
||||
void Initialize(Rect r)
|
||||
{
|
||||
this->tile = TileXY(r.left, r.top);
|
||||
this->w = r.right - r.left + 1;
|
||||
this->h = r.bottom - r.top + 1;
|
||||
this->data.clear();
|
||||
this->data.resize(Index(w, h));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tile as part of the tile area.
|
||||
* @param tile Tile to add.
|
||||
*/
|
||||
inline void SetTile(TileIndex tile)
|
||||
{
|
||||
assert(this->Contains(tile));
|
||||
this->data[Index(tile)] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a tile from the tile area.
|
||||
* @param tile Tile to clear
|
||||
*/
|
||||
inline void ClrTile(TileIndex tile)
|
||||
{
|
||||
assert(this->Contains(tile));
|
||||
this->data[Index(tile)] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a tile is part of the tile area.
|
||||
* @param tile Tile to check
|
||||
*/
|
||||
inline bool HasTile(TileIndex tile) const
|
||||
{
|
||||
return this->Contains(tile) && this->data[Index(tile)];
|
||||
}
|
||||
};
|
||||
|
||||
/** Iterator to iterate over all tiles belonging to a bitmaptilearea. */
|
||||
class BitmapTileIterator : public OrthogonalTileIterator {
|
||||
protected:
|
||||
const BitmapTileArea *bitmap;
|
||||
public:
|
||||
/**
|
||||
* Construct the iterator.
|
||||
* @param bitmap BitmapTileArea to iterate.
|
||||
*/
|
||||
BitmapTileIterator(const BitmapTileArea &bitmap) : OrthogonalTileIterator(bitmap), bitmap(&bitmap)
|
||||
{
|
||||
if (!this->bitmap->HasTile(TileIndex(this->tile))) ++(*this);
|
||||
}
|
||||
|
||||
inline TileIterator& operator ++()
|
||||
{
|
||||
(*this).OrthogonalTileIterator::operator++();
|
||||
while (this->tile != INVALID_TILE && !this->bitmap->HasTile(TileIndex(this->tile))) {
|
||||
(*this).OrthogonalTileIterator::operator++();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual TileIterator *Clone() const
|
||||
{
|
||||
return new BitmapTileIterator(*this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* BITMAP_TYPE_HPP */
|
@@ -12,6 +12,7 @@
|
||||
#include "../stdafx.h"
|
||||
#include "../video/video_driver.hpp"
|
||||
#include "32bpp_anim.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
#include "../table/sprites.h"
|
||||
|
||||
@@ -321,6 +322,24 @@ void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8 colour)
|
||||
this->anim_buf[this->ScreenToAnimOffset((uint32 *)video) + x + y * this->anim_buf_pitch] = colour | (DEFAULT_BRIGHTNESS << 8);
|
||||
}
|
||||
|
||||
void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
|
||||
{
|
||||
const Colour c = LookupColourInPalette(colour);
|
||||
|
||||
if (_screen_disable_anim) {
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||
});
|
||||
} else {
|
||||
uint16 * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32 *)video);
|
||||
const uint16 anim_colour = colour | (DEFAULT_BRIGHTNESS << 8);
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
|
||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||
offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colour)
|
||||
{
|
||||
if (_screen_disable_anim) {
|
||||
|
@@ -37,20 +37,21 @@ public:
|
||||
|
||||
~Blitter_32bppAnim();
|
||||
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal);
|
||||
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
|
||||
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
|
||||
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
|
||||
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
|
||||
/* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y);
|
||||
/* virtual */ int BufferSize(int width, int height);
|
||||
/* virtual */ void PaletteAnimate(const Palette &palette);
|
||||
/* virtual */ Blitter::PaletteAnimation UsePaletteAnimation();
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
|
||||
void SetPixel(void *video, int x, int y, uint8 colour) override;
|
||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override;
|
||||
void DrawRect(void *video, int width, int height, uint8 colour) override;
|
||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
||||
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override;
|
||||
int BufferSize(int width, int height) override;
|
||||
void PaletteAnimate(const Palette &palette) override;
|
||||
Blitter::PaletteAnimation UsePaletteAnimation() override;
|
||||
|
||||
/* virtual */ const char *GetName() { return "32bpp-anim"; }
|
||||
/* virtual */ int GetBytesPerPixel() { return 6; }
|
||||
/* virtual */ void PostResize();
|
||||
const char *GetName() override { return "32bpp-anim"; }
|
||||
int GetBytesPerPixel() override { return 6; }
|
||||
void PostResize() override;
|
||||
|
||||
/**
|
||||
* Look up the colour in the current palette.
|
||||
@@ -76,7 +77,7 @@ public:
|
||||
class FBlitter_32bppAnim : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppAnim() : BlitterFactory("32bpp-anim", "32bpp Animation Blitter (palette animation)") {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppAnim(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppAnim(); }
|
||||
};
|
||||
|
||||
#endif /* BLITTER_32BPP_ANIM_HPP */
|
||||
|
@@ -28,15 +28,15 @@
|
||||
/** A partially 32 bpp blitter with palette animation. */
|
||||
class Blitter_32bppSSE2_Anim : public Blitter_32bppAnim {
|
||||
public:
|
||||
/* virtual */ void PaletteAnimate(const Palette &palette);
|
||||
/* virtual */ const char *GetName() { return "32bpp-sse2-anim"; }
|
||||
void PaletteAnimate(const Palette &palette) override;
|
||||
const char *GetName() override { return "32bpp-sse2-anim"; }
|
||||
};
|
||||
|
||||
/** Factory for the partially 32bpp blitter with animation. */
|
||||
class FBlitter_32bppSSE2_Anim : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppSSE2_Anim() : BlitterFactory("32bpp-sse2-anim", "32bpp partially SSE2 Animation Blitter (palette animation)", HasCPUIDFlag(1, 3, 26)) {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE2_Anim(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppSSE2_Anim(); }
|
||||
};
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file 32bpp_sse4_anim.cpp Implementation of the SSE4 32 bpp blitter with animation support. */
|
||||
/** @file 32bpp_anim_sse4.cpp Implementation of the SSE4 32 bpp blitter with animation support. */
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file 32bpp_sse4_anim.hpp A SSE4 32 bpp blitter with animation support. */
|
||||
/** @file 32bpp_anim_sse4.hpp A SSE4 32 bpp blitter with animation support. */
|
||||
|
||||
#ifndef BLITTER_32BPP_SSE4_ANIM_HPP
|
||||
#define BLITTER_32BPP_SSE4_ANIM_HPP
|
||||
@@ -35,19 +35,19 @@ private:
|
||||
|
||||
public:
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent, bool animated>
|
||||
/* virtual */ void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) {
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override {
|
||||
return Blitter_32bppSSE_Base::Encode(sprite, allocator);
|
||||
}
|
||||
/* virtual */ const char *GetName() { return "32bpp-sse4-anim"; }
|
||||
const char *GetName() override { return "32bpp-sse4-anim"; }
|
||||
};
|
||||
|
||||
/** Factory for the SSE4 32 bpp blitter (with palette animation). */
|
||||
class FBlitter_32bppSSE4_Anim: public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppSSE4_Anim() : BlitterFactory("32bpp-sse4-anim", "SSE4 Blitter (palette animation)", HasCPUIDFlag(1, 2, 19)) {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE4_Anim(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppSSE4_Anim(); }
|
||||
};
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "32bpp_base.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -24,6 +25,14 @@ void Blitter_32bppBase::SetPixel(void *video, int x, int y, uint8 colour)
|
||||
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour);
|
||||
}
|
||||
|
||||
void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
|
||||
{
|
||||
const Colour c = LookupColourInPalette(colour);
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
||||
*((Colour *)video + x + y * _screen.pitch) = c;
|
||||
});
|
||||
}
|
||||
|
||||
void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8 colour)
|
||||
{
|
||||
Colour colour32 = LookupColourInPalette(colour);
|
||||
|
@@ -20,18 +20,19 @@
|
||||
/** Base for all 32bpp blitters. */
|
||||
class Blitter_32bppBase : public Blitter {
|
||||
public:
|
||||
/* virtual */ uint8 GetScreenDepth() { return 32; }
|
||||
/* virtual */ void *MoveTo(void *video, int x, int y);
|
||||
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
|
||||
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
|
||||
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
|
||||
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
|
||||
/* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch);
|
||||
/* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y);
|
||||
/* virtual */ int BufferSize(int width, int height);
|
||||
/* virtual */ void PaletteAnimate(const Palette &palette);
|
||||
/* virtual */ Blitter::PaletteAnimation UsePaletteAnimation();
|
||||
/* virtual */ int GetBytesPerPixel() { return 4; }
|
||||
uint8 GetScreenDepth() override { return 32; }
|
||||
void *MoveTo(void *video, int x, int y) override;
|
||||
void SetPixel(void *video, int x, int y, uint8 colour) override;
|
||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override;
|
||||
void DrawRect(void *video, int width, int height, uint8 colour) override;
|
||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
||||
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
||||
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override;
|
||||
int BufferSize(int width, int height) override;
|
||||
void PaletteAnimate(const Palette &palette) override;
|
||||
Blitter::PaletteAnimation UsePaletteAnimation() override;
|
||||
int GetBytesPerPixel() override { return 4; }
|
||||
|
||||
/**
|
||||
* Look up the colour in the current palette.
|
||||
|
@@ -23,10 +23,10 @@ public:
|
||||
byte data[]; ///< Data, all zoomlevels.
|
||||
};
|
||||
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override;
|
||||
|
||||
/* virtual */ const char *GetName() { return "32bpp-optimized"; }
|
||||
const char *GetName() override { return "32bpp-optimized"; }
|
||||
|
||||
template <BlitterMode mode> void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
};
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
class FBlitter_32bppOptimized : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppOptimized() : BlitterFactory("32bpp-optimized", "32bpp Optimized Blitter (no palette animation)") {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppOptimized(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppOptimized(); }
|
||||
};
|
||||
|
||||
#endif /* BLITTER_32BPP_OPTIMIZED_HPP */
|
||||
|
@@ -26,18 +26,18 @@ class Blitter_32bppSimple : public Blitter_32bppBase {
|
||||
uint8 v; ///< Brightness-channel
|
||||
};
|
||||
public:
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal);
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override;
|
||||
|
||||
/* virtual */ const char *GetName() { return "32bpp-simple"; }
|
||||
const char *GetName() override { return "32bpp-simple"; }
|
||||
};
|
||||
|
||||
/** Factory for the simple 32 bpp blitter. */
|
||||
class FBlitter_32bppSimple : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppSimple() : BlitterFactory("32bpp-simple", "32bpp Simple Blitter (no palette animation)") {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSimple(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppSimple(); }
|
||||
};
|
||||
|
||||
#endif /* BLITTER_32BPP_SIMPLE_HPP */
|
||||
|
@@ -82,22 +82,22 @@ DECLARE_ENUM_AS_BIT_SET(Blitter_32bppSSE_Base::SpriteFlags);
|
||||
/** The SSE2 32 bpp blitter (without palette animation). */
|
||||
class Blitter_32bppSSE2 : public Blitter_32bppSimple, public Blitter_32bppSSE_Base {
|
||||
public:
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) {
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override {
|
||||
return Blitter_32bppSSE_Base::Encode(sprite, allocator);
|
||||
}
|
||||
|
||||
/* virtual */ const char *GetName() { return "32bpp-sse2"; }
|
||||
const char *GetName() override { return "32bpp-sse2"; }
|
||||
};
|
||||
|
||||
/** Factory for the SSE2 32 bpp blitter (without palette animation). */
|
||||
class FBlitter_32bppSSE2 : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppSSE2() : BlitterFactory("32bpp-sse2", "32bpp SSE2 Blitter (no palette animation)", HasCPUIDFlag(1, 3, 26)) {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE2(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppSSE2(); }
|
||||
};
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -27,17 +27,17 @@
|
||||
/** The SSE4 32 bpp blitter (without palette animation). */
|
||||
class Blitter_32bppSSE4 : public Blitter_32bppSSSE3 {
|
||||
public:
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
/* virtual */ const char *GetName() { return "32bpp-sse4"; }
|
||||
const char *GetName() override { return "32bpp-sse4"; }
|
||||
};
|
||||
|
||||
/** Factory for the SSE4 32 bpp blitter (without palette animation). */
|
||||
class FBlitter_32bppSSE4: public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppSSE4() : BlitterFactory("32bpp-sse4", "32bpp SSE4 Blitter (no palette animation)", HasCPUIDFlag(1, 2, 19)) {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE4(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppSSE4(); }
|
||||
};
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -7,10 +7,10 @@
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file 32bpp_sse_type.hpp Types related to SSE 32 bpp blitter. */
|
||||
/** @file 32bpp_sse_type.h Types related to SSE 32 bpp blitter. */
|
||||
|
||||
#ifndef BLITTER_32BPP_SSE_TYPE_HPP
|
||||
#define BLITTER_32BPP_SSE_TYPE_HPP
|
||||
#ifndef BLITTER_32BPP_SSE_TYPE_H
|
||||
#define BLITTER_32BPP_SSE_TYPE_H
|
||||
|
||||
#ifdef WITH_SSE
|
||||
|
||||
@@ -55,4 +55,4 @@ typedef union ALIGN(16) um128i {
|
||||
#define TRANSPARENT_NOM_BASE _mm_setr_epi16(256, 256, 256, 256, 256, 256, 256, 256)
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
#endif /* BLITTER_32BPP_SSE_TYPE_HPP */
|
||||
#endif /* BLITTER_32BPP_SSE_TYPE_H */
|
||||
|
@@ -27,17 +27,17 @@
|
||||
/** The SSSE3 32 bpp blitter (without palette animation). */
|
||||
class Blitter_32bppSSSE3 : public Blitter_32bppSSE2 {
|
||||
public:
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
|
||||
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
|
||||
/* virtual */ const char *GetName() { return "32bpp-ssse3"; }
|
||||
const char *GetName() override { return "32bpp-ssse3"; }
|
||||
};
|
||||
|
||||
/** Factory for the SSSE3 32 bpp blitter (without palette animation). */
|
||||
class FBlitter_32bppSSSE3: public BlitterFactory {
|
||||
public:
|
||||
FBlitter_32bppSSSE3() : BlitterFactory("32bpp-ssse3", "32bpp SSSE3 Blitter (no palette animation)", HasCPUIDFlag(1, 2, 9)) {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSSE3(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_32bppSSSE3(); }
|
||||
};
|
||||
|
||||
#endif /* WITH_SSE */
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "../stdafx.h"
|
||||
#include "../gfx_func.h"
|
||||
#include "8bpp_base.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -35,6 +36,13 @@ void Blitter_8bppBase::SetPixel(void *video, int x, int y, uint8 colour)
|
||||
*((uint8 *)video + x + y * _screen.pitch) = colour;
|
||||
}
|
||||
|
||||
void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
|
||||
{
|
||||
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
|
||||
*((uint8 *)video + x + y * _screen.pitch) = colour;
|
||||
});
|
||||
}
|
||||
|
||||
void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8 colour)
|
||||
{
|
||||
do {
|
||||
|
@@ -17,19 +17,20 @@
|
||||
/** Base for all 8bpp blitters. */
|
||||
class Blitter_8bppBase : public Blitter {
|
||||
public:
|
||||
/* virtual */ uint8 GetScreenDepth() { return 8; }
|
||||
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal);
|
||||
/* virtual */ void *MoveTo(void *video, int x, int y);
|
||||
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
|
||||
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
|
||||
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
|
||||
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
|
||||
/* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch);
|
||||
/* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y);
|
||||
/* virtual */ int BufferSize(int width, int height);
|
||||
/* virtual */ void PaletteAnimate(const Palette &palette);
|
||||
/* virtual */ Blitter::PaletteAnimation UsePaletteAnimation();
|
||||
/* virtual */ int GetBytesPerPixel() { return 1; }
|
||||
uint8 GetScreenDepth() override { return 8; }
|
||||
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
|
||||
void *MoveTo(void *video, int x, int y) override;
|
||||
void SetPixel(void *video, int x, int y, uint8 colour) override;
|
||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override;
|
||||
void DrawRect(void *video, int width, int height, uint8 colour) override;
|
||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override;
|
||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override;
|
||||
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override;
|
||||
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override;
|
||||
int BufferSize(int width, int height) override;
|
||||
void PaletteAnimate(const Palette &palette) override;
|
||||
Blitter::PaletteAnimation UsePaletteAnimation() override;
|
||||
int GetBytesPerPixel() override { return 1; }
|
||||
};
|
||||
|
||||
#endif /* BLITTER_8BPP_BASE_HPP */
|
||||
|
@@ -24,17 +24,17 @@ public:
|
||||
byte data[]; ///< Data, all zoomlevels.
|
||||
};
|
||||
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override;
|
||||
|
||||
/* virtual */ const char *GetName() { return "8bpp-optimized"; }
|
||||
const char *GetName() override { return "8bpp-optimized"; }
|
||||
};
|
||||
|
||||
/** Factory for the 8bpp blitter optimised for speed. */
|
||||
class FBlitter_8bppOptimized : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_8bppOptimized() : BlitterFactory("8bpp-optimized", "8bpp Optimized Blitter (compression + all-ZoomLevel cache)") {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_8bppOptimized(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_8bppOptimized(); }
|
||||
};
|
||||
|
||||
#endif /* BLITTER_8BPP_OPTIMIZED_HPP */
|
||||
|
@@ -18,17 +18,17 @@
|
||||
/** Most trivial 8bpp blitter. */
|
||||
class Blitter_8bppSimple FINAL : public Blitter_8bppBase {
|
||||
public:
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override;
|
||||
|
||||
/* virtual */ const char *GetName() { return "8bpp-simple"; }
|
||||
const char *GetName() override { return "8bpp-simple"; }
|
||||
};
|
||||
|
||||
/** Factory for the most trivial 8bpp blitter. */
|
||||
class FBlitter_8bppSimple : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_8bppSimple() : BlitterFactory("8bpp-simple", "8bpp Simple Blitter (relative slow, but never wrong)") {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_8bppSimple(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_8bppSimple(); }
|
||||
};
|
||||
|
||||
#endif /* BLITTER_8BPP_SIMPLE_HPP */
|
||||
|
@@ -122,7 +122,7 @@ public:
|
||||
* @param width Line width.
|
||||
* @param dash Length of dashes for dashed lines. 0 means solid line.
|
||||
*/
|
||||
virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0);
|
||||
virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0) = 0;
|
||||
|
||||
/**
|
||||
* Copy from a buffer to the screen.
|
||||
@@ -203,6 +203,8 @@ public:
|
||||
virtual void PostResize() { };
|
||||
|
||||
virtual ~Blitter() { }
|
||||
|
||||
template <typename SetPixelT> void DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel);
|
||||
};
|
||||
|
||||
#endif /* BLITTER_BASE_HPP */
|
||||
|
@@ -7,15 +7,18 @@
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file base.cpp Implementation of the base for all blitters. */
|
||||
/** @file common.hpp Common functionality for all blitter implementations. */
|
||||
|
||||
#ifndef BLITTER_COMMON_HPP
|
||||
#define BLITTER_COMMON_HPP
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "base.hpp"
|
||||
#include "../core/math_func.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
#include <utility>
|
||||
|
||||
void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
|
||||
template <typename SetPixelT>
|
||||
void Blitter::DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel)
|
||||
{
|
||||
int dy;
|
||||
int dx;
|
||||
@@ -40,7 +43,7 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
|
||||
|
||||
if (dx == 0 && dy == 0) {
|
||||
/* The algorithm below cannot handle this special case; make it work at least for line width 1 */
|
||||
if (x >= 0 && x < screen_width && y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour);
|
||||
if (x >= 0 && x < screen_width && y >= 0 && y < screen_height) set_pixel(x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,11 +52,11 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
|
||||
/* compute frac_diff = width * sqrt(dx*dx + dy*dy)
|
||||
* Start interval:
|
||||
* max(dx, dy) <= sqrt(dx*dx + dy*dy) <= sqrt(2) * max(dx, dy) <= 3/2 * max(dx, dy) */
|
||||
int frac_sq = width * width * (dx * dx + dy * dy);
|
||||
int64 frac_sq = ((int64) width) * ((int64) width) * (((int64) dx) * ((int64) dx) + ((int64) dy) * ((int64) dy));
|
||||
int frac_max = 3 * frac_diff / 2;
|
||||
while (frac_diff < frac_max) {
|
||||
int frac_test = (frac_diff + frac_max) / 2;
|
||||
if (frac_test * frac_test < frac_sq) {
|
||||
if (((int64) frac_test) * ((int64) frac_test) < frac_sq) {
|
||||
frac_diff = frac_test + 1;
|
||||
} else {
|
||||
frac_max = frac_test - 1;
|
||||
@@ -65,25 +68,52 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
|
||||
if (dash == 0) dash = 1;
|
||||
int dash_count = 0;
|
||||
if (dx > dy) {
|
||||
if (stepx < 0) {
|
||||
std::swap(x, x2);
|
||||
std::swap(y, y2);
|
||||
stepy = -stepy;
|
||||
}
|
||||
if (x2 < 0 || x >= screen_width) return;
|
||||
|
||||
int y_low = y;
|
||||
int y_high = y;
|
||||
int frac_low = dy - frac_diff / 2;
|
||||
int frac_high = dy + frac_diff / 2;
|
||||
|
||||
while (frac_low + dx / 2 < 0) {
|
||||
while (frac_low < -(dx / 2)) {
|
||||
frac_low += dx;
|
||||
y_low -= stepy;
|
||||
}
|
||||
while (frac_high - dx / 2 >= 0) {
|
||||
while (frac_high >= dx / 2) {
|
||||
frac_high -= dx;
|
||||
y_high += stepy;
|
||||
}
|
||||
x2 += stepx;
|
||||
|
||||
if (x < 0) {
|
||||
dash_count = (-x) % (dash + gap);
|
||||
auto adjust_frac = [&](int64 frac, int &y_bound) -> int {
|
||||
frac -= ((int64) dy) * ((int64) x);
|
||||
if (frac >= 0) {
|
||||
int quotient = frac / dx;
|
||||
int remainder = frac % dx;
|
||||
y_bound += (1 + quotient) * stepy;
|
||||
frac = remainder - dx;
|
||||
}
|
||||
return frac;
|
||||
};
|
||||
frac_low = adjust_frac(frac_low, y_low);
|
||||
frac_high = adjust_frac(frac_high, y_high);
|
||||
x = 0;
|
||||
}
|
||||
x2++;
|
||||
if (x2 > screen_width) {
|
||||
x2 = screen_width;
|
||||
}
|
||||
|
||||
while (x != x2) {
|
||||
if (dash_count < dash && x >= 0 && x < screen_width) {
|
||||
if (dash_count < dash) {
|
||||
for (int y = y_low; y != y_high; y += stepy) {
|
||||
if (y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour);
|
||||
if (y >= 0 && y < screen_height) set_pixel(x, y);
|
||||
}
|
||||
}
|
||||
if (frac_low >= 0) {
|
||||
@@ -94,31 +124,58 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
|
||||
y_high += stepy;
|
||||
frac_high -= dx;
|
||||
}
|
||||
x += stepx;
|
||||
x++;
|
||||
frac_low += dy;
|
||||
frac_high += dy;
|
||||
if (++dash_count >= dash + gap) dash_count = 0;
|
||||
}
|
||||
} else {
|
||||
if (stepy < 0) {
|
||||
std::swap(x, x2);
|
||||
std::swap(y, y2);
|
||||
stepx = -stepx;
|
||||
}
|
||||
if (y2 < 0 || y >= screen_height) return;
|
||||
|
||||
int x_low = x;
|
||||
int x_high = x;
|
||||
int frac_low = dx - frac_diff / 2;
|
||||
int frac_high = dx + frac_diff / 2;
|
||||
|
||||
while (frac_low + dy / 2 < 0) {
|
||||
while (frac_low < -(dy / 2)) {
|
||||
frac_low += dy;
|
||||
x_low -= stepx;
|
||||
}
|
||||
while (frac_high - dy / 2 >= 0) {
|
||||
while (frac_high >= dy / 2) {
|
||||
frac_high -= dy;
|
||||
x_high += stepx;
|
||||
}
|
||||
y2 += stepy;
|
||||
|
||||
if (y < 0) {
|
||||
dash_count = (-y) % (dash + gap);
|
||||
auto adjust_frac = [&](int64 frac, int &x_bound) -> int {
|
||||
frac -= ((int64) dx) * ((int64) y);
|
||||
if (frac >= 0) {
|
||||
int quotient = frac / dy;
|
||||
int remainder = frac % dy;
|
||||
x_bound += (1 + quotient) * stepx;
|
||||
frac = remainder - dy;
|
||||
}
|
||||
return frac;
|
||||
};
|
||||
frac_low = adjust_frac(frac_low, x_low);
|
||||
frac_high = adjust_frac(frac_high, x_high);
|
||||
y = 0;
|
||||
}
|
||||
y2++;
|
||||
if (y2 > screen_height) {
|
||||
y2 = screen_height;
|
||||
}
|
||||
|
||||
while (y != y2) {
|
||||
if (dash_count < dash && y >= 0 && y < screen_height) {
|
||||
if (dash_count < dash) {
|
||||
for (int x = x_low; x != x_high; x += stepx) {
|
||||
if (x >= 0 && x < screen_width) this->SetPixel(video, x, y, colour);
|
||||
if (x >= 0 && x < screen_width) set_pixel(x, y);
|
||||
}
|
||||
}
|
||||
if (frac_low >= 0) {
|
||||
@@ -129,10 +186,12 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
|
||||
x_high += stepx;
|
||||
frac_high -= dy;
|
||||
}
|
||||
y += stepy;
|
||||
y++;
|
||||
frac_low += dx;
|
||||
frac_high += dx;
|
||||
if (++dash_count >= dash + gap) dash_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BLITTER_COMMON_HPP */
|
@@ -17,31 +17,31 @@
|
||||
/** Blitter that does nothing. */
|
||||
class Blitter_Null : public Blitter {
|
||||
public:
|
||||
/* virtual */ uint8 GetScreenDepth() { return 0; }
|
||||
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) {};
|
||||
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) {};
|
||||
/* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator);
|
||||
/* virtual */ void *MoveTo(void *video, int x, int y) { return NULL; };
|
||||
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour) {};
|
||||
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour) {};
|
||||
/* virtual */ void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) {};
|
||||
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height) {};
|
||||
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height) {};
|
||||
/* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) {};
|
||||
/* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) {};
|
||||
/* virtual */ int BufferSize(int width, int height) { return 0; };
|
||||
/* virtual */ void PaletteAnimate(const Palette &palette) { };
|
||||
/* virtual */ Blitter::PaletteAnimation UsePaletteAnimation() { return Blitter::PALETTE_ANIMATION_NONE; };
|
||||
uint8 GetScreenDepth() override { return 0; }
|
||||
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override {};
|
||||
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override {};
|
||||
Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override;
|
||||
void *MoveTo(void *video, int x, int y) override { return NULL; };
|
||||
void SetPixel(void *video, int x, int y, uint8 colour) override {};
|
||||
void DrawRect(void *video, int width, int height, uint8 colour) override {};
|
||||
void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override {};
|
||||
void CopyFromBuffer(void *video, const void *src, int width, int height) override {};
|
||||
void CopyToBuffer(const void *video, void *dst, int width, int height) override {};
|
||||
void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override {};
|
||||
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override {};
|
||||
int BufferSize(int width, int height) override { return 0; };
|
||||
void PaletteAnimate(const Palette &palette) override { };
|
||||
Blitter::PaletteAnimation UsePaletteAnimation() override { return Blitter::PALETTE_ANIMATION_NONE; };
|
||||
|
||||
/* virtual */ const char *GetName() { return "null"; }
|
||||
/* virtual */ int GetBytesPerPixel() { return 0; }
|
||||
const char *GetName() override { return "null"; }
|
||||
int GetBytesPerPixel() override { return 0; }
|
||||
};
|
||||
|
||||
/** Factory for the blitter that does nothing. */
|
||||
class FBlitter_Null : public BlitterFactory {
|
||||
public:
|
||||
FBlitter_Null() : BlitterFactory("null", "Null Blitter (does nothing)") {}
|
||||
/* virtual */ Blitter *CreateInstance() { return new Blitter_Null(); }
|
||||
Blitter *CreateInstance() override { return new Blitter_Null(); }
|
||||
};
|
||||
|
||||
#endif /* BLITTER_NULL_HPP */
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#include "base_media_base.h"
|
||||
#include "blitter/factory.hpp"
|
||||
|
||||
#if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE)
|
||||
#if defined(WITH_FREETYPE)
|
||||
|
||||
#include "core/geometry_func.hpp"
|
||||
#include "fontcache.h"
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
ResizeWindow(this, _screen.width, _screen.height);
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE);
|
||||
GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER);
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnDownloadComplete(ContentID cid)
|
||||
void OnDownloadComplete(ContentID cid) override
|
||||
{
|
||||
/* We have completed downloading. We can trigger finding the right set now. */
|
||||
BaseGraphics::FindSets();
|
||||
@@ -142,7 +142,7 @@ public:
|
||||
_network_content_client.RemoveCallback(this);
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
/* We cache the button size. This is safe as no reinit can happen here. */
|
||||
if (this->button_size.width == 0) {
|
||||
@@ -165,14 +165,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
if (widget != 0) return;
|
||||
|
||||
DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMETEXT_TOP, r.bottom - WD_FRAMETEXT_BOTTOM, STR_MISSING_GRAPHICS_SET_MESSAGE, TC_FROMSTRING, SA_CENTER);
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BAFD_YES:
|
||||
@@ -189,13 +189,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnConnect(bool success)
|
||||
void OnConnect(bool success) override
|
||||
{
|
||||
/* Once connected, request the metadata. */
|
||||
_network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
|
||||
}
|
||||
|
||||
virtual void OnReceiveContentInfo(const ContentInfo *ci)
|
||||
void OnReceiveContentInfo(const ContentInfo *ci) override
|
||||
{
|
||||
/* And once the meta data is received, start downloading it. */
|
||||
_network_content_client.Select(ci->id);
|
||||
@@ -204,7 +204,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) */
|
||||
#endif /* defined(WITH_FREETYPE) */
|
||||
|
||||
/**
|
||||
* Handle all procedures for bootstrapping OpenTTD without a base graphics set.
|
||||
@@ -220,7 +220,7 @@ bool HandleBootstrap()
|
||||
if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
|
||||
|
||||
/* If there is no network or no freetype, then there is nothing we can do. Go straight to failure. */
|
||||
#if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(WIN32) || defined(__APPLE__))
|
||||
#if defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(_WIN32) || defined(__APPLE__))
|
||||
if (!_network_available) goto failure;
|
||||
|
||||
/* First tell the game we're bootstrapping. */
|
||||
|
@@ -113,11 +113,11 @@ private:
|
||||
void BuildBridge(uint8 i)
|
||||
{
|
||||
switch ((TransportType)(this->type >> 15)) {
|
||||
case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->Get(i)->index; break;
|
||||
case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->Get(i)->index; break;
|
||||
case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->at(i).index; break;
|
||||
case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->at(i).index; break;
|
||||
default: break;
|
||||
}
|
||||
DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->Get(i)->index,
|
||||
DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->at(i).index,
|
||||
CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge);
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
this->bridges->NeedResort();
|
||||
this->SortBridgeList();
|
||||
|
||||
this->vscroll->SetCount(bl->Length());
|
||||
this->vscroll->SetCount((uint)bl->size());
|
||||
}
|
||||
|
||||
~BuildBridgeWindow()
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
delete bridges;
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BBS_DROPDOWN_ORDER: {
|
||||
@@ -186,11 +186,11 @@ public:
|
||||
case WID_BBS_BRIDGE_LIST: {
|
||||
Dimension sprite_dim = {0, 0}; // Biggest bridge sprite dimension
|
||||
Dimension text_dim = {0, 0}; // Biggest text dimension
|
||||
for (int i = 0; i < (int)this->bridges->Length(); i++) {
|
||||
const BridgeSpec *b = this->bridges->Get(i)->spec;
|
||||
for (int i = 0; i < (int)this->bridges->size(); i++) {
|
||||
const BridgeSpec *b = this->bridges->at(i).spec;
|
||||
sprite_dim = maxdim(sprite_dim, GetSpriteSize(b->sprite));
|
||||
|
||||
SetDParam(2, this->bridges->Get(i)->cost);
|
||||
SetDParam(2, this->bridges->at(i).cost);
|
||||
SetDParam(1, b->speed);
|
||||
SetDParam(0, b->material);
|
||||
text_dim = maxdim(text_dim, GetStringBoundingBox(_game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_SCENEDIT_INFO : STR_SELECT_BRIDGE_INFO));
|
||||
@@ -207,7 +207,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
|
||||
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
|
||||
{
|
||||
/* Position the window so hopefully the first bridge from the list is under the mouse pointer. */
|
||||
NWidgetBase *list = this->GetWidget<NWidgetBase>(WID_BBS_BRIDGE_LIST);
|
||||
@@ -217,7 +217,7 @@ public:
|
||||
return corner;
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BBS_DROPDOWN_ORDER:
|
||||
@@ -226,10 +226,10 @@ public:
|
||||
|
||||
case WID_BBS_BRIDGE_LIST: {
|
||||
uint y = r.top;
|
||||
for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < (int)this->bridges->Length(); i++) {
|
||||
const BridgeSpec *b = this->bridges->Get(i)->spec;
|
||||
for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < (int)this->bridges->size(); i++) {
|
||||
const BridgeSpec *b = this->bridges->at(i).spec;
|
||||
|
||||
SetDParam(2, this->bridges->Get(i)->cost);
|
||||
SetDParam(2, this->bridges->at(i).cost);
|
||||
SetDParam(1, b->speed);
|
||||
SetDParam(0, b->material);
|
||||
|
||||
@@ -243,10 +243,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual EventState OnKeyPress(WChar key, uint16 keycode)
|
||||
EventState OnKeyPress(WChar key, uint16 keycode) override
|
||||
{
|
||||
const uint8 i = keycode - '1';
|
||||
if (i < 9 && i < this->bridges->Length()) {
|
||||
if (i < 9 && i < this->bridges->size()) {
|
||||
/* Build the requested bridge */
|
||||
this->BuildBridge(i);
|
||||
delete this;
|
||||
@@ -255,13 +255,13 @@ public:
|
||||
return ES_NOT_HANDLED;
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
default: break;
|
||||
case WID_BBS_BRIDGE_LIST: {
|
||||
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BBS_BRIDGE_LIST);
|
||||
if (i < this->bridges->Length()) {
|
||||
if (i < this->bridges->size()) {
|
||||
this->BuildBridge(i);
|
||||
delete this;
|
||||
}
|
||||
@@ -279,7 +279,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnDropdownSelect(int widget, int index)
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
if (widget == WID_BBS_DROPDOWN_CRITERIA && this->bridges->SortType() != index) {
|
||||
this->bridges->SetSortType(index);
|
||||
@@ -288,7 +288,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_BBS_BRIDGE_LIST);
|
||||
}
|
||||
@@ -416,17 +416,18 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
|
||||
for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
|
||||
if (CheckBridgeAvailability(brd_type, bridge_len).Succeeded()) {
|
||||
/* bridge is accepted, add to list */
|
||||
BuildBridgeData *item = bl->Append();
|
||||
item->index = brd_type;
|
||||
item->spec = GetBridgeSpec(brd_type);
|
||||
/*C++17: BuildBridgeData &item = */ bl->emplace_back();
|
||||
BuildBridgeData &item = bl->back();
|
||||
item.index = brd_type;
|
||||
item.spec = GetBridgeSpec(brd_type);
|
||||
/* Add to terraforming & bulldozing costs the cost of the
|
||||
* bridge itself (not computed with DC_QUERY_COST) */
|
||||
item->cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price[PR_BUILD_BRIDGE] * item->spec->price) >> 8) + infra_cost;
|
||||
item.cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price[PR_BUILD_BRIDGE] * item.spec->price) >> 8) + infra_cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bl != NULL && bl->Length() != 0) {
|
||||
if (bl != NULL && bl->size() != 0) {
|
||||
new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl);
|
||||
} else {
|
||||
delete bl;
|
||||
|
@@ -56,7 +56,7 @@ TileIndex GetSouthernBridgeEnd(TileIndex t)
|
||||
|
||||
/**
|
||||
* Starting at one bridge end finds the other bridge end
|
||||
* @param t the bridge ramp tile to find the other bridge ramp for
|
||||
* @param tile the bridge ramp tile to find the other bridge ramp for
|
||||
*/
|
||||
TileIndex GetOtherBridgeEnd(TileIndex tile)
|
||||
{
|
||||
@@ -66,7 +66,7 @@ TileIndex GetOtherBridgeEnd(TileIndex tile)
|
||||
|
||||
/**
|
||||
* Get the height ('z') of a bridge.
|
||||
* @param tile the bridge ramp tile to get the bridge height from
|
||||
* @param t the bridge ramp tile to get the bridge height from
|
||||
* @return the height of the bridge.
|
||||
*/
|
||||
int GetBridgeHeight(TileIndex t)
|
||||
|
@@ -532,11 +532,11 @@ static GUIEngineList::FilterFunction * const _filter_funcs[] = {
|
||||
&CargoFilter,
|
||||
};
|
||||
|
||||
static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine)
|
||||
static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, TestedEngineDetails &te)
|
||||
{
|
||||
CargoArray cap;
|
||||
CargoTypes refits;
|
||||
GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits);
|
||||
GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits, te.cargo, te.capacity);
|
||||
|
||||
for (CargoID c = 0; c < NUM_CARGO; c++) {
|
||||
if (cap[c] == 0) continue;
|
||||
@@ -552,19 +552,25 @@ static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine)
|
||||
}
|
||||
|
||||
/* Draw rail wagon specific details */
|
||||
static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi)
|
||||
static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine_number);
|
||||
|
||||
/* Purchase cost */
|
||||
SetDParam(0, e->GetCost());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST);
|
||||
if (te.cost != 0) {
|
||||
SetDParam(0, e->GetCost() + te.cost);
|
||||
SetDParam(1, te.cost);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
|
||||
} else {
|
||||
SetDParam(0, e->GetCost());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST);
|
||||
}
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
|
||||
/* Wagon weight - (including cargo) */
|
||||
uint weight = e->GetDisplayWeight();
|
||||
SetDParam(0, weight);
|
||||
uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0);
|
||||
uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0);
|
||||
SetDParam(1, cargo_weight + weight);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
@@ -590,14 +596,21 @@ static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine
|
||||
}
|
||||
|
||||
/* Draw locomotive specific details */
|
||||
static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi)
|
||||
static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine_number);
|
||||
|
||||
/* Purchase Cost - Engine weight */
|
||||
SetDParam(0, e->GetCost());
|
||||
SetDParam(1, e->GetDisplayWeight());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
|
||||
if (te.cost != 0) {
|
||||
SetDParam(0, e->GetCost() + te.cost);
|
||||
SetDParam(1, te.cost);
|
||||
SetDParam(2, e->GetDisplayWeight());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_WEIGHT);
|
||||
} else {
|
||||
SetDParam(0, e->GetCost());
|
||||
SetDParam(1, e->GetDisplayWeight());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
|
||||
}
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
|
||||
/* Max speed - Engine power */
|
||||
@@ -632,20 +645,26 @@ static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engin
|
||||
}
|
||||
|
||||
/* Draw road vehicle specific details */
|
||||
static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number)
|
||||
static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine_number);
|
||||
|
||||
if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) {
|
||||
/* Purchase Cost */
|
||||
SetDParam(0, e->GetCost());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST);
|
||||
if (te.cost != 0) {
|
||||
SetDParam(0, e->GetCost() + te.cost);
|
||||
SetDParam(1, te.cost);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
|
||||
} else {
|
||||
SetDParam(0, e->GetCost());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST);
|
||||
}
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
|
||||
/* Road vehicle weight - (including cargo) */
|
||||
int16 weight = e->GetDisplayWeight();
|
||||
SetDParam(0, weight);
|
||||
uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0);
|
||||
uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0);
|
||||
SetDParam(1, cargo_weight + weight);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
@@ -662,9 +681,16 @@ static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_n
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
} else {
|
||||
/* Purchase cost - Max speed */
|
||||
SetDParam(0, e->GetCost());
|
||||
SetDParam(1, e->GetDisplayMaxSpeed());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
|
||||
if (te.cost != 0) {
|
||||
SetDParam(0, e->GetCost() + te.cost);
|
||||
SetDParam(1, te.cost);
|
||||
SetDParam(2, e->GetDisplayMaxSpeed());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
|
||||
} else {
|
||||
SetDParam(0, e->GetCost());
|
||||
SetDParam(2, e->GetDisplayMaxSpeed());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
|
||||
}
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
}
|
||||
|
||||
@@ -677,7 +703,7 @@ static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_n
|
||||
}
|
||||
|
||||
/* Draw ship specific details */
|
||||
static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable)
|
||||
static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine_number);
|
||||
|
||||
@@ -686,13 +712,27 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb
|
||||
uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
|
||||
uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
|
||||
|
||||
SetDParam(0, e->GetCost());
|
||||
if (ocean_speed == canal_speed) {
|
||||
SetDParam(1, ocean_speed);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
|
||||
if (te.cost != 0) {
|
||||
SetDParam(0, e->GetCost() + te.cost);
|
||||
SetDParam(1, te.cost);
|
||||
SetDParam(2, ocean_speed);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
|
||||
} else {
|
||||
SetDParam(0, e->GetCost());
|
||||
SetDParam(1, ocean_speed);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
|
||||
}
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
} else {
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST);
|
||||
if (te.cost != 0) {
|
||||
SetDParam(0, e->GetCost() + te.cost);
|
||||
SetDParam(1, te.cost);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT);
|
||||
} else {
|
||||
SetDParam(0, e->GetCost());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST);
|
||||
}
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
|
||||
SetDParam(0, ocean_speed);
|
||||
@@ -705,8 +745,8 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb
|
||||
}
|
||||
|
||||
/* Cargo type + capacity */
|
||||
SetDParam(0, e->GetDefaultCargoType());
|
||||
SetDParam(1, e->GetDisplayDefaultCapacity());
|
||||
SetDParam(0, te.cargo);
|
||||
SetDParam(1, te.capacity);
|
||||
SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
@@ -728,31 +768,35 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb
|
||||
* @param refittable If set, the aircraft can be refitted.
|
||||
* @return Bottom of the used area.
|
||||
*/
|
||||
static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable)
|
||||
static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine_number);
|
||||
CargoID cargo = e->GetDefaultCargoType();
|
||||
|
||||
/* Purchase cost - Max speed */
|
||||
SetDParam(0, e->GetCost());
|
||||
SetDParam(1, e->GetDisplayMaxSpeed());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
|
||||
if (te.cost != 0) {
|
||||
SetDParam(0, e->GetCost() + te.cost);
|
||||
SetDParam(1, te.cost);
|
||||
SetDParam(2, e->GetDisplayMaxSpeed());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED);
|
||||
} else {
|
||||
SetDParam(0, e->GetCost());
|
||||
SetDParam(1, e->GetDisplayMaxSpeed());
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
|
||||
}
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
|
||||
/* Cargo capacity */
|
||||
uint16 mail_capacity;
|
||||
uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
|
||||
if (mail_capacity > 0) {
|
||||
SetDParam(0, cargo);
|
||||
SetDParam(1, capacity);
|
||||
if (te.mail_capacity > 0) {
|
||||
SetDParam(0, te.cargo);
|
||||
SetDParam(1, te.capacity);
|
||||
SetDParam(2, CT_MAIL);
|
||||
SetDParam(3, mail_capacity);
|
||||
SetDParam(3, te.mail_capacity);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY);
|
||||
} else {
|
||||
/* Note, if the default capacity is selected by the refit capacity
|
||||
* callback, then the capacity shown is likely to be incorrect. */
|
||||
SetDParam(0, cargo);
|
||||
SetDParam(1, capacity);
|
||||
SetDParam(0, te.cargo);
|
||||
SetDParam(1, te.capacity);
|
||||
SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
|
||||
DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
|
||||
}
|
||||
@@ -809,7 +853,7 @@ static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
|
||||
* @param engine_number the engine of which to draw the info of
|
||||
* @return y after drawing all the text
|
||||
*/
|
||||
int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number)
|
||||
int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te)
|
||||
{
|
||||
const Engine *e = Engine::Get(engine_number);
|
||||
YearMonthDay ymd;
|
||||
@@ -821,30 +865,30 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number)
|
||||
default: NOT_REACHED();
|
||||
case VEH_TRAIN:
|
||||
if (e->u.rail.railveh_type == RAILVEH_WAGON) {
|
||||
y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail);
|
||||
y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
|
||||
} else {
|
||||
y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail);
|
||||
y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
|
||||
}
|
||||
articulated_cargo = true;
|
||||
break;
|
||||
|
||||
case VEH_ROAD:
|
||||
y = DrawRoadVehPurchaseInfo(left, right, y, engine_number);
|
||||
y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te);
|
||||
articulated_cargo = true;
|
||||
break;
|
||||
|
||||
case VEH_SHIP:
|
||||
y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable);
|
||||
y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te);
|
||||
break;
|
||||
|
||||
case VEH_AIRCRAFT:
|
||||
y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable);
|
||||
y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te);
|
||||
break;
|
||||
}
|
||||
|
||||
if (articulated_cargo) {
|
||||
/* Cargo type + capacity, or N/A */
|
||||
int new_y = DrawCargoCapacityInfo(left, right, y, engine_number);
|
||||
int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, te);
|
||||
|
||||
if (new_y == y) {
|
||||
SetDParam(0, CT_INVALID);
|
||||
@@ -896,7 +940,7 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *
|
||||
static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
|
||||
|
||||
/* Obligatory sanity checks! */
|
||||
assert(max <= eng_list->Length());
|
||||
assert(max <= eng_list->size());
|
||||
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
int step_size = GetEngineListHeight(type);
|
||||
@@ -988,6 +1032,23 @@ struct BuildVehicleWindow : Window {
|
||||
byte cargo_filter_criteria; ///< Selected cargo filter
|
||||
int details_height; ///< Minimal needed height of the details panels (found so far).
|
||||
Scrollbar *vscroll;
|
||||
TestedEngineDetails te; ///< Tested cost and capacity after refit.
|
||||
|
||||
void SetBuyVehicleText()
|
||||
{
|
||||
NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
|
||||
|
||||
bool refit = this->sel_engine != INVALID_ENGINE && this->cargo_filter[this->cargo_filter_criteria] != CF_ANY && this->cargo_filter[this->cargo_filter_criteria] != CF_NONE;
|
||||
if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter[this->cargo_filter_criteria];
|
||||
|
||||
if (refit) {
|
||||
widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type;
|
||||
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this->vehicle_type;
|
||||
} else {
|
||||
widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type;
|
||||
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this->vehicle_type;
|
||||
}
|
||||
}
|
||||
|
||||
BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc)
|
||||
{
|
||||
@@ -1031,10 +1092,6 @@ struct BuildVehicleWindow : Window {
|
||||
widget = this->GetWidget<NWidgetCore>(WID_BV_SHOW_HIDE);
|
||||
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type;
|
||||
|
||||
widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
|
||||
widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + type;
|
||||
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + type;
|
||||
|
||||
widget = this->GetWidget<NWidgetCore>(WID_BV_RENAME);
|
||||
widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type;
|
||||
widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type;
|
||||
@@ -1053,7 +1110,11 @@ struct BuildVehicleWindow : Window {
|
||||
this->eng_list.ForceRebuild();
|
||||
this->GenerateBuildList(); // generate the list, since we need it in the next line
|
||||
/* Select the first engine in the list as default when opening the window */
|
||||
if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0];
|
||||
if (this->eng_list.size() > 0) {
|
||||
this->SelectEngine(this->eng_list[0]);
|
||||
} else {
|
||||
this->SelectEngine(INVALID_ENGINE);
|
||||
}
|
||||
}
|
||||
|
||||
/** Populate the filter list and set the cargo filter criteria. */
|
||||
@@ -1070,7 +1131,7 @@ struct BuildVehicleWindow : Window {
|
||||
* This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
|
||||
if (this->vehicle_type == VEH_TRAIN) {
|
||||
this->cargo_filter[filter_items] = CF_NONE;
|
||||
this->cargo_filter_texts[filter_items] = STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE;
|
||||
this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_NONE;
|
||||
filter_items++;
|
||||
}
|
||||
|
||||
@@ -1100,7 +1161,42 @@ struct BuildVehicleWindow : Window {
|
||||
this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
|
||||
}
|
||||
|
||||
void OnInit()
|
||||
void SelectEngine(EngineID engine)
|
||||
{
|
||||
CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
|
||||
if (cargo == CF_ANY) cargo = CF_NONE;
|
||||
|
||||
this->sel_engine = engine;
|
||||
this->SetBuyVehicleText();
|
||||
|
||||
if (this->sel_engine == INVALID_ENGINE) return;
|
||||
|
||||
const Engine *e = Engine::Get(this->sel_engine);
|
||||
if (!e->CanCarryCargo()) {
|
||||
this->te.cost = 0;
|
||||
this->te.cargo = CT_INVALID;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->listview_mode) {
|
||||
/* Query for cost and refitted capacity */
|
||||
CommandCost ret = DoCommand(this->window_number, this->sel_engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), NULL);
|
||||
if (ret.Succeeded()) {
|
||||
this->te.cost = ret.GetCost() - e->GetCost();
|
||||
this->te.capacity = _returned_refit_capacity;
|
||||
this->te.mail_capacity = _returned_mail_refit_capacity;
|
||||
this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Purchase test was not possible or failed, fill in the defaults instead. */
|
||||
this->te.cost = 0;
|
||||
this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity);
|
||||
this->te.cargo = e->GetDefaultCargoType();
|
||||
}
|
||||
|
||||
void OnInit() override
|
||||
{
|
||||
this->SetCargoFilterArray();
|
||||
}
|
||||
@@ -1109,10 +1205,10 @@ struct BuildVehicleWindow : Window {
|
||||
void FilterEngineList()
|
||||
{
|
||||
this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]);
|
||||
if (0 == this->eng_list.Length()) { // no engine passed through the filter, invalidate the previously selected engine
|
||||
this->sel_engine = INVALID_ENGINE;
|
||||
} else if (!this->eng_list.Contains(this->sel_engine)) { // previously selected engine didn't pass the filter, select the first engine of the list
|
||||
this->sel_engine = this->eng_list[0];
|
||||
if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
|
||||
this->SelectEngine(INVALID_ENGINE);
|
||||
} else if (std::find(this->eng_list.begin(), this->eng_list.end(), this->sel_engine) == this->eng_list.end()) { // previously selected engine didn't pass the filter, select the first engine of the list
|
||||
this->SelectEngine(this->eng_list[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1132,7 +1228,7 @@ struct BuildVehicleWindow : Window {
|
||||
|
||||
this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number);
|
||||
|
||||
this->eng_list.Clear();
|
||||
this->eng_list.clear();
|
||||
|
||||
/* Make list of all available train engines and wagons.
|
||||
* Also check to see if the previously selected engine is still available,
|
||||
@@ -1150,7 +1246,7 @@ struct BuildVehicleWindow : Window {
|
||||
/* Filter now! So num_engines and num_wagons is valid */
|
||||
if (!FilterSingleEngine(eid)) continue;
|
||||
|
||||
*this->eng_list.Append() = eid;
|
||||
this->eng_list.push_back(eid);
|
||||
|
||||
if (rvi->railveh_type != RAILVEH_WAGON) {
|
||||
num_engines++;
|
||||
@@ -1161,7 +1257,7 @@ struct BuildVehicleWindow : Window {
|
||||
if (eid == this->sel_engine) sel_id = eid;
|
||||
}
|
||||
|
||||
this->sel_engine = sel_id;
|
||||
this->SelectEngine(sel_id);
|
||||
|
||||
/* make engines first, and then wagons, sorted by selected sort_criteria */
|
||||
_engine_sort_direction = false;
|
||||
@@ -1180,7 +1276,7 @@ struct BuildVehicleWindow : Window {
|
||||
{
|
||||
EngineID sel_id = INVALID_ENGINE;
|
||||
|
||||
this->eng_list.Clear();
|
||||
this->eng_list.clear();
|
||||
|
||||
const Engine *e;
|
||||
FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
|
||||
@@ -1188,29 +1284,29 @@ struct BuildVehicleWindow : Window {
|
||||
EngineID eid = e->index;
|
||||
if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
|
||||
if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
|
||||
*this->eng_list.Append() = eid;
|
||||
this->eng_list.push_back(eid);
|
||||
|
||||
if (eid == this->sel_engine) sel_id = eid;
|
||||
}
|
||||
this->sel_engine = sel_id;
|
||||
this->SelectEngine(sel_id);
|
||||
}
|
||||
|
||||
/* Figure out what ship EngineIDs to put in the list */
|
||||
void GenerateBuildShipList()
|
||||
{
|
||||
EngineID sel_id = INVALID_ENGINE;
|
||||
this->eng_list.Clear();
|
||||
this->eng_list.clear();
|
||||
|
||||
const Engine *e;
|
||||
FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
|
||||
if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue;
|
||||
EngineID eid = e->index;
|
||||
if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
|
||||
*this->eng_list.Append() = eid;
|
||||
this->eng_list.push_back(eid);
|
||||
|
||||
if (eid == this->sel_engine) sel_id = eid;
|
||||
}
|
||||
this->sel_engine = sel_id;
|
||||
this->SelectEngine(sel_id);
|
||||
}
|
||||
|
||||
/* Figure out what aircraft EngineIDs to put in the list */
|
||||
@@ -1218,7 +1314,7 @@ struct BuildVehicleWindow : Window {
|
||||
{
|
||||
EngineID sel_id = INVALID_ENGINE;
|
||||
|
||||
this->eng_list.Clear();
|
||||
this->eng_list.clear();
|
||||
|
||||
const Station *st = this->listview_mode ? NULL : Station::GetByTile(this->window_number);
|
||||
|
||||
@@ -1234,11 +1330,11 @@ struct BuildVehicleWindow : Window {
|
||||
/* First VEH_END window_numbers are fake to allow a window open for all different types at once */
|
||||
if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
|
||||
|
||||
*this->eng_list.Append() = eid;
|
||||
this->eng_list.push_back(eid);
|
||||
if (eid == this->sel_engine) sel_id = eid;
|
||||
}
|
||||
|
||||
this->sel_engine = sel_id;
|
||||
this->SelectEngine(sel_id);
|
||||
}
|
||||
|
||||
/* Generate the list of vehicles */
|
||||
@@ -1249,7 +1345,7 @@ struct BuildVehicleWindow : Window {
|
||||
default: NOT_REACHED();
|
||||
case VEH_TRAIN:
|
||||
this->GenerateBuildTrainList();
|
||||
this->eng_list.Compact();
|
||||
this->eng_list.shrink_to_fit();
|
||||
this->eng_list.RebuildDone();
|
||||
return; // trains should not reach the last sorting
|
||||
case VEH_ROAD:
|
||||
@@ -1268,11 +1364,11 @@ struct BuildVehicleWindow : Window {
|
||||
_engine_sort_direction = this->descending_sort_order;
|
||||
EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
|
||||
|
||||
this->eng_list.Compact();
|
||||
this->eng_list.shrink_to_fit();
|
||||
this->eng_list.RebuildDone();
|
||||
}
|
||||
|
||||
void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BV_SORT_ASCENDING_DESCENDING:
|
||||
@@ -1292,8 +1388,8 @@ struct BuildVehicleWindow : Window {
|
||||
|
||||
case WID_BV_LIST: {
|
||||
uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST);
|
||||
size_t num_items = this->eng_list.Length();
|
||||
this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE;
|
||||
size_t num_items = this->eng_list.size();
|
||||
this->SelectEngine((i < num_items) ? this->eng_list[i] : INVALID_ENGINE);
|
||||
this->SetDirty();
|
||||
if (_ctrl_pressed) {
|
||||
this->OnClick(pt, WID_BV_SHOW_HIDE, 1);
|
||||
@@ -1323,7 +1419,9 @@ struct BuildVehicleWindow : Window {
|
||||
EngineID sel_eng = this->sel_engine;
|
||||
if (sel_eng != INVALID_ENGINE) {
|
||||
CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
|
||||
DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback);
|
||||
CargoID cargo = this->cargo_filter[this->cargo_filter_criteria];
|
||||
if (cargo == CF_ANY) cargo = CF_NONE;
|
||||
DoCommandP(this->window_number, sel_eng | (cargo << 24), 0, GetCmdBuildVeh(this->vehicle_type), callback);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1345,7 +1443,7 @@ struct BuildVehicleWindow : Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
/* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */
|
||||
@@ -1358,7 +1456,7 @@ struct BuildVehicleWindow : Window {
|
||||
this->eng_list.ForceRebuild();
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BV_CAPTION:
|
||||
@@ -1390,7 +1488,7 @@ struct BuildVehicleWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BV_LIST:
|
||||
@@ -1411,6 +1509,13 @@ struct BuildVehicleWindow : Window {
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_BV_BUILD:
|
||||
*size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
|
||||
*size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
|
||||
size->width += padding.width;
|
||||
size->height += padding.height;
|
||||
break;
|
||||
|
||||
case WID_BV_SHOW_HIDE:
|
||||
*size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
|
||||
*size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
|
||||
@@ -1420,11 +1525,11 @@ struct BuildVehicleWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BV_LIST:
|
||||
DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP);
|
||||
DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->eng_list.size()), this->sel_engine, false, DEFAULT_GROUP);
|
||||
break;
|
||||
|
||||
case WID_BV_SORT_ASCENDING_DESCENDING:
|
||||
@@ -1433,12 +1538,12 @@ struct BuildVehicleWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
this->GenerateBuildList();
|
||||
this->vscroll->SetCount(this->eng_list.Length());
|
||||
this->vscroll->SetCount((uint)this->eng_list.size());
|
||||
|
||||
this->SetWidgetDisabledState(WID_BV_SHOW_HIDE, this->sel_engine == INVALID_ENGINE);
|
||||
this->SetWidgetsDisabledState(this->sel_engine == INVALID_ENGINE, WID_BV_SHOW_HIDE, WID_BV_BUILD, WID_BV_RENAME, WIDGET_LIST_END);
|
||||
|
||||
this->DrawWidgets();
|
||||
|
||||
@@ -1448,7 +1553,7 @@ struct BuildVehicleWindow : Window {
|
||||
if (this->sel_engine != INVALID_ENGINE) {
|
||||
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_BV_PANEL);
|
||||
int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT,
|
||||
nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine);
|
||||
nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine, this->te);
|
||||
needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM);
|
||||
}
|
||||
if (needed_height != this->details_height) { // Details window are not high enough, enlarge them.
|
||||
@@ -1460,14 +1565,14 @@ struct BuildVehicleWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnQueryTextFinished(char *str)
|
||||
void OnQueryTextFinished(char *str) override
|
||||
{
|
||||
if (str == NULL) return;
|
||||
|
||||
DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str);
|
||||
}
|
||||
|
||||
virtual void OnDropdownSelect(int widget, int index)
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BV_SORT_DROPDOWN:
|
||||
@@ -1485,13 +1590,14 @@ struct BuildVehicleWindow : Window {
|
||||
/* deactivate filter if criteria is 'Show All', activate it otherwise */
|
||||
this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
|
||||
this->eng_list.ForceRebuild();
|
||||
this->SelectEngine(this->sel_engine);
|
||||
}
|
||||
break;
|
||||
}
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST);
|
||||
}
|
||||
|
@@ -70,6 +70,11 @@ enum CargoType {
|
||||
CT_INVALID = 0xFF, ///< Invalid cargo type.
|
||||
};
|
||||
|
||||
/** Test whether cargo type is not CT_INVALID */
|
||||
inline bool IsCargoTypeValid(CargoType t) { return t != CT_INVALID; }
|
||||
/** Test whether cargo type is not CT_INVALID */
|
||||
inline bool IsCargoIDValid(CargoID t) { return t != CT_INVALID; }
|
||||
|
||||
typedef uint64 CargoTypes;
|
||||
|
||||
static const CargoTypes ALL_CARGOTYPES = (CargoTypes)UINT64_MAX;
|
||||
|
@@ -117,8 +117,9 @@ int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring)
|
||||
* @param src_type type of \a src.
|
||||
* @param src index of source.
|
||||
* @param st station where the cargo is delivered to.
|
||||
* @param dest industry index where the cargo is delivered to.
|
||||
*/
|
||||
void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st)
|
||||
void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st, IndustryID dest)
|
||||
{
|
||||
if (amount == 0) return;
|
||||
|
||||
@@ -150,8 +151,9 @@ void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, Sour
|
||||
if (iter != _cargo_deliveries.end()) iter->second += amount;
|
||||
|
||||
/* Industry delivery. */
|
||||
for (const Industry * const *ip = st->industries_near.Begin(); ip != st->industries_near.End(); ip++) {
|
||||
CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, (*ip)->index);
|
||||
for (Industry *ind : st->industries_near) {
|
||||
if (ind->index != dest) continue;
|
||||
CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, ind->index);
|
||||
CargoMonitorMap::iterator iter = _cargo_deliveries.find(num);
|
||||
if (iter != _cargo_deliveries.end()) iter->second += amount;
|
||||
}
|
||||
|
@@ -45,11 +45,14 @@ enum CargoCompanyBits {
|
||||
CCB_IS_INDUSTRY_BIT = 16, ///< Bit indicating the town/industry number is an industry.
|
||||
CCB_IS_INDUSTRY_BIT_VALUE = 1ul << CCB_IS_INDUSTRY_BIT, ///< Value of the #CCB_IS_INDUSTRY_BIT bit.
|
||||
CCB_CARGO_TYPE_START = 19, ///< Start bit of the cargo type field.
|
||||
CCB_CARGO_TYPE_LENGTH = 5, ///< Number of bits of the cargo type field.
|
||||
CCB_COMPANY_START = 24, ///< Start bit of the company field.
|
||||
CCB_COMPANY_LENGTH = 8, ///< Number of bits of the company field.
|
||||
CCB_CARGO_TYPE_LENGTH = 6, ///< Number of bits of the cargo type field.
|
||||
CCB_COMPANY_START = 25, ///< Start bit of the company field.
|
||||
CCB_COMPANY_LENGTH = 4, ///< Number of bits of the company field.
|
||||
};
|
||||
|
||||
assert_compile(NUM_CARGO <= (1 << CCB_CARGO_TYPE_LENGTH));
|
||||
assert_compile(MAX_COMPANIES <= (1 << CCB_COMPANY_LENGTH));
|
||||
|
||||
|
||||
/**
|
||||
* Encode a cargo monitor for pickup or delivery at an industry.
|
||||
@@ -61,6 +64,7 @@ enum CargoCompanyBits {
|
||||
static inline CargoMonitorID EncodeCargoIndustryMonitor(CompanyID company, CargoID ctype, IndustryID ind)
|
||||
{
|
||||
assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH));
|
||||
assert(company < (1 << CCB_COMPANY_LENGTH));
|
||||
|
||||
uint32 ret = 0;
|
||||
SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, ind);
|
||||
@@ -80,6 +84,7 @@ static inline CargoMonitorID EncodeCargoIndustryMonitor(CompanyID company, Cargo
|
||||
static inline CargoMonitorID EncodeCargoTownMonitor(CompanyID company, CargoID ctype, TownID town)
|
||||
{
|
||||
assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH));
|
||||
assert(company < (1 << CCB_COMPANY_LENGTH));
|
||||
|
||||
uint32 ret = 0;
|
||||
SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, town);
|
||||
@@ -144,6 +149,6 @@ void ClearCargoPickupMonitoring(CompanyID company = INVALID_OWNER);
|
||||
void ClearCargoDeliveryMonitoring(CompanyID company = INVALID_OWNER);
|
||||
int32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring);
|
||||
int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring);
|
||||
void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st);
|
||||
void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st, IndustryID dest = INVALID_INDUSTRY);
|
||||
|
||||
#endif /* CARGOMONITOR_H */
|
||||
|
@@ -602,7 +602,7 @@ uint VehicleCargoList::Reassign<VehicleCargoList::MTA_DELIVER, VehicleCargoList:
|
||||
* Returns reserved cargo to the station and removes it from the cache.
|
||||
* @param max_move Maximum amount of cargo to move.
|
||||
* @param dest Station the cargo is returned to.
|
||||
* @param ID of next the station the cargo wants to go next.
|
||||
* @param next ID of the next station the cargo wants to go to.
|
||||
* @return Amount of cargo actually returned.
|
||||
*/
|
||||
uint VehicleCargoList::Return(uint max_move, StationCargoList *dest, StationID next)
|
||||
@@ -668,7 +668,7 @@ uint VehicleCargoList::Truncate(uint max_move)
|
||||
* @param dest List to prepend the cargo to.
|
||||
* @param avoid Station to exclude from routing and current next hop of packets to reroute.
|
||||
* @param avoid2 Additional station to exclude from routing.
|
||||
* @oaram ge GoodsEntry to get the routing info from.
|
||||
* @param ge GoodsEntry to get the routing info from.
|
||||
*/
|
||||
uint VehicleCargoList::Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
|
||||
{
|
||||
@@ -859,7 +859,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, TileIndex loa
|
||||
* @param dest List to append the cargo to.
|
||||
* @param avoid Station to exclude from routing and current next hop of packets to reroute.
|
||||
* @param avoid2 Additional station to exclude from routing.
|
||||
* @oaram ge GoodsEntry to get the routing info from.
|
||||
* @param ge GoodsEntry to get the routing info from.
|
||||
*/
|
||||
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
|
||||
{
|
||||
|
@@ -221,7 +221,7 @@ struct CheatWindow : Window {
|
||||
this->InitNested();
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
if (widget != WID_C_PANEL) return;
|
||||
|
||||
@@ -283,7 +283,7 @@ struct CheatWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
if (widget != WID_C_PANEL) return;
|
||||
|
||||
@@ -330,7 +330,7 @@ struct CheatWindow : Window {
|
||||
size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + this->line_height * lengthof(_cheats_ui);
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_C_PANEL);
|
||||
uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / this->line_height;
|
||||
@@ -384,13 +384,13 @@ struct CheatWindow : Window {
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnTimeout()
|
||||
void OnTimeout() override
|
||||
{
|
||||
this->clicked = 0;
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnQueryTextFinished(char *str)
|
||||
void OnQueryTextFinished(char *str) override
|
||||
{
|
||||
/* Was 'cancel' pressed or nothing entered? */
|
||||
if (str == NULL || StrEmpty(str)) return;
|
||||
|
@@ -208,16 +208,19 @@ static void TileLoopClearAlps(TileIndex tile)
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if at least one surrounding tile is desert
|
||||
* Tests if at least one surrounding tile is non-desert
|
||||
* @param tile tile to check
|
||||
* @return does this tile have at least one desert tile around?
|
||||
* @return does this tile have at least one non-desert tile around?
|
||||
*/
|
||||
static inline bool NeighbourIsDesert(TileIndex tile)
|
||||
static inline bool NeighbourIsNormal(TileIndex tile)
|
||||
{
|
||||
return GetTropicZone(tile + TileDiffXY( 1, 0)) == TROPICZONE_DESERT ||
|
||||
GetTropicZone(tile + TileDiffXY( -1, 0)) == TROPICZONE_DESERT ||
|
||||
GetTropicZone(tile + TileDiffXY( 0, 1)) == TROPICZONE_DESERT ||
|
||||
GetTropicZone(tile + TileDiffXY( 0, -1)) == TROPICZONE_DESERT;
|
||||
for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
|
||||
TileIndex t = tile + TileOffsByDiagDir(dir);
|
||||
if (!IsValidTile(t)) continue;
|
||||
if (GetTropicZone(t) != TROPICZONE_DESERT) return true;
|
||||
if (HasTileWaterClass(t) && GetWaterClass(t) == WATER_CLASS_SEA) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void TileLoopClearDesert(TileIndex tile)
|
||||
@@ -229,9 +232,7 @@ static void TileLoopClearDesert(TileIndex tile)
|
||||
/* Expected desert level - 0 if it shouldn't be desert */
|
||||
uint expected = 0;
|
||||
if (GetTropicZone(tile) == TROPICZONE_DESERT) {
|
||||
expected = 3;
|
||||
} else if (NeighbourIsDesert(tile)) {
|
||||
expected = 1;
|
||||
expected = NeighbourIsNormal(tile) ? 1 : 3;
|
||||
}
|
||||
|
||||
if (current == expected) return;
|
||||
|
@@ -269,6 +269,7 @@ static inline void MakeClear(TileIndex t, ClearGround g, uint density)
|
||||
SetClearGroundDensity(t, g, density); // Sets m5
|
||||
_me[t].m6 = 0;
|
||||
_me[t].m7 = 0;
|
||||
_me[t].m8 = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -289,6 +290,7 @@ static inline void MakeField(TileIndex t, uint field_type, IndustryID industry)
|
||||
SetClearGroundDensity(t, CLEAR_FIELDS, 3);
|
||||
SB(_me[t].m6, 2, 4, 0);
|
||||
_me[t].m7 = 0;
|
||||
_me[t].m8 = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -194,6 +194,7 @@ CommandProc CmdAddVehicleGroup;
|
||||
CommandProc CmdAddSharedVehicleGroup;
|
||||
CommandProc CmdRemoveAllVehiclesGroup;
|
||||
CommandProc CmdSetGroupReplaceProtection;
|
||||
CommandProc CmdSetGroupLivery;
|
||||
|
||||
CommandProc CmdMoveOrder;
|
||||
CommandProc CmdChangeTimetable;
|
||||
@@ -286,7 +287,7 @@ static const Command _command_proc_table[] = {
|
||||
|
||||
DEF_CMD(CmdTurnRoadVeh, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_TURN_ROADVEH
|
||||
|
||||
DEF_CMD(CmdPause, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_PAUSE
|
||||
DEF_CMD(CmdPause, CMD_SERVER | CMD_NO_EST, CMDT_SERVER_SETTING ), // CMD_PAUSE
|
||||
|
||||
DEF_CMD(CmdBuyShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_SHARE_IN_COMPANY
|
||||
DEF_CMD(CmdSellShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_SELL_SHARE_IN_COMPANY
|
||||
@@ -310,7 +311,7 @@ static const Command _command_proc_table[] = {
|
||||
DEF_CMD(CmdChangeBankBalance, CMD_DEITY, CMDT_MONEY_MANAGEMENT ), // CMD_CHANGE_BANK_BALANCE
|
||||
DEF_CMD(CmdBuildCanal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_CANAL
|
||||
DEF_CMD(CmdCreateSubsidy, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_SUBSIDY
|
||||
DEF_CMD(CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID, CMDT_SERVER_SETTING ), // CMD_COMPANY_CTRL
|
||||
DEF_CMD(CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID | CMD_NO_EST, CMDT_SERVER_SETTING ), // CMD_COMPANY_CTRL
|
||||
DEF_CMD(CmdCustomNewsItem, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CUSTOM_NEWS_ITEM
|
||||
DEF_CMD(CmdCreateGoal, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_GOAL
|
||||
DEF_CMD(CmdRemoveGoal, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_GOAL
|
||||
@@ -353,6 +354,7 @@ static const Command _command_proc_table[] = {
|
||||
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(CmdSetGroupLivery, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_LIVERY
|
||||
DEF_CMD(CmdMoveOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MOVE_ORDER
|
||||
DEF_CMD(CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CHANGE_TIMETABLE
|
||||
DEF_CMD(CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_VEHICLE_ON_TIME
|
||||
@@ -553,7 +555,7 @@ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags,
|
||||
|
||||
/* only execute the test call if it's toplevel, or we're not execing. */
|
||||
if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) {
|
||||
if (_docommand_recursive == 1) _cleared_object_areas.Clear();
|
||||
if (_docommand_recursive == 1) _cleared_object_areas.clear();
|
||||
SetTownRatingTestMode(true);
|
||||
res = proc(tile, flags & ~DC_EXEC, p1, p2, text);
|
||||
SetTownRatingTestMode(false);
|
||||
@@ -576,7 +578,7 @@ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags,
|
||||
|
||||
/* Execute the command here. All cost-relevant functions set the expenses type
|
||||
* themselves to the cost object at some point */
|
||||
if (_docommand_recursive == 1) _cleared_object_areas.Clear();
|
||||
if (_docommand_recursive == 1) _cleared_object_areas.clear();
|
||||
res = proc(tile, flags, p1, p2, text);
|
||||
if (res.Failed()) {
|
||||
error:
|
||||
@@ -645,7 +647,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
|
||||
bool estimate_only = _shift_pressed && IsLocalCompany() &&
|
||||
!_generating_world &&
|
||||
!(cmd & CMD_NETWORK_COMMAND) &&
|
||||
(cmd & CMD_ID_MASK) != CMD_PAUSE;
|
||||
!(GetCommandFlags(cmd) & CMD_NO_EST);
|
||||
|
||||
/* We're only sending the command, so don't do
|
||||
* fancy things for 'success'. */
|
||||
@@ -660,10 +662,8 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
/* Only set p2 when the command does not come from the network. */
|
||||
if (!(cmd & CMD_NETWORK_COMMAND) && GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = CLIENT_ID_SERVER;
|
||||
#endif
|
||||
|
||||
CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only);
|
||||
if (res.Failed()) {
|
||||
@@ -704,7 +704,6 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac
|
||||
/**
|
||||
* Helper to deduplicate the code for returning.
|
||||
* @param cmd the command cost to return.
|
||||
* @param clear whether to keep the storage changes or not.
|
||||
*/
|
||||
#define return_dcpi(cmd) { _docommand_recursive = 0; return cmd; }
|
||||
|
||||
@@ -744,10 +743,8 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
|
||||
/* Flags get send to the DoCommand */
|
||||
DoCommandFlag flags = CommandFlagsToDCFlags(cmd_flags);
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
/* Make sure p2 is properly set to a ClientID. */
|
||||
assert(!(cmd_flags & CMD_CLIENT_ID) || p2 != 0);
|
||||
#endif
|
||||
|
||||
/* Do not even think about executing out-of-bounds tile-commands */
|
||||
if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return_dcpi(CMD_ERROR);
|
||||
@@ -768,7 +765,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
|
||||
bool test_and_exec_can_differ = (cmd_flags & CMD_NO_TEST) != 0;
|
||||
|
||||
/* Test the command. */
|
||||
_cleared_object_areas.Clear();
|
||||
_cleared_object_areas.clear();
|
||||
SetTownRatingTestMode(true);
|
||||
BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE);
|
||||
CommandCost res = proc(tile, flags, p1, p2, text);
|
||||
@@ -794,7 +791,6 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
|
||||
return_dcpi(res);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
/*
|
||||
* If we are in network, and the command is not from the network
|
||||
* send it to the command-queue and abort execution
|
||||
@@ -809,12 +805,11 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd,
|
||||
* reset the storages as we've not executed the command. */
|
||||
return_dcpi(CommandCost());
|
||||
}
|
||||
#endif /* ENABLE_NETWORK */
|
||||
DEBUG(desync, 1, "cmd: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, GetCommandName(cmd));
|
||||
|
||||
/* Actually try and execute the command. If no cost-type is given
|
||||
* use the construction one */
|
||||
_cleared_object_areas.Clear();
|
||||
_cleared_object_areas.clear();
|
||||
BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND);
|
||||
CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text);
|
||||
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND);
|
||||
|
@@ -42,9 +42,7 @@ bool DoCommandP(const CommandContainer *container, bool my_cmd = true);
|
||||
|
||||
CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only);
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
extern Money _additional_cash_required;
|
||||
|
||||
|
@@ -337,6 +337,7 @@ enum Commands {
|
||||
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_LIVERY, ///< set the livery for a group
|
||||
|
||||
CMD_MOVE_ORDER, ///< move an order
|
||||
CMD_CHANGE_TIMETABLE, ///< change the timetable for a vehicle
|
||||
@@ -409,6 +410,7 @@ enum CommandFlags {
|
||||
CMD_CLIENT_ID = 0x080, ///< set p2 with the ClientID of the sending client.
|
||||
CMD_DEITY = 0x100, ///< the command may be executed by COMPANY_DEITY
|
||||
CMD_STR_CTRL = 0x200, ///< the command's string may contain control strings
|
||||
CMD_NO_EST = 0x400, ///< the command is never estimated.
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(CommandFlags)
|
||||
|
||||
|
@@ -91,7 +91,7 @@ struct CompanyProperties {
|
||||
*/
|
||||
bool is_ai;
|
||||
|
||||
Money yearly_expenses[3][EXPENSES_END]; ///< Expenses of the company for the last three years, in every #Expenses category.
|
||||
Money yearly_expenses[3][EXPENSES_END]; ///< Expenses of the company for the last three years, in every #ExpensesType category.
|
||||
CompanyEconomyEntry cur_economy; ///< Economic data of the company of this quarter.
|
||||
CompanyEconomyEntry old_economy[MAX_HISTORY_QUARTERS]; ///< Economic data of the company of the last #MAX_HISTORY_QUARTERS quarters.
|
||||
byte num_valid_stat_ent; ///< Number of valid statistical entries in #old_economy.
|
||||
|
@@ -104,10 +104,8 @@ void SetLocalCompany(CompanyID new_company)
|
||||
/* company could also be COMPANY_SPECTATOR or OWNER_NONE */
|
||||
assert(Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE);
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
/* Delete the chat window, if you were team chatting. */
|
||||
InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_TEAM, _local_company);
|
||||
#endif
|
||||
|
||||
assert(IsLocalCompany());
|
||||
|
||||
@@ -188,7 +186,7 @@ void InvalidateCompanyWindows(const Company *company)
|
||||
|
||||
/**
|
||||
* Verify whether the company can pay the bill.
|
||||
* @param cost [inout] Money to pay, is changed to an error if the company does not have enough money.
|
||||
* @param[in,out] cost Money to pay, is changed to an error if the company does not have enough money.
|
||||
* @return Function returns \c true if the company has enough money, else it returns \c false.
|
||||
*/
|
||||
bool CheckCompanyHasMoney(CommandCost &cost)
|
||||
@@ -517,10 +515,19 @@ restart:;
|
||||
void ResetCompanyLivery(Company *c)
|
||||
{
|
||||
for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) {
|
||||
c->livery[scheme].in_use = false;
|
||||
c->livery[scheme].in_use = 0;
|
||||
c->livery[scheme].colour1 = c->colour;
|
||||
c->livery[scheme].colour2 = c->colour;
|
||||
}
|
||||
|
||||
Group *g;
|
||||
FOR_ALL_GROUPS(g) {
|
||||
if (g->owner == c->index) {
|
||||
g->livery.in_use = 0;
|
||||
g->livery.colour1 = c->colour;
|
||||
g->livery.colour2 = c->colour;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -586,11 +593,9 @@ void StartupCompanies()
|
||||
}
|
||||
|
||||
/** Start a new competitor company if possible. */
|
||||
static void MaybeStartNewCompany()
|
||||
static bool MaybeStartNewCompany()
|
||||
{
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return;
|
||||
#endif /* ENABLE_NETWORK */
|
||||
if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return false;
|
||||
|
||||
Company *c;
|
||||
|
||||
@@ -603,8 +608,10 @@ static void MaybeStartNewCompany()
|
||||
if (n < (uint)_settings_game.difficulty.max_no_competitors) {
|
||||
/* Send a command to all clients to start up a new AI.
|
||||
* Works fine for Multiplayer and Singleplayer */
|
||||
DoCommandP(0, 1 | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
|
||||
return DoCommandP(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Initialize the pool of companies. */
|
||||
@@ -705,11 +712,19 @@ void OnTick_Companies()
|
||||
}
|
||||
|
||||
if (_next_competitor_start == 0) {
|
||||
_next_competitor_start = AI::GetStartNextTime() * DAY_TICKS;
|
||||
/* AI::GetStartNextTime() can return 0. */
|
||||
_next_competitor_start = max(1, AI::GetStartNextTime() * DAY_TICKS);
|
||||
}
|
||||
|
||||
if (AI::CanStartNew() && _game_mode != GM_MENU && --_next_competitor_start == 0) {
|
||||
MaybeStartNewCompany();
|
||||
if (_game_mode != GM_MENU && AI::CanStartNew() && --_next_competitor_start == 0) {
|
||||
/* Allow multiple AIs to possibly start in the same tick. */
|
||||
do {
|
||||
if (!MaybeStartNewCompany()) break;
|
||||
|
||||
/* In networking mode, we can only send a command to start but it
|
||||
* didn't execute yet, so we cannot loop. */
|
||||
if (_networking) break;
|
||||
} while (AI::GetStartNextTime() == 0);
|
||||
}
|
||||
|
||||
_cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES;
|
||||
@@ -773,9 +788,7 @@ void CompanyNewsInformation::FillData(const Company *c, const Company *other)
|
||||
*/
|
||||
void CompanyAdminUpdate(const Company *company)
|
||||
{
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (_network_server) NetworkAdminCompanyUpdate(company);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -785,9 +798,7 @@ void CompanyAdminUpdate(const Company *company)
|
||||
*/
|
||||
void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
|
||||
{
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (_network_server) NetworkAdminCompanyRemove(company_id, (AdminCompanyRemoveReason)reason);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -795,11 +806,9 @@ void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
|
||||
* @param tile unused
|
||||
* @param flags operation to perform
|
||||
* @param p1 various functionality
|
||||
* - bits 0..15:
|
||||
* = 0 - create a new company
|
||||
* = 1 - create a new AI company
|
||||
* = 2 - delete a company
|
||||
* - bits 16..24: CompanyID
|
||||
* - bits 0..15: CompanyCtrlAction
|
||||
* - bits 16..23: CompanyID
|
||||
* - bits 24..31: CompanyRemoveReason (with CCA_DELETE)
|
||||
* @param p2 ClientID
|
||||
* @param text unused
|
||||
* @return the cost of this operation or an error
|
||||
@@ -808,18 +817,16 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
{
|
||||
InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
|
||||
CompanyID company_id = (CompanyID)GB(p1, 16, 8);
|
||||
#ifdef ENABLE_NETWORK
|
||||
ClientID client_id = (ClientID)p2;
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
switch (GB(p1, 0, 16)) {
|
||||
case 0: { // Create a new company
|
||||
switch ((CompanyCtrlAction)GB(p1, 0, 16)) {
|
||||
case CCA_NEW: { // Create a new company
|
||||
/* This command is only executed in a multiplayer game */
|
||||
if (!_networking) return CMD_ERROR;
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
/* Has the network client a correct ClientIndex? */
|
||||
if (!(flags & DC_EXEC)) return CommandCost();
|
||||
|
||||
ClientID client_id = (ClientID)p2;
|
||||
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
|
||||
#ifndef DEBUG_DUMP_COMMANDS
|
||||
/* When replaying the client ID is not a valid client; there
|
||||
@@ -859,23 +866,20 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
|
||||
NetworkServerNewCompany(c, ci);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: { // Make a new AI company
|
||||
case CCA_NEW_AI: { // Make a new AI company
|
||||
if (!(flags & DC_EXEC)) return CommandCost();
|
||||
|
||||
if (company_id != INVALID_COMPANY && (company_id >= MAX_COMPANIES || Company::IsValidID(company_id))) return CMD_ERROR;
|
||||
Company *c = DoStartupNewCompany(true, company_id);
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (c != NULL) NetworkServerNewCompany(c, NULL);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: { // Delete a company
|
||||
CompanyRemoveReason reason = (CompanyRemoveReason)GB(p2, 0, 2);
|
||||
case CCA_DELETE: { // Delete a company
|
||||
CompanyRemoveReason reason = (CompanyRemoveReason)GB(p1, 24, 8);
|
||||
if (reason >= CRR_END) return CMD_ERROR;
|
||||
|
||||
Company *c = Company::GetIfValid(company_id);
|
||||
@@ -946,23 +950,26 @@ CommandCost CmdSetCompanyManagerFace(TileIndex tile, DoCommandFlag flags, uint32
|
||||
* @param flags operation to perform
|
||||
* @param p1 bitstuffed:
|
||||
* p1 bits 0-7 scheme to set
|
||||
* p1 bits 8-9 set in use state or first/second colour
|
||||
* p1 bit 8 set first/second colour
|
||||
* @param p2 new colour for vehicles, property, etc.
|
||||
* @param text unused
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||
{
|
||||
Colours colour = Extract<Colours, 0, 4>(p2);
|
||||
Colours colour = Extract<Colours, 0, 8>(p2);
|
||||
LiveryScheme scheme = Extract<LiveryScheme, 0, 8>(p1);
|
||||
byte state = GB(p1, 8, 2);
|
||||
bool second = HasBit(p1, 8);
|
||||
|
||||
if (scheme >= LS_END || state >= 3 || colour == INVALID_COLOUR) return CMD_ERROR;
|
||||
if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR;
|
||||
|
||||
/* Default scheme can't be reset to invalid. */
|
||||
if (scheme == LS_DEFAULT && colour == INVALID_COLOUR) return CMD_ERROR;
|
||||
|
||||
Company *c = Company::Get(_current_company);
|
||||
|
||||
/* Ensure no two companies have the same primary colour */
|
||||
if (scheme == LS_DEFAULT && state == 0) {
|
||||
if (scheme == LS_DEFAULT && !second) {
|
||||
const Company *cc;
|
||||
FOR_ALL_COMPANIES(cc) {
|
||||
if (cc != c && cc->colour == colour) return CMD_ERROR;
|
||||
@@ -970,52 +977,48 @@ CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
switch (state) {
|
||||
case 0:
|
||||
c->livery[scheme].colour1 = colour;
|
||||
if (!second) {
|
||||
if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 0, 1, colour != INVALID_COLOUR);
|
||||
if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour1;
|
||||
c->livery[scheme].colour1 = colour;
|
||||
|
||||
/* If setting the first colour of the default scheme, adjust the
|
||||
* original and cached company colours too. */
|
||||
if (scheme == LS_DEFAULT) {
|
||||
_company_colours[_current_company] = colour;
|
||||
c->colour = colour;
|
||||
CompanyAdminUpdate(c);
|
||||
/* If setting the first colour of the default scheme, adjust the
|
||||
* original and cached company colours too. */
|
||||
if (scheme == LS_DEFAULT) {
|
||||
for (int i = 1; i < LS_END; i++) {
|
||||
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = colour;
|
||||
}
|
||||
break;
|
||||
_company_colours[_current_company] = colour;
|
||||
c->colour = colour;
|
||||
CompanyAdminUpdate(c);
|
||||
}
|
||||
} else {
|
||||
if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 1, 1, colour != INVALID_COLOUR);
|
||||
if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour2;
|
||||
c->livery[scheme].colour2 = colour;
|
||||
|
||||
case 1:
|
||||
c->livery[scheme].colour2 = colour;
|
||||
break;
|
||||
if (scheme == LS_DEFAULT) {
|
||||
for (int i = 1; i < LS_END; i++) {
|
||||
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = colour;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case 2:
|
||||
c->livery[scheme].in_use = colour != 0;
|
||||
|
||||
/* Now handle setting the default scheme's in_use flag.
|
||||
* This is different to the other schemes, as it signifies if any
|
||||
* scheme is active at all. If this flag is not set, then no
|
||||
* processing of vehicle types occurs at all, and only the default
|
||||
* colours will be used. */
|
||||
|
||||
/* If enabling a scheme, set the default scheme to be in use too */
|
||||
if (colour != 0) {
|
||||
c->livery[LS_DEFAULT].in_use = true;
|
||||
if (c->livery[scheme].in_use != 0) {
|
||||
/* If enabling a scheme, set the default scheme to be in use too */
|
||||
c->livery[LS_DEFAULT].in_use = 1;
|
||||
} else {
|
||||
/* Else loop through all schemes to see if any are left enabled.
|
||||
* If not, disable the default scheme too. */
|
||||
c->livery[LS_DEFAULT].in_use = 0;
|
||||
for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (c->livery[scheme].in_use != 0) {
|
||||
c->livery[LS_DEFAULT].in_use = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Else loop through all schemes to see if any are left enabled.
|
||||
* If not, disable the default scheme too. */
|
||||
c->livery[LS_DEFAULT].in_use = false;
|
||||
for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (c->livery[scheme].in_use) {
|
||||
c->livery[LS_DEFAULT].in_use = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ResetVehicleColourMap();
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "water.h"
|
||||
#include "station_func.h"
|
||||
#include "zoom_func.h"
|
||||
#include "sortlist_type.h"
|
||||
|
||||
#include "widgets/company_widget.h"
|
||||
|
||||
@@ -268,10 +269,7 @@ static const NWidgetPart _nested_company_finances_widgets[] = {
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
/**
|
||||
* Window class displaying the company finances.
|
||||
* @todo #money_width should be calculated dynamically.
|
||||
*/
|
||||
/** Window class displaying the company finances. */
|
||||
struct CompanyFinancesWindow : Window {
|
||||
static Money max_money; ///< The maximum amount of money a company has had this 'run'
|
||||
bool small; ///< Window is toggled to 'small'.
|
||||
@@ -286,7 +284,7 @@ struct CompanyFinancesWindow : Window {
|
||||
this->owner = (Owner)this->window_number;
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_CF_CAPTION:
|
||||
@@ -305,7 +303,7 @@ struct CompanyFinancesWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
int type = _settings_client.gui.expenses_layout;
|
||||
switch (widget) {
|
||||
@@ -333,7 +331,7 @@ struct CompanyFinancesWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_CF_EXPS_CATEGORY:
|
||||
@@ -394,7 +392,7 @@ struct CompanyFinancesWindow : Window {
|
||||
this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->SetDisplayedPlane(plane);
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
if (!this->IsShaded()) {
|
||||
if (!this->small) {
|
||||
@@ -424,7 +422,7 @@ struct CompanyFinancesWindow : Window {
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_CF_TOGGLE_SIZE: // toggle size
|
||||
@@ -453,7 +451,7 @@ struct CompanyFinancesWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnHundredthTick()
|
||||
void OnHundredthTick() override
|
||||
{
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
if (c->money > CompanyFinancesWindow::max_money) {
|
||||
@@ -521,30 +519,28 @@ class DropDownListColourItem : public DropDownListItem {
|
||||
public:
|
||||
DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
|
||||
|
||||
virtual ~DropDownListColourItem() {}
|
||||
|
||||
StringID String() const
|
||||
{
|
||||
return _colour_dropdown[this->result];
|
||||
return this->result >= COLOUR_END ? STR_COLOUR_DEFAULT : _colour_dropdown[this->result];
|
||||
}
|
||||
|
||||
uint Height(uint width) const
|
||||
uint Height(uint width) const override
|
||||
{
|
||||
return max(FONT_HEIGHT_NORMAL, ScaleGUITrad(12) + 2);
|
||||
}
|
||||
|
||||
bool Selectable() const
|
||||
bool Selectable() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
|
||||
void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const override
|
||||
{
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
int height = bottom - top;
|
||||
int icon_y_offset = height / 2;
|
||||
int text_y_offset = (height - FONT_HEIGHT_NORMAL) / 2 + 1;
|
||||
DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOUR_START + this->result,
|
||||
DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOUR_START + (this->result % COLOUR_END),
|
||||
rtl ? right - 2 - ScaleGUITrad(14) : left + ScaleGUITrad(14) + 2,
|
||||
top + icon_y_offset);
|
||||
DrawString(rtl ? left + 2 : left + ScaleGUITrad(28) + 4,
|
||||
@@ -553,61 +549,198 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static const int LEVEL_WIDTH = 10; ///< Indenting width of a sub-group in pixels
|
||||
|
||||
typedef GUIList<const Group*> GUIGroupList;
|
||||
|
||||
/** Company livery colour scheme window. */
|
||||
struct SelectCompanyLiveryWindow : public Window {
|
||||
private:
|
||||
uint32 sel;
|
||||
LiveryClass livery_class;
|
||||
Dimension square;
|
||||
Dimension box;
|
||||
uint rows;
|
||||
uint line_height;
|
||||
GUIGroupList groups;
|
||||
std::vector<int> indents;
|
||||
Scrollbar *vscroll;
|
||||
|
||||
void ShowColourDropDownMenu(uint32 widget)
|
||||
{
|
||||
uint32 used_colours = 0;
|
||||
const Livery *livery;
|
||||
LiveryScheme scheme;
|
||||
const Company *c;
|
||||
const Livery *livery, *default_livery = NULL;
|
||||
bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
|
||||
byte default_col;
|
||||
|
||||
/* Disallow other company colours for the primary colour */
|
||||
if (HasBit(this->sel, LS_DEFAULT) && widget == WID_SCL_PRI_COL_DROPDOWN) {
|
||||
const Company *c;
|
||||
if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
|
||||
FOR_ALL_COMPANIES(c) {
|
||||
if (c->index != _local_company) SetBit(used_colours, c->colour);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the first selected livery to use as the default dropdown item */
|
||||
for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
|
||||
if (HasBit(this->sel, scheme)) break;
|
||||
c = Company::Get((CompanyID)this->window_number);
|
||||
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
/* Get the first selected livery to use as the default dropdown item */
|
||||
LiveryScheme scheme;
|
||||
for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
|
||||
if (HasBit(this->sel, scheme)) break;
|
||||
}
|
||||
if (scheme == LS_END) scheme = LS_DEFAULT;
|
||||
livery = &c->livery[scheme];
|
||||
if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT];
|
||||
} else {
|
||||
const Group *g = Group::Get(this->sel);
|
||||
livery = &g->livery;
|
||||
if (g->parent == INVALID_GROUP) {
|
||||
default_livery = &c->livery[LS_DEFAULT];
|
||||
} else {
|
||||
const Group *pg = Group::Get(g->parent);
|
||||
default_livery = &pg->livery;
|
||||
}
|
||||
}
|
||||
if (scheme == LS_END) scheme = LS_DEFAULT;
|
||||
livery = &Company::Get((CompanyID)this->window_number)->livery[scheme];
|
||||
|
||||
DropDownList *list = new DropDownList();
|
||||
if (default_livery != NULL) {
|
||||
/* Add COLOUR_END to put the colour out of range, but also allow us to show what the default is */
|
||||
default_col = (primary ? default_livery->colour1 : default_livery->colour2) + COLOUR_END;
|
||||
list->push_back(new DropDownListColourItem(default_col, false));
|
||||
}
|
||||
for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
|
||||
*list->Append() = new DropDownListColourItem(i, HasBit(used_colours, i));
|
||||
list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
|
||||
}
|
||||
|
||||
ShowDropDownList(this, list, widget == WID_SCL_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
|
||||
byte sel = (default_livery == NULL || HasBit(livery->in_use, primary ? 0 : 1)) ? (primary ? livery->colour1 : livery->colour2) : default_col;
|
||||
ShowDropDownList(this, list, sel, widget);
|
||||
}
|
||||
|
||||
static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b)
|
||||
{
|
||||
static const Group *last_group[2] = { NULL, NULL };
|
||||
static char last_name[2][64] = { "", "" };
|
||||
|
||||
if (*a != last_group[0]) {
|
||||
last_group[0] = *a;
|
||||
SetDParam(0, (*a)->index);
|
||||
GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0]));
|
||||
}
|
||||
|
||||
if (*b != last_group[1]) {
|
||||
last_group[1] = *b;
|
||||
SetDParam(0, (*b)->index);
|
||||
GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1]));
|
||||
}
|
||||
|
||||
int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting).
|
||||
if (r == 0) return (*a)->index - (*b)->index;
|
||||
return r;
|
||||
}
|
||||
|
||||
void AddChildren(GUIGroupList *source, GroupID parent, int indent)
|
||||
{
|
||||
for (const Group *g : *source) {
|
||||
if (g->parent != parent) continue;
|
||||
this->groups.push_back(g);
|
||||
this->indents.push_back(indent);
|
||||
AddChildren(source, g->index, indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void BuildGroupList(CompanyID owner)
|
||||
{
|
||||
if (!this->groups.NeedRebuild()) return;
|
||||
|
||||
this->groups.clear();
|
||||
this->indents.clear();
|
||||
|
||||
if (this->livery_class >= LC_GROUP_RAIL) {
|
||||
GUIGroupList list;
|
||||
VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
|
||||
|
||||
const Group *g;
|
||||
FOR_ALL_GROUPS(g) {
|
||||
if (g->owner == owner && g->vehicle_type == vtype) {
|
||||
list.push_back(g);
|
||||
}
|
||||
}
|
||||
|
||||
list.ForceResort();
|
||||
list.Sort(&GroupNameSorter);
|
||||
|
||||
AddChildren(&list, INVALID_GROUP, 0);
|
||||
}
|
||||
|
||||
this->groups.shrink_to_fit();
|
||||
this->groups.RebuildDone();
|
||||
}
|
||||
|
||||
void SetRows()
|
||||
{
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
this->rows = 0;
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
|
||||
this->rows++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->rows = (uint)this->groups.size();
|
||||
}
|
||||
|
||||
this->vscroll->SetCount(this->rows);
|
||||
}
|
||||
|
||||
public:
|
||||
SelectCompanyLiveryWindow(WindowDesc *desc, CompanyID company) : Window(desc)
|
||||
SelectCompanyLiveryWindow(WindowDesc *desc, CompanyID company, GroupID group) : Window(desc)
|
||||
{
|
||||
this->livery_class = LC_OTHER;
|
||||
this->sel = 1;
|
||||
this->CreateNestedTree();
|
||||
this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR);
|
||||
|
||||
this->square = GetSpriteSize(SPR_SQUARE);
|
||||
this->box = maxdim(GetSpriteSize(SPR_BOX_CHECKED), GetSpriteSize(SPR_BOX_EMPTY));
|
||||
this->line_height = max(max(this->square.height, this->box.height), (uint)FONT_HEIGHT_NORMAL) + 4;
|
||||
if (group == INVALID_GROUP) {
|
||||
this->livery_class = LC_OTHER;
|
||||
this->sel = 1;
|
||||
this->LowerWidget(WID_SCL_CLASS_GENERAL);
|
||||
this->BuildGroupList(company);
|
||||
this->SetRows();
|
||||
} else {
|
||||
this->SetSelectedGroup(company, group);
|
||||
}
|
||||
|
||||
this->InitNested(company);
|
||||
this->FinishInitNested(company);
|
||||
this->owner = company;
|
||||
this->LowerWidget(WID_SCL_CLASS_GENERAL);
|
||||
this->InvalidateData(1);
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void SetSelectedGroup(CompanyID company, GroupID group)
|
||||
{
|
||||
this->RaiseWidget(this->livery_class + WID_SCL_CLASS_GENERAL);
|
||||
const Group *g = Group::Get(group);
|
||||
switch (g->vehicle_type) {
|
||||
case VEH_TRAIN: this->livery_class = LC_GROUP_RAIL; break;
|
||||
case VEH_ROAD: this->livery_class = LC_GROUP_ROAD; break;
|
||||
case VEH_SHIP: this->livery_class = LC_GROUP_SHIP; break;
|
||||
case VEH_AIRCRAFT: this->livery_class = LC_GROUP_AIRCRAFT; break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
this->sel = group;
|
||||
this->LowerWidget(this->livery_class + WID_SCL_CLASS_GENERAL);
|
||||
|
||||
this->groups.ForceRebuild();
|
||||
this->BuildGroupList(company);
|
||||
this->SetRows();
|
||||
|
||||
/* Position scrollbar to selected group */
|
||||
for (uint i = 0; i < this->rows; i++) {
|
||||
if (this->groups[i]->index == sel) {
|
||||
this->vscroll->SetPosition(Clamp(i - this->vscroll->GetCapacity() / 2, 0, max(this->vscroll->GetCount() - this->vscroll->GetCapacity(), 0)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SCL_SPACER_DROPDOWN: {
|
||||
@@ -616,19 +749,28 @@ public:
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
|
||||
}
|
||||
size->width = max(size->width, 5 + this->box.width + d.width + WD_FRAMERECT_RIGHT);
|
||||
|
||||
/* And group names */
|
||||
const Group *g;
|
||||
FOR_ALL_GROUPS(g) {
|
||||
if (g->owner == (CompanyID)this->window_number) {
|
||||
SetDParam(0, g->index);
|
||||
d = maxdim(d, GetStringBoundingBox(STR_GROUP_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
size->width = max(size->width, 5 + d.width + WD_FRAMERECT_RIGHT);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_SCL_MATRIX: {
|
||||
uint livery_height = 0;
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
|
||||
livery_height++;
|
||||
}
|
||||
}
|
||||
size->height = livery_height * this->line_height;
|
||||
this->GetWidget<NWidgetCore>(WID_SCL_MATRIX)->widget_data = (livery_height << MAT_ROW_START) | (1 << MAT_COL_START);
|
||||
/* 11 items in the default rail class */
|
||||
this->square = GetSpriteSize(SPR_SQUARE);
|
||||
this->line_height = max(this->square.height, (uint)FONT_HEIGHT_NORMAL) + 4;
|
||||
|
||||
size->height = 11 * this->line_height;
|
||||
resize->width = 1;
|
||||
resize->height = this->line_height;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -640,45 +782,72 @@ public:
|
||||
FALLTHROUGH;
|
||||
|
||||
case WID_SCL_PRI_COL_DROPDOWN: {
|
||||
this->square = GetSpriteSize(SPR_SQUARE);
|
||||
int padding = this->square.width + NWidgetScrollbar::GetVerticalDimension().width + 10;
|
||||
for (const StringID *id = _colour_dropdown; id != endof(_colour_dropdown); id++) {
|
||||
size->width = max(size->width, GetStringBoundingBox(*id).width + padding);
|
||||
}
|
||||
size->width = max(size->width, GetStringBoundingBox(STR_COLOUR_DEFAULT).width + padding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
bool local = (CompanyID)this->window_number == _local_company;
|
||||
|
||||
/* Disable dropdown controls if no scheme is selected */
|
||||
this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, this->sel == 0);
|
||||
this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, this->sel == 0);
|
||||
bool disabled = this->livery_class < LC_GROUP_RAIL ? (this->sel == 0) : (this->sel == INVALID_GROUP);
|
||||
this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, !local || disabled);
|
||||
this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, !local || disabled);
|
||||
|
||||
this->BuildGroupList((CompanyID)this->window_number);
|
||||
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SCL_CAPTION:
|
||||
SetDParam(0, (CompanyID)this->window_number);
|
||||
break;
|
||||
|
||||
case WID_SCL_PRI_COL_DROPDOWN:
|
||||
case WID_SCL_SEC_COL_DROPDOWN: {
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
LiveryScheme scheme = LS_DEFAULT;
|
||||
bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
|
||||
StringID colour = STR_COLOUR_DEFAULT;
|
||||
|
||||
if (this->sel != 0) {
|
||||
for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
|
||||
if (HasBit(this->sel, scheme)) break;
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
if (this->sel != 0) {
|
||||
LiveryScheme scheme = LS_DEFAULT;
|
||||
for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
|
||||
if (HasBit(this->sel, scheme)) break;
|
||||
}
|
||||
if (scheme == LS_END) scheme = LS_DEFAULT;
|
||||
const Livery *livery = &c->livery[scheme];
|
||||
if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) {
|
||||
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this->sel != INVALID_GROUP) {
|
||||
const Group *g = Group::Get(this->sel);
|
||||
const Livery *livery = &g->livery;
|
||||
if (HasBit(livery->in_use, primary ? 0 : 1)) {
|
||||
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
|
||||
}
|
||||
}
|
||||
if (scheme == LS_END) scheme = LS_DEFAULT;
|
||||
}
|
||||
SetDParam(0, STR_COLOUR_DARK_BLUE + ((widget == WID_SCL_PRI_COL_DROPDOWN) ? c->livery[scheme].colour1 : c->livery[scheme].colour2));
|
||||
SetDParam(0, colour);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
if (widget != WID_SCL_MATRIX) return;
|
||||
|
||||
@@ -697,41 +866,52 @@ public:
|
||||
int sec_left = nwi->pos_x;
|
||||
int sec_right = sec_left + nwi->current_x - 1;
|
||||
|
||||
int text_left = (rtl ? (uint)WD_FRAMERECT_LEFT : (this->box.width + 5));
|
||||
int text_right = (rtl ? (this->box.width + 5) : (uint)WD_FRAMERECT_RIGHT);
|
||||
int text_left = (rtl ? (uint)WD_FRAMERECT_LEFT : (this->square.width + 5));
|
||||
int text_right = (rtl ? (this->square.width + 5) : (uint)WD_FRAMERECT_RIGHT);
|
||||
|
||||
int box_offs = (this->line_height - this->box.height) / 2;
|
||||
int square_offs = (this->line_height - this->square.height) / 2 + 1;
|
||||
int text_offs = (this->line_height - FONT_HEIGHT_NORMAL) / 2 + 1;
|
||||
|
||||
int y = r.top;
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
|
||||
bool sel = HasBit(this->sel, scheme) != 0;
|
||||
|
||||
/* Optional check box + scheme name. */
|
||||
if (scheme != LS_DEFAULT) {
|
||||
DrawSprite(c->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, (rtl ? sch_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : sch_left) + WD_FRAMERECT_LEFT, y + box_offs);
|
||||
/* Helper function to draw livery info. */
|
||||
auto draw_livery = [&](StringID str, const Livery &liv, bool sel, bool def, int indent) {
|
||||
/* Livery Label. */
|
||||
DrawString(sch_left + WD_FRAMERECT_LEFT + (rtl ? 0 : indent), sch_right - WD_FRAMERECT_RIGHT - (rtl ? indent : 0), y + text_offs, str, sel ? TC_WHITE : TC_BLACK);
|
||||
|
||||
/* Text below the first dropdown. */
|
||||
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(liv.colour1), (rtl ? pri_right - (this->square.width + 5) + WD_FRAMERECT_RIGHT : pri_left) + WD_FRAMERECT_LEFT, y + square_offs);
|
||||
DrawString(pri_left + text_left, pri_right - text_right, y + text_offs, (def || HasBit(liv.in_use, 0)) ? STR_COLOUR_DARK_BLUE + liv.colour1 : STR_COLOUR_DEFAULT, sel ? TC_WHITE : TC_GOLD);
|
||||
|
||||
/* Text below the second dropdown. */
|
||||
if (sec_right > sec_left) { // Second dropdown has non-zero size.
|
||||
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(liv.colour2), (rtl ? sec_right - (this->square.width + 5) + WD_FRAMERECT_RIGHT : sec_left) + WD_FRAMERECT_LEFT, y + square_offs);
|
||||
DrawString(sec_left + text_left, sec_right - text_right, y + text_offs, (def || HasBit(liv.in_use, 1)) ? STR_COLOUR_DARK_BLUE + liv.colour2 : STR_COLOUR_DEFAULT, sel ? TC_WHITE : TC_GOLD);
|
||||
}
|
||||
|
||||
y += this->line_height;
|
||||
};
|
||||
|
||||
if (livery_class < LC_GROUP_RAIL) {
|
||||
int pos = this->vscroll->GetPosition();
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
|
||||
if (pos-- > 0) continue;
|
||||
draw_livery(STR_LIVERY_DEFAULT + scheme, c->livery[scheme], HasBit(this->sel, scheme), scheme == LS_DEFAULT, 0);
|
||||
}
|
||||
DrawString(sch_left + text_left, sch_right - text_right, y + text_offs, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
|
||||
|
||||
/* Text below the first dropdown. */
|
||||
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour1), (rtl ? pri_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : pri_left) + WD_FRAMERECT_LEFT, y + square_offs);
|
||||
DrawString(pri_left + text_left, pri_right - text_right, y + text_offs, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
|
||||
|
||||
/* Text below the second dropdown. */
|
||||
if (sec_right > sec_left) { // Second dropdown has non-zero size.
|
||||
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour2), (rtl ? sec_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : sec_left) + WD_FRAMERECT_LEFT, y + square_offs);
|
||||
DrawString(sec_left + text_left, sec_right - text_right, y + text_offs, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
|
||||
}
|
||||
|
||||
y += this->line_height;
|
||||
}
|
||||
} else {
|
||||
uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->groups.size());
|
||||
for (uint i = this->vscroll->GetPosition(); i < max; ++i) {
|
||||
const Group *g = this->groups[i];
|
||||
SetDParam(0, g->index);
|
||||
draw_livery(STR_GROUP_NAME, g->livery, this->sel == g->index, false, this->indents[i] * LEVEL_WIDTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
/* Livery Class buttons */
|
||||
@@ -740,20 +920,35 @@ public:
|
||||
case WID_SCL_CLASS_ROAD:
|
||||
case WID_SCL_CLASS_SHIP:
|
||||
case WID_SCL_CLASS_AIRCRAFT:
|
||||
case WID_SCL_GROUPS_RAIL:
|
||||
case WID_SCL_GROUPS_ROAD:
|
||||
case WID_SCL_GROUPS_SHIP:
|
||||
case WID_SCL_GROUPS_AIRCRAFT:
|
||||
this->RaiseWidget(this->livery_class + WID_SCL_CLASS_GENERAL);
|
||||
this->livery_class = (LiveryClass)(widget - WID_SCL_CLASS_GENERAL);
|
||||
this->LowerWidget(this->livery_class + WID_SCL_CLASS_GENERAL);
|
||||
|
||||
/* Select the first item in the list */
|
||||
this->sel = 0;
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
|
||||
this->sel = 1 << scheme;
|
||||
break;
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
this->sel = 0;
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
|
||||
this->sel = 1 << scheme;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->sel = INVALID_GROUP;
|
||||
this->groups.ForceRebuild();
|
||||
this->BuildGroupList((CompanyID)this->window_number);
|
||||
|
||||
if (this->groups.size() > 0) {
|
||||
this->sel = this->groups[0]->index;
|
||||
}
|
||||
}
|
||||
|
||||
this->ReInit();
|
||||
this->SetRows();
|
||||
this->SetDirty();
|
||||
break;
|
||||
|
||||
case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown
|
||||
@@ -765,24 +960,24 @@ public:
|
||||
break;
|
||||
|
||||
case WID_SCL_MATRIX: {
|
||||
const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SCL_MATRIX);
|
||||
LiveryScheme j = (LiveryScheme)((pt.y - wid->pos_y) / this->line_height);
|
||||
uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SCL_MATRIX, 0, this->line_height);
|
||||
if (row >= this->rows) return;
|
||||
|
||||
for (LiveryScheme scheme = LS_BEGIN; scheme <= j; scheme++) {
|
||||
if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
|
||||
if (scheme >= LS_END) return;
|
||||
}
|
||||
if (j >= LS_END) return;
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
LiveryScheme j = (LiveryScheme)row;
|
||||
|
||||
/* If clicking on the left edge, toggle using the livery */
|
||||
if (_current_text_dir == TD_RTL ? pt.x - wid->pos_x > wid->current_x - (this->box.width + 5) : pt.x - wid->pos_x < (this->box.width + 5)) {
|
||||
DoCommandP(0, j | (2 << 8), !Company::Get((CompanyID)this->window_number)->livery[j].in_use, CMD_SET_COMPANY_COLOUR);
|
||||
}
|
||||
for (LiveryScheme scheme = LS_BEGIN; scheme <= j && scheme < LS_END; scheme++) {
|
||||
if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
|
||||
}
|
||||
assert(j < LS_END);
|
||||
|
||||
if (_ctrl_pressed) {
|
||||
ToggleBit(this->sel, j);
|
||||
if (_ctrl_pressed) {
|
||||
ToggleBit(this->sel, j);
|
||||
} else {
|
||||
this->sel = 1 << j;
|
||||
}
|
||||
} else {
|
||||
this->sel = 1 << j;
|
||||
this->sel = this->groups[row]->index;
|
||||
}
|
||||
this->SetDirty();
|
||||
break;
|
||||
@@ -790,13 +985,29 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnDropdownSelect(int widget, int index)
|
||||
void OnResize() override
|
||||
{
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
/* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
|
||||
if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
|
||||
DoCommandP(0, scheme | (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR);
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX);
|
||||
}
|
||||
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
bool local = (CompanyID)this->window_number == _local_company;
|
||||
if (!local) return;
|
||||
|
||||
if (index >= COLOUR_END) index = INVALID_COLOUR;
|
||||
|
||||
if (this->livery_class < LC_GROUP_RAIL) {
|
||||
/* Set company colour livery */
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
/* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
|
||||
if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
|
||||
DoCommandP(0, scheme | (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Setting group livery */
|
||||
DoCommandP(0, this->sel, (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256) | (index << 16), CMD_SET_GROUP_LIVERY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -805,18 +1016,36 @@ public:
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
|
||||
if (data != -1) {
|
||||
/* data contains a VehicleType, rebuild list if it displayed */
|
||||
if (this->livery_class == data + LC_GROUP_RAIL) {
|
||||
this->groups.ForceRebuild();
|
||||
this->BuildGroupList((CompanyID)this->window_number);
|
||||
this->SetRows();
|
||||
|
||||
if (!Group::IsValidID(this->sel)) {
|
||||
this->sel = INVALID_GROUP;
|
||||
if (this->groups.size() > 0) this->sel = this->groups[0]->index;
|
||||
}
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this->SetWidgetsDisabledState(true, WID_SCL_CLASS_RAIL, WID_SCL_CLASS_ROAD, WID_SCL_CLASS_SHIP, WID_SCL_CLASS_AIRCRAFT, WIDGET_LIST_END);
|
||||
|
||||
bool current_class_valid = this->livery_class == LC_OTHER;
|
||||
bool current_class_valid = this->livery_class == LC_OTHER || this->livery_class >= LC_GROUP_RAIL;
|
||||
if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
|
||||
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
|
||||
if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
|
||||
if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
|
||||
this->EnableWidget(WID_SCL_CLASS_GENERAL + _livery_class[scheme]);
|
||||
} else {
|
||||
} else if (this->livery_class < LC_GROUP_RAIL) {
|
||||
ClrBit(this->sel, scheme);
|
||||
}
|
||||
}
|
||||
@@ -825,8 +1054,6 @@ public:
|
||||
if (!current_class_valid) {
|
||||
Point pt = {0, 0};
|
||||
this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
|
||||
} else if (data == 0) {
|
||||
this->ReInit();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -842,6 +1069,10 @@ static const NWidgetPart _nested_select_company_livery_widgets [] = {
|
||||
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
|
||||
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
|
||||
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
|
||||
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_TRAIN, STR_LIVERY_TRAIN_TOOLTIP),
|
||||
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_ROADVEH, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
|
||||
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_SHIP, STR_LIVERY_SHIP_TOOLTIP),
|
||||
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_AIRCRAFT, STR_LIVERY_AIRCRAFT_TOOLTIP),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(90, 22), SetFill(1, 1), EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
@@ -850,7 +1081,13 @@ static const NWidgetPart _nested_select_company_livery_widgets [] = {
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1),
|
||||
SetDataTip(STR_BLACK_STRING, STR_LIVERY_SECONDARY_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_SCL_MATRIX), SetMinimalSize(275, 15), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_LIVERY_PANEL_TOOLTIP),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_SCL_MATRIX), SetMinimalSize(275, 0), SetResize(1, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_LIVERY_PANEL_TOOLTIP), SetScrollbar(WID_SCL_MATRIX_SCROLLBAR),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCL_MATRIX_SCROLLBAR),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _select_company_livery_desc(
|
||||
@@ -860,6 +1097,16 @@ static WindowDesc _select_company_livery_desc(
|
||||
_nested_select_company_livery_widgets, lengthof(_nested_select_company_livery_widgets)
|
||||
);
|
||||
|
||||
void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
|
||||
{
|
||||
SelectCompanyLiveryWindow *w = (SelectCompanyLiveryWindow *)BringWindowToFrontById(WC_COMPANY_COLOUR, company);
|
||||
if (w == NULL) {
|
||||
new SelectCompanyLiveryWindow(&_select_company_livery_desc, company, group);
|
||||
} else if (group != INVALID_GROUP) {
|
||||
w->SetSelectedGroup(company, group);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the face of a company manager's face.
|
||||
* @param cmf the company manager's face
|
||||
@@ -1121,7 +1368,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnInit()
|
||||
void OnInit() override
|
||||
{
|
||||
/* Size of the boolean yes/no button. */
|
||||
Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO));
|
||||
@@ -1144,7 +1391,7 @@ public:
|
||||
this->number_dim = number_dim;
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SCMF_FACE: {
|
||||
@@ -1203,7 +1450,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
/* lower the non-selected gender button */
|
||||
this->SetWidgetsLoweredState(!this->is_female, WID_SCMF_MALE, WID_SCMF_MALE2, WIDGET_LIST_END);
|
||||
@@ -1264,7 +1511,7 @@ public:
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
|
||||
@@ -1353,7 +1600,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
/* Toggle size, advanced/simple face selection */
|
||||
@@ -1462,7 +1709,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnQueryTextFinished(char *str)
|
||||
void OnQueryTextFinished(char *str) override
|
||||
{
|
||||
if (str == NULL) return;
|
||||
/* Set a new company manager face number */
|
||||
@@ -1509,9 +1756,6 @@ static WindowDesc _select_company_manager_face_desc(
|
||||
* Open the simple/advanced company manager face selection window
|
||||
*
|
||||
* @param parent the parent company window
|
||||
* @param adv simple or advanced face selection window
|
||||
* @param top previous top position of the window
|
||||
* @param left previous left position of the window
|
||||
*/
|
||||
static void DoSelectCompanyManagerFace(Window *parent)
|
||||
{
|
||||
@@ -1620,7 +1864,7 @@ struct CompanyInfrastructureWindow : Window
|
||||
return total;
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_CI_CAPTION:
|
||||
@@ -1629,7 +1873,7 @@ struct CompanyInfrastructureWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
|
||||
@@ -1752,7 +1996,7 @@ struct CompanyInfrastructureWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
int y = r.top;
|
||||
@@ -1855,7 +2099,7 @@ struct CompanyInfrastructureWindow : Window
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
|
||||
@@ -2021,7 +2265,7 @@ struct CompanyWindow : Window
|
||||
this->OnInvalidateData();
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
bool local = this->window_number == _local_company;
|
||||
@@ -2090,7 +2334,7 @@ struct CompanyWindow : Window
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_C_FACE: {
|
||||
@@ -2143,15 +2387,13 @@ struct CompanyWindow : Window
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
case WID_C_HAS_PASSWORD:
|
||||
*size = maxdim(*size, GetSpriteSize(SPR_LOCK));
|
||||
break;
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
const Company *c = Company::Get((CompanyID)this->window_number);
|
||||
switch (widget) {
|
||||
@@ -2200,16 +2442,16 @@ struct CompanyWindow : Window
|
||||
uint y = r.top;
|
||||
|
||||
/* Collect rail and road counts. */
|
||||
uint rail_pices = c->infrastructure.signal;
|
||||
uint rail_pieces = c->infrastructure.signal;
|
||||
uint road_pieces = 0;
|
||||
for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pices += c->infrastructure.rail[i];
|
||||
for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pieces += c->infrastructure.rail[i];
|
||||
for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i];
|
||||
|
||||
if (rail_pices == 0 && road_pieces == 0 && c->infrastructure.water == 0 && c->infrastructure.station == 0 && c->infrastructure.airport == 0) {
|
||||
if (rail_pieces == 0 && road_pieces == 0 && c->infrastructure.water == 0 && c->infrastructure.station == 0 && c->infrastructure.airport == 0) {
|
||||
DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
|
||||
} else {
|
||||
if (rail_pices != 0) {
|
||||
SetDParam(0, rail_pices);
|
||||
if (rail_pieces != 0) {
|
||||
SetDParam(0, rail_pieces);
|
||||
DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL);
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
}
|
||||
@@ -2254,17 +2496,15 @@ struct CompanyWindow : Window
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
case WID_C_HAS_PASSWORD:
|
||||
if (_networking && NetworkCompanyIsPassworded(c->index)) {
|
||||
DrawSprite(SPR_LOCK, PAL_NONE, r.left, r.top);
|
||||
}
|
||||
break;
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_C_CAPTION:
|
||||
@@ -2282,14 +2522,13 @@ struct CompanyWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
|
||||
|
||||
case WID_C_COLOUR_SCHEME:
|
||||
if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break;
|
||||
new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
|
||||
ShowCompanyLiveryWindow((CompanyID)this->window_number, INVALID_GROUP);
|
||||
break;
|
||||
|
||||
case WID_C_PRESIDENT_NAME:
|
||||
@@ -2351,7 +2590,6 @@ struct CompanyWindow : Window
|
||||
DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_SELL_25_SHARE_IN));
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
case WID_C_COMPANY_PASSWORD:
|
||||
if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
|
||||
break;
|
||||
@@ -2371,17 +2609,16 @@ struct CompanyWindow : Window
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnHundredthTick()
|
||||
void OnHundredthTick() override
|
||||
{
|
||||
/* redraw the window every now and then */
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnPlaceObject(Point pt, TileIndex tile)
|
||||
void OnPlaceObject(Point pt, TileIndex tile) override
|
||||
{
|
||||
if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS)) && !_shift_pressed) {
|
||||
ResetObjectToPlace();
|
||||
@@ -2389,12 +2626,12 @@ struct CompanyWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPlaceObjectAbort()
|
||||
void OnPlaceObjectAbort() override
|
||||
{
|
||||
this->RaiseButtons();
|
||||
}
|
||||
|
||||
virtual void OnQueryTextFinished(char *str)
|
||||
void OnQueryTextFinished(char *str) override
|
||||
{
|
||||
if (str == NULL) return;
|
||||
|
||||
@@ -2409,11 +2646,9 @@ struct CompanyWindow : Window
|
||||
DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME), NULL, str);
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
case WID_C_COMPANY_JOIN:
|
||||
NetworkClientRequestMove((CompanyID)this->window_number, str);
|
||||
break;
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2423,7 +2658,7 @@ struct CompanyWindow : Window
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (this->window_number == _local_company) return;
|
||||
|
||||
@@ -2482,7 +2717,7 @@ struct BuyCompanyWindow : Window {
|
||||
this->InitNested(window_number);
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BC_FACE:
|
||||
@@ -2498,7 +2733,7 @@ struct BuyCompanyWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BC_CAPTION:
|
||||
@@ -2508,7 +2743,7 @@ struct BuyCompanyWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BC_FACE: {
|
||||
@@ -2527,7 +2762,7 @@ struct BuyCompanyWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BC_NO:
|
||||
|
@@ -13,11 +13,13 @@
|
||||
#define COMPANY_GUI_H
|
||||
|
||||
#include "company_type.h"
|
||||
#include "group.h"
|
||||
#include "gfx_type.h"
|
||||
|
||||
TextColour GetDrawStringCompanyColour(CompanyID company);
|
||||
void DrawCompanyIcon(CompanyID c, int x, int y);
|
||||
|
||||
void ShowCompanyLiveryWindow(CompanyID company, GroupID group);
|
||||
void ShowCompanyStations(CompanyID company);
|
||||
void ShowCompanyFinances(CompanyID company);
|
||||
void ShowCompany(CompanyID company);
|
||||
|
@@ -64,4 +64,13 @@ enum CompanyRemoveReason {
|
||||
CRR_END, ///< Sentinel for end.
|
||||
};
|
||||
|
||||
/** The action to do with CMD_COMPANY_CTRL. */
|
||||
enum CompanyCtrlAction {
|
||||
CCA_NEW, ///< Create a new company.
|
||||
CCA_NEW_AI, ///< Create a new AI company.
|
||||
CCA_DELETE, ///< Delete a company.
|
||||
|
||||
CCA_END, ///< Sentinel for end.
|
||||
};
|
||||
|
||||
#endif /* COMPANY_TYPE_H */
|
||||
|
@@ -33,10 +33,8 @@ FILE *_iconsole_output_file;
|
||||
void IConsoleInit()
|
||||
{
|
||||
_iconsole_output_file = NULL;
|
||||
#ifdef ENABLE_NETWORK /* Initialize network only variables */
|
||||
_redirect_console_to_client = INVALID_CLIENT_ID;
|
||||
_redirect_console_to_admin = INVALID_ADMIN_ID;
|
||||
#endif
|
||||
|
||||
IConsoleGUIInit();
|
||||
|
||||
@@ -90,7 +88,6 @@ void IConsolePrint(TextColour colour_code, const char *string)
|
||||
assert(IsValidConsoleColour(colour_code));
|
||||
|
||||
char *str;
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (_redirect_console_to_client != INVALID_CLIENT_ID) {
|
||||
/* Redirect the string to the client */
|
||||
NetworkServerSendRcon(_redirect_console_to_client, colour_code, string);
|
||||
@@ -101,7 +98,6 @@ void IConsolePrint(TextColour colour_code, const char *string)
|
||||
NetworkServerSendAdminRcon(_redirect_console_to_admin, colour_code, string);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Create a copy of the string, strip if of colours and invalid
|
||||
* characters and (when applicable) assign it to the console buffer */
|
||||
@@ -110,9 +106,7 @@ void IConsolePrint(TextColour colour_code, const char *string)
|
||||
str_validate(str, str + strlen(str));
|
||||
|
||||
if (_network_dedicated) {
|
||||
#ifdef ENABLE_NETWORK
|
||||
NetworkAdminConsole("console", str);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
fprintf(stdout, "%s%s\n", GetLogPrefix(), str);
|
||||
fflush(stdout);
|
||||
IConsoleWriteToLogFile(str);
|
||||
@@ -235,8 +229,8 @@ void IConsoleAddSorted(T **base, T *item_new)
|
||||
|
||||
/**
|
||||
* Remove underscores from a string; the string will be modified!
|
||||
* @param name The string to remove the underscores from.
|
||||
* @return #name.
|
||||
* @param[in,out] name String to remove the underscores from.
|
||||
* @return \a name, with its contents modified.
|
||||
*/
|
||||
char *RemoveUnderscores(char *name)
|
||||
{
|
||||
|
@@ -62,7 +62,7 @@ public:
|
||||
|
||||
/**
|
||||
* (Re-)validate the file storage cache. Only makes a change if the storage was invalid, or if \a force_reload.
|
||||
* @param Always reload the file storage cache.
|
||||
* @param force_reload Always reload the file storage cache.
|
||||
*/
|
||||
void ValidateFileList(bool force_reload = false)
|
||||
{
|
||||
@@ -86,8 +86,6 @@ static ConsoleFileList _console_file_list; ///< File storage cache for the conso
|
||||
* command hooks
|
||||
****************/
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
|
||||
/**
|
||||
* Check network availability and inform in console about failure of detection.
|
||||
* @return Network availability.
|
||||
@@ -159,10 +157,6 @@ DEF_CONSOLE_HOOK(ConHookNoNetwork)
|
||||
return CHR_ALLOW;
|
||||
}
|
||||
|
||||
#else
|
||||
# define ConHookNoNetwork NULL
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool)
|
||||
{
|
||||
if (_settings_client.gui.newgrf_developer_tools) {
|
||||
@@ -170,11 +164,7 @@ DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool)
|
||||
if (echo) IConsoleError("This command is only available in game and editor.");
|
||||
return CHR_DISALLOW;
|
||||
}
|
||||
#ifdef ENABLE_NETWORK
|
||||
return ConHookNoNetwork(echo);
|
||||
#else
|
||||
return CHR_ALLOW;
|
||||
#endif
|
||||
}
|
||||
return CHR_HIDE;
|
||||
}
|
||||
@@ -256,8 +246,8 @@ DEF_CONSOLE_CMD(ConResetTile)
|
||||
|
||||
/**
|
||||
* Scroll to a tile on the map.
|
||||
* @param arg1 tile tile number or tile x coordinate.
|
||||
* @param arg2 optionally tile y coordinate.
|
||||
* param x tile number or tile x coordinate.
|
||||
* param y optional y coordinate.
|
||||
* @note When only one argument is given it is intepreted as the tile number.
|
||||
* When two arguments are given, they are interpreted as the tile's x
|
||||
* and y coordinates.
|
||||
@@ -304,7 +294,7 @@ DEF_CONSOLE_CMD(ConScrollToTile)
|
||||
|
||||
/**
|
||||
* Save the map to a file.
|
||||
* @param filename the filename to save the map to.
|
||||
* param filename the filename to save the map to.
|
||||
* @return True when help was displayed or the file attempted to be saved.
|
||||
*/
|
||||
DEF_CONSOLE_CMD(ConSave)
|
||||
@@ -479,7 +469,6 @@ DEF_CONSOLE_CMD(ConClearBuffer)
|
||||
/**********************************
|
||||
* Network Core Console Commands
|
||||
**********************************/
|
||||
#ifdef ENABLE_NETWORK
|
||||
|
||||
static bool ConKickOrBan(const char *argv, bool ban)
|
||||
{
|
||||
@@ -563,21 +552,21 @@ DEF_CONSOLE_CMD(ConUnBan)
|
||||
|
||||
/* Try by IP. */
|
||||
uint index;
|
||||
for (index = 0; index < _network_ban_list.Length(); index++) {
|
||||
for (index = 0; index < _network_ban_list.size(); index++) {
|
||||
if (strcmp(_network_ban_list[index], argv[1]) == 0) break;
|
||||
}
|
||||
|
||||
/* Try by index. */
|
||||
if (index >= _network_ban_list.Length()) {
|
||||
if (index >= _network_ban_list.size()) {
|
||||
index = atoi(argv[1]) - 1U; // let it wrap
|
||||
}
|
||||
|
||||
if (index < _network_ban_list.Length()) {
|
||||
if (index < _network_ban_list.size()) {
|
||||
char msg[64];
|
||||
seprintf(msg, lastof(msg), "Unbanned %s", _network_ban_list[index]);
|
||||
IConsolePrint(CC_DEFAULT, msg);
|
||||
free(_network_ban_list[index]);
|
||||
_network_ban_list.Erase(_network_ban_list.Get(index));
|
||||
_network_ban_list.erase(_network_ban_list.begin() + index);
|
||||
} else {
|
||||
IConsolePrint(CC_DEFAULT, "Invalid list index or IP not in ban-list.");
|
||||
IConsolePrint(CC_DEFAULT, "For a list of banned IP's, see the command 'banlist'");
|
||||
@@ -596,8 +585,8 @@ DEF_CONSOLE_CMD(ConBanList)
|
||||
IConsolePrint(CC_DEFAULT, "Banlist: ");
|
||||
|
||||
uint i = 1;
|
||||
for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++, i++) {
|
||||
IConsolePrintF(CC_DEFAULT, " %d) %s", i, *iter);
|
||||
for (char *entry : _network_ban_list) {
|
||||
IConsolePrintF(CC_DEFAULT, " %d) %s", i, entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -836,7 +825,7 @@ DEF_CONSOLE_CMD(ConResetCompany)
|
||||
}
|
||||
|
||||
/* It is safe to remove this company */
|
||||
DoCommandP(0, 2 | index << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL);
|
||||
IConsolePrint(CC_DEFAULT, "Company deleted.");
|
||||
|
||||
return true;
|
||||
@@ -930,8 +919,6 @@ DEF_CONSOLE_CMD(ConNetworkConnect)
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
/*********************************
|
||||
* script file console commands
|
||||
*********************************/
|
||||
@@ -1178,7 +1165,7 @@ DEF_CONSOLE_CMD(ConStartAI)
|
||||
}
|
||||
|
||||
/* Start a new AI company */
|
||||
DoCommandP(0, 1 | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1213,8 +1200,8 @@ DEF_CONSOLE_CMD(ConReloadAI)
|
||||
}
|
||||
|
||||
/* First kill the company of the AI, then start a new one. This should start the current AI again */
|
||||
DoCommandP(0, 2 | company_id << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, 1 | company_id << 16, 0, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0,CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, CCA_NEW_AI | company_id << 16, 0, CMD_COMPANY_CTRL);
|
||||
IConsolePrint(CC_DEFAULT, "AI reloaded.");
|
||||
|
||||
return true;
|
||||
@@ -1250,7 +1237,7 @@ DEF_CONSOLE_CMD(ConStopAI)
|
||||
}
|
||||
|
||||
/* Now kill the company of the AI. */
|
||||
DoCommandP(0, 2 | company_id << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
|
||||
DoCommandP(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL);
|
||||
IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
|
||||
|
||||
return true;
|
||||
@@ -1547,12 +1534,9 @@ DEF_CONSOLE_CMD(ConCompanies)
|
||||
const char *password_state = "";
|
||||
if (c->is_ai) {
|
||||
password_state = "AI";
|
||||
}
|
||||
#ifdef ENABLE_NETWORK
|
||||
else if (_network_server) {
|
||||
} else if (_network_server) {
|
||||
password_state = StrEmpty(_network_company_states[c->index].password) ? "unprotected" : "protected";
|
||||
}
|
||||
#endif
|
||||
|
||||
char colour[512];
|
||||
GetString(colour, STR_COLOUR_DARK_BLUE + _company_colours[c->index], lastof(colour));
|
||||
@@ -1569,8 +1553,6 @@ DEF_CONSOLE_CMD(ConCompanies)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
|
||||
DEF_CONSOLE_CMD(ConSay)
|
||||
{
|
||||
if (argc == 0) {
|
||||
@@ -1812,7 +1794,6 @@ DEF_CONSOLE_CMD(ConContent)
|
||||
return false;
|
||||
}
|
||||
#endif /* defined(WITH_ZLIB) */
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
DEF_CONSOLE_CMD(ConSetting)
|
||||
{
|
||||
@@ -2005,7 +1986,7 @@ void IConsoleStdLibRegister()
|
||||
IConsoleAliasRegister("players", "companies");
|
||||
|
||||
/* networking functions */
|
||||
#ifdef ENABLE_NETWORK
|
||||
|
||||
/* Content downloading is only available with ZLIB */
|
||||
#if defined(WITH_ZLIB)
|
||||
IConsoleCmdRegister("content", ConContent);
|
||||
@@ -2063,7 +2044,6 @@ void IConsoleStdLibRegister()
|
||||
IConsoleAliasRegister("restart_game_year", "setting restart_game_year %+");
|
||||
IConsoleAliasRegister("min_players", "setting min_active_clients %+");
|
||||
IConsoleAliasRegister("reload_cfg", "setting reload_cfg %+");
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
/* debugging stuff */
|
||||
#ifdef _DEBUG
|
||||
|
@@ -201,7 +201,7 @@ struct IConsoleWindow : Window
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
const int right = this->width - 5;
|
||||
|
||||
@@ -229,7 +229,7 @@ struct IConsoleWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnHundredthTick()
|
||||
void OnHundredthTick() override
|
||||
{
|
||||
if (IConsoleLine::Truncate() &&
|
||||
(IConsoleWindow::scroll > IConsoleLine::size)) {
|
||||
@@ -238,12 +238,12 @@ struct IConsoleWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnMouseLoop()
|
||||
void OnMouseLoop() override
|
||||
{
|
||||
if (_iconsole_cmdline.HandleCaret()) this->SetDirty();
|
||||
}
|
||||
|
||||
virtual EventState OnKeyPress(WChar key, uint16 keycode)
|
||||
EventState OnKeyPress(WChar key, uint16 keycode) override
|
||||
{
|
||||
if (_focused_window != this) return ES_NOT_HANDLED;
|
||||
|
||||
@@ -314,7 +314,7 @@ struct IConsoleWindow : Window
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
virtual void InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end)
|
||||
void InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) override
|
||||
{
|
||||
if (_iconsole_cmdline.InsertString(str, marked, caret, insert_location, replacement_end)) {
|
||||
IConsoleWindow::scroll = 0;
|
||||
@@ -323,17 +323,17 @@ struct IConsoleWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
virtual const char *GetFocusedText() const
|
||||
const char *GetFocusedText() const override
|
||||
{
|
||||
return _iconsole_cmdline.buf;
|
||||
}
|
||||
|
||||
virtual const char *GetCaret() const
|
||||
const char *GetCaret() const override
|
||||
{
|
||||
return _iconsole_cmdline.buf + _iconsole_cmdline.caretpos;
|
||||
}
|
||||
|
||||
virtual const char *GetMarkedText(size_t *length) const
|
||||
const char *GetMarkedText(size_t *length) const override
|
||||
{
|
||||
if (_iconsole_cmdline.markend == 0) return NULL;
|
||||
|
||||
@@ -341,7 +341,7 @@ struct IConsoleWindow : Window
|
||||
return _iconsole_cmdline.buf + _iconsole_cmdline.markpos;
|
||||
}
|
||||
|
||||
virtual Point GetCaretPosition() const
|
||||
Point GetCaretPosition() const override
|
||||
{
|
||||
int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0);
|
||||
Point pt = {this->line_offset + delta + _iconsole_cmdline.caretxoffs, this->height - this->line_height};
|
||||
@@ -349,7 +349,7 @@ struct IConsoleWindow : Window
|
||||
return pt;
|
||||
}
|
||||
|
||||
virtual Rect GetTextBoundingRect(const char *from, const char *to) const
|
||||
Rect GetTextBoundingRect(const char *from, const char *to) const override
|
||||
{
|
||||
int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0);
|
||||
|
||||
@@ -360,7 +360,7 @@ struct IConsoleWindow : Window
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual const char *GetTextCharacterAtPosition(const Point &pt) const
|
||||
const char *GetTextCharacterAtPosition(const Point &pt) const override
|
||||
{
|
||||
int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0);
|
||||
|
||||
@@ -369,12 +369,12 @@ struct IConsoleWindow : Window
|
||||
return GetCharAtPosition(_iconsole_cmdline.buf, pt.x - delta);
|
||||
}
|
||||
|
||||
virtual void OnMouseWheel(int wheel)
|
||||
void OnMouseWheel(int wheel) override
|
||||
{
|
||||
this->Scroll(-wheel);
|
||||
}
|
||||
|
||||
virtual void OnFocusLost()
|
||||
void OnFocusLost() override
|
||||
{
|
||||
VideoDriver::GetInstance()->EditBoxLostFocus();
|
||||
}
|
||||
|
@@ -25,24 +25,8 @@
|
||||
*/
|
||||
template <typename T, size_t length>
|
||||
struct SmallStackSafeStackAlloc {
|
||||
#if !defined(__NDS__)
|
||||
/** Storing the data on the stack */
|
||||
T data[length];
|
||||
#else
|
||||
/** Storing it on the heap */
|
||||
T *data;
|
||||
/** The length (in elements) of data in this allocator. */
|
||||
size_t len;
|
||||
|
||||
/** Allocating the memory */
|
||||
SmallStackSafeStackAlloc() : data(MallocT<T>(length)), len(length) {}
|
||||
|
||||
/** And freeing when it goes out of scope */
|
||||
~SmallStackSafeStackAlloc()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets a pointer to the data stored in this wrapper.
|
||||
@@ -69,11 +53,7 @@ struct SmallStackSafeStackAlloc {
|
||||
*/
|
||||
inline T *EndOf()
|
||||
{
|
||||
#if !defined(__NDS__)
|
||||
return endof(data);
|
||||
#else
|
||||
return &data[len];
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -302,6 +302,7 @@ static inline bool HasAtMostOneBit(T value)
|
||||
template <typename T>
|
||||
static inline T ROL(const T x, const uint8 n)
|
||||
{
|
||||
if (n == 0) return x;
|
||||
return (T)(x << n | x >> (sizeof(x) * 8 - n));
|
||||
}
|
||||
|
||||
@@ -317,6 +318,7 @@ static inline T ROL(const T x, const uint8 n)
|
||||
template <typename T>
|
||||
static inline T ROR(const T x, const uint8 n)
|
||||
{
|
||||
if (n == 0) return x;
|
||||
return (T)(x >> n | x << (sizeof(x) * 8 - n));
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
#define TTD_BIG_ENDIAN 1
|
||||
|
||||
/* Windows has always LITTLE_ENDIAN */
|
||||
#if defined(WIN32) || defined(__OS2__) || defined(WIN64)
|
||||
#if defined(_WIN32) || defined(__OS2__) || defined(__HAIKU__)
|
||||
# define TTD_ENDIAN TTD_LITTLE_ENDIAN
|
||||
#elif defined(OSX)
|
||||
# include <sys/types.h>
|
||||
@@ -42,6 +42,6 @@
|
||||
# else
|
||||
# define TTD_ENDIAN TTD_BIG_ENDIAN
|
||||
# endif
|
||||
#endif /* WIN32 || __OS2__ || WIN64 */
|
||||
#endif /* _WIN32 || __OS2__ */
|
||||
|
||||
#endif /* ENDIAN_TYPE_HPP */
|
||||
|
@@ -12,11 +12,6 @@
|
||||
#ifndef GEOMETRY_TYPE_HPP
|
||||
#define GEOMETRY_TYPE_HPP
|
||||
|
||||
#if defined(__AMIGA__)
|
||||
/* AmigaOS already has a Point declared */
|
||||
#define Point OTTD_Point
|
||||
#endif /* __AMIGA__ */
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Mac OS X already has both Rect and Point declared */
|
||||
#define Rect OTTD_Rect
|
||||
|
473
src/core/kdtree.hpp
Normal file
473
src/core/kdtree.hpp
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file kdtree.hpp K-d tree template specialised for 2-dimensional Manhattan geometry */
|
||||
|
||||
#ifndef KDTREE_HPP
|
||||
#define KDTREE_HPP
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
/**
|
||||
* K-dimensional tree, specialised for 2-dimensional space.
|
||||
* This is not intended as a primary storage of data, but as an index into existing data.
|
||||
* Usually the type stored by this tree should be an index into an existing array.
|
||||
*
|
||||
* This implementation assumes Manhattan distances are used.
|
||||
*
|
||||
* Be careful when using this in game code, depending on usage pattern, the tree shape may
|
||||
* end up different for different clients in multiplayer, causing iteration order to differ
|
||||
* and possibly having elements returned in different order. The using code should be designed
|
||||
* to produce the same result regardless of iteration order.
|
||||
*
|
||||
* The element type T must be less-than comparable for FindNearest to work.
|
||||
*
|
||||
* @tparam T Type stored in the tree, should be cheap to copy.
|
||||
* @tparam TxyFunc Functor type to extract coordinate from a T value and dimension index (0 or 1).
|
||||
* @tparam CoordT Type of coordinate values extracted via TxyFunc.
|
||||
* @tparam DistT Type to use for representing distance values.
|
||||
*/
|
||||
template <typename T, typename TxyFunc, typename CoordT, typename DistT>
|
||||
class Kdtree {
|
||||
/** Type of a node in the tree */
|
||||
struct node {
|
||||
T element; ///< Element stored at node
|
||||
size_t left; ///< Index of node to the left, INVALID_NODE if none
|
||||
size_t right; ///< Index of node to the right, INVALID_NODE if none
|
||||
|
||||
node(T element) : element(element), left(INVALID_NODE), right(INVALID_NODE) { }
|
||||
};
|
||||
|
||||
static const size_t INVALID_NODE = SIZE_MAX; ///< Index value indicating no-such-node
|
||||
|
||||
std::vector<node> nodes; ///< Pool of all nodes in the tree
|
||||
std::vector<size_t> free_list; ///< List of dead indices in the nodes vector
|
||||
size_t root; ///< Index of root node
|
||||
TxyFunc xyfunc; ///< Functor to extract a coordinate from an element
|
||||
size_t unbalanced; ///< Number approximating how unbalanced the tree might be
|
||||
|
||||
/** Create one new node in the tree, return its index in the pool */
|
||||
size_t AddNode(const T &element)
|
||||
{
|
||||
if (this->free_list.size() == 0) {
|
||||
this->nodes.emplace_back(element);
|
||||
return this->nodes.size() - 1;
|
||||
} else {
|
||||
size_t newidx = this->free_list.back();
|
||||
this->free_list.pop_back();
|
||||
this->nodes[newidx] = node{ element };
|
||||
return newidx;
|
||||
}
|
||||
}
|
||||
|
||||
/** Find a coordinate value to split a range of elements at */
|
||||
template <typename It>
|
||||
CoordT SelectSplitCoord(It begin, It end, int level)
|
||||
{
|
||||
It mid = begin + (end - begin) / 2;
|
||||
std::nth_element(begin, mid, end, [&](T a, T b) { return this->xyfunc(a, level % 2) < this->xyfunc(b, level % 2); });
|
||||
return this->xyfunc(*mid, level % 2);
|
||||
}
|
||||
|
||||
/** Construct a subtree from elements between begin and end iterators, return index of root */
|
||||
template <typename It>
|
||||
size_t BuildSubtree(It begin, It end, int level)
|
||||
{
|
||||
ptrdiff_t count = end - begin;
|
||||
|
||||
if (count == 0) {
|
||||
return INVALID_NODE;
|
||||
} else if (count == 1) {
|
||||
return this->AddNode(*begin);
|
||||
} else if (count > 1) {
|
||||
CoordT split_coord = SelectSplitCoord(begin, end, level);
|
||||
It split = std::partition(begin, end, [&](T v) { return this->xyfunc(v, level % 2) < split_coord; });
|
||||
size_t newidx = this->AddNode(*split);
|
||||
this->nodes[newidx].left = this->BuildSubtree(begin, split, level + 1);
|
||||
this->nodes[newidx].right = this->BuildSubtree(split + 1, end, level + 1);
|
||||
return newidx;
|
||||
} else {
|
||||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
/** Rebuild the tree with all existing elements, optionally adding or removing one more */
|
||||
bool Rebuild(const T *include_element, const T *exclude_element)
|
||||
{
|
||||
size_t initial_count = this->Count();
|
||||
if (initial_count < 8) return false; // arbitrary value for "not worth rebalancing"
|
||||
|
||||
T root_element = this->nodes[this->root].element;
|
||||
std::vector<T> elements = this->FreeSubtree(this->root);
|
||||
elements.push_back(root_element);
|
||||
|
||||
if (include_element != NULL) {
|
||||
elements.push_back(*include_element);
|
||||
initial_count++;
|
||||
}
|
||||
if (exclude_element != NULL) {
|
||||
typename std::vector<T>::iterator removed = std::remove(elements.begin(), elements.end(), *exclude_element);
|
||||
elements.erase(removed, elements.end());
|
||||
initial_count--;
|
||||
}
|
||||
|
||||
this->Build(elements.begin(), elements.end());
|
||||
assert(initial_count == this->Count());
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Insert one element in the tree somewhere below node_idx */
|
||||
void InsertRecursive(const T &element, size_t node_idx, int level)
|
||||
{
|
||||
/* Dimension index of current level */
|
||||
int dim = level % 2;
|
||||
/* Node reference */
|
||||
node &n = this->nodes[node_idx];
|
||||
|
||||
/* Coordinate of element splitting at this node */
|
||||
CoordT nc = this->xyfunc(n.element, dim);
|
||||
/* Coordinate of the new element */
|
||||
CoordT ec = this->xyfunc(element, dim);
|
||||
/* Which side to insert on */
|
||||
size_t &next = (ec < nc) ? n.left : n.right;
|
||||
|
||||
if (next == INVALID_NODE) {
|
||||
/* New leaf */
|
||||
size_t newidx = this->AddNode(element);
|
||||
/* Vector may have been reallocated at this point, n and next are invalid */
|
||||
node &nn = this->nodes[node_idx];
|
||||
if (ec < nc) nn.left = newidx; else nn.right = newidx;
|
||||
} else {
|
||||
this->InsertRecursive(element, next, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free all children of the given node
|
||||
* @return Collection of elements that were removed from tree.
|
||||
*/
|
||||
std::vector<T> FreeSubtree(size_t node_idx)
|
||||
{
|
||||
std::vector<T> subtree_elements;
|
||||
node &n = this->nodes[node_idx];
|
||||
|
||||
/* We'll be appending items to the free_list, get index of our first item */
|
||||
size_t first_free = this->free_list.size();
|
||||
/* Prepare the descent with our children */
|
||||
if (n.left != INVALID_NODE) this->free_list.push_back(n.left);
|
||||
if (n.right != INVALID_NODE) this->free_list.push_back(n.right);
|
||||
n.left = n.right = INVALID_NODE;
|
||||
|
||||
/* Recursively free the nodes being collected */
|
||||
for (size_t i = first_free; i < this->free_list.size(); i++) {
|
||||
node &fn = this->nodes[this->free_list[i]];
|
||||
subtree_elements.push_back(fn.element);
|
||||
if (fn.left != INVALID_NODE) this->free_list.push_back(fn.left);
|
||||
if (fn.right != INVALID_NODE) this->free_list.push_back(fn.right);
|
||||
fn.left = fn.right = INVALID_NODE;
|
||||
}
|
||||
|
||||
return subtree_elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and remove one element from the tree.
|
||||
* @param element The element to search for
|
||||
* @param node_idx Sub-tree to search in
|
||||
* @param level Current depth in the tree
|
||||
* @return New root node index of the sub-tree processed
|
||||
*/
|
||||
size_t RemoveRecursive(const T &element, size_t node_idx, int level)
|
||||
{
|
||||
/* Node reference */
|
||||
node &n = this->nodes[node_idx];
|
||||
|
||||
if (n.element == element) {
|
||||
/* Remove this one */
|
||||
this->free_list.push_back(node_idx);
|
||||
if (n.left == INVALID_NODE && n.right == INVALID_NODE) {
|
||||
/* Simple case, leaf, new child node for parent is "none" */
|
||||
return INVALID_NODE;
|
||||
} else {
|
||||
/* Complex case, rebuild the sub-tree */
|
||||
std::vector<T> subtree_elements = this->FreeSubtree(node_idx);
|
||||
return this->BuildSubtree(subtree_elements.begin(), subtree_elements.end(), level);;
|
||||
}
|
||||
} else {
|
||||
/* Search in a sub-tree */
|
||||
/* Dimension index of current level */
|
||||
int dim = level % 2;
|
||||
/* Coordinate of element splitting at this node */
|
||||
CoordT nc = this->xyfunc(n.element, dim);
|
||||
/* Coordinate of the element being removed */
|
||||
CoordT ec = this->xyfunc(element, dim);
|
||||
/* Which side to remove from */
|
||||
size_t next = (ec < nc) ? n.left : n.right;
|
||||
assert(next != INVALID_NODE); // node must exist somewhere and must be found before a leaf is reached
|
||||
/* Descend */
|
||||
size_t new_branch = this->RemoveRecursive(element, next, level + 1);
|
||||
if (new_branch != next) {
|
||||
/* Vector may have been reallocated at this point, n and next are invalid */
|
||||
node &nn = this->nodes[node_idx];
|
||||
if (ec < nc) nn.left = new_branch; else nn.right = new_branch;
|
||||
}
|
||||
return node_idx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DistT ManhattanDistance(const T &element, CoordT x, CoordT y) const
|
||||
{
|
||||
return abs((DistT)this->xyfunc(element, 0) - (DistT)x) + abs((DistT)this->xyfunc(element, 1) - (DistT)y);
|
||||
}
|
||||
|
||||
/** A data element and its distance to a searched-for point */
|
||||
using node_distance = std::pair<T, DistT>;
|
||||
/** Ordering function for node_distance objects, elements with equal distance are ordered by less-than comparison */
|
||||
static node_distance SelectNearestNodeDistance(const node_distance &a, const node_distance &b)
|
||||
{
|
||||
if (a.second < b.second) return a;
|
||||
if (b.second < a.second) return b;
|
||||
if (a.first < b.first) return a;
|
||||
if (b.first < a.first) return b;
|
||||
NOT_REACHED(); // a.first == b.first: same element must not be inserted twice
|
||||
}
|
||||
/** Search a sub-tree for the element nearest to a given point */
|
||||
node_distance FindNearestRecursive(CoordT xy[2], size_t node_idx, int level) const
|
||||
{
|
||||
/* Dimension index of current level */
|
||||
int dim = level % 2;
|
||||
/* Node reference */
|
||||
const node &n = this->nodes[node_idx];
|
||||
|
||||
/* Coordinate of element splitting at this node */
|
||||
CoordT c = this->xyfunc(n.element, dim);
|
||||
/* This node's distance to target */
|
||||
DistT thisdist = ManhattanDistance(n.element, xy[0], xy[1]);
|
||||
/* Assume this node is the best choice for now */
|
||||
node_distance best = std::make_pair(n.element, thisdist);
|
||||
|
||||
/* Next node to visit */
|
||||
size_t next = (xy[dim] < c) ? n.left : n.right;
|
||||
if (next != INVALID_NODE) {
|
||||
/* Check if there is a better node down the tree */
|
||||
best = SelectNearestNodeDistance(best, this->FindNearestRecursive(xy, next, level + 1));
|
||||
}
|
||||
|
||||
/* Check if the distance from current best is worse than distance from target to splitting line,
|
||||
* if it is we also need to check the other side of the split. */
|
||||
size_t opposite = (xy[dim] >= c) ? n.left : n.right; // reverse of above
|
||||
if (opposite != INVALID_NODE && best.second >= abs((int)xy[dim] - (int)c)) {
|
||||
node_distance other_candidate = this->FindNearestRecursive(xy, opposite, level + 1);
|
||||
best = SelectNearestNodeDistance(best, other_candidate);
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
template <typename Outputter>
|
||||
void FindContainedRecursive(CoordT p1[2], CoordT p2[2], size_t node_idx, int level, Outputter outputter) const
|
||||
{
|
||||
/* Dimension index of current level */
|
||||
int dim = level % 2;
|
||||
/* Node reference */
|
||||
const node &n = this->nodes[node_idx];
|
||||
|
||||
/* Coordinate of element splitting at this node */
|
||||
CoordT ec = this->xyfunc(n.element, dim);
|
||||
/* Opposite coordinate of element */
|
||||
CoordT oc = this->xyfunc(n.element, 1 - dim);
|
||||
|
||||
/* Test if this element is within rectangle */
|
||||
if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element);
|
||||
|
||||
/* Recurse left if part of rectangle is left of split */
|
||||
if (p1[dim] < ec && n.left != INVALID_NODE) this->FindContainedRecursive(p1, p2, n.left, level + 1, outputter);
|
||||
|
||||
/* Recurse right if part of rectangle is right of split */
|
||||
if (p2[dim] > ec && n.right != INVALID_NODE) this->FindContainedRecursive(p1, p2, n.right, level + 1, outputter);
|
||||
}
|
||||
|
||||
/** Debugging function, counts number of occurrences of an element regardless of its correct position in the tree */
|
||||
size_t CountValue(const T &element, size_t node_idx) const
|
||||
{
|
||||
if (node_idx == INVALID_NODE) return 0;
|
||||
const node &n = this->nodes[node_idx];
|
||||
return CountValue(element, n.left) + CountValue(element, n.right) + ((n.element == element) ? 1 : 0);
|
||||
}
|
||||
|
||||
void IncrementUnbalanced(size_t amount = 1)
|
||||
{
|
||||
this->unbalanced += amount;
|
||||
}
|
||||
|
||||
/** Check if the entire tree is in need of rebuilding */
|
||||
bool IsUnbalanced()
|
||||
{
|
||||
size_t count = this->Count();
|
||||
if (count < 8) return false;
|
||||
return this->unbalanced > this->Count() / 4;
|
||||
}
|
||||
|
||||
/** Verify that the invariant is true for a sub-tree, assert if not */
|
||||
void CheckInvariant(size_t node_idx, int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y)
|
||||
{
|
||||
if (node_idx == INVALID_NODE) return;
|
||||
|
||||
const node &n = this->nodes[node_idx];
|
||||
CoordT cx = this->xyfunc(n.element, 0);
|
||||
CoordT cy = this->xyfunc(n.element, 1);
|
||||
|
||||
assert(cx >= min_x);
|
||||
assert(cx < max_x);
|
||||
assert(cy >= min_y);
|
||||
assert(cy < max_y);
|
||||
|
||||
if (level % 2 == 0) {
|
||||
// split in dimension 0 = x
|
||||
CheckInvariant(n.left, level + 1, min_x, cx, min_y, max_y);
|
||||
CheckInvariant(n.right, level + 1, cx, max_x, min_y, max_y);
|
||||
} else {
|
||||
// split in dimension 1 = y
|
||||
CheckInvariant(n.left, level + 1, min_x, max_x, min_y, cy);
|
||||
CheckInvariant(n.right, level + 1, min_x, max_x, cy, max_y);
|
||||
}
|
||||
}
|
||||
|
||||
/** Verify the invariant for the entire tree, does nothing unless KDTREE_DEBUG is defined */
|
||||
void CheckInvariant()
|
||||
{
|
||||
#ifdef KDTREE_DEBUG
|
||||
CheckInvariant(this->root, 0, std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max(), std::numeric_limits<CoordT>::min(), std::numeric_limits<CoordT>::max());
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
/** Construct a new Kdtree with the given xyfunc */
|
||||
Kdtree(TxyFunc xyfunc) : root(INVALID_NODE), xyfunc(xyfunc), unbalanced(0) { }
|
||||
|
||||
/**
|
||||
* Clear and rebuild the tree from a new sequence of elements,
|
||||
* @tparam It Iterator type for element sequence.
|
||||
* @param begin First element in sequence.
|
||||
* @param end One past last element in sequence.
|
||||
*/
|
||||
template <typename It>
|
||||
void Build(It begin, It end)
|
||||
{
|
||||
this->nodes.clear();
|
||||
this->free_list.clear();
|
||||
this->unbalanced = 0;
|
||||
if (begin == end) return;
|
||||
this->nodes.reserve(end - begin);
|
||||
|
||||
this->root = this->BuildSubtree(begin, end, 0);
|
||||
CheckInvariant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstruct the tree with the same elements, letting it be fully balanced.
|
||||
*/
|
||||
void Rebuild()
|
||||
{
|
||||
this->Rebuild(NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a single element in the tree.
|
||||
* Repeatedly inserting single elements may cause the tree to become unbalanced.
|
||||
* Undefined behaviour if the element already exists in the tree.
|
||||
*/
|
||||
void Insert(const T &element)
|
||||
{
|
||||
if (this->Count() == 0) {
|
||||
this->root = this->AddNode(element);
|
||||
} else {
|
||||
if (!this->IsUnbalanced() || !this->Rebuild(&element, NULL)) {
|
||||
this->InsertRecursive(element, this->root, 0);
|
||||
this->IncrementUnbalanced();
|
||||
}
|
||||
CheckInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a single element from the tree, if it exists.
|
||||
* Since elements are stored in interior nodes as well as leaf nodes, removing one may
|
||||
* require a larger sub-tree to be re-built. Because of this, worst case run time is
|
||||
* as bad as a full tree rebuild.
|
||||
*/
|
||||
void Remove(const T &element)
|
||||
{
|
||||
size_t count = this->Count();
|
||||
if (count == 0) return;
|
||||
if (!this->IsUnbalanced() || !this->Rebuild(NULL, &element)) {
|
||||
/* If the removed element is the root node, this modifies this->root */
|
||||
this->root = this->RemoveRecursive(element, this->root, 0);
|
||||
this->IncrementUnbalanced();
|
||||
}
|
||||
CheckInvariant();
|
||||
}
|
||||
|
||||
/** Get number of elements stored in tree */
|
||||
size_t Count() const
|
||||
{
|
||||
assert(this->free_list.size() <= this->nodes.size());
|
||||
return this->nodes.size() - this->free_list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the element closest to given coordinate, in Manhattan distance.
|
||||
* For multiple elements with the same distance, the one comparing smaller with
|
||||
* a less-than comparison is chosen.
|
||||
*/
|
||||
T FindNearest(CoordT x, CoordT y) const
|
||||
{
|
||||
assert(this->Count() > 0);
|
||||
|
||||
CoordT xy[2] = { x, y };
|
||||
return this->FindNearestRecursive(xy, this->root, 0).first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all items contained within the given rectangle.
|
||||
* @note Start coordinates are inclusive, end coordinates are exclusive. x1<x2 && y1<y2 is a precondition.
|
||||
* @param x1 Start first coordinate, points found are greater or equals to this.
|
||||
* @param y1 Start second coordinate, points found are greater or equals to this.
|
||||
* @param x2 End first coordinate, points found are less than this.
|
||||
* @param y2 End second coordinate, points found are less than this.
|
||||
* @param outputter Callback used to return values from the search.
|
||||
*/
|
||||
template <typename Outputter>
|
||||
void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2, Outputter outputter) const
|
||||
{
|
||||
assert(x1 < x2);
|
||||
assert(y1 < y2);
|
||||
|
||||
if (this->Count() == 0) return;
|
||||
|
||||
CoordT p1[2] = { x1, y1 };
|
||||
CoordT p2[2] = { x2, y2 };
|
||||
this->FindContainedRecursive(p1, p2, this->root, 0, outputter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all items contained within the given rectangle.
|
||||
* @note End coordinates are exclusive, x1<x2 && y1<y2 is a precondition.
|
||||
*/
|
||||
std::vector<T> FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2) const
|
||||
{
|
||||
std::vector<T> result;
|
||||
this->FindContained(x1, y1, x2, y2, [&result](T e) {result.push_back(e); });
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@@ -247,9 +247,9 @@ static inline T Delta(const T a, const T b)
|
||||
* @return True if the value is in the interval, false else.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool IsInsideBS(const T x, const uint base, const uint size)
|
||||
static inline bool IsInsideBS(const T x, const size_t base, const size_t size)
|
||||
{
|
||||
return (uint)(x - base) < size;
|
||||
return (size_t)(x - base) < size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,9 +263,9 @@ static inline bool IsInsideBS(const T x, const uint base, const uint size)
|
||||
* @see IsInsideBS()
|
||||
*/
|
||||
template <typename T>
|
||||
static inline bool IsInsideMM(const T x, const uint min, const uint max)
|
||||
static inline bool IsInsideMM(const T x, const size_t min, const size_t max)
|
||||
{
|
||||
return (uint)(x - min) < (max - min);
|
||||
return (size_t)(x - min) < (max - min);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,6 +370,23 @@ static inline int RoundDivSU(int a, uint b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes (a / b) rounded away from zero.
|
||||
* @param a Numerator
|
||||
* @param b Denominator
|
||||
* @return Quotient, rounded away from zero
|
||||
*/
|
||||
static inline int DivAwayFromZero(int a, uint b)
|
||||
{
|
||||
const int _b = static_cast<int>(b);
|
||||
if (a > 0) {
|
||||
return (a + _b - 1) / _b;
|
||||
} else {
|
||||
/* Note: Behaviour of negative numerator division is truncation toward zero. */
|
||||
return (a - _b + 1) / _b;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 IntSqrt(uint32 num);
|
||||
|
||||
#endif /* MATH_FUNC_HPP */
|
||||
|
@@ -21,8 +21,8 @@
|
||||
/* virtual */ PoolBase::~PoolBase()
|
||||
{
|
||||
PoolVector *pools = PoolBase::GetPools();
|
||||
pools->Erase(pools->Find(this));
|
||||
if (pools->Length() == 0) delete pools;
|
||||
pools->erase(std::find(pools->begin(), pools->end(), this));
|
||||
if (pools->size() == 0) delete pools;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,10 +31,7 @@
|
||||
*/
|
||||
/* static */ void PoolBase::Clean(PoolType pt)
|
||||
{
|
||||
PoolVector *pools = PoolBase::GetPools();
|
||||
PoolBase **end = pools->End();
|
||||
for (PoolBase **ppool = pools->Begin(); ppool != end; ppool++) {
|
||||
PoolBase *pool = *ppool;
|
||||
for (PoolBase *pool : *PoolBase::GetPools()) {
|
||||
if (pool->type & pt) pool->CleanPool();
|
||||
}
|
||||
}
|
||||
|
@@ -152,18 +152,20 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
|
||||
* @param size size of item
|
||||
* @param index index of item
|
||||
* @return pointer to allocated item
|
||||
* @note usererror() on failure! (index out of range or already used)
|
||||
* @note SlErrorCorruptFmt() on failure! (index out of range or already used)
|
||||
*/
|
||||
DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
|
||||
{
|
||||
extern void NORETURN SlErrorCorruptFmt(const char *format, ...);
|
||||
|
||||
if (index >= Tmax_size) {
|
||||
usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
|
||||
SlErrorCorruptFmt("%s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
|
||||
}
|
||||
|
||||
if (index >= this->size) this->ResizeFor(index);
|
||||
|
||||
if (this->data[index] != NULL) {
|
||||
usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index);
|
||||
SlErrorCorruptFmt("%s index " PRINTF_SIZE " already in use", this->name, index);
|
||||
}
|
||||
|
||||
return this->AllocateItem(size, index);
|
||||
|
@@ -26,7 +26,7 @@ enum PoolType {
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(PoolType)
|
||||
|
||||
typedef SmallVector<struct PoolBase *, 4> PoolVector; ///< Vector of pointers to PoolBase
|
||||
typedef std::vector<struct PoolBase *> PoolVector; ///< Vector of pointers to PoolBase
|
||||
|
||||
/** Base class for base of all pools. */
|
||||
struct PoolBase {
|
||||
@@ -50,7 +50,7 @@ struct PoolBase {
|
||||
*/
|
||||
PoolBase(PoolType pt) : type(pt)
|
||||
{
|
||||
*PoolBase::GetPools()->Append() = this;
|
||||
PoolBase::GetPools()->push_back(this);
|
||||
}
|
||||
|
||||
virtual ~PoolBase();
|
||||
|
@@ -29,7 +29,7 @@ struct Randomizer {
|
||||
void SetSeed(uint32 seed);
|
||||
};
|
||||
extern Randomizer _random; ///< Random used in the game state calculations
|
||||
extern Randomizer _interactive_random; ///< Random used every else where is does not (directly) influence the game state
|
||||
extern Randomizer _interactive_random; ///< Random used everywhere else, where it does not (directly) influence the game state
|
||||
|
||||
/** Stores the state of all random number generators */
|
||||
struct SavedRandomSeeds {
|
||||
|
@@ -27,6 +27,7 @@ struct SmallPair {
|
||||
|
||||
/** Initializes this Pair with data */
|
||||
inline SmallPair(const T &first, const U &second) : first(first), second(second) { }
|
||||
SmallPair() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,8 +39,8 @@ struct SmallPair {
|
||||
*
|
||||
* @see SmallVector
|
||||
*/
|
||||
template <typename T, typename U, uint S = 16>
|
||||
struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
template <typename T, typename U>
|
||||
struct SmallMap : std::vector<SmallPair<T, U> > {
|
||||
typedef ::SmallPair<T, U> Pair;
|
||||
typedef Pair *iterator;
|
||||
typedef const Pair *const_iterator;
|
||||
@@ -54,12 +55,13 @@ struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
* @param key key to find
|
||||
* @return &Pair(key, data) if found, this->End() if not
|
||||
*/
|
||||
inline const Pair *Find(const T &key) const
|
||||
inline typename std::vector<Pair>::const_iterator Find(const T &key) const
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) return &this->data[i];
|
||||
typename std::vector<Pair>::const_iterator it;
|
||||
for (it = std::vector<Pair>::begin(); it != std::vector<Pair>::end(); it++) {
|
||||
if (key == it->first) return it;
|
||||
}
|
||||
return this->End();
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,18 +71,39 @@ struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
*/
|
||||
inline Pair *Find(const T &key)
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) return &this->data[i];
|
||||
for (uint i = 0; i < std::vector<Pair>::size(); i++) {
|
||||
if (key == std::vector<Pair>::operator[](i).first) return &std::vector<Pair>::operator[](i);
|
||||
}
|
||||
return this->End();
|
||||
}
|
||||
|
||||
inline const Pair *End() const
|
||||
{
|
||||
return std::vector<Pair>::data() + std::vector<Pair>::size();
|
||||
}
|
||||
|
||||
inline Pair *End()
|
||||
{
|
||||
return std::vector<Pair>::data() + std::vector<Pair>::size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether a key is assigned in this map.
|
||||
* @param key key to test
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &key) const
|
||||
{
|
||||
return this->Find(key) != std::vector<Pair>::end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a key is assigned in this map.
|
||||
* @param key key to test
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &key)
|
||||
{
|
||||
return this->Find(key) != this->End();
|
||||
}
|
||||
@@ -92,8 +115,9 @@ struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
*/
|
||||
inline void Erase(Pair *pair)
|
||||
{
|
||||
assert(pair >= this->Begin() && pair < this->End());
|
||||
*pair = this->data[--this->items];
|
||||
assert(pair >= std::vector<Pair>::data() && pair < this->End());
|
||||
auto distance = pair - std::vector<Pair>::data();
|
||||
std::vector<Pair>::erase(std::vector<Pair>::begin() + distance);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,13 +128,11 @@ struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
*/
|
||||
inline bool Erase(const T &key)
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) {
|
||||
this->data[i] = this->data[--this->items];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
auto *pair = this->Find(key);
|
||||
if (pair == this->End()) return false;
|
||||
|
||||
this->Erase(pair);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,9 +144,7 @@ struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
inline bool Insert(const T &key, const U &data)
|
||||
{
|
||||
if (this->Contains(key)) return false;
|
||||
Pair *n = this->Append();
|
||||
n->first = key;
|
||||
n->second = data;
|
||||
std::vector<Pair>::emplace_back(key, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -136,17 +156,18 @@ struct SmallMap : SmallVector<SmallPair<T, U>, S> {
|
||||
*/
|
||||
inline U &operator[](const T &key)
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
if (key == this->data[i].first) return this->data[i].second;
|
||||
for (uint i = 0; i < std::vector<Pair>::size(); i++) {
|
||||
if (key == std::vector<Pair>::operator[](i).first) return std::vector<Pair>::operator[](i).second;
|
||||
}
|
||||
Pair *n = this->Append();
|
||||
n->first = key;
|
||||
return n->second;
|
||||
/*C++17: Pair &n = */ std::vector<Pair>::emplace_back();
|
||||
Pair &n = std::vector<Pair>::back();
|
||||
n.first = key;
|
||||
return n.second;
|
||||
}
|
||||
|
||||
inline void SortByKey()
|
||||
{
|
||||
QSortT(this->Begin(), this->items, KeySorter);
|
||||
QSortT(std::vector<Pair>::data(), std::vector<Pair>::size(), KeySorter);
|
||||
}
|
||||
|
||||
static int CDECL KeySorter(const Pair *a, const Pair *b)
|
||||
|
@@ -159,7 +159,7 @@ public:
|
||||
|
||||
/**
|
||||
* Erase a row, replacing it with the last one.
|
||||
* @param x Position of the row.
|
||||
* @param y Position of the row.
|
||||
*/
|
||||
void EraseRow(uint y)
|
||||
{
|
||||
@@ -174,7 +174,7 @@ public:
|
||||
|
||||
/**
|
||||
* Remove columns from the matrix while preserving the order of other columns.
|
||||
* @param x First column to remove.
|
||||
* @param y First column to remove.
|
||||
* @param count Number of consecutive columns to remove.
|
||||
*/
|
||||
void EraseRowPreservingOrder(uint y, uint count = 1)
|
||||
@@ -210,8 +210,8 @@ public:
|
||||
/**
|
||||
* Set the size to a specific width and height, preserving item positions
|
||||
* as far as possible in the process.
|
||||
* @param width Target width.
|
||||
* @param height Target height.
|
||||
* @param new_width Target width.
|
||||
* @param new_height Target height.
|
||||
*/
|
||||
inline void Resize(uint new_width, uint new_height)
|
||||
{
|
||||
@@ -297,7 +297,7 @@ public:
|
||||
/**
|
||||
* Get column "number" (const)
|
||||
*
|
||||
* @param X Position of the column.
|
||||
* @param x Position of the column.
|
||||
* @return Column at "number".
|
||||
*/
|
||||
inline const T *operator[](uint x) const
|
||||
@@ -309,7 +309,7 @@ public:
|
||||
/**
|
||||
* Get column "number" (const)
|
||||
*
|
||||
* @param X Position of the column.
|
||||
* @param x Position of the column.
|
||||
* @return Column at "number".
|
||||
*/
|
||||
inline T *operator[](uint x)
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#define SMALLSTACK_TYPE_HPP
|
||||
|
||||
#include "smallvec_type.hpp"
|
||||
#include "../thread/thread.h"
|
||||
#include <mutex>
|
||||
|
||||
/**
|
||||
* A simplified pool which stores values instead of pointers and doesn't
|
||||
@@ -23,15 +23,14 @@
|
||||
template<typename Titem, typename Tindex, Tindex Tgrowth_step, Tindex Tmax_size>
|
||||
class SimplePool {
|
||||
public:
|
||||
inline SimplePool() : first_unused(0), first_free(0), mutex(ThreadMutex::New()) {}
|
||||
inline ~SimplePool() { delete this->mutex; }
|
||||
inline SimplePool() : first_unused(0), first_free(0) {}
|
||||
|
||||
/**
|
||||
* Get the mutex. We don't lock the mutex in the pool methods as the
|
||||
* SmallStack isn't necessarily in a consistent state after each method.
|
||||
* @return Mutex.
|
||||
*/
|
||||
inline ThreadMutex *GetMutex() { return this->mutex; }
|
||||
inline std::mutex &GetMutex() { return this->mutex; }
|
||||
|
||||
/**
|
||||
* Get the item at position index.
|
||||
@@ -73,8 +72,8 @@ private:
|
||||
if (!this->data[index].valid) return index;
|
||||
}
|
||||
|
||||
if (index >= this->data.Length() && index < Tmax_size) {
|
||||
this->data.Resize(index + 1);
|
||||
if (index >= this->data.size() && index < Tmax_size) {
|
||||
this->data.resize(index + 1);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
@@ -86,8 +85,8 @@ private:
|
||||
Tindex first_unused;
|
||||
Tindex first_free;
|
||||
|
||||
ThreadMutex *mutex;
|
||||
SmallVector<SimplePoolPoolItem, Tgrowth_step> data;
|
||||
std::mutex mutex;
|
||||
std::vector<SimplePoolPoolItem> data;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -106,6 +105,7 @@ struct SmallStackItem {
|
||||
*/
|
||||
inline SmallStackItem(const Titem &value, Tindex next) :
|
||||
next(next), value(value) {}
|
||||
SmallStackItem() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -195,7 +195,7 @@ public:
|
||||
inline void Push(const Titem &item)
|
||||
{
|
||||
if (this->value != Tinvalid) {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
std::lock_guard<std::mutex> lock(SmallStack::GetPool().GetMutex());
|
||||
Tindex new_item = SmallStack::GetPool().Create();
|
||||
if (new_item != Tmax_size) {
|
||||
PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item);
|
||||
@@ -218,7 +218,7 @@ public:
|
||||
if (this->next == Tmax_size) {
|
||||
this->value = Tinvalid;
|
||||
} else {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
std::lock_guard<std::mutex> lock(SmallStack::GetPool().GetMutex());
|
||||
PooledSmallStack &popped = SmallStack::GetPool().Get(this->next);
|
||||
this->value = popped.value;
|
||||
if (popped.branch_count == 0) {
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
{
|
||||
if (item == Tinvalid || item == this->value) return true;
|
||||
if (this->next != Tmax_size) {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
std::lock_guard<std::mutex> lock(SmallStack::GetPool().GetMutex());
|
||||
const SmallStack *in_list = this;
|
||||
do {
|
||||
in_list = static_cast<const SmallStack *>(
|
||||
@@ -281,7 +281,7 @@ protected:
|
||||
inline void Branch()
|
||||
{
|
||||
if (this->next != Tmax_size) {
|
||||
ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
|
||||
std::lock_guard<std::mutex> lock(SmallStack::GetPool().GetMutex());
|
||||
++(SmallStack::GetPool().Get(this->next).branch_count);
|
||||
}
|
||||
}
|
||||
|
@@ -14,375 +14,60 @@
|
||||
|
||||
#include "alloc_func.hpp"
|
||||
#include "mem_func.hpp"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* Simple vector template class.
|
||||
* Helper function to append an item to a vector if it is not already contained
|
||||
* Consider using std::set, std::unordered_set or std::flat_set in new code
|
||||
*
|
||||
* @note There are no asserts in the class so you have
|
||||
* to care about that you grab an item which is
|
||||
* inside the list.
|
||||
* @param vec A reference to the vector to be extended
|
||||
* @param item Reference to the item to be copy-constructed if not found
|
||||
*
|
||||
* @tparam T The type of the items stored
|
||||
* @tparam S The steps of allocation
|
||||
* @return Whether the item was already present
|
||||
*/
|
||||
template <typename T, uint S>
|
||||
class SmallVector {
|
||||
protected:
|
||||
T *data; ///< The pointer to the first item
|
||||
uint items; ///< The number of items stored
|
||||
uint capacity; ///< The available space for storing items
|
||||
template <typename T>
|
||||
inline bool include(std::vector<T>& vec, const T &item)
|
||||
{
|
||||
const bool is_member = std::find(vec.begin(), vec.end(), item) != vec.end();
|
||||
if (!is_member) vec.emplace_back(item);
|
||||
return is_member;
|
||||
}
|
||||
|
||||
public:
|
||||
SmallVector() : data(NULL), items(0), capacity(0) { }
|
||||
/**
|
||||
* Helper function to get the index of an item
|
||||
* Consider using std::set, std::unordered_set or std::flat_set in new code
|
||||
*
|
||||
* @param vec A reference to the vector to be extended
|
||||
* @param item Reference to the item to be search for
|
||||
*
|
||||
* @return Index of element if found, otherwise -1
|
||||
*/
|
||||
template <typename T>
|
||||
int find_index(std::vector<T> const& vec, T const& item)
|
||||
{
|
||||
auto const it = std::find(vec.begin(), vec.end(), item);
|
||||
if (it != vec.end()) return it - vec.begin();
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param other The other vector to copy.
|
||||
*/
|
||||
SmallVector(const SmallVector &other) : data(NULL), items(0), capacity(0)
|
||||
{
|
||||
this->Assign(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic copy constructor.
|
||||
* @param other The other vector to copy.
|
||||
*/
|
||||
template <uint X>
|
||||
SmallVector(const SmallVector<T, X> &other) : data(NULL), items(0), capacity(0)
|
||||
{
|
||||
this->Assign(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assignment.
|
||||
* @param other The other vector to assign.
|
||||
*/
|
||||
SmallVector &operator=(const SmallVector &other)
|
||||
{
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic assignment.
|
||||
* @param other The other vector to assign.
|
||||
*/
|
||||
template <uint X>
|
||||
SmallVector &operator=(const SmallVector<T, X> &other)
|
||||
{
|
||||
this->Assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~SmallVector()
|
||||
{
|
||||
free(this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign items from other vector.
|
||||
*/
|
||||
template <uint X>
|
||||
inline void Assign(const SmallVector<T, X> &other)
|
||||
{
|
||||
if ((const void *)&other == (void *)this) return;
|
||||
|
||||
this->Clear();
|
||||
if (other.Length() > 0) MemCpyT<T>(this->Append(other.Length()), other.Begin(), other.Length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list.
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
/* In fact we just reset the item counter avoiding the need to
|
||||
* probably reallocate the same amount of memory the list was
|
||||
* previously using. */
|
||||
this->items = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list and free allocated memory.
|
||||
*/
|
||||
inline void Reset()
|
||||
{
|
||||
this->items = 0;
|
||||
this->capacity = 0;
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact the list down to the smallest block size boundary.
|
||||
*/
|
||||
inline void Compact()
|
||||
{
|
||||
uint capacity = Align(this->items, S);
|
||||
if (capacity >= this->capacity) return;
|
||||
|
||||
this->capacity = capacity;
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an item and return it.
|
||||
* @param to_add the number of items to append
|
||||
* @return pointer to newly allocated item
|
||||
*/
|
||||
inline T *Append(uint to_add = 1)
|
||||
{
|
||||
uint begin = this->items;
|
||||
this->items += to_add;
|
||||
|
||||
if (this->items > this->capacity) {
|
||||
this->capacity = Align(this->items, S);
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
|
||||
return &this->data[begin];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the vector, effectively truncating items from the end or appending uninitialised ones.
|
||||
* @param num_items Target size.
|
||||
*/
|
||||
inline void Resize(uint num_items)
|
||||
{
|
||||
this->items = num_items;
|
||||
|
||||
if (this->items > this->capacity) {
|
||||
this->capacity = Align(this->items, S);
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new item at a specific position into the vector, moving all following items.
|
||||
* @param item Position at which the new item should be inserted
|
||||
* @return pointer to the new item
|
||||
*/
|
||||
inline T *Insert(T *item)
|
||||
{
|
||||
assert(item >= this->Begin() && item <= this->End());
|
||||
|
||||
size_t to_move = this->End() - item;
|
||||
size_t start = item - this->Begin();
|
||||
|
||||
this->Append();
|
||||
if (to_move > 0) MemMoveT(this->Begin() + start + 1, this->Begin() + start, to_move);
|
||||
return this->Begin() + start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first occurrence of an item.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to search for
|
||||
* @return The position of the item, or End() when not present
|
||||
*/
|
||||
inline const T *Find(const T &item) const
|
||||
{
|
||||
const T *pos = this->Begin();
|
||||
const T *end = this->End();
|
||||
while (pos != end && *pos != item) pos++;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first occurrence of an item.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to search for
|
||||
* @return The position of the item, or End() when not present
|
||||
*/
|
||||
inline T *Find(const T &item)
|
||||
{
|
||||
T *pos = this->Begin();
|
||||
const T *end = this->End();
|
||||
while (pos != end && *pos != item) pos++;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the first occurrence of an item.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to search for
|
||||
* @return The position of the item, or -1 when not present
|
||||
*/
|
||||
inline int FindIndex(const T &item) const
|
||||
{
|
||||
int index = 0;
|
||||
const T *pos = this->Begin();
|
||||
const T *end = this->End();
|
||||
while (pos != end && *pos != item) {
|
||||
pos++;
|
||||
index++;
|
||||
}
|
||||
return pos == end ? -1 : index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a item is present in the vector.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to test for
|
||||
* @return true iff the item is present
|
||||
*/
|
||||
inline bool Contains(const T &item) const
|
||||
{
|
||||
return this->Find(item) != this->End();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given item from this vector
|
||||
* @param item item to remove
|
||||
* @note it has to be pointer to item in this map. It is overwritten by the last item.
|
||||
*/
|
||||
inline void Erase(T *item)
|
||||
{
|
||||
assert(item >= this->Begin() && item < this->End());
|
||||
*item = this->data[--this->items];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove items from the vector while preserving the order of other items.
|
||||
* @param pos First item to remove.
|
||||
* @param count Number of consecutive items to remove.
|
||||
*/
|
||||
void ErasePreservingOrder(uint pos, uint count = 1)
|
||||
{
|
||||
ErasePreservingOrder(this->data + pos, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove items from the vector while preserving the order of other items.
|
||||
* @param item First item to remove.
|
||||
* @param count Number of consecutive items to remove.
|
||||
*/
|
||||
inline void ErasePreservingOrder(T *item, uint count = 1)
|
||||
{
|
||||
if (count == 0) return;
|
||||
assert(item >= this->Begin());
|
||||
assert(item + count <= this->End());
|
||||
|
||||
this->items -= count;
|
||||
ptrdiff_t to_move = this->End() - item;
|
||||
if (to_move > 0) MemMoveT(item, item + count, to_move);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a item is present in the vector, and appends it to the end if not.
|
||||
* The '!=' operator of T is used for comparison.
|
||||
* @param item Item to test for
|
||||
* @return true iff the item is was already present
|
||||
*/
|
||||
inline bool Include(const T &item)
|
||||
{
|
||||
bool is_member = this->Contains(item);
|
||||
if (!is_member) *this->Append() = item;
|
||||
return is_member;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of items in the list.
|
||||
*
|
||||
* @return The number of items in the list.
|
||||
*/
|
||||
inline uint Length() const
|
||||
{
|
||||
return this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to the first item (const)
|
||||
*
|
||||
* @return the pointer to the first item
|
||||
*/
|
||||
inline const T *Begin() const
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to the first item
|
||||
*
|
||||
* @return the pointer to the first item
|
||||
*/
|
||||
inline T *Begin()
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer behind the last valid item (const)
|
||||
*
|
||||
* @return the pointer behind the last valid item
|
||||
*/
|
||||
inline const T *End() const
|
||||
{
|
||||
return &this->data[this->items];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer behind the last valid item
|
||||
*
|
||||
* @return the pointer behind the last valid item
|
||||
*/
|
||||
inline T *End()
|
||||
{
|
||||
return &this->data[this->items];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to item "number" (const)
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the pointer to the item
|
||||
*/
|
||||
inline const T *Get(uint index) const
|
||||
{
|
||||
/* Allow access to the 'first invalid' item */
|
||||
assert(index <= this->items);
|
||||
return &this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to item "number"
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the pointer to the item
|
||||
*/
|
||||
inline T *Get(uint index)
|
||||
{
|
||||
/* Allow access to the 'first invalid' item */
|
||||
assert(index <= this->items);
|
||||
return &this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item "number" (const)
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the item
|
||||
*/
|
||||
inline const T &operator[](uint index) const
|
||||
{
|
||||
assert(index < this->items);
|
||||
return this->data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item "number"
|
||||
*
|
||||
* @param index the position of the item
|
||||
* @return the item
|
||||
*/
|
||||
inline T &operator[](uint index)
|
||||
{
|
||||
assert(index < this->items);
|
||||
return this->data[index];
|
||||
}
|
||||
};
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to append N default-constructed elements and get a pointer to the first new element
|
||||
* Consider using std::back_inserter in new code
|
||||
*
|
||||
* @param vec A reference to the vector to be extended
|
||||
* @param num Number of elements to be default-constructed
|
||||
*
|
||||
* @return Pointer to the first new element
|
||||
*/
|
||||
template <typename T>
|
||||
T* grow(std::vector<T>& vec, std::size_t num)
|
||||
{
|
||||
std::size_t const pos = vec.size();
|
||||
vec.resize(pos + num);
|
||||
return vec.data() + pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple vector template class, with automatic free.
|
||||
@@ -392,10 +77,9 @@ public:
|
||||
* inside the list.
|
||||
*
|
||||
* @param T The type of the items stored, must be a pointer
|
||||
* @param S The steps of allocation
|
||||
*/
|
||||
template <typename T, uint S>
|
||||
class AutoFreeSmallVector : public SmallVector<T, S> {
|
||||
template <typename T>
|
||||
class AutoFreeSmallVector : public std::vector<T> {
|
||||
public:
|
||||
~AutoFreeSmallVector()
|
||||
{
|
||||
@@ -407,11 +91,11 @@ public:
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
free(this->data[i]);
|
||||
for (T p : *this) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
this->items = 0;
|
||||
std::vector<T>::clear();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -423,10 +107,9 @@ public:
|
||||
* inside the list.
|
||||
*
|
||||
* @param T The type of the items stored, must be a pointer
|
||||
* @param S The steps of allocation
|
||||
*/
|
||||
template <typename T, uint S>
|
||||
class AutoDeleteSmallVector : public SmallVector<T, S> {
|
||||
template <typename T>
|
||||
class AutoDeleteSmallVector : public std::vector<T> {
|
||||
public:
|
||||
~AutoDeleteSmallVector()
|
||||
{
|
||||
@@ -438,14 +121,14 @@ public:
|
||||
*/
|
||||
inline void Clear()
|
||||
{
|
||||
for (uint i = 0; i < this->items; i++) {
|
||||
delete this->data[i];
|
||||
for (T p : *this) {
|
||||
delete p;
|
||||
}
|
||||
|
||||
this->items = 0;
|
||||
std::vector<T>::clear();
|
||||
}
|
||||
};
|
||||
|
||||
typedef AutoFreeSmallVector<char*, 4> StringList; ///< Type for a list of strings.
|
||||
typedef AutoFreeSmallVector<char*> StringList; ///< Type for a list of strings.
|
||||
|
||||
#endif /* SMALLVEC_TYPE_HPP */
|
||||
|
@@ -25,7 +25,7 @@
|
||||
* @param desc Sort descending.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void QSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
static inline void QSortT(T *base, size_t num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
{
|
||||
if (num < 2) return;
|
||||
|
||||
@@ -49,7 +49,7 @@ static inline void QSortT(T *base, uint num, int (CDECL *comparator)(const T*, c
|
||||
* @param desc Sort descending.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void GSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
static inline void GSortT(T *base, size_t num, int (CDECL *comparator)(const T*, const T*), bool desc = false)
|
||||
{
|
||||
if (num < 2) return;
|
||||
|
||||
|
@@ -35,7 +35,7 @@ unsigned __int64 ottd_rdtsc();
|
||||
#endif
|
||||
|
||||
/* rdtsc for all other *nix-en (hopefully). Use GCC syntax */
|
||||
#if (defined(__i386__) || defined(__x86_64__)) && !defined(__DJGPP__) && !defined(RDTSC_AVAILABLE)
|
||||
#if (defined(__i386__) || defined(__x86_64__)) && !defined(RDTSC_AVAILABLE)
|
||||
uint64 ottd_rdtsc()
|
||||
{
|
||||
uint32 high, low;
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#include "news_gui.h"
|
||||
#include "scope_info.h"
|
||||
#include "command_func.h"
|
||||
#include "thread/thread.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "ai/ai_info.hpp"
|
||||
#include "game/game.hpp"
|
||||
@@ -56,17 +56,16 @@
|
||||
# include <ft2build.h>
|
||||
# include FT_FREETYPE_H
|
||||
#endif /* WITH_FREETYPE */
|
||||
#if defined(WITH_ICU_LAYOUT) || defined(WITH_ICU_SORT)
|
||||
#if defined(WITH_ICU_LX) || defined(WITH_ICU_I18N)
|
||||
# include <unicode/uversion.h>
|
||||
#endif /* WITH_ICU_SORT || WITH_ICU_LAYOUT */
|
||||
#ifdef WITH_LZMA
|
||||
#endif /* WITH_ICU_LX || WITH_ICU_I18N */
|
||||
#ifdef WITH_LIBLZMA
|
||||
# include <lzma.h>
|
||||
#endif
|
||||
#ifdef WITH_LZO
|
||||
#include <lzo/lzo1x.h>
|
||||
#endif
|
||||
#ifdef WITH_SDL
|
||||
# include "sdl.h"
|
||||
# include <SDL.h>
|
||||
#endif /* WITH_SDL */
|
||||
#ifdef WITH_ZLIB
|
||||
@@ -265,21 +264,21 @@ char *CrashLog::LogLibraries(char *buffer, const char *last) const
|
||||
buffer += seprintf(buffer, last, " FreeType: %d.%d.%d\n", major, minor, patch);
|
||||
#endif /* WITH_FREETYPE */
|
||||
|
||||
#if defined(WITH_ICU_LAYOUT) || defined(WITH_ICU_SORT)
|
||||
#if defined(WITH_ICU_LX) || defined(WITH_ICU_I18N)
|
||||
/* 4 times 0-255, separated by dots (.) and a trailing '\0' */
|
||||
char buf[4 * 3 + 3 + 1];
|
||||
UVersionInfo ver;
|
||||
u_getVersion(ver);
|
||||
u_versionToString(ver, buf);
|
||||
#ifdef WITH_ICU_SORT
|
||||
#ifdef WITH_ICU_I18N
|
||||
buffer += seprintf(buffer, last, " ICU i18n: %s\n", buf);
|
||||
#endif
|
||||
#ifdef WITH_ICU_LAYOUT
|
||||
#ifdef WITH_ICU_LX
|
||||
buffer += seprintf(buffer, last, " ICU lx: %s\n", buf);
|
||||
#endif
|
||||
#endif /* WITH_ICU_SORT || WITH_ICU_LAYOUT */
|
||||
#endif /* WITH_ICU_LX || WITH_ICU_I18N */
|
||||
|
||||
#ifdef WITH_LZMA
|
||||
#ifdef WITH_LIBLZMA
|
||||
buffer += seprintf(buffer, last, " LZMA: %s\n", lzma_version_string());
|
||||
#endif
|
||||
|
||||
@@ -292,14 +291,8 @@ char *CrashLog::LogLibraries(char *buffer, const char *last) const
|
||||
#endif /* WITH_PNG */
|
||||
|
||||
#ifdef WITH_SDL
|
||||
#ifdef DYNAMICALLY_LOADED_SDL
|
||||
if (SDL_CALL SDL_Linked_Version != NULL) {
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
const SDL_version *v = SDL_CALL SDL_Linked_Version();
|
||||
buffer += seprintf(buffer, last, " SDL: %d.%d.%d\n", v->major, v->minor, v->patch);
|
||||
}
|
||||
const SDL_version *v = SDL_Linked_Version();
|
||||
buffer += seprintf(buffer, last, " SDL: %d.%d.%d\n", v->major, v->minor, v->patch);
|
||||
#endif /* WITH_SDL */
|
||||
|
||||
#ifdef WITH_ZLIB
|
||||
@@ -401,7 +394,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
|
||||
|
||||
if (IsNonMainThread()) {
|
||||
buffer += seprintf(buffer, last, "Non-main thread (");
|
||||
buffer += GetThreadName(buffer, last);
|
||||
buffer += GetCurrentThreadName(buffer, last);
|
||||
buffer += seprintf(buffer, last, ")\n\n");
|
||||
}
|
||||
|
||||
|
@@ -62,6 +62,8 @@ static const CurrencySpec origin_currency_specs[CURRENCY_END] = {
|
||||
{ 1, "", CF_NOEURO, "", "", 2, STR_GAME_OPTIONS_CURRENCY_CUSTOM }, ///< custom currency (add further languages below)
|
||||
{ 3, "", CF_NOEURO, "", NBSP "GEL", 1, STR_GAME_OPTIONS_CURRENCY_GEL }, ///< Georgian Lari
|
||||
{ 4901, "", CF_NOEURO, "", NBSP "Rls", 1, STR_GAME_OPTIONS_CURRENCY_IRR }, ///< Iranian Rial
|
||||
{ 80, "", CF_NOEURO, "", NBSP "rub", 1, STR_GAME_OPTIONS_CURRENCY_RUB }, ///< New Russian Ruble
|
||||
{ 24, "", CF_NOEURO, "$", "", 0, STR_GAME_OPTIONS_CURRENCY_MXN }, ///< Mexican peso
|
||||
};
|
||||
|
||||
/** Array of currencies used by the system */
|
||||
|
@@ -58,6 +58,8 @@ enum Currencies {
|
||||
CURRENCY_CUSTOM, ///< Custom currency
|
||||
CURRENCY_GEL, ///< Georgian Lari
|
||||
CURRENCY_IRR, ///< Iranian Rial
|
||||
CURRENCY_RUB, ///< New Russian Ruble
|
||||
CURRENCY_MXN, ///< Mexican Peso
|
||||
CURRENCY_END, ///< always the last item
|
||||
};
|
||||
|
||||
|
@@ -195,9 +195,7 @@ static void OnNewYear()
|
||||
VehiclesYearlyLoop();
|
||||
TownsYearlyLoop();
|
||||
InvalidateWindowClassesData(WC_BUILD_STATION);
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (_network_server) NetworkServerYearlyLoop();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
if (_cur_year == _settings_client.gui.semaphore_build_before) ResetSignalVariant();
|
||||
|
||||
@@ -217,11 +215,9 @@ static void OnNewYear()
|
||||
LinkGraph *lg;
|
||||
FOR_ALL_LINK_GRAPHS(lg) lg->ShiftDates(-days_this_year);
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
|
||||
* all of them if the date is set back, else those messages will hang for ever */
|
||||
NetworkInitChatMessage();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
|
||||
if (_settings_client.gui.auto_euro) CheckSwitchToEuro();
|
||||
@@ -244,9 +240,7 @@ static void OnNewMonth()
|
||||
IndustryMonthlyLoop();
|
||||
SubsidyMonthlyLoop();
|
||||
StationMonthlyLoop();
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (_network_server) NetworkServerMonthlyLoop();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,9 +248,7 @@ static void OnNewMonth()
|
||||
*/
|
||||
static void OnNewDay()
|
||||
{
|
||||
#ifdef ENABLE_NETWORK
|
||||
if (_network_server) NetworkServerDailyLoop();
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
DisasterDailyLoop();
|
||||
IndustryDailyLoop();
|
||||
|
@@ -55,7 +55,7 @@ struct SetDateWindow : Window {
|
||||
this->date.year = Clamp(this->date.year, min_year, max_year);
|
||||
}
|
||||
|
||||
virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
|
||||
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
|
||||
{
|
||||
Point pt = { this->parent->left + this->parent->width / 2 - sm_width / 2, this->parent->top + this->parent->height / 2 - sm_height / 2 };
|
||||
return pt;
|
||||
@@ -75,14 +75,14 @@ struct SetDateWindow : Window {
|
||||
|
||||
case WID_SD_DAY:
|
||||
for (uint i = 0; i < 31; i++) {
|
||||
*list->Append() = new DropDownListStringItem(STR_DAY_NUMBER_1ST + i, i + 1, false);
|
||||
list->push_back(new DropDownListStringItem(STR_DAY_NUMBER_1ST + i, i + 1, false));
|
||||
}
|
||||
selected = this->date.day;
|
||||
break;
|
||||
|
||||
case WID_SD_MONTH:
|
||||
for (uint i = 0; i < 12; i++) {
|
||||
*list->Append() = new DropDownListStringItem(STR_MONTH_JAN + i, i, false);
|
||||
list->push_back(new DropDownListStringItem(STR_MONTH_JAN + i, i, false));
|
||||
}
|
||||
selected = this->date.month;
|
||||
break;
|
||||
@@ -91,7 +91,7 @@ struct SetDateWindow : Window {
|
||||
for (Year i = this->min_year; i <= this->max_year; i++) {
|
||||
DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false);
|
||||
item->SetParam(0, i);
|
||||
*list->Append() = item;
|
||||
list->push_back(item);
|
||||
}
|
||||
selected = this->date.year;
|
||||
break;
|
||||
@@ -100,7 +100,7 @@ struct SetDateWindow : Window {
|
||||
ShowDropDownList(this, list, selected, widget);
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
Dimension d = {0, 0};
|
||||
switch (widget) {
|
||||
@@ -129,7 +129,7 @@ struct SetDateWindow : Window {
|
||||
*size = d;
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SD_DAY: SetDParam(0, this->date.day - 1 + STR_DAY_NUMBER_1ST); break;
|
||||
@@ -138,7 +138,7 @@ struct SetDateWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SD_DAY:
|
||||
@@ -154,7 +154,7 @@ struct SetDateWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnDropdownSelect(int widget, int index)
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SD_DAY:
|
||||
|
@@ -17,16 +17,14 @@
|
||||
#include "fileio_func.h"
|
||||
#include "settings_type.h"
|
||||
|
||||
#if defined(WIN32) || defined(WIN64)
|
||||
#if defined(_WIN32)
|
||||
#include "os/windows/win32.h"
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if defined(ENABLE_NETWORK)
|
||||
#include "network/network_admin.h"
|
||||
SOCKET _debug_socket = INVALID_SOCKET;
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -111,7 +109,6 @@ char *DumpDebugFacilityNames(char *buf, char *last)
|
||||
*/
|
||||
static void debug_print(const char *dbg, const char *buf)
|
||||
{
|
||||
#if defined(ENABLE_NETWORK)
|
||||
if (_debug_socket != INVALID_SOCKET) {
|
||||
char buf2[1024 + 32];
|
||||
|
||||
@@ -121,7 +118,6 @@ static void debug_print(const char *dbg, const char *buf)
|
||||
send(_debug_socket, buf2, (int)strlen(buf2), 0);
|
||||
return;
|
||||
}
|
||||
#endif /* ENABLE_NETWORK */
|
||||
if (strcmp(dbg, "desync") == 0) {
|
||||
static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
|
||||
if (f == NULL) return;
|
||||
@@ -139,16 +135,14 @@ static void debug_print(const char *dbg, const char *buf)
|
||||
} else {
|
||||
char buffer[512];
|
||||
seprintf(buffer, lastof(buffer), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf);
|
||||
#if defined(WIN32) || defined(WIN64)
|
||||
#if defined(_WIN32)
|
||||
TCHAR system_buf[512];
|
||||
convert_to_fs(buffer, system_buf, lengthof(system_buf), true);
|
||||
_fputts(system_buf, stderr);
|
||||
#else
|
||||
fputs(buffer, stderr);
|
||||
#endif
|
||||
#ifdef ENABLE_NETWORK
|
||||
NetworkAdminConsole(dbg, buf);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
IConsoleDebug(dbg, buf);
|
||||
}
|
||||
}
|
||||
|
34
src/debug.h
34
src/debug.h
@@ -13,6 +13,7 @@
|
||||
#define DEBUG_H
|
||||
|
||||
#include "cpu.h"
|
||||
#include <chrono>
|
||||
|
||||
/* Debugging messages policy:
|
||||
* These should be the severities used for direct DEBUG() calls
|
||||
@@ -83,21 +84,40 @@ const char *GetDebugString();
|
||||
*
|
||||
* TIC() / TOC() creates its own block, so make sure not the mangle
|
||||
* it with another block.
|
||||
*
|
||||
* The output is counted in CPU cycles, and not comparable accross
|
||||
* machines. Mainly useful for local optimisations.
|
||||
**/
|
||||
#define TIC() {\
|
||||
uint64 _xxx_ = ottd_rdtsc();\
|
||||
static uint64 __sum__ = 0;\
|
||||
static uint32 __i__ = 0;
|
||||
static uint64 _sum_ = 0;\
|
||||
static uint32 _i_ = 0;
|
||||
|
||||
#define TOC(str, count)\
|
||||
__sum__ += ottd_rdtsc() - _xxx_;\
|
||||
if (++__i__ == count) {\
|
||||
DEBUG(misc, 0, "[%s] " OTTD_PRINTF64 " [avg: %.1f]", str, __sum__, __sum__/(double)__i__);\
|
||||
__i__ = 0;\
|
||||
__sum__ = 0;\
|
||||
_sum_ += ottd_rdtsc() - _xxx_;\
|
||||
if (++_i_ == count) {\
|
||||
DEBUG(misc, 0, "[%s] " OTTD_PRINTF64 " [avg: %.1f]", str, _sum_, _sum_/(double)_i_);\
|
||||
_i_ = 0;\
|
||||
_sum_ = 0;\
|
||||
}\
|
||||
}
|
||||
|
||||
/* Chrono based version. The output is in microseconds. */
|
||||
#define TICC() {\
|
||||
auto _start_ = std::chrono::high_resolution_clock::now();\
|
||||
static uint64 _sum_ = 0;\
|
||||
static uint32 _i_ = 0;
|
||||
|
||||
#define TOCC(str, _count_)\
|
||||
_sum_ += (std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - _start_)).count();\
|
||||
if (++_i_ == _count_) {\
|
||||
DEBUG(misc, 0, "[%s] " OTTD_PRINTF64 " us [avg: %.1f us]", str, _sum_, _sum_/(double)_i_);\
|
||||
_i_ = 0;\
|
||||
_sum_ = 0;\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
void ShowInfo(const char *str);
|
||||
void CDECL ShowInfoF(const char *str, ...) WARN_FORMAT(1, 2);
|
||||
|
||||
|
@@ -11,21 +11,18 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifdef ENABLE_NETWORK
|
||||
|
||||
char *_log_file = NULL; ///< File to reroute output of a forked OpenTTD to
|
||||
FILE *_log_fd = NULL; ///< File to reroute output of a forked OpenTTD to
|
||||
|
||||
#if defined(UNIX) && !defined(__MORPHOS__)
|
||||
#if defined(UNIX)
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
#if (defined(SUNOS) && !defined(_LP64) && !defined(_I32LPx)) || defined(__HAIKU__)
|
||||
#if defined(SUNOS) && !defined(_LP64) && !defined(_I32LPx)
|
||||
/* Solaris has, in certain situation, pid_t defined as long, while in other
|
||||
* cases it has it defined as int... this handles all cases nicely.
|
||||
* Haiku has also defined pid_t as a long.
|
||||
*/
|
||||
# define PRINTF_PID_T "%ld"
|
||||
#else
|
||||
@@ -68,10 +65,3 @@ void DedicatedFork()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/** Empty helper function call for NOT(UNIX and not MORPHOS) systems */
|
||||
void DedicatedFork() {}
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
@@ -217,22 +217,22 @@ enum Token {
|
||||
TOKEN_LOCAL, ///< Read a local include
|
||||
TOKEN_GLOBAL, ///< Read a global include
|
||||
TOKEN_IDENTIFIER, ///< Identifier within the data.
|
||||
TOKEN_DEFINE, ///< (#)define in code
|
||||
TOKEN_IF, ///< (#)if in code
|
||||
TOKEN_IFDEF, ///< (#)ifdef in code
|
||||
TOKEN_IFNDEF, ///< (#)ifndef in code
|
||||
TOKEN_ELIF, ///< (#)elif in code
|
||||
TOKEN_ELSE, ///< (#)else in code
|
||||
TOKEN_ENDIF, ///< (#)endif in code
|
||||
TOKEN_UNDEF, ///< (#)undef in code
|
||||
TOKEN_OR, ///< '||' within <tt>#if</tt> expression
|
||||
TOKEN_AND, ///< '&&' within <tt>#if</tt> expression
|
||||
TOKEN_DEFINED, ///< 'defined' within <tt>#if</tt> expression
|
||||
TOKEN_OPEN, ///< '(' within <tt>#if</tt> expression
|
||||
TOKEN_CLOSE, ///< ')' within <tt>#if</tt> expression
|
||||
TOKEN_NOT, ///< '!' within <tt>#if</tt> expression
|
||||
TOKEN_ZERO, ///< '0' within <tt>#if</tt> expression
|
||||
TOKEN_INCLUDE, ///< (#)include in code
|
||||
TOKEN_DEFINE, ///< \c \#define in code
|
||||
TOKEN_IF, ///< \c \#if in code
|
||||
TOKEN_IFDEF, ///< \c \#ifdef in code
|
||||
TOKEN_IFNDEF, ///< \c \#ifndef in code
|
||||
TOKEN_ELIF, ///< \c \#elif in code
|
||||
TOKEN_ELSE, ///< \c \#else in code
|
||||
TOKEN_ENDIF, ///< \c \#endif in code
|
||||
TOKEN_UNDEF, ///< \c \#undef in code
|
||||
TOKEN_OR, ///< '||' within \c \#if expression
|
||||
TOKEN_AND, ///< '&&' within \c \#if expression
|
||||
TOKEN_DEFINED, ///< 'defined' within \c \#if expression
|
||||
TOKEN_OPEN, ///< '(' within \c \#if expression
|
||||
TOKEN_CLOSE, ///< ')' within \c \#if expression
|
||||
TOKEN_NOT, ///< '!' within \c \#if expression
|
||||
TOKEN_ZERO, ///< '0' within \c \#if expression
|
||||
TOKEN_INCLUDE, ///< \c \#include in code
|
||||
};
|
||||
|
||||
/** Mapping from a C-style keyword representation to a Token. */
|
||||
@@ -681,8 +681,8 @@ bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose)
|
||||
/** Enumerator to tell how long to ignore 'stuff'. */
|
||||
enum Ignore {
|
||||
NOT_IGNORE, ///< No ignoring.
|
||||
IGNORE_UNTIL_ELSE, ///< Ignore till a #else is reached.
|
||||
IGNORE_UNTIL_ENDIF, ///< Ignore till a #endif is reached.
|
||||
IGNORE_UNTIL_ELSE, ///< Ignore till a \c \#else is reached.
|
||||
IGNORE_UNTIL_ENDIF, ///< Ignore till a \c \#endif is reached.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1008,7 +1008,7 @@ int main(int argc, char *argv[])
|
||||
fclose(src);
|
||||
|
||||
/* Then append it to the real file. */
|
||||
src = fopen(backup, "rb");
|
||||
src = fopen(backup, "r");
|
||||
while (fgets(content, size, src) != NULL) {
|
||||
fputs(content, dst);
|
||||
if (!strncmp(content, delimiter, strlen(delimiter))) found_delimiter = true;
|
||||
|
@@ -364,7 +364,7 @@ struct DepotWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
if (widget != WID_D_MATRIX) return;
|
||||
|
||||
@@ -398,7 +398,7 @@ struct DepotWindow : Window {
|
||||
uint16 rows_in_display = wid->current_y / wid->resize_y;
|
||||
|
||||
uint16 num = this->vscroll->GetPosition() * this->num_columns;
|
||||
int maxval = min(this->vehicle_list.Length(), num + (rows_in_display * this->num_columns));
|
||||
int maxval = min((uint)this->vehicle_list.size(), num + (rows_in_display * this->num_columns));
|
||||
int y;
|
||||
for (y = r.top + 1; num < maxval; y += this->resize.step_height) { // Draw the rows
|
||||
for (byte i = 0; i < this->num_columns && num < maxval; i++, num++) {
|
||||
@@ -413,16 +413,16 @@ struct DepotWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
maxval = min(this->vehicle_list.Length() + this->wagon_list.Length(), (this->vscroll->GetPosition() * this->num_columns) + (rows_in_display * this->num_columns));
|
||||
maxval = min((uint)this->vehicle_list.size() + (uint)this->wagon_list.size(), (this->vscroll->GetPosition() * this->num_columns) + (rows_in_display * this->num_columns));
|
||||
|
||||
/* Draw the train wagons without an engine in front. */
|
||||
for (; num < maxval; num++, y += this->resize.step_height) {
|
||||
const Vehicle *v = this->wagon_list[num - this->vehicle_list.Length()];
|
||||
const Vehicle *v = this->wagon_list[num - this->vehicle_list.size()];
|
||||
this->DrawVehicleInDepot(v, r.left, r.right, y);
|
||||
}
|
||||
}
|
||||
|
||||
void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
if (widget != WID_D_CAPTION) return;
|
||||
|
||||
@@ -465,7 +465,7 @@ struct DepotWindow : Window {
|
||||
|
||||
uint pos = ((row + this->vscroll->GetPosition()) * this->num_columns) + xt;
|
||||
|
||||
if (this->vehicle_list.Length() + this->wagon_list.Length() <= pos) {
|
||||
if (this->vehicle_list.size() + this->wagon_list.size() <= pos) {
|
||||
/* Clicking on 'line' / 'block' without a vehicle */
|
||||
if (this->type == VEH_TRAIN) {
|
||||
/* End the dragging */
|
||||
@@ -478,12 +478,12 @@ struct DepotWindow : Window {
|
||||
}
|
||||
|
||||
bool wagon = false;
|
||||
if (this->vehicle_list.Length() > pos) {
|
||||
if (this->vehicle_list.size() > pos) {
|
||||
*veh = this->vehicle_list[pos];
|
||||
/* Skip vehicles that are scrolled off the list */
|
||||
if (this->type == VEH_TRAIN) x += this->hscroll->GetPosition();
|
||||
} else {
|
||||
pos -= this->vehicle_list.Length();
|
||||
pos -= (uint)this->vehicle_list.size();
|
||||
*veh = this->wagon_list[pos];
|
||||
/* free wagons don't have an initial loco. */
|
||||
x -= ScaleGUITrad(VEHICLEINFO_FULL_VEHICLE_WIDTH);
|
||||
@@ -650,7 +650,7 @@ struct DepotWindow : Window {
|
||||
uint flag_width;
|
||||
uint flag_height;
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_D_MATRIX: {
|
||||
@@ -701,12 +701,12 @@ struct DepotWindow : Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
this->generate_list = true;
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
if (this->generate_list) {
|
||||
/* Generate the vehicle list
|
||||
@@ -726,7 +726,7 @@ struct DepotWindow : Window {
|
||||
/* determine amount of items for scroller */
|
||||
if (this->type == VEH_TRAIN) {
|
||||
uint max_width = ScaleGUITrad(VEHICLEINFO_FULL_VEHICLE_WIDTH);
|
||||
for (uint num = 0; num < this->vehicle_list.Length(); num++) {
|
||||
for (uint num = 0; num < this->vehicle_list.size(); num++) {
|
||||
uint width = 0;
|
||||
for (const Train *v = Train::From(this->vehicle_list[num]); v != NULL; v = v->Next()) {
|
||||
width += v->GetDisplayImageWidth();
|
||||
@@ -734,11 +734,11 @@ struct DepotWindow : Window {
|
||||
max_width = max(max_width, width);
|
||||
}
|
||||
/* Always have 1 empty row, so people can change the setting of the train */
|
||||
this->vscroll->SetCount(this->vehicle_list.Length() + this->wagon_list.Length() + 1);
|
||||
this->vscroll->SetCount((uint)this->vehicle_list.size() + (uint)this->wagon_list.size() + 1);
|
||||
/* Always make it longer than the longest train, so you can attach vehicles at the end, and also see the next vertical tile separator line */
|
||||
this->hscroll->SetCount(max_width + ScaleGUITrad(2 * VEHICLEINFO_FULL_VEHICLE_WIDTH + 1));
|
||||
} else {
|
||||
this->vscroll->SetCount(CeilDiv(this->vehicle_list.Length(), this->num_columns));
|
||||
this->vscroll->SetCount(CeilDiv((uint)this->vehicle_list.size(), this->num_columns));
|
||||
}
|
||||
|
||||
/* Setup disabled buttons. */
|
||||
@@ -758,7 +758,7 @@ struct DepotWindow : Window {
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_D_MATRIX: { // List
|
||||
@@ -811,7 +811,7 @@ struct DepotWindow : Window {
|
||||
|
||||
case WID_D_SELL_ALL:
|
||||
/* Only open the confirmation window if there are anything to sell */
|
||||
if (this->vehicle_list.Length() != 0 || this->wagon_list.Length() != 0) {
|
||||
if (this->vehicle_list.size() != 0 || this->wagon_list.size() != 0) {
|
||||
TileIndex tile = this->window_number;
|
||||
byte vehtype = this->type;
|
||||
|
||||
@@ -837,7 +837,7 @@ struct DepotWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnQueryTextFinished(char *str)
|
||||
void OnQueryTextFinished(char *str) override
|
||||
{
|
||||
if (str == NULL) return;
|
||||
|
||||
@@ -845,7 +845,7 @@ struct DepotWindow : Window {
|
||||
DoCommandP(0, GetDepotIndex(this->window_number), 0, CMD_RENAME_DEPOT | CMD_MSG(STR_ERROR_CAN_T_RENAME_DEPOT), NULL, str);
|
||||
}
|
||||
|
||||
virtual bool OnRightClick(Point pt, int widget)
|
||||
bool OnRightClick(Point pt, int widget) override
|
||||
{
|
||||
if (widget != WID_D_MATRIX) return false;
|
||||
|
||||
@@ -906,15 +906,22 @@ struct DepotWindow : Window {
|
||||
* @param v the original vehicle to clone
|
||||
* @return Always true.
|
||||
*/
|
||||
virtual bool OnVehicleSelect(const Vehicle *v)
|
||||
bool OnVehicleSelect(const Vehicle *v) override
|
||||
{
|
||||
if (DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), CcCloneVehicle)) {
|
||||
ResetObjectToPlace();
|
||||
if (_ctrl_pressed) {
|
||||
/* Share-clone, do not open new viewport, and keep tool active */
|
||||
DoCommandP(this->window_number, v->index, 1, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), NULL);
|
||||
} else {
|
||||
/* Copy-clone, open viewport for new vehicle, and deselect the tool (assume player wants to changs things on new vehicle) */
|
||||
if (DoCommandP(this->window_number, v->index, 0, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), CcCloneVehicle)) {
|
||||
ResetObjectToPlace();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void OnPlaceObjectAbort()
|
||||
void OnPlaceObjectAbort() override
|
||||
{
|
||||
/* abort clone */
|
||||
this->RaiseWidget(WID_D_CLONE);
|
||||
@@ -932,7 +939,7 @@ struct DepotWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnMouseDrag(Point pt, int widget)
|
||||
void OnMouseDrag(Point pt, int widget) override
|
||||
{
|
||||
if (this->sel == INVALID_VEHICLE) return;
|
||||
if (widget != this->hovered_widget) {
|
||||
@@ -984,7 +991,7 @@ struct DepotWindow : Window {
|
||||
this->SetWidgetDirty(widget);
|
||||
}
|
||||
|
||||
virtual void OnDragDrop(Point pt, int widget)
|
||||
void OnDragDrop(Point pt, int widget) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_D_MATRIX: {
|
||||
@@ -1039,7 +1046,7 @@ struct DepotWindow : Window {
|
||||
_cursor.vehchain = false;
|
||||
}
|
||||
|
||||
virtual void OnTimeout()
|
||||
void OnTimeout() override
|
||||
{
|
||||
if (!this->IsWidgetDisabled(WID_D_SELL)) {
|
||||
this->RaiseWidget(WID_D_SELL);
|
||||
@@ -1051,7 +1058,7 @@ struct DepotWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_D_MATRIX);
|
||||
NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_D_MATRIX);
|
||||
@@ -1062,7 +1069,7 @@ struct DepotWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual EventState OnCTRLStateChange()
|
||||
EventState OnCTRLStateChange() override
|
||||
{
|
||||
if (this->sel != INVALID_VEHICLE) {
|
||||
_cursor.vehchain = _ctrl_pressed;
|
||||
|
@@ -56,8 +56,8 @@ void CcPlaySound_SPLAT_WATER(const CommandCost &result, TileIndex tile, uint32 p
|
||||
|
||||
/**
|
||||
* Gets the other end of the aqueduct, if possible.
|
||||
* @param tile_from The begin tile for the aqueduct.
|
||||
* @param [out] tile_to The tile till where to show a selection for the aqueduct.
|
||||
* @param tile_from The begin tile for the aqueduct.
|
||||
* @param[out] tile_to The tile till where to show a selection for the aqueduct.
|
||||
* @return The other end of the aqueduct, or otherwise a tile in line with the aqueduct to cause the right error message.
|
||||
*/
|
||||
static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = NULL)
|
||||
@@ -113,7 +113,7 @@ struct BuildDocksToolbarWindow : Window {
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
|
||||
@@ -129,7 +129,7 @@ struct BuildDocksToolbarWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_DT_CANAL: // Build canal button
|
||||
@@ -173,7 +173,7 @@ struct BuildDocksToolbarWindow : Window {
|
||||
this->last_clicked_widget = (DockToolbarWidgets)widget;
|
||||
}
|
||||
|
||||
virtual void OnPlaceObject(Point pt, TileIndex tile)
|
||||
void OnPlaceObject(Point pt, TileIndex tile) override
|
||||
{
|
||||
switch (this->last_clicked_widget) {
|
||||
case WID_DT_CANAL: // Build canal button
|
||||
@@ -222,12 +222,12 @@ struct BuildDocksToolbarWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
|
||||
void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override
|
||||
{
|
||||
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
|
||||
}
|
||||
|
||||
virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
|
||||
void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override
|
||||
{
|
||||
if (pt.x != -1) {
|
||||
switch (select_proc) {
|
||||
@@ -246,7 +246,7 @@ struct BuildDocksToolbarWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPlaceObjectAbort()
|
||||
void OnPlaceObjectAbort() override
|
||||
{
|
||||
this->RaiseButtons();
|
||||
|
||||
@@ -256,7 +256,7 @@ struct BuildDocksToolbarWindow : Window {
|
||||
DeleteWindowByClass(WC_BUILD_BRIDGE);
|
||||
}
|
||||
|
||||
virtual void OnPlacePresize(Point pt, TileIndex tile_from)
|
||||
void OnPlacePresize(Point pt, TileIndex tile_from) override
|
||||
{
|
||||
TileIndex tile_to = tile_from;
|
||||
|
||||
@@ -410,7 +410,7 @@ public:
|
||||
DeleteWindowById(WC_SELECT_STATION, 0);
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
int rad = (_settings_game.station.modified_catchment) ? CA_DOCK : CA_UNMODIFIED;
|
||||
|
||||
@@ -437,7 +437,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case BDSW_LT_OFF:
|
||||
@@ -451,7 +451,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnTick()
|
||||
void OnRealtimeTick(uint delta_ms) override
|
||||
{
|
||||
CheckRedrawStationCoverage(this);
|
||||
}
|
||||
@@ -505,7 +505,7 @@ public:
|
||||
UpdateDocksDirection();
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BDD_X:
|
||||
@@ -516,7 +516,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
this->DrawWidgets();
|
||||
|
||||
@@ -531,7 +531,7 @@ public:
|
||||
DrawShipDepotSprite(this->GetWidget<NWidgetBase>(WID_BDD_Y)->pos_x + x1, this->GetWidget<NWidgetBase>(WID_BDD_Y)->pos_y + y2, AXIS_Y, DEPOT_PART_SOUTH);
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_BDD_X:
|
||||
|
@@ -77,7 +77,7 @@ static inline int32 BigMulS(const int32 a, const int32 b, const uint8 shift)
|
||||
return (int32)((int64)a * (int64)b >> shift);
|
||||
}
|
||||
|
||||
typedef SmallVector<Industry *, 16> SmallIndustryList;
|
||||
typedef std::vector<Industry *> SmallIndustryList;
|
||||
|
||||
/**
|
||||
* Score info, values used for computing the detailed performance rating.
|
||||
@@ -95,7 +95,7 @@ const ScoreInfo _score_info[] = {
|
||||
{ 0, 0} // SCORE_TOTAL
|
||||
};
|
||||
|
||||
int _score_part[MAX_COMPANIES][SCORE_END];
|
||||
int64 _score_part[MAX_COMPANIES][SCORE_END];
|
||||
Economy _economy;
|
||||
Prices _price;
|
||||
Money _additional_cash_required;
|
||||
@@ -183,7 +183,7 @@ int UpdateCompanyRatingAndValue(Company *c, bool update)
|
||||
_score_part[owner][SCORE_VEHICLES] = num;
|
||||
/* Don't allow negative min_profit to show */
|
||||
if (min_profit > 0) {
|
||||
_score_part[owner][SCORE_MIN_PROFIT] = ClampToI32(min_profit);
|
||||
_score_part[owner][SCORE_MIN_PROFIT] = min_profit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,10 +213,10 @@ int UpdateCompanyRatingAndValue(Company *c, bool update)
|
||||
} while (++cee, --numec);
|
||||
|
||||
if (min_income > 0) {
|
||||
_score_part[owner][SCORE_MIN_INCOME] = ClampToI32(min_income);
|
||||
_score_part[owner][SCORE_MIN_INCOME] = min_income;
|
||||
}
|
||||
|
||||
_score_part[owner][SCORE_MAX_INCOME] = ClampToI32(max_income);
|
||||
_score_part[owner][SCORE_MAX_INCOME] = max_income;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ int UpdateCompanyRatingAndValue(Company *c, bool update)
|
||||
total_delivered += cee->delivered_cargo.GetSum<OverflowSafeInt64>();
|
||||
} while (++cee, --numec);
|
||||
|
||||
_score_part[owner][SCORE_DELIVERED] = ClampToI32(total_delivered);
|
||||
_score_part[owner][SCORE_DELIVERED] = total_delivered;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,13 +242,13 @@ int UpdateCompanyRatingAndValue(Company *c, bool update)
|
||||
/* Generate score for company's money */
|
||||
{
|
||||
if (c->money > 0) {
|
||||
_score_part[owner][SCORE_MONEY] = ClampToI32(c->money);
|
||||
_score_part[owner][SCORE_MONEY] = c->money;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate score for loan */
|
||||
{
|
||||
_score_part[owner][SCORE_LOAN] = ClampToI32(_score_info[SCORE_LOAN].needed - c->current_loan);
|
||||
_score_part[owner][SCORE_LOAN] = _score_info[SCORE_LOAN].needed - c->current_loan;
|
||||
}
|
||||
|
||||
/* Now we calculate the score for each item.. */
|
||||
@@ -260,7 +260,7 @@ int UpdateCompanyRatingAndValue(Company *c, bool update)
|
||||
/* Skip the total */
|
||||
if (i == SCORE_TOTAL) continue;
|
||||
/* Check the score */
|
||||
s = Clamp(_score_part[owner][i], 0, _score_info[i].needed) * _score_info[i].score / _score_info[i].needed;
|
||||
s = Clamp<int64>(_score_part[owner][i], 0, _score_info[i].needed) * _score_info[i].score / _score_info[i].needed;
|
||||
score += s;
|
||||
total_score += _score_info[i].score;
|
||||
}
|
||||
@@ -292,10 +292,8 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
|
||||
* the client. This is needed as it needs to know whether "you" really
|
||||
* are the current local company. */
|
||||
Backup<CompanyByte> cur_company(_current_company, old_owner, FILE_LINE);
|
||||
#ifdef ENABLE_NETWORK
|
||||
/* In all cases, make spectators of clients connected to that company */
|
||||
if (_networking) NetworkClientsToSpectators(old_owner);
|
||||
#endif /* ENABLE_NETWORK */
|
||||
if (old_owner == _local_company) {
|
||||
/* Single player cheated to AI company.
|
||||
* There are no spectators in single player, so we must pick some other company. */
|
||||
@@ -642,7 +640,7 @@ static void CompanyCheckBankrupt(Company *c)
|
||||
* that changing the current company is okay. In case of single
|
||||
* player we are sure (the above check) that we are not the local
|
||||
* company and thus we won't be moved. */
|
||||
if (!_networking || _network_server) DoCommandP(0, 2 | (c->index << 16), CRR_BANKRUPT, CMD_COMPANY_CTRL);
|
||||
if (!_networking || _network_server) DoCommandP(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, CMD_COMPANY_CTRL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1030,9 +1028,10 @@ static SmallIndustryList _cargo_delivery_destinations;
|
||||
* @param cargo_type Type of cargo delivered
|
||||
* @param num_pieces Amount of cargo delivered
|
||||
* @param source The source of the cargo
|
||||
* @param company The company delivering the cargo
|
||||
* @return actually accepted pieces of cargo
|
||||
*/
|
||||
static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint num_pieces, IndustryID source)
|
||||
static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint num_pieces, IndustryID source, CompanyID company)
|
||||
{
|
||||
/* Find the nearest industrytile to the station sign inside the catchment area, whose industry accepts the cargo.
|
||||
* This fails in three cases:
|
||||
@@ -1043,8 +1042,9 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n
|
||||
|
||||
uint accepted = 0;
|
||||
|
||||
for (uint i = 0; i < st->industries_near.Length() && num_pieces != 0; i++) {
|
||||
Industry *ind = st->industries_near[i];
|
||||
for (Industry *ind : st->industries_near) {
|
||||
if (num_pieces == 0) break;
|
||||
|
||||
if (ind->index == source) continue;
|
||||
|
||||
uint cargo_index;
|
||||
@@ -1058,12 +1058,16 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n
|
||||
if (IndustryTemporarilyRefusesCargo(ind, cargo_type)) continue;
|
||||
|
||||
/* Insert the industry into _cargo_delivery_destinations, if not yet contained */
|
||||
_cargo_delivery_destinations.Include(ind);
|
||||
include(_cargo_delivery_destinations, ind);
|
||||
|
||||
uint amount = min(num_pieces, 0xFFFFU - ind->incoming_cargo_waiting[cargo_index]);
|
||||
ind->incoming_cargo_waiting[cargo_index] += amount;
|
||||
ind->last_cargo_accepted_at[cargo_index] = _date;
|
||||
num_pieces -= amount;
|
||||
accepted += amount;
|
||||
|
||||
/* Update the cargo monitor. */
|
||||
AddCargoDelivery(cargo_type, company, amount, ST_INDUSTRY, source, st, ind->index);
|
||||
}
|
||||
|
||||
return accepted;
|
||||
@@ -1089,30 +1093,30 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, Ti
|
||||
Station *st = Station::Get(dest);
|
||||
|
||||
/* Give the goods to the industry. */
|
||||
uint accepted = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src_type == ST_INDUSTRY ? src : INVALID_INDUSTRY);
|
||||
uint accepted_ind = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src_type == ST_INDUSTRY ? src : INVALID_INDUSTRY, company->index);
|
||||
|
||||
/* If this cargo type is always accepted, accept all */
|
||||
if (HasBit(st->always_accepted, cargo_type)) accepted = num_pieces;
|
||||
uint accepted_total = HasBit(st->always_accepted, cargo_type) ? num_pieces : accepted_ind;
|
||||
|
||||
/* Update station statistics */
|
||||
if (accepted > 0) {
|
||||
if (accepted_total > 0) {
|
||||
SetBit(st->goods[cargo_type].status, GoodsEntry::GES_EVER_ACCEPTED);
|
||||
SetBit(st->goods[cargo_type].status, GoodsEntry::GES_CURRENT_MONTH);
|
||||
SetBit(st->goods[cargo_type].status, GoodsEntry::GES_ACCEPTED_BIGTICK);
|
||||
}
|
||||
|
||||
/* Update company statistics */
|
||||
company->cur_economy.delivered_cargo[cargo_type] += accepted;
|
||||
company->cur_economy.delivered_cargo[cargo_type] += accepted_total;
|
||||
|
||||
/* Increase town's counter for town effects */
|
||||
const CargoSpec *cs = CargoSpec::Get(cargo_type);
|
||||
st->town->received[cs->town_effect].new_act += accepted;
|
||||
st->town->received[cs->town_effect].new_act += accepted_total;
|
||||
|
||||
/* Determine profit */
|
||||
Money profit = GetTransportedGoodsIncome(accepted, DistanceManhattan(source_tile, st->xy), days_in_transit, cargo_type);
|
||||
Money profit = GetTransportedGoodsIncome(accepted_total, DistanceManhattan(source_tile, st->xy), days_in_transit, cargo_type);
|
||||
|
||||
/* Update the cargo monitor. */
|
||||
AddCargoDelivery(cargo_type, company->index, accepted, src_type, src, st);
|
||||
AddCargoDelivery(cargo_type, company->index, accepted_total - accepted_ind, src_type, src, st);
|
||||
|
||||
/* Modify profit if a subsidy is in effect */
|
||||
if (CheckSubsidised(cargo_type, company->index, src_type, src, st)) {
|
||||
@@ -1138,7 +1142,6 @@ static void TriggerIndustryProduction(Industry *i)
|
||||
uint16 callback = indspec->callback_mask;
|
||||
|
||||
i->was_cargo_delivered = true;
|
||||
i->last_cargo_accepted_at = _date;
|
||||
|
||||
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
|
||||
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
|
||||
@@ -1147,14 +1150,15 @@ static void TriggerIndustryProduction(Industry *i)
|
||||
SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
|
||||
}
|
||||
} else {
|
||||
for (uint cargo_index = 0; cargo_index < lengthof(i->incoming_cargo_waiting); cargo_index++) {
|
||||
uint cargo_waiting = i->incoming_cargo_waiting[cargo_index];
|
||||
for (uint ci_in = 0; ci_in < lengthof(i->incoming_cargo_waiting); ci_in++) {
|
||||
uint cargo_waiting = i->incoming_cargo_waiting[ci_in];
|
||||
if (cargo_waiting == 0) continue;
|
||||
|
||||
i->produced_cargo_waiting[0] = min(i->produced_cargo_waiting[0] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][0] / 256), 0xFFFF);
|
||||
i->produced_cargo_waiting[1] = min(i->produced_cargo_waiting[1] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][1] / 256), 0xFFFF);
|
||||
for (uint ci_out = 0; ci_out < lengthof(i->produced_cargo_waiting); ci_out++) {
|
||||
i->produced_cargo_waiting[ci_out] = min(i->produced_cargo_waiting[ci_out] + (cargo_waiting * indspec->input_cargo_multiplier[ci_in][ci_out] / 256), 0xFFFF);
|
||||
}
|
||||
|
||||
i->incoming_cargo_waiting[cargo_index] = 0;
|
||||
i->incoming_cargo_waiting[ci_in] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,7 +1246,6 @@ Money CargoPayment::PayTransfer(const CargoPacket *cp, uint count)
|
||||
|
||||
/**
|
||||
* Prepare the vehicle to be unloaded.
|
||||
* @param curr_station the station where the consist is at the moment
|
||||
* @param front_v the vehicle to be unloaded
|
||||
*/
|
||||
void PrepareUnload(Vehicle *front_v)
|
||||
@@ -1484,7 +1487,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
|
||||
if (st->goods[cid].cargo.HasCargoFor(next_station)) {
|
||||
/* Try to find out if auto-refitting would succeed. In case the refit is allowed,
|
||||
* the returned refit capacity will be greater than zero. */
|
||||
DoCommand(v_start->tile, v_start->index, cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts.
|
||||
DoCommand(v_start->tile, v_start->index, cid | 1U << 24 | 0xFF << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts.
|
||||
/* Try to balance different loadable cargoes between parts of the consist, so that
|
||||
* all of them can be loaded. Avoid a situation where all vehicles suddenly switch
|
||||
* to the first loadable cargo for which there is only one packet. If the capacities
|
||||
@@ -1507,7 +1510,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
|
||||
* "via any station" before reserving. We rather produce some more "any station" cargo than
|
||||
* misrouting it. */
|
||||
IterateVehicleParts(v_start, ReturnCargoAction(st, INVALID_STATION));
|
||||
CommandCost cost = DoCommand(v_start->tile, v_start->index, new_cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_EXEC, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts.
|
||||
CommandCost cost = DoCommand(v_start->tile, v_start->index, new_cid | 1U << 24 | 0xFF << 8 | 1U << 16, DC_EXEC, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts.
|
||||
if (cost.Succeeded()) v->First()->profit_this_year -= cost.GetCost() << 8;
|
||||
}
|
||||
|
||||
@@ -1518,6 +1521,17 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
|
||||
cur_company.Restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether a vehicle can load cargo at a station even if exclusive transport rights are present.
|
||||
* @param st Station with cargo waiting to be loaded.
|
||||
* @param v Vehicle loading the cargo.
|
||||
* @return true when a vehicle can load the cargo.
|
||||
*/
|
||||
static bool MayLoadUnderExclusiveRights(const Station *st, const Vehicle *v)
|
||||
{
|
||||
return st->owner != OWNER_NONE || st->town->exclusive_counter == 0 || st->town->exclusivity == v->owner;
|
||||
}
|
||||
|
||||
struct ReserveCargoAction {
|
||||
Station *st;
|
||||
StationIDStack *next_station;
|
||||
@@ -1527,7 +1541,7 @@ struct ReserveCargoAction {
|
||||
|
||||
bool operator()(Vehicle *v)
|
||||
{
|
||||
if (v->cargo_cap > v->cargo.RemainingCount()) {
|
||||
if (v->cargo_cap > v->cargo.RemainingCount() && MayLoadUnderExclusiveRights(st, v)) {
|
||||
st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
|
||||
&v->cargo, st->xy, *next_station);
|
||||
}
|
||||
@@ -1751,7 +1765,7 @@ static void LoadUnloadVehicle(Vehicle *front)
|
||||
/* If there's goods waiting at the station, and the vehicle
|
||||
* has capacity for it, load it on the vehicle. */
|
||||
uint cap_left = v->cargo_cap - v->cargo.StoredCount();
|
||||
if (cap_left > 0 && (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0 || ge->cargo.AvailableCount() > 0)) {
|
||||
if (cap_left > 0 && (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0 || ge->cargo.AvailableCount() > 0) && MayLoadUnderExclusiveRights(st, v)) {
|
||||
if (v->cargo.StoredCount() == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
|
||||
if (_settings_game.order.gradual_loading) cap_left = min(cap_left, GetLoadAmount(v));
|
||||
|
||||
@@ -1931,11 +1945,10 @@ void LoadUnloadStation(Station *st)
|
||||
}
|
||||
|
||||
/* Call the production machinery of industries */
|
||||
const Industry * const *isend = _cargo_delivery_destinations.End();
|
||||
for (Industry **iid = _cargo_delivery_destinations.Begin(); iid != isend; iid++) {
|
||||
TriggerIndustryProduction(*iid);
|
||||
for (Industry *iid : _cargo_delivery_destinations) {
|
||||
TriggerIndustryProduction(iid);
|
||||
}
|
||||
_cargo_delivery_destinations.Clear();
|
||||
_cargo_delivery_destinations.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -22,7 +22,7 @@ void ResetPriceBaseMultipliers();
|
||||
void SetPriceBaseMultiplier(Price price, int factor);
|
||||
|
||||
extern const ScoreInfo _score_info[];
|
||||
extern int _score_part[MAX_COMPANIES][SCORE_END];
|
||||
extern int64 _score_part[MAX_COMPANIES][SCORE_END];
|
||||
extern Economy _economy;
|
||||
/* Prices and also the fractional part. */
|
||||
extern Prices _price;
|
||||
|
@@ -431,9 +431,9 @@ uint Engine::GetDisplayMaxTractiveEffort() const
|
||||
/* Only trains and road vehicles have 'tractive effort'. */
|
||||
switch (this->type) {
|
||||
case VEH_TRAIN:
|
||||
return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256;
|
||||
return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256 / 1000;
|
||||
case VEH_ROAD:
|
||||
return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256;
|
||||
return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256 / 1000;
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
@@ -487,14 +487,15 @@ StringID Engine::GetAircraftTypeText() const
|
||||
*/
|
||||
void EngineOverrideManager::ResetToDefaultMapping()
|
||||
{
|
||||
this->Clear();
|
||||
this->clear();
|
||||
for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
|
||||
for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) {
|
||||
EngineIDMapping *eid = this->Append();
|
||||
eid->type = type;
|
||||
eid->grfid = INVALID_GRFID;
|
||||
eid->internal_id = internal_id;
|
||||
eid->substitute_id = internal_id;
|
||||
/*C++17: EngineIDMapping &eid = */ this->emplace_back();
|
||||
EngineIDMapping &eid = this->back();
|
||||
eid.type = type;
|
||||
eid.grfid = INVALID_GRFID;
|
||||
eid.internal_id = internal_id;
|
||||
eid.substitute_id = internal_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -510,12 +511,12 @@ void EngineOverrideManager::ResetToDefaultMapping()
|
||||
*/
|
||||
EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid)
|
||||
{
|
||||
const EngineIDMapping *end = this->End();
|
||||
EngineID index = 0;
|
||||
for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) {
|
||||
if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) {
|
||||
for (const EngineIDMapping &eid : *this) {
|
||||
if (eid.type == type && eid.grfid == grfid && eid.internal_id == grf_local_id) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return INVALID_ENGINE;
|
||||
}
|
||||
@@ -547,15 +548,15 @@ void SetupEngines()
|
||||
DeleteWindowByClass(WC_ENGINE_PREVIEW);
|
||||
_engine_pool.CleanPool();
|
||||
|
||||
assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES);
|
||||
const EngineIDMapping *end = _engine_mngr.End();
|
||||
assert(_engine_mngr.size() >= _engine_mngr.NUM_DEFAULT_ENGINES);
|
||||
uint index = 0;
|
||||
for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) {
|
||||
for (const EngineIDMapping &eid : _engine_mngr) {
|
||||
/* Assert is safe; there won't be more than 256 original vehicles
|
||||
* in any case, and we just cleaned the pool. */
|
||||
assert(Engine::CanAllocateItem());
|
||||
const Engine *e = new Engine(eid->type, eid->internal_id);
|
||||
const Engine *e = new Engine(eid.type, eid.internal_id);
|
||||
assert(e->index == index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,7 +574,7 @@ static bool IsWagon(EngineID index)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update #reliability of engine \a e, (if needed) update the engine GUIs.
|
||||
* Update #Engine::reliability and (if needed) update the engine GUIs.
|
||||
* @param e %Engine to update.
|
||||
*/
|
||||
static void CalcEngineReliability(Engine *e)
|
||||
@@ -652,7 +653,14 @@ void StartupOneEngine(Engine *e, Date aging_date)
|
||||
/* Don't randomise the start-date in the first two years after gamestart to ensure availability
|
||||
* of engines in early starting games.
|
||||
* Note: TTDP uses fixed 1922 */
|
||||
SavedRandomSeeds saved_seeds;
|
||||
SaveRandomSeeds(&saved_seeds);
|
||||
SetRandomSeed(_settings_game.game_creation.generation_seed ^
|
||||
ei->base_intro ^
|
||||
e->type ^
|
||||
e->GetGRFID());
|
||||
uint32 r = Random();
|
||||
|
||||
e->intro_date = ei->base_intro <= ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro;
|
||||
if (e->intro_date <= _date) {
|
||||
e->age = (aging_date - e->intro_date) >> 5;
|
||||
@@ -672,6 +680,7 @@ void StartupOneEngine(Engine *e, Date aging_date)
|
||||
|
||||
e->reliability_spd_dec = ei->decay_speed << 2;
|
||||
|
||||
RestoreRandomSeeds(saved_seeds);
|
||||
CalcEngineReliability(e);
|
||||
|
||||
/* prevent certain engines from ever appearing. */
|
||||
|
@@ -156,7 +156,7 @@ struct EngineIDMapping {
|
||||
* Stores the mapping of EngineID to the internal id of newgrfs.
|
||||
* Note: This is not part of Engine, as the data in the EngineOverrideManager and the engine pool get resetted in different cases.
|
||||
*/
|
||||
struct EngineOverrideManager : SmallVector<EngineIDMapping, 256> {
|
||||
struct EngineOverrideManager : std::vector<EngineIDMapping> {
|
||||
static const uint NUM_DEFAULT_ENGINES; ///< Number of default entries
|
||||
|
||||
void ResetToDefaultMapping();
|
||||
|
@@ -26,7 +26,7 @@ extern const uint8 _engine_offsets[4];
|
||||
|
||||
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company);
|
||||
bool IsEngineRefittable(EngineID engine);
|
||||
void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits);
|
||||
void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint16 cargo_capacity);
|
||||
void SetYearEngineAgingStops();
|
||||
void StartupOneEngine(Engine *e, Date aging_date);
|
||||
|
||||
|
@@ -75,7 +75,7 @@ struct EnginePreviewWindow : Window {
|
||||
this->flags |= WF_STICKY;
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
if (widget != WID_EP_QUESTION) return;
|
||||
|
||||
@@ -102,13 +102,13 @@ struct EnginePreviewWindow : Window {
|
||||
size->height += GetStringHeight(GetEngineInfoString(engine), size->width);
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
if (widget != WID_EP_QUESTION) return;
|
||||
|
||||
EngineID engine = this->window_number;
|
||||
SetDParam(0, GetEngineCategoryName(engine));
|
||||
int y = r.top + GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, r.right - r.top + 1);
|
||||
int y = r.top + GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, r.right - r.left + 1);
|
||||
y = DrawStringMultiLine(r.left, r.right, r.top, y, STR_ENGINE_PREVIEW_MESSAGE, TC_FROMSTRING, SA_CENTER) + WD_PAR_VSEP_WIDE;
|
||||
|
||||
SetDParam(0, engine);
|
||||
@@ -121,7 +121,7 @@ struct EnginePreviewWindow : Window {
|
||||
DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER);
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_EP_YES:
|
||||
@@ -133,7 +133,7 @@ struct EnginePreviewWindow : Window {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
|
||||
@@ -325,11 +325,11 @@ void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID eng
|
||||
*/
|
||||
void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare)
|
||||
{
|
||||
uint size = el->Length();
|
||||
size_t size = el->size();
|
||||
/* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems)
|
||||
* generally, do not sort if there are less than 2 items */
|
||||
if (size < 2) return;
|
||||
QSortT(el->Begin(), size, compare);
|
||||
QSortT(el->data(), size, compare);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -342,8 +342,8 @@ void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare)
|
||||
void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items)
|
||||
{
|
||||
if (num_items < 2) return;
|
||||
assert(begin < el->Length());
|
||||
assert(begin + num_items <= el->Length());
|
||||
QSortT(el->Get(begin), num_items, compare);
|
||||
assert(begin < el->size());
|
||||
assert(begin + num_items <= el->size());
|
||||
QSortT(el->data() + begin, num_items, compare);
|
||||
}
|
||||
|
||||
|
@@ -180,7 +180,7 @@ public:
|
||||
this->InitNested();
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_EM_MESSAGE: {
|
||||
@@ -208,7 +208,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
|
||||
Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
|
||||
{
|
||||
/* Position (0, 0) given, center the window. */
|
||||
if (this->position.x == 0 && this->position.y == 0) {
|
||||
@@ -244,18 +244,18 @@ public:
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
/* If company gets shut down, while displaying an error about it, remove the error message. */
|
||||
if (this->face != INVALID_COMPANY && !Company::IsValidID(this->face)) delete this;
|
||||
}
|
||||
|
||||
virtual void SetStringParameters(int widget) const
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
if (widget == WID_EM_CAPTION) CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_EM_FACE: {
|
||||
@@ -292,13 +292,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnMouseLoop()
|
||||
void OnMouseLoop() override
|
||||
{
|
||||
/* Disallow closing the window too easily, if timeout is disabled */
|
||||
if (_right_button_down && this->duration != 0) delete this;
|
||||
}
|
||||
|
||||
virtual void OnHundredthTick()
|
||||
void OnHundredthTick() override
|
||||
{
|
||||
/* Timeout enabled? */
|
||||
if (this->duration != 0) {
|
||||
@@ -313,7 +313,7 @@ public:
|
||||
if (_window_system_initialized) ShowFirstError();
|
||||
}
|
||||
|
||||
virtual EventState OnKeyPress(WChar key, uint16 keycode)
|
||||
EventState OnKeyPress(WChar key, uint16 keycode) override
|
||||
{
|
||||
if (keycode != WKC_SPACE) return ES_NOT_HANDLED;
|
||||
delete this;
|
||||
@@ -425,7 +425,7 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel
|
||||
/**
|
||||
* Schedule a list of errors.
|
||||
* Note: This does not try to display the error now. This is useful if the window system is not yet running.
|
||||
* @param data Error message datas; cleared afterwards
|
||||
* @param datas Error message datas; cleared afterwards
|
||||
*/
|
||||
void ScheduleErrorMessage(ErrorList &datas)
|
||||
{
|
||||
|
@@ -15,7 +15,7 @@
|
||||
#include "fios.h"
|
||||
#include "string_func.h"
|
||||
#include "tar_type.h"
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
# define access _taccess
|
||||
#elif defined(__HAIKU__)
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef WITH_XDG_BASEDIR
|
||||
#include "basedir.h"
|
||||
#include <basedir.h>
|
||||
#endif
|
||||
|
||||
#include "safeguards.h"
|
||||
@@ -347,7 +347,7 @@ char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory su
|
||||
|
||||
/**
|
||||
* Find a path to the filename in one of the search directories.
|
||||
* @param buf [out] Destination buffer for the path.
|
||||
* @param[out] buf Destination buffer for the path.
|
||||
* @param last End of the destination buffer.
|
||||
* @param subdir Subdirectory to try.
|
||||
* @param filename Filename to look for.
|
||||
@@ -361,7 +361,7 @@ char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const ch
|
||||
FOR_ALL_SEARCHPATHS(sp) {
|
||||
FioGetFullPath(buf, last, sp, subdir, filename);
|
||||
if (FileExists(buf)) return buf;
|
||||
#if !defined(WIN32)
|
||||
#if !defined(_WIN32)
|
||||
/* Be, as opening files, aware that sometimes the filename
|
||||
* might be in uppercase when it is in lowercase on the
|
||||
* disk. Of course Windows doesn't care about casing. */
|
||||
@@ -399,7 +399,7 @@ char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir)
|
||||
|
||||
static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize)
|
||||
{
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
/* fopen is implemented as a define with ellipses for
|
||||
* Unicode support (prepend an L). As we are not sending
|
||||
* a string, but a variable, it 'renames' the variable,
|
||||
@@ -416,12 +416,12 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s
|
||||
seprintf(buf, lastof(buf), "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename);
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
#if defined(_WIN32)
|
||||
if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) return NULL;
|
||||
#endif
|
||||
|
||||
f = fopen(buf, mode);
|
||||
#if !defined(WIN32)
|
||||
#if !defined(_WIN32)
|
||||
if (f == NULL && strtolower(buf + ((subdir == NO_DIRECTORY) ? 0 : strlen(_searchpaths[sp]) - 1))) {
|
||||
f = fopen(buf, mode);
|
||||
}
|
||||
@@ -438,7 +438,7 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s
|
||||
/**
|
||||
* Opens a file from inside a tar archive.
|
||||
* @param entry The entry to open.
|
||||
* @param filesize [out] If not \c NULL, size of the opened file.
|
||||
* @param[out] filesize If not \c NULL, size of the opened file.
|
||||
* @return File handle of the opened file, or \c NULL if the file is not available.
|
||||
* @note The file is read from within the tar file, and may not return \c EOF after reading the whole file.
|
||||
*/
|
||||
@@ -460,7 +460,6 @@ FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize)
|
||||
* Opens a OpenTTD file somewhere in a personal or global directory.
|
||||
* @param filename Name of the file to open.
|
||||
* @param subdir Subdirectory to open.
|
||||
* @param filename Name of the file to open.
|
||||
* @return File handle of the opened file, or \c NULL if the file is not available.
|
||||
*/
|
||||
FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize)
|
||||
@@ -536,20 +535,10 @@ void FioCreateDirectory(const char *name)
|
||||
{
|
||||
/* Ignore directory creation errors; they'll surface later on, and most
|
||||
* of the time they are 'directory already exists' errors anyhow. */
|
||||
#if defined(WIN32)
|
||||
#if defined(_WIN32)
|
||||
CreateDirectory(OTTD2FS(name), NULL);
|
||||
#elif defined(OS2) && !defined(__INNOTEK_LIBC__)
|
||||
mkdir(OTTD2FS(name));
|
||||
#elif defined(__MORPHOS__) || defined(__AMIGAOS__)
|
||||
char buf[MAX_PATH];
|
||||
strecpy(buf, name, lastof(buf));
|
||||
|
||||
size_t len = strlen(name) - 1;
|
||||
if (buf[len] == '/') {
|
||||
buf[len] = '\0'; // Kill pathsep, so mkdir() will not fail
|
||||
}
|
||||
|
||||
mkdir(OTTD2FS(buf), 0755);
|
||||
#else
|
||||
mkdir(OTTD2FS(name), 0755);
|
||||
#endif
|
||||
@@ -632,7 +621,7 @@ static void SimplifyFileName(char *name)
|
||||
|
||||
/**
|
||||
* Perform the scanning of a particular subdirectory.
|
||||
* @param subdir The subdirectory to scan.
|
||||
* @param sd The subdirectory to scan.
|
||||
* @return The number of found tar files.
|
||||
*/
|
||||
uint TarScanner::DoScan(Subdirectory sd)
|
||||
@@ -980,14 +969,14 @@ bool ExtractTar(const char *tar_filename, Subdirectory subdir)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
#if defined(_WIN32)
|
||||
/**
|
||||
* Determine the base (personal dir and game data dir) paths
|
||||
* @param exe the path from the current path to the executable
|
||||
* @note defined in the OS related files (os2.cpp, win32.cpp, unix.cpp etc)
|
||||
*/
|
||||
extern void DetermineBasePaths(const char *exe);
|
||||
#else /* defined(WIN32) */
|
||||
#else /* defined(_WIN32) */
|
||||
|
||||
/**
|
||||
* Changes the working directory to the path of the give executable.
|
||||
@@ -1011,10 +1000,6 @@ static bool ChangeWorkingDirectoryToExecutable(const char *exe)
|
||||
char *s = strrchr(tmp, PATHSEPCHAR);
|
||||
if (s != NULL) {
|
||||
*s = '\0';
|
||||
#if defined(__DJGPP__)
|
||||
/* If we want to go to the root, we can't use cd C:, but we must use '/' */
|
||||
if (s > tmp && *(s - 1) == ':') chdir("/");
|
||||
#endif
|
||||
if (chdir(tmp) != 0) {
|
||||
DEBUG(misc, 0, "Directory with the binary does not exist?");
|
||||
} else {
|
||||
@@ -1067,7 +1052,7 @@ void DetermineBasePaths(const char *exe)
|
||||
AppendPathSeparator(tmp, lastof(tmp));
|
||||
_searchpaths[SP_PERSONAL_DIR_XDG] = stredup(tmp);
|
||||
#endif
|
||||
#if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) || !defined(WITH_PERSONAL_DIR)
|
||||
#if defined(OS2) || !defined(WITH_PERSONAL_DIR)
|
||||
_searchpaths[SP_PERSONAL_DIR] = NULL;
|
||||
#else
|
||||
#ifdef __HAIKU__
|
||||
@@ -1110,13 +1095,9 @@ void DetermineBasePaths(const char *exe)
|
||||
_searchpaths[SP_SHARED_DIR] = NULL;
|
||||
#endif
|
||||
|
||||
#if defined(__MORPHOS__) || defined(__AMIGA__)
|
||||
_searchpaths[SP_WORKING_DIR] = NULL;
|
||||
#else
|
||||
if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0';
|
||||
AppendPathSeparator(tmp, lastof(tmp));
|
||||
_searchpaths[SP_WORKING_DIR] = stredup(tmp);
|
||||
#endif
|
||||
|
||||
_do_scan_working_directory = DoScanWorkingDirectory();
|
||||
|
||||
@@ -1136,7 +1117,7 @@ void DetermineBasePaths(const char *exe)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2)
|
||||
#if !defined(GLOBAL_DATA_DIR)
|
||||
_searchpaths[SP_INSTALLATION_DIR] = NULL;
|
||||
#else
|
||||
seprintf(tmp, lastof(tmp), "%s", GLOBAL_DATA_DIR);
|
||||
@@ -1150,7 +1131,7 @@ extern void cocoaSetApplicationBundleDir();
|
||||
_searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL;
|
||||
#endif
|
||||
}
|
||||
#endif /* defined(WIN32) */
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
const char *_personal_dir;
|
||||
|
||||
@@ -1240,7 +1221,7 @@ void DeterminePaths(const char *exe)
|
||||
}
|
||||
|
||||
/* Make the necessary folders */
|
||||
#if !defined(__MORPHOS__) && !defined(__AMIGA__) && defined(WITH_PERSONAL_DIR)
|
||||
#if defined(WITH_PERSONAL_DIR)
|
||||
FioCreateDirectory(config_dir);
|
||||
if (config_dir != _personal_dir) FioCreateDirectory(_personal_dir);
|
||||
#endif
|
||||
@@ -1259,7 +1240,6 @@ void DeterminePaths(const char *exe)
|
||||
|
||||
/* If we have network we make a directory for the autodownloading of content */
|
||||
_searchpaths[SP_AUTODOWNLOAD_DIR] = str_fmt("%s%s", _personal_dir, "content_download" PATHSEP);
|
||||
#ifdef ENABLE_NETWORK
|
||||
FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]);
|
||||
|
||||
/* Create the directory for each of the types of content */
|
||||
@@ -1272,14 +1252,6 @@ void DeterminePaths(const char *exe)
|
||||
|
||||
extern char *_log_file;
|
||||
_log_file = str_fmt("%sopenttd.log", _personal_dir);
|
||||
#else /* ENABLE_NETWORK */
|
||||
/* If we don't have networking, we don't need to make the directory. But
|
||||
* if it exists we keep it, otherwise remove it from the search paths. */
|
||||
if (!FileExists(_searchpaths[SP_AUTODOWNLOAD_DIR])) {
|
||||
free(_searchpaths[SP_AUTODOWNLOAD_DIR]);
|
||||
_searchpaths[SP_AUTODOWNLOAD_DIR] = NULL;
|
||||
}
|
||||
#endif /* ENABLE_NETWORK */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1303,7 +1275,7 @@ void SanitizeFilename(char *filename)
|
||||
/**
|
||||
* Load a file into memory.
|
||||
* @param filename Name of the file to load.
|
||||
* @param lenp [out] Length of loaded data.
|
||||
* @param[out] lenp Length of loaded data.
|
||||
* @param maxsize Maximum size to load.
|
||||
* @return Pointer to new memory containing the loaded data, or \c NULL if loading failed.
|
||||
* @note If \a maxsize less than the length of the file, loading fails.
|
||||
|
@@ -107,7 +107,7 @@ public:
|
||||
ALL = BASESET | NEWGRF | AI | SCENARIO | GAME, ///< Scan for everything.
|
||||
};
|
||||
|
||||
/* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = NULL);
|
||||
bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = NULL) override;
|
||||
|
||||
bool AddFile(Subdirectory sd, const char *filename);
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
DECLARE_ENUM_AS_BIT_SET(TarScanner::Mode)
|
||||
|
||||
/* Implementation of opendir/readdir/closedir for Windows */
|
||||
#if defined(WIN32)
|
||||
#if defined(_WIN32)
|
||||
struct DIR;
|
||||
|
||||
struct dirent { // XXX - only d_name implemented
|
||||
@@ -136,7 +136,7 @@ int closedir(DIR *d);
|
||||
/* Use system-supplied opendir/readdir/closedir functions */
|
||||
# include <sys/types.h>
|
||||
# include <dirent.h>
|
||||
#endif /* defined(WIN32) */
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/**
|
||||
* A wrapper around opendir() which will convert the string from
|
||||
|
61
src/fios.cpp
61
src/fios.cpp
@@ -13,16 +13,18 @@
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "fios.h"
|
||||
#include "3rdparty/md5/md5.h"
|
||||
#include "fileio_func.h"
|
||||
#include "tar_type.h"
|
||||
#include "fios.h"
|
||||
#include "network/network_content.h"
|
||||
#include "screenshot.h"
|
||||
#include "string_func.h"
|
||||
#include "tar_type.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#ifndef _WIN32
|
||||
# include <unistd.h>
|
||||
#endif /* WIN32 */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -153,7 +155,7 @@ const char *FiosBrowseTo(const FiosItem *item)
|
||||
{
|
||||
switch (item->type) {
|
||||
case FIOS_TYPE_DRIVE:
|
||||
#if defined(WIN32) || defined(__OS2__)
|
||||
#if defined(_WIN32) || defined(__OS2__)
|
||||
seprintf(_fios_path, _fios_path_last, "%c:" PATHSEP, item->title[0]);
|
||||
#endif
|
||||
break;
|
||||
@@ -162,7 +164,7 @@ const char *FiosBrowseTo(const FiosItem *item)
|
||||
break;
|
||||
|
||||
case FIOS_TYPE_PARENT: {
|
||||
/* Check for possible NULL ptr (not required for UNIXes, but AmigaOS-alikes) */
|
||||
/* Check for possible NULL ptr */
|
||||
char *s = strrchr(_fios_path, PATHSEPCHAR);
|
||||
if (s != NULL && s != _fios_path) {
|
||||
s[0] = '\0'; // Remove last path separator character, so we can go up one level.
|
||||
@@ -170,11 +172,6 @@ const char *FiosBrowseTo(const FiosItem *item)
|
||||
s = strrchr(_fios_path, PATHSEPCHAR);
|
||||
if (s != NULL) {
|
||||
s[1] = '\0'; // go up a directory
|
||||
#if defined(__MORPHOS__) || defined(__AMIGAOS__)
|
||||
/* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
|
||||
} else if ((s = strrchr(_fios_path, ':')) != NULL) {
|
||||
s[1] = '\0';
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -215,21 +212,7 @@ static void FiosMakeFilename(char *buf, const char *path, const char *name, cons
|
||||
/* Don't append the extension if it is already there */
|
||||
period = strrchr(name, '.');
|
||||
if (period != NULL && strcasecmp(period, ext) == 0) ext = "";
|
||||
#if defined(__MORPHOS__) || defined(__AMIGAOS__)
|
||||
if (path != NULL) {
|
||||
unsigned char sepchar = path[(strlen(path) - 1)];
|
||||
|
||||
if (sepchar != ':' && sepchar != '/') {
|
||||
seprintf(buf, last, "%s" PATHSEP "%s%s", path, name, ext);
|
||||
} else {
|
||||
seprintf(buf, last, "%s%s%s", path, name, ext);
|
||||
}
|
||||
} else {
|
||||
seprintf(buf, last, "%s%s", name, ext);
|
||||
}
|
||||
#else
|
||||
seprintf(buf, last, "%s" PATHSEP "%s%s", path, name, ext);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,7 +276,7 @@ public:
|
||||
fop(fop), callback_proc(callback_proc), file_list(file_list)
|
||||
{}
|
||||
|
||||
/* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename);
|
||||
bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -318,7 +301,7 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons
|
||||
}
|
||||
|
||||
FiosItem *fios = file_list.Append();
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
struct _stat sb;
|
||||
if (_tstat(OTTD2FS(filename), &sb) == 0) {
|
||||
#else
|
||||
@@ -359,7 +342,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c
|
||||
struct dirent *dirent;
|
||||
DIR *dir;
|
||||
FiosItem *fios;
|
||||
int sort_start;
|
||||
size_t sort_start;
|
||||
char d_name[sizeof(fios->name)];
|
||||
|
||||
file_list.Clear();
|
||||
@@ -397,7 +380,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c
|
||||
{
|
||||
SortingBits order = _savegame_sort_order;
|
||||
_savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
|
||||
QSortT(file_list.files.Begin(), file_list.files.Length(), CompareFiosItems);
|
||||
QSortT(file_list.files.data(), file_list.files.size(), CompareFiosItems);
|
||||
_savegame_sort_order = order;
|
||||
}
|
||||
|
||||
@@ -651,10 +634,6 @@ const char *FiosGetScreenshotDir()
|
||||
return fios_screenshot_path;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_NETWORK)
|
||||
#include "network/network_content.h"
|
||||
#include "3rdparty/md5/md5.h"
|
||||
|
||||
/** Basic data to distinguish a scenario. Used in the server list window */
|
||||
struct ScenarioIdentifier {
|
||||
uint32 scenid; ///< ID for the scenario (generated by content).
|
||||
@@ -676,7 +655,7 @@ struct ScenarioIdentifier {
|
||||
/**
|
||||
* Scanner to find the unique IDs of scenarios
|
||||
*/
|
||||
class ScenarioScanner : protected FileScanner, public SmallVector<ScenarioIdentifier, 8> {
|
||||
class ScenarioScanner : protected FileScanner, public std::vector<ScenarioIdentifier> {
|
||||
bool scanned; ///< Whether we've already scanned
|
||||
public:
|
||||
/** Initialise */
|
||||
@@ -694,7 +673,7 @@ public:
|
||||
this->scanned = true;
|
||||
}
|
||||
|
||||
/* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
|
||||
bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override
|
||||
{
|
||||
FILE *f = FioFOpenFile(filename, "r", SCENARIO_DIR);
|
||||
if (f == NULL) return false;
|
||||
@@ -727,7 +706,7 @@ public:
|
||||
|
||||
FioFCloseFile(f);
|
||||
|
||||
this->Include(id);
|
||||
include(*this, id);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -745,10 +724,10 @@ const char *FindScenario(const ContentInfo *ci, bool md5sum)
|
||||
{
|
||||
_scanner.Scan(false);
|
||||
|
||||
for (ScenarioIdentifier *id = _scanner.Begin(); id != _scanner.End(); id++) {
|
||||
if (md5sum ? (memcmp(id->md5sum, ci->md5sum, sizeof(id->md5sum)) == 0)
|
||||
: (id->scenid == ci->unique_id)) {
|
||||
return id->filename;
|
||||
for (ScenarioIdentifier &id : _scanner) {
|
||||
if (md5sum ? (memcmp(id.md5sum, ci->md5sum, sizeof(id.md5sum)) == 0)
|
||||
: (id.scenid == ci->unique_id)) {
|
||||
return id.filename;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,5 +752,3 @@ void ScanScenarios()
|
||||
{
|
||||
_scanner.Scan(true);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
36
src/fios.h
36
src/fios.h
@@ -18,6 +18,13 @@
|
||||
#include "network/core/tcp_content.h"
|
||||
|
||||
|
||||
/** Special values for save-load window for the data parameter of #InvalidateWindowData. */
|
||||
enum SaveLoadInvalidateWindowData {
|
||||
SLIWD_RESCAN_FILES, ///< Rescan all files (when changed directory, ...)
|
||||
SLIWD_SELECTION_CHANGES, ///< File selection has changed (user click, ...)
|
||||
SLIWD_FILTER_CHANGES, ///< The filename filter has changed (via the editbox)
|
||||
};
|
||||
|
||||
typedef SmallMap<uint, CompanyProperties *> CompanyPropertiesMap;
|
||||
|
||||
/**
|
||||
@@ -113,16 +120,17 @@ public:
|
||||
*/
|
||||
inline FiosItem *Append()
|
||||
{
|
||||
return this->files.Append();
|
||||
/*C++17: return &*/ this->files.emplace_back();
|
||||
return &this->files.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of files in the list.
|
||||
* @return The number of files stored in the list.
|
||||
*/
|
||||
inline uint Length() const
|
||||
inline size_t Length() const
|
||||
{
|
||||
return this->files.Length();
|
||||
return this->files.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +139,7 @@ public:
|
||||
*/
|
||||
inline const FiosItem *Begin() const
|
||||
{
|
||||
return this->files.Begin();
|
||||
return this->files.data();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,28 +148,28 @@ public:
|
||||
*/
|
||||
inline const FiosItem *End() const
|
||||
{
|
||||
return this->files.End();
|
||||
return this->Begin() + this->Length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to the indicated file information. File information must exist.
|
||||
* @return Address of the indicated existing file information.
|
||||
*/
|
||||
inline const FiosItem *Get(uint index) const
|
||||
inline const FiosItem *Get(size_t index) const
|
||||
{
|
||||
return this->files.Get(index);
|
||||
return this->files.data() + index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pointer to the indicated file information. File information must exist.
|
||||
* @return Address of the indicated existing file information.
|
||||
*/
|
||||
inline FiosItem *Get(uint index)
|
||||
inline FiosItem *Get(size_t index)
|
||||
{
|
||||
return this->files.Get(index);
|
||||
return this->files.data() + index;
|
||||
}
|
||||
|
||||
inline const FiosItem &operator[](uint index) const
|
||||
inline const FiosItem &operator[](size_t index) const
|
||||
{
|
||||
return this->files[index];
|
||||
}
|
||||
@@ -170,7 +178,7 @@ public:
|
||||
* Get a reference to the indicated file information. File information must exist.
|
||||
* @return The requested file information.
|
||||
*/
|
||||
inline FiosItem &operator[](uint index)
|
||||
inline FiosItem &operator[](size_t index)
|
||||
{
|
||||
return this->files[index];
|
||||
}
|
||||
@@ -178,19 +186,19 @@ public:
|
||||
/** Remove all items from the list. */
|
||||
inline void Clear()
|
||||
{
|
||||
this->files.Clear();
|
||||
this->files.clear();
|
||||
}
|
||||
|
||||
/** Compact the list down to the smallest block size boundary. */
|
||||
inline void Compact()
|
||||
{
|
||||
this->files.Compact();
|
||||
this->files.shrink_to_fit();
|
||||
}
|
||||
|
||||
void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop);
|
||||
const FiosItem *FindItem(const char *file);
|
||||
|
||||
SmallVector<FiosItem, 32> files; ///< The list of files.
|
||||
std::vector<FiosItem> files; ///< The list of files.
|
||||
};
|
||||
|
||||
enum SortingBits {
|
||||
|
208
src/fios_gui.cpp
208
src/fios_gui.cpp
@@ -28,6 +28,7 @@
|
||||
#include "date_func.h"
|
||||
#include "core/geometry_func.hpp"
|
||||
#include "gamelog.h"
|
||||
#include "stringfilter_type.h"
|
||||
|
||||
#include "widgets/fios_widget.h"
|
||||
|
||||
@@ -56,11 +57,10 @@ void LoadCheckData::Clear()
|
||||
this->current_date = 0;
|
||||
memset(&this->settings, 0, sizeof(this->settings));
|
||||
|
||||
const CompanyPropertiesMap::iterator end = this->companies.End();
|
||||
for (CompanyPropertiesMap::iterator it = this->companies.Begin(); it != end; it++) {
|
||||
delete it->second;
|
||||
for (auto &pair : this->companies) {
|
||||
delete pair.second;
|
||||
}
|
||||
companies.Clear();
|
||||
companies.clear();
|
||||
|
||||
GamelogFree(this->gamelog_action, this->gamelog_actions);
|
||||
this->gamelog_action = NULL;
|
||||
@@ -76,9 +76,20 @@ static const NWidgetPart _nested_load_dialog_widgets[] = {
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
|
||||
NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
/* Current directory and free space */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(),
|
||||
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(NWID_VERTICAL),
|
||||
/* Left side : filter box and available files */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 1),
|
||||
/* Filter box with label */
|
||||
NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, 0, WD_FRAMERECT_BOTTOM, 0),
|
||||
SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, 0),
|
||||
NWidget(WWT_TEXT, COLOUR_GREY), SetFill(0, 1), SetDataTip(STR_SAVELOAD_FILTER_TITLE , STR_NULL),
|
||||
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0),
|
||||
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||
EndContainer(),
|
||||
/* Sort buttons */
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
|
||||
@@ -86,6 +97,7 @@ static const NWidgetPart _nested_load_dialog_widgets[] = {
|
||||
EndContainer(),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON),
|
||||
EndContainer(),
|
||||
/* Files */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetFill(1, 1), SetPadding(2, 1, 2, 2),
|
||||
@@ -98,6 +110,8 @@ static const NWidgetPart _nested_load_dialog_widgets[] = {
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
|
||||
/* Right side : game details */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SL_DETAILS), SetResize(1, 1), SetFill(1, 1),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_MISSING_NEWGRFS), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
|
||||
@@ -119,8 +133,18 @@ static const NWidgetPart _nested_load_heightmap_dialog_widgets[] = {
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
|
||||
NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
/* Current directory and free space */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(),
|
||||
NWidget(NWID_VERTICAL),
|
||||
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 1),
|
||||
/* Filter box with label */
|
||||
NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, 0, WD_FRAMERECT_BOTTOM, 0),
|
||||
SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, 0),
|
||||
NWidget(WWT_TEXT, COLOUR_GREY), SetFill(0, 1), SetDataTip(STR_SAVELOAD_FILTER_TITLE , STR_NULL),
|
||||
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0),
|
||||
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||
EndContainer(),
|
||||
/* Sort Buttons */
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
|
||||
@@ -128,6 +152,7 @@ static const NWidgetPart _nested_load_heightmap_dialog_widgets[] = {
|
||||
EndContainer(),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON),
|
||||
EndContainer(),
|
||||
/* Files */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetFill(1, 1), SetPadding(2, 1, 2, 2),
|
||||
@@ -152,9 +177,19 @@ static const NWidgetPart _nested_save_dialog_widgets[] = {
|
||||
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
|
||||
NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
/* Current directory and free space */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(NWID_VERTICAL),
|
||||
/* Left side : filter box and available files */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 1),
|
||||
/* Filter box with label */
|
||||
NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, 0, WD_FRAMERECT_BOTTOM, 0),
|
||||
SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, 0),
|
||||
NWidget(WWT_TEXT, COLOUR_GREY), SetFill(0, 1), SetDataTip(STR_SAVELOAD_FILTER_TITLE , STR_NULL),
|
||||
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0),
|
||||
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||
EndContainer(),
|
||||
/* Sort buttons */
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
|
||||
@@ -162,6 +197,7 @@ static const NWidgetPart _nested_save_dialog_widgets[] = {
|
||||
EndContainer(),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON),
|
||||
EndContainer(),
|
||||
/* Files */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetPadding(2, 1, 0, 2),
|
||||
@@ -171,11 +207,14 @@ static const NWidgetPart _nested_save_dialog_widgets[] = {
|
||||
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_SAVE_OSK_TITLE), SetPadding(3, 2, 2, 2), SetFill(1, 0), SetResize(1, 0),
|
||||
SetDataTip(STR_SAVELOAD_OSKTITLE, STR_SAVELOAD_EDITBOX_TOOLTIP),
|
||||
EndContainer(),
|
||||
/* Save/delete buttons */
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_DELETE_SELECTION), SetDataTip(STR_SAVELOAD_DELETE_BUTTON, STR_SAVELOAD_DELETE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
|
||||
/* Right side : game details */
|
||||
NWidget(WWT_PANEL, COLOUR_GREY),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SL_DETAILS), SetResize(1, 1), SetFill(1, 1),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
@@ -201,12 +240,12 @@ static const TextColour _fios_colours[] = {
|
||||
|
||||
/**
|
||||
* Sort the collected list save games prior to displaying it in the save/load gui.
|
||||
* @param [inout] file_list List of save game files found in the directory.
|
||||
* @param[in,out] file_list List of save game files found in the directory.
|
||||
*/
|
||||
static void SortSaveGameList(FileList &file_list)
|
||||
{
|
||||
uint sort_start = 0;
|
||||
uint sort_end = 0;
|
||||
size_t sort_start = 0;
|
||||
size_t sort_end = 0;
|
||||
|
||||
/* Directories are always above the files (FIOS_TYPE_DIR)
|
||||
* Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
|
||||
@@ -221,12 +260,14 @@ static void SortSaveGameList(FileList &file_list)
|
||||
}
|
||||
}
|
||||
|
||||
uint s_amount = file_list.Length() - sort_start - sort_end;
|
||||
size_t s_amount = file_list.Length() - sort_start - sort_end;
|
||||
QSortT(file_list.Get(sort_start), s_amount, CompareFiosItems);
|
||||
}
|
||||
|
||||
struct SaveLoadWindow : public Window {
|
||||
private:
|
||||
static const uint EDITBOX_MAX_SIZE = 50;
|
||||
|
||||
QueryString filename_editbox; ///< Filename editbox.
|
||||
AbstractFileType abstract_filetype; /// Type of file to select.
|
||||
SaveLoadOperation fop; ///< File operation to perform.
|
||||
@@ -234,6 +275,23 @@ private:
|
||||
FiosItem o_dir;
|
||||
const FiosItem *selected; ///< Selected game in #fios_items, or \c NULL.
|
||||
Scrollbar *vscroll;
|
||||
|
||||
StringFilter string_filter; ///< Filter for available games.
|
||||
QueryString filter_editbox; ///< Filter editbox;
|
||||
std::vector<bool> fios_items_shown; ///< Map of the filtered out fios items
|
||||
|
||||
static void SaveGameConfirmationCallback(Window *w, bool confirmed)
|
||||
{
|
||||
/* File name has already been written to _file_to_saveload */
|
||||
if (confirmed) _switch_mode = SM_SAVE_GAME;
|
||||
}
|
||||
|
||||
static void SaveHeightmapConfirmationCallback(Window *w, bool confirmed)
|
||||
{
|
||||
/* File name has already been written to _file_to_saveload */
|
||||
if (confirmed) _switch_mode = SM_SAVE_HEIGHTMAP;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** Generate a default save filename. */
|
||||
@@ -244,7 +302,7 @@ public:
|
||||
}
|
||||
|
||||
SaveLoadWindow(WindowDesc *desc, AbstractFileType abstract_filetype, SaveLoadOperation fop)
|
||||
: Window(desc), filename_editbox(64), abstract_filetype(abstract_filetype), fop(fop)
|
||||
: Window(desc), filename_editbox(64), abstract_filetype(abstract_filetype), fop(fop), filter_editbox(EDITBOX_MAX_SIZE)
|
||||
{
|
||||
assert(this->fop == SLO_SAVE || this->fop == SLO_LOAD);
|
||||
|
||||
@@ -296,6 +354,8 @@ public:
|
||||
this->FinishInitNested(0);
|
||||
|
||||
this->LowerWidget(WID_SL_DRIVES_DIRECTORIES_LIST);
|
||||
this->querystrings[WID_SL_FILTER] = &this->filter_editbox;
|
||||
this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
|
||||
|
||||
/* pause is only used in single-player, non-editor mode, non-menu mode. It
|
||||
* will be unpaused in the WE_DESTROY event handler. */
|
||||
@@ -304,7 +364,7 @@ public:
|
||||
}
|
||||
SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
|
||||
|
||||
this->OnInvalidateData(0);
|
||||
this->OnInvalidateData(SLIWD_RESCAN_FILES);
|
||||
|
||||
ResetObjectToPlace();
|
||||
|
||||
@@ -327,8 +387,15 @@ public:
|
||||
strecpy(o_dir.name, _personal_dir, lastof(o_dir.name));
|
||||
}
|
||||
|
||||
/* Focus the edit box by default in the save windows */
|
||||
if (this->fop == SLO_SAVE) this->SetFocusedWidget(WID_SL_SAVE_OSK_TITLE);
|
||||
switch (this->fop) {
|
||||
case SLO_SAVE:
|
||||
/* Focus the edit box by default in the save window */
|
||||
this->SetFocusedWidget(WID_SL_SAVE_OSK_TITLE);
|
||||
break;
|
||||
|
||||
default:
|
||||
this->SetFocusedWidget(WID_SL_FILTER);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~SaveLoadWindow()
|
||||
@@ -339,7 +406,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void DrawWidget(const Rect &r, int widget) const
|
||||
void DrawWidget(const Rect &r, int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SL_SORT_BYNAME:
|
||||
@@ -369,8 +436,15 @@ public:
|
||||
GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK);
|
||||
|
||||
uint y = r.top + WD_FRAMERECT_TOP;
|
||||
for (uint pos = this->vscroll->GetPosition(); pos < this->fios_items.Length(); pos++) {
|
||||
const FiosItem *item = this->fios_items.Get(pos);
|
||||
uint scroll_pos = this->vscroll->GetPosition();
|
||||
for (uint row = 0; row < this->fios_items.Length(); row++) {
|
||||
if (!this->fios_items_shown[row]) {
|
||||
/* The current item is filtered out : we do not show it */
|
||||
scroll_pos++;
|
||||
continue;
|
||||
}
|
||||
if (row < scroll_pos) continue;
|
||||
const FiosItem *item = this->fios_items.Get(row);
|
||||
|
||||
if (item == this->selected) {
|
||||
GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_BLUE);
|
||||
@@ -456,10 +530,9 @@ public:
|
||||
if (y > y_max) break;
|
||||
|
||||
/* Companies / AIs */
|
||||
CompanyPropertiesMap::const_iterator end = _load_check_data.companies.End();
|
||||
for (CompanyPropertiesMap::const_iterator it = _load_check_data.companies.Begin(); it != end; it++) {
|
||||
SetDParam(0, it->first + 1);
|
||||
const CompanyProperties &c = *it->second;
|
||||
for (auto &pair : _load_check_data.companies) {
|
||||
SetDParam(0, pair.first + 1);
|
||||
const CompanyProperties &c = *pair.second;
|
||||
if (c.name != NULL) {
|
||||
SetDParam(1, STR_JUST_RAW_STRING);
|
||||
SetDParamStr(2, c.name);
|
||||
@@ -478,7 +551,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SL_BACKGROUND:
|
||||
@@ -500,18 +573,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPaint()
|
||||
void OnPaint() override
|
||||
{
|
||||
if (_savegame_sort_dirty) {
|
||||
_savegame_sort_dirty = false;
|
||||
SortSaveGameList(this->fios_items);
|
||||
this->OnInvalidateData(SLIWD_FILTER_CHANGES);
|
||||
}
|
||||
|
||||
this->vscroll->SetCount(this->fios_items.Length());
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
virtual void OnClick(Point pt, int widget, int click_count)
|
||||
void OnClick(Point pt, int widget, int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_SL_SORT_BYNAME: // Sort save names by name
|
||||
@@ -530,7 +603,7 @@ public:
|
||||
|
||||
case WID_SL_HOME_BUTTON: // OpenTTD 'button', jumps to OpenTTD directory
|
||||
FiosBrowseTo(&o_dir);
|
||||
this->InvalidateData();
|
||||
this->InvalidateData(SLIWD_RESCAN_FILES);
|
||||
break;
|
||||
|
||||
case WID_SL_LOAD_BUTTON:
|
||||
@@ -562,9 +635,7 @@ public:
|
||||
if (!_network_available) {
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
|
||||
} else if (_load_check_data.HasNewGrfs()) {
|
||||
#if defined(ENABLE_NETWORK)
|
||||
ShowMissingContentWindow(_load_check_data.grfconfig);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -572,6 +643,12 @@ public:
|
||||
int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WD_FRAMERECT_TOP);
|
||||
if (y == INT_MAX) return;
|
||||
|
||||
/* Get the corresponding non-filtered out item from the list */
|
||||
int i = 0;
|
||||
while (i <= y) {
|
||||
if (!this->fios_items_shown[i]) y++;
|
||||
i++;
|
||||
}
|
||||
const FiosItem *file = this->fios_items.Get(y);
|
||||
|
||||
const char *name = FiosBrowseTo(file);
|
||||
@@ -586,7 +663,7 @@ public:
|
||||
SaveOrLoad(name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false);
|
||||
}
|
||||
|
||||
this->InvalidateData(1);
|
||||
this->InvalidateData(SLIWD_SELECTION_CHANGES);
|
||||
}
|
||||
if (this->fop == SLO_SAVE) {
|
||||
/* Copy clicked name to editbox */
|
||||
@@ -611,7 +688,7 @@ public:
|
||||
}
|
||||
} else {
|
||||
/* Changed directory, need refresh. */
|
||||
this->InvalidateData();
|
||||
this->InvalidateData(SLIWD_RESCAN_FILES);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -620,14 +697,12 @@ public:
|
||||
if (!_network_available) {
|
||||
ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
|
||||
} else {
|
||||
#if defined(ENABLE_NETWORK)
|
||||
assert(this->fop == SLO_LOAD);
|
||||
switch (this->abstract_filetype) {
|
||||
default: NOT_REACHED();
|
||||
case FT_SCENARIO: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_SCENARIO); break;
|
||||
case FT_HEIGHTMAP: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_HEIGHTMAP); break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -641,7 +716,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual EventState OnKeyPress(WChar key, uint16 keycode)
|
||||
EventState OnKeyPress(WChar key, uint16 keycode) override
|
||||
{
|
||||
if (keycode == WKC_ESC) {
|
||||
delete this;
|
||||
@@ -651,7 +726,7 @@ public:
|
||||
return ES_NOT_HANDLED;
|
||||
}
|
||||
|
||||
virtual void OnTimeout()
|
||||
void OnTimeout() override
|
||||
{
|
||||
/* Widgets WID_SL_DELETE_SELECTION and WID_SL_SAVE_GAME only exist when saving to a file. */
|
||||
if (this->fop != SLO_SAVE) return;
|
||||
@@ -660,17 +735,25 @@ public:
|
||||
if (!FiosDelete(this->filename_editbox.text.buf)) {
|
||||
ShowErrorMessage(STR_ERROR_UNABLE_TO_DELETE_FILE, INVALID_STRING_ID, WL_ERROR);
|
||||
} else {
|
||||
this->InvalidateData();
|
||||
this->InvalidateData(SLIWD_RESCAN_FILES);
|
||||
/* Reset file name to current date on successful delete */
|
||||
if (this->abstract_filetype == FT_SAVEGAME) GenerateFileName();
|
||||
}
|
||||
} else if (this->IsWidgetLowered(WID_SL_SAVE_GAME)) { // Save button clicked
|
||||
if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) {
|
||||
_switch_mode = SM_SAVE_GAME;
|
||||
FiosMakeSavegameName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name));
|
||||
if (FioCheckFileExists(_file_to_saveload.name, Subdirectory::SAVE_DIR)) {
|
||||
ShowQuery(STR_SAVELOAD_OVERWRITE_TITLE, STR_SAVELOAD_OVERWRITE_WARNING, this, SaveLoadWindow::SaveGameConfirmationCallback);
|
||||
} else {
|
||||
_switch_mode = SM_SAVE_GAME;
|
||||
}
|
||||
} else {
|
||||
_switch_mode = SM_SAVE_HEIGHTMAP;
|
||||
FiosMakeHeightmapName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name));
|
||||
if (FioCheckFileExists(_file_to_saveload.name, Subdirectory::SAVE_DIR)) {
|
||||
ShowQuery(STR_SAVELOAD_OVERWRITE_TITLE, STR_SAVELOAD_OVERWRITE_WARNING, this, SaveLoadWindow::SaveHeightmapConfirmationCallback);
|
||||
} else {
|
||||
_switch_mode = SM_SAVE_HEIGHTMAP;
|
||||
}
|
||||
}
|
||||
|
||||
/* In the editor set up the vehicle engines correctly (date might have changed) */
|
||||
@@ -678,7 +761,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnResize()
|
||||
void OnResize() override
|
||||
{
|
||||
this->vscroll->SetCapacityFromWidget(this, WID_SL_DRIVES_DIRECTORIES_LIST);
|
||||
}
|
||||
@@ -688,10 +771,10 @@ public:
|
||||
* @param data Information about the changed data.
|
||||
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
|
||||
*/
|
||||
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
switch (data) {
|
||||
case 0:
|
||||
case SLIWD_RESCAN_FILES:
|
||||
/* Rescan files */
|
||||
this->selected = NULL;
|
||||
_load_check_data.Clear();
|
||||
@@ -699,12 +782,16 @@ public:
|
||||
|
||||
_fios_path_changed = true;
|
||||
this->fios_items.BuildFileList(this->abstract_filetype, this->fop);
|
||||
this->vscroll->SetCount(this->fios_items.Length());
|
||||
this->vscroll->SetCount((uint)this->fios_items.Length());
|
||||
this->selected = NULL;
|
||||
_load_check_data.Clear();
|
||||
|
||||
/* We reset the files filtered */
|
||||
this->OnInvalidateData(SLIWD_FILTER_CHANGES);
|
||||
|
||||
FALLTHROUGH;
|
||||
|
||||
case 1:
|
||||
case SLIWD_SELECTION_CHANGES:
|
||||
/* Selection changes */
|
||||
if (!gui_scope) break;
|
||||
|
||||
@@ -732,6 +819,41 @@ public:
|
||||
NOT_REACHED();
|
||||
}
|
||||
break;
|
||||
|
||||
case SLIWD_FILTER_CHANGES:
|
||||
/* Filter changes */
|
||||
this->fios_items_shown.resize(this->fios_items.Length());
|
||||
uint items_shown_count = 0; ///< The number of items shown in the list
|
||||
/* We pass through every fios item */
|
||||
for (uint i = 0; i < this->fios_items.Length(); i++) {
|
||||
if (this->string_filter.IsEmpty()) {
|
||||
/* We don't filter anything out if the filter editbox is empty */
|
||||
this->fios_items_shown[i] = true;
|
||||
items_shown_count++;
|
||||
} else {
|
||||
this->string_filter.ResetState();
|
||||
this->string_filter.AddLine(this->fios_items[i].title);
|
||||
/* We set the vector to show this fios element as filtered depending on the result of the filter */
|
||||
this->fios_items_shown[i] = this->string_filter.GetState();
|
||||
if (this->fios_items_shown[i]) items_shown_count++;
|
||||
|
||||
if (&(this->fios_items[i]) == this->selected && this->fios_items_shown[i] == false) {
|
||||
/* The selected element has been filtered out */
|
||||
this->selected = NULL;
|
||||
this->OnInvalidateData(SLIWD_SELECTION_CHANGES);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->vscroll->SetCount(items_shown_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEditboxChanged(int wid) override
|
||||
{
|
||||
if (wid == WID_SL_FILTER) {
|
||||
this->string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||
this->InvalidateData(SLIWD_FILTER_CHANGES);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user