/** * Window to configure which AIs will start. */ struct AIConfigWindow : public Window { CompanyID selected_slot; ///< The currently selected AI slot or \c INVALID_COMPANY. int line_height; ///< Height of a single AI-name line. uint cid_width; ///< Width of Company # string. AIConfigWindow() : Window(&_ai_config_desc) { this->InitNested(WN_GAME_OPTIONS_AI); // Initializes 'this->line_height' as a side effect. this->selected_slot = INVALID_COMPANY; this->OnInvalidateData(0); } ~AIConfigWindow() { DeleteWindowByClass(WC_AI_LIST); if (_game_mode != GM_NORMAL) DeleteWindowByClass(WC_AI_SETTINGS); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AIC_CAPTION: SetDParam(0, (_game_mode != GM_NORMAL) ? STR_AI_CONFIG_CAPTION : STR_AI_CONFIG_CAPTION_INGAME); break; case WID_AIC_NUMBER: SetDParam(0, GetGameSettings().difficulty.max_no_competitors); break; case WID_AIC_CHANGE: switch (selected_slot) { case OWNER_DEITY: SetDParam(0, STR_AI_CONFIG_CHANGE_GAMESCRIPT); break; case INVALID_COMPANY: SetDParam(0, STR_AI_CONFIG_CHANGE_NONE); break; default: SetDParam(0, STR_AI_CONFIG_CHANGE_AI); break; } break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_AIC_GAMELIST: this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 1 * this->line_height; for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { StringID cid = STR_AI_CONFIG_AILIST_COMPANY_ID_1 + i; this->cid_width = max(GetStringBoundingBox(cid).width, GetStringBoundingBox(cid_width).width); } break; case WID_AIC_LIST: this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 15 * this->line_height; break; } } /** * Can the AI config in the given company slot be edited? * @param slot The slot to query. * @return True if and only if the given AI Config slot can e edited. */ static bool IsEditable(CompanyID slot) { if (slot == OWNER_DEITY) return _game_mode != GM_NORMAL || Game::GetInstance() != NULL; if (_game_mode != GM_NORMAL) { return slot >= 0 && slot < MAX_COMPANIES; } if (Company::IsValidHumanID(slot) || slot < 0) return false; return slot < MAX_COMPANIES; } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_AIC_GAMELIST: { StringID text = STR_AI_CONFIG_NONE; if (GameConfig::GetConfig()->GetInfo() != NULL) { SetDParamStr(0, GameConfig::GetConfig()->GetInfo()->GetName()); text = STR_JUST_RAW_STRING; } DrawString(r.left + 10, r.right - 10, r.top + WD_MATRIX_TOP, text, (this->selected_slot == OWNER_DEITY) ? TC_WHITE : (IsEditable(OWNER_DEITY) ? (_game_mode == GM_NORMAL) ? (IsDead(OWNER_DEITY)) ? TC_RED : TC_GREEN : TC_ORANGE : TC_SILVER)); break; } case WID_AIC_LIST: { int y = r.top; for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { StringID cid = STR_AI_CONFIG_AILIST_COMPANY_ID_1 + i; DrawString(r.left + 10, r.left + 90, y + WD_MATRIX_TOP, cid); StringID text; if (_game_mode == GM_NORMAL && Company::IsValidHumanID(i)) { text = STR_AI_CONFIG_HUMAN_PLAYER; } else if (AIConfig::GetConfig((CompanyID)i)->GetInfo() != NULL) { SetDParamStr(0, AIConfig::GetConfig((CompanyID)i)->GetInfo()->GetName()); text = STR_JUST_RAW_STRING; } else { text = STR_AI_CONFIG_RANDOM_AI; } DrawString(r.left + 10 + 90, r.right - 10, y + WD_MATRIX_TOP, text, (this->selected_slot == i) ? TC_WHITE : (IsEditable((CompanyID)i) ? Company::IsValidAiID(i) ? IsDead((CompanyID)i) ? TC_RED : TC_GREEN : TC_ORANGE : TC_SILVER)); y += this->line_height; } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_END) { if (this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot) == NULL) return; ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot); return; } switch (widget) { case WID_AIC_DECREASE: case WID_AIC_INCREASE: { int new_value; if (widget == WID_AIC_DECREASE) { new_value = max(0, GetGameSettings().difficulty.max_no_competitors - 1); } else { new_value = min(MAX_COMPANIES, GetGameSettings().difficulty.max_no_competitors + 1); } IConsoleSetSetting("difficulty.max_no_competitors", new_value); this->InvalidateData(); break; } case WID_AIC_GAMELIST: { this->selected_slot = OWNER_DEITY; this->InvalidateData(); if (click_count > 1 && this->selected_slot != INVALID_COMPANY && _game_mode != GM_NORMAL) ShowAIListWindow((CompanyID)this->selected_slot); break; } case WID_AIC_LIST: { // Select a slot this->selected_slot = (CompanyID)this->GetRowFromWidget(pt.y, widget, 0, this->line_height); this->InvalidateData(); if (click_count > 1 && this->selected_slot != INVALID_COMPANY) ShowAIListWindow((CompanyID)this->selected_slot); break; } case WID_AIC_MOVE_UP: if (IsEditable(this->selected_slot) && IsDead(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot - 1)) && IsDead((CompanyID)(this->selected_slot - 1))) { Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot - 1]); this->selected_slot--; this->InvalidateData(); } break; case WID_AIC_MOVE_DOWN: if (IsEditable(this->selected_slot) && IsDead(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot + 1)) && IsDead((CompanyID)(this->selected_slot + 1))) { Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot + 1]); this->selected_slot++; this->InvalidateData(); } break; case WID_AIC_CHANGE: // choose other AI ShowAIListWindow((CompanyID)this->selected_slot); break; case WID_AIC_CONFIGURE: // change the settings for an AI ShowAISettingsWindow((CompanyID)this->selected_slot); break; case WID_AIC_CLOSE: delete this; break; case WID_AIC_CONTENT_DOWNLOAD: 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; } } /** * Some data on this window has become invalid. * @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) { if (!IsEditable(this->selected_slot)) { this->selected_slot = INVALID_COMPANY; } if (!gui_scope) return; this->SetWidgetDisabledState(WID_AIC_DECREASE, GetGameSettings().difficulty.max_no_competitors == 0); this->SetWidgetDisabledState(WID_AIC_INCREASE, GetGameSettings().difficulty.max_no_competitors == MAX_COMPANIES); this->SetWidgetDisabledState(WID_AIC_CHANGE, this->selected_slot == INVALID_COMPANY || _game_mode == GM_NORMAL && (this->selected_slot == OWNER_DEITY || !IsDead(this->selected_slot))); this->SetWidgetDisabledState(WID_AIC_CONFIGURE, this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot)->GetConfigList()->size() == 0); /* Display either Settings or Configure button */ NWidgetCore *configure_button = this->GetWidget(WID_AIC_CONFIGURE); if (_game_mode == GM_NORMAL && this->selected_slot != INVALID_COMPANY && !IsDead(this->selected_slot)) { configure_button->SetDataTip(STR_AI_DEBUG_SETTINGS, STR_AI_DEBUG_SETTINGS_TOOLTIP); } else { configure_button->SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP); } this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == INVALID_COMPANY || this->selected_slot == OWNER_DEITY || !IsDead(this->selected_slot) || !IsEditable((CompanyID)(this->selected_slot - 1)) || !IsDead((CompanyID)(this->selected_slot - 1))); this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, this->selected_slot == INVALID_COMPANY || this->selected_slot == OWNER_DEITY || !IsDead(this->selected_slot) || !IsEditable((CompanyID)(this->selected_slot + 1)) || !IsDead((CompanyID)(this->selected_slot + 1))); for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == INVALID_COMPANY || (GetConfig(this->selected_slot)->GetTextfile(tft, this->selected_slot) == NULL)); } } };