/**
* 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<NWidgetBase>(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<AIInfo *>((*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);
}
};