/** * Window that let you choose an available AI. */ struct AIListWindow : public Window { const ScriptInfoList *info_list; ///< The list of Scripts. int selected; ///< The currently selected Script. CompanyID slot; ///< The company we're selecting a new Script for. int line_height; ///< Height of a row in the matrix widget. Scrollbar *vscroll; ///< Cache of the vertical scrollbar. /** * Constructor for the window. * @param desc The description of the window. * @param slot The company we're changing the AI for. */ AIListWindow(WindowDesc *desc, CompanyID slot) : Window(desc), slot(slot) { if (slot == OWNER_DEITY) { this->info_list = Game::GetUniqueInfoList(); } else { this->info_list = AI::GetUniqueInfoList(); } this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_AIL_SCROLLBAR); this->FinishInitNested(); // Initializes 'this->line_height' as side effect. this->vscroll->SetCount((int)this->info_list->size() + 1); /* Try if we can find the currently selected AI */ this->selected = -1; if (GetConfig(slot)->HasScript()) { ScriptInfo *info = GetConfig(slot)->GetInfo(); int i = 0; for (ScriptInfoList::const_iterator it = this->info_list->begin(); it != this->info_list->end(); it++, i++) { if ((*it).second == info) { this->selected = i; break; } } } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AIL_CAPTION: SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_LIST_CAPTION_GAMESCRIPT : STR_AI_LIST_CAPTION_AI); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_AIL_LIST) { this->line_height = max((uint)FONT_HEIGHT_NORMAL, GetSpriteSize(SPR_AICONFIG_RANDOM).height) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->width = 1; resize->height = this->line_height; size->height = 5 * this->line_height; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_AIL_LIST: { /* Draw a list of all available AIs. */ int y = this->GetWidget(WID_AIL_LIST)->pos_y; Dimension rai = GetSpriteSize(SPR_AICONFIG_RANDOM); uint rai_y_offset = (line_height - rai.height) / 2; /* First AI in the list is hardcoded to random */ if (this->vscroll->IsVisible(0)) { StringID text = STR_AI_CONFIG_RANDOM_AI; if (this->slot == OWNER_DEITY) text = STR_AI_CONFIG_NONE; if (text == STR_AI_CONFIG_RANDOM_AI) DrawSprite(SPR_AICONFIG_RANDOM, PAL_NONE, r.left + WD_MATRIX_LEFT, r.left + WD_MATRIX_LEFT + GetSpriteSize(SPR_AICONFIG_RANDOM).width, y + rai_y_offset); DrawString(r.left + WD_MATRIX_LEFT + GetSpriteSize(SPR_AICONFIG_RANDOM).width + 10, r.right - WD_MATRIX_LEFT, y + WD_MATRIX_TOP, text, this->selected == -1 ? TC_WHITE : TC_ORANGE); y += this->line_height; } ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 1; it != this->info_list->end(); i++, it++) { if (this->vscroll->IsVisible(i)) { DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, (*it).second->GetName(), (this->selected == i - 1) ? TC_WHITE : TC_ORANGE); y += this->line_height; } } break; } case WID_AIL_INFO_BG: { AIInfo *selected_info = NULL; ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 1; selected_info == NULL && it != this->info_list->end(); i++, it++) { if (this->selected == i - 1) selected_info = static_cast((*it).second); } /* Some info about the currently selected AI. */ if (selected_info != NULL) { int y = r.top + WD_FRAMERECT_TOP; SetDParamStr(0, selected_info->GetAuthor()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_AUTHOR); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; SetDParam(0, selected_info->GetVersion()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_VERSION); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; if (selected_info->GetURL() != NULL) { SetDParamStr(0, selected_info->GetURL()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_URL); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; } SetDParamStr(0, selected_info->GetDescription()); DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_FRAMERECT_BOTTOM, STR_JUST_RAW_STRING, TC_WHITE); } break; } } } /** * Changes the AI of the current slot. */ void ChangeAI() { if (this->selected == -1) { GetConfig(slot)->Change(NULL); } else { ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 0; i < this->selected; i++) it++; GetConfig(slot)->Change((*it).second->GetName(), (*it).second->GetVersion()); } InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_AI); DeleteWindowByClass(WC_AI_SETTINGS); DeleteWindowByClass(WC_TEXTFILE); DeleteWindowByClass(WC_QUERY_STRING); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_AIL_LIST: { // Select one of the AIs int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_AIL_LIST, 0, this->line_height) - 1; if (sel < (int)this->info_list->size()) { this->selected = sel; this->SetDirty(); if (click_count > 1) { this->ChangeAI(); delete this; } } break; } case WID_AIL_ACCEPT: { this->ChangeAI(); delete this; break; } case WID_AIL_CANCEL: delete this; break; } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_AIL_LIST); } /** * 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 (_game_mode == GM_NORMAL && Company::IsValidID(this->slot)) { delete this; return; } if (!gui_scope) return; this->vscroll->SetCount((int)this->info_list->size() + 1); /* selected goes from -1 .. length of ai list - 1. */ this->selected = min(this->selected, this->vscroll->GetCount() - 2); } };