# ai_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: ai_gui.cpp 15723 2009-03-15 15:12:06Z rubidium $ */
    00002
    00005 #include "../stdafx.h"
    00006 #include "../gui.h"
    00007 #include "../window_gui.h"
    00008 #include "../company_func.h"
    00009 #include "../company_base.h"
    00010 #include "../company_gui.h"
    00011 #include "../strings_func.h"
    00012 #include "../window_func.h"
    00013 #include "../gfx_func.h"
    00014 #include "../command_func.h"
    00015 #include "../network/network.h"
    00016 #include "../string_func.h"
    00017 #include "../textbuf_gui.h"
    00018 #include "../settings_type.h"
    00019 #include "../settings_func.h"
    00020 #include "../network/network_content.h"
    00021
    00022 #include "ai.hpp"
    00023 #include "api/ai_log.hpp"
    00024 #include "ai_config.hpp"
    00025
    00026 #include "table/strings.h"
    00027
    00031 struct AIListWindow : public Window {
    00033   enum AIListWindowWidgets {
    00034     AIL_WIDGET_CLOSEBOX = 0,
    00035     AIL_WIDGET_CAPTION,
    00036     AIL_WIDGET_LIST,
    00037     AIL_WIDGET_SCROLLBAR,
    00038     AIL_WIDGET_INFO_BG,
    00039     AIL_WIDGET_ACCEPT,
    00040     AIL_WIDGET_CANCEL,
    00041     AIL_WIDGET_CONTENT_DOWNLOAD,
    00042     AIL_WIDGET_RESIZE,
    00043   };
    00044
    00045   const AIInfoList *ai_info_list;
    00046   int selected;
    00047   CompanyID slot;
    00048
    00049   AIListWindow(const WindowDesc *desc, CompanyID slot) : Window(desc, 0),
    00050     slot(slot)
    00051   {
    00052     this->ai_info_list = AI::GetUniqueInfoList();
    00053     this->resize.step_height = 14;
    00054     this->vscroll.cap = (this->widget[AIL_WIDGET_LIST].bottom - this->widget[AIL_WIDGET_LIST].top) / 14 + 1;
    00055     this->widget[AIL_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
    00056     SetVScrollCount(this, (int)this->ai_info_list->size() + 1);
    00057
    00058     /* Try if we can find the currently selected AI */
    00059     this->selected = -1;
    00060     if (AIConfig::GetConfig(slot)->HasAI()) {
    00061       AIInfo *info = AIConfig::GetConfig(slot)->GetInfo();
    00062       int i = 0;
    00063       for (AIInfoList::const_iterator it = this->ai_info_list->begin(); it != this->ai_info_list->end(); it++, i++) {
    00064         if ((*it).second == info) {
    00065           this->selected = i;
    00066           break;
    00067         }
    00068       }
    00069     }
    00070
    00071     this->FindWindowPlacementAndResize(desc);
    00072   }
    00073
    00074   virtual void OnPaint()
    00075   {
    00076     this->DrawWidgets();
    00077
    00078     /* Draw a list of all available AIs. */
    00079     int y = this->widget[AIL_WIDGET_LIST].top;
    00080     /* First AI in the list is hardcoded to random */
    00081     if (this->vscroll.pos == 0) {
    00082       DrawStringTruncated(4, y + 3, STR_AI_RANDOM_AI, this->selected == -1 ? TC_WHITE : TC_BLACK, this->width - 8);
    00083       y += 14;
    00084     }
    00085     AIInfo *selected_info = NULL;
    00086     AIInfoList::const_iterator it = this->ai_info_list->begin();
    00087     for (int i = 1; it != this->ai_info_list->end(); i++, it++) {
    00088       if (this->selected == i - 1) selected_info = (*it).second;
    00089       if (IsInsideBS(i, this->vscroll.pos, this->vscroll.cap)) {
    00090         DoDrawStringTruncated((*it).second->GetName(), 4, y + 3, (this->selected == i - 1) ? TC_WHITE : TC_BLACK, this->width - 8);
    00091         y += 14;
    00092       }
    00093     }
    00094
    00095     /* Some info about the currently selected AI. */
    00096     if (selected_info != NULL) {
    00097       int y = this->widget[AIL_WIDGET_INFO_BG].top + 6;
    00098       int x = DrawString(4, y, STR_AI_AUTHOR, TC_BLACK);
    00099       DoDrawStringTruncated(selected_info->GetAuthor(), x + 5, y, TC_BLACK, this->width - x - 8);
    00100       y += 13;
    00101       x = DrawString(4, y, STR_AI_VERSION, TC_BLACK);
    00102       static char buf[8];
    00103       sprintf(buf, "%d", selected_info->GetVersion());
    00104       DoDrawStringTruncated(buf, x + 5, y, TC_BLACK, this->width - x - 8);
    00105       y += 13;
    00106       SetDParamStr(0, selected_info->GetDescription());
    00107       DrawStringMultiLine(4, y, STR_JUST_RAW_STRING, this->width - 8, this->widget[AIL_WIDGET_INFO_BG].bottom - y);
    00108     }
    00109   }
    00110
    00111   void ChangeAI()
    00112   {
    00113     if (this->selected == -1) {
    00114       AIConfig::GetConfig(slot)->ChangeAI(NULL);
    00115     } else {
    00116       AIInfoList::const_iterator it = this->ai_info_list->begin();
    00117       for (int i = 0; i < this->selected; i++) it++;
    00118       AIConfig::GetConfig(slot)->ChangeAI((*it).second->GetName(), (*it).second->GetVersion());
    00119     }
    00120     InvalidateWindow(WC_GAME_OPTIONS, 0);
    00121   }
    00122
    00123   virtual void OnClick(Point pt, int widget)
    00124   {
    00125     switch (widget) {
    00126       case AIL_WIDGET_LIST: { // Select one of the AIs
    00127         int sel = (pt.y - this->widget[AIL_WIDGET_LIST].top) / 14 + this->vscroll.pos - 1;
    00128         if (sel < (int)this->ai_info_list->size()) {
    00129           this->selected = sel;
    00130           this->SetDirty();
    00131         }
    00132         break;
    00133       }
    00134
    00135       case AIL_WIDGET_ACCEPT: {
    00136         this->ChangeAI();
    00137         delete this;
    00138         break;
    00139       }
    00140
    00141       case AIL_WIDGET_CANCEL:
    00142         delete this;
    00143         break;
    00144
    00145       case AIL_WIDGET_CONTENT_DOWNLOAD:
    00146         if (!_network_available) {
    00147           ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
    00148         } else {
    00149 #if defined(ENABLE_NETWORK)
    00150           ShowNetworkContentListWindow(NULL, CONTENT_TYPE_AI);
    00151 #endif
    00152         }
    00153         break;
    00154     }
    00155   }
    00156
    00157   virtual void OnDoubleClick(Point pt, int widget)
    00158   {
    00159     switch (widget) {
    00160       case AIL_WIDGET_LIST: {
    00161         int sel = (pt.y - this->widget[AIL_WIDGET_LIST].top) / 14 + this->vscroll.pos - 1;
    00162         if (sel < (int)this->ai_info_list->size()) {
    00163           this->selected = sel;
    00164           this->ChangeAI();
    00165           delete this;
    00166         }
    00167         break;
    00168       }
    00169     }
    00170   }
    00171
    00172   virtual void OnResize(Point new_size, Point delta)
    00173   {
    00174     if (delta.x != 0) {
    00175       ResizeButtons(this, AIL_WIDGET_ACCEPT, AIL_WIDGET_CANCEL);
    00176     }
    00177
    00178     this->vscroll.cap += delta.y / 14;
    00179     this->widget[AIL_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
    00180   }
    00181 };
    00182
    00183 /* Widget definition for the ai list window. */
    00184 static const Widget _ai_list_widgets[] = {
    00185 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_MAUVE,    0,   10,    0,   13,  STR_00C5,                 STR_018B_CLOSE_WINDOW},             // AIL_WIDGET_CLOSEBOX
    00186 {    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_MAUVE,   11,  199,    0,   13,  STR_AI_LIST_CAPTION,      STR_018C_WINDOW_TITLE_DRAG_THIS},   // AIL_WIDGET_CAPTION
    00187 {     WWT_MATRIX,     RESIZE_RB,  COLOUR_MAUVE,    0,  187,   14,  125,  0x501,                    STR_AI_AILIST_TIP},                 // AIL_WIDGET_LIST
    00188 {  WWT_SCROLLBAR,    RESIZE_LRB,  COLOUR_MAUVE,  188,  199,   14,  125,  0x0,                      STR_0190_SCROLL_BAR_SCROLLS_LIST }, // AIL_WIDGET_SCROLLBAR
    00189 {      WWT_PANEL,    RESIZE_RTB,  COLOUR_MAUVE,    0,  199,  126,  209,  0x0,                      STR_NULL},                          // AIL_WIDGET_INFO_BG
    00190 { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_MAUVE,    0,   99,  210,  221,  STR_AI_ACCEPT,            STR_AI_ACCEPT_TIP},                 // AIL_WIDGET_ACCEPT
    00191 { WWT_PUSHTXTBTN,    RESIZE_RTB,  COLOUR_MAUVE,  100,  199,  210,  221,  STR_AI_CANCEL,            STR_AI_CANCEL_TIP},                 // AIL_WIDGET_CANCEL
    00192 { WWT_PUSHTXTBTN,    RESIZE_RTB,  COLOUR_MAUVE,    0,  187,  222,  233,  STR_CONTENT_INTRO_BUTTON, STR_CONTENT_INTRO_BUTTON_TIP},      // AIL_WIDGET_DOWNLOAD_CONTENT
    00193 {  WWT_RESIZEBOX,   RESIZE_LRTB,  COLOUR_MAUVE,  188,  199,  222,  233,  STR_NULL,                 STR_RESIZE_BUTTON},                 // AIL_WIDGET_RESIZE
    00194 {   WIDGETS_END},
    00195 };
    00196
    00197 /* Window definition for the ai list window. */
    00198 static const WindowDesc _ai_list_desc(
    00199   WDP_CENTER, WDP_CENTER, 200, 234, 200, 234,
    00200   WC_AI_LIST, WC_NONE,
    00201   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
    00202   _ai_list_widgets
    00203 );
    00204
    00205 void ShowAIListWindow(CompanyID slot)
    00206 {
    00207   DeleteWindowByClass(WC_AI_LIST);
    00208   new AIListWindow(&_ai_list_desc, slot);
    00209 }
    00210
    00214 struct AISettingsWindow : public Window {
    00216   enum AISettingsWindowWidgest {
    00217     AIS_WIDGET_CLOSEBOX = 0,
    00218     AIS_WIDGET_CAPTION,
    00219     AIS_WIDGET_BACKGROUND,
    00220     AIS_WIDGET_SCROLLBAR,
    00221     AIS_WIDGET_ACCEPT,
    00222     AIS_WIDGET_RESET,
    00223     AIS_WIDGET_RESIZE,
    00224   };
    00225
    00226   CompanyID slot;
    00227   AIConfig *ai_config;
    00228   int clicked_button;
    00229   bool clicked_increase;
    00230   int timeout;
    00231   int clicked_row;
    00232
    00233   AISettingsWindow(const WindowDesc *desc, CompanyID slot) : Window(desc, 0),
    00234     slot(slot),
    00235     clicked_button(-1),
    00236     timeout(0)
    00237   {
    00238     this->FindWindowPlacementAndResize(desc);
    00239     this->ai_config = AIConfig::GetConfig(slot);
    00240     this->resize.step_height = 14;
    00241     this->vscroll.cap = (this->widget[AIS_WIDGET_BACKGROUND].bottom - this->widget[AIS_WIDGET_BACKGROUND].top) / 14 + 1;
    00242     this->widget[AIS_WIDGET_BACKGROUND].data = (this->vscroll.cap << 8) + 1;
    00243     SetVScrollCount(this, (int)this->ai_config->GetConfigList()->size());
    00244     this->FindWindowPlacementAndResize(desc);
    00245   }
    00246
    00247   virtual void OnPaint()
    00248   {
    00249     this->DrawWidgets();
    00250
    00251     AIConfig *config = this->ai_config;
    00252     AIConfigItemList::const_iterator it = config->GetConfigList()->begin();
    00253     int i = 0;
    00254     for (; i < this->vscroll.pos; i++) it++;
    00255
    00256     int y = this->widget[AIS_WIDGET_BACKGROUND].top;
    00257     for (; i < this->vscroll.pos + this->vscroll.cap && it != config->GetConfigList()->end(); i++, it++) {
    00258       int current_value = config->GetSetting((*it).name);
    00259
    00260       int x = 0;
    00261       if (((*it).flags & AICONFIG_BOOLEAN) != 0) {
    00262         DrawFrameRect(4, y  + 2, 23, y + 10, (current_value != 0) ? COLOUR_GREEN : COLOUR_RED, (current_value != 0) ? FR_LOWERED : FR_NONE);
    00263       } else {
    00264         DrawArrowButtons(4, y + 2, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + !!this->clicked_increase : 0, current_value > (*it).min_value, current_value < (*it).max_value);
    00265         if (it->labels != NULL && it->labels->Find(current_value) != it->labels->End()) {
    00266           x = DoDrawStringTruncated(it->labels->Find(current_value)->second, 28, y + 3, TC_ORANGE, this->width - 32);
    00267         } else {
    00268           SetDParam(0, current_value);
    00269           x = DrawStringTruncated(28, y + 3, STR_JUST_INT, TC_ORANGE, this->width - 32);
    00270         }
    00271       }
    00272
    00273       DoDrawStringTruncated((*it).description, max(x + 3, 54), y + 3, TC_LIGHT_BLUE, this->width - (4 + max(x + 3, 54)));
    00274       y += 14;
    00275     }
    00276   }
    00277
    00278   virtual void OnClick(Point pt, int widget)
    00279   {
    00280     switch (widget) {
    00281       case AIS_WIDGET_BACKGROUND: {
    00282         int num = (pt.y - this->widget[AIS_WIDGET_BACKGROUND].top) / 14 + this->vscroll.pos;
    00283         if (num >= (int)this->ai_config->GetConfigList()->size()) break;
    00284
    00285         AIConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin();
    00286         for (int i = 0; i < num; i++) it++;
    00287         AIConfigItem config_item = *it;
    00288         bool bool_item = (config_item.flags & AICONFIG_BOOLEAN) != 0;
    00289
    00290         const int x = pt.x - 4;
    00291         /* One of the arrows is clicked (or green/red rect in case of bool value) */
    00292         if (IsInsideMM(x, 0, 21)) {
    00293           int new_val = this->ai_config->GetSetting(config_item.name);
    00294           if (bool_item) {
    00295             new_val = !new_val;
    00296           } else if (x >= 10) {
    00297             /* Increase button clicked */
    00298             new_val += config_item.step_size;
    00299             if (new_val > config_item.max_value) new_val = config_item.max_value;
    00300             this->clicked_increase = true;
    00301           } else {
    00302             /* Decrease button clicked */
    00303             new_val -= config_item.step_size;
    00304             if (new_val < config_item.min_value) new_val = config_item.min_value;
    00305             this->clicked_increase = false;
    00306           }
    00307
    00308           this->ai_config->SetSetting(config_item.name, new_val);
    00309           this->clicked_button = num;
    00310           this->timeout = 5;
    00311
    00312           if (_settings_newgame.difficulty.diff_level != 3) {
    00313             _settings_newgame.difficulty.diff_level = 3;
    00314             ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
    00315           }
    00316         } else if (!bool_item) {
    00317           /* Display a query box so users can enter a custom value. */
    00318           this->clicked_row = num;
    00319           SetDParam(0, this->ai_config->GetSetting(config_item.name));
    00320           ShowQueryString(STR_CONFIG_SETTING_INT32, STR_CONFIG_SETTING_QUERY_CAPT, 10, 100, this, CS_NUMERAL, QSF_NONE);
    00321         }
    00322
    00323         this->SetDirty();
    00324         break;
    00325       }
    00326
    00327       case AIS_WIDGET_ACCEPT:
    00328         delete this;
    00329         break;
    00330
    00331       case AIS_WIDGET_RESET:
    00332         this->ai_config->ResetSettings();
    00333         this->SetDirty();
    00334         break;
    00335     }
    00336   }
    00337
    00338   virtual void OnQueryTextFinished(char *str)
    00339   {
    00340     if (StrEmpty(str)) return;
    00341     AIConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin();
    00342     for (int i = 0; i < this->clicked_row; i++) it++;
    00343     int32 value = atoi(str);
    00344     this->ai_config->SetSetting((*it).name, value);
    00345     this->SetDirty();
    00346   }
    00347
    00348   virtual void OnResize(Point new_size, Point delta)
    00349   {
    00350     if (delta.x != 0) {
    00351       ResizeButtons(this, AIS_WIDGET_ACCEPT, AIS_WIDGET_RESET);
    00352     }
    00353
    00354     this->vscroll.cap += delta.y / 14;
    00355     this->widget[AIS_WIDGET_BACKGROUND].data = (this->vscroll.cap << 8) + 1;
    00356   }
    00357
    00358   virtual void OnTick()
    00359   {
    00360     if (--this->timeout == 0) {
    00361       this->clicked_button = -1;
    00362       this->SetDirty();
    00363     }
    00364   }
    00365 };
    00366
    00367 /* Widget definition for the AI settings window. */
    00368 static const Widget _ai_settings_widgets[] = {
    00369 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_MAUVE,    0,   10,    0,   13,  STR_00C5,                 STR_018B_CLOSE_WINDOW},             // AIS_WIDGET_CLOSEBOX
    00370 {    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_MAUVE,   11,  199,    0,   13,  STR_AI_SETTINGS_CAPTION,  STR_018C_WINDOW_TITLE_DRAG_THIS},   // AIS_WIDGET_CAPTION
    00371 {     WWT_MATRIX,     RESIZE_RB,  COLOUR_MAUVE,    0,  187,   14,  195,  0x501,                    STR_NULL},                          // AIS_WIDGET_BACKGROUND
    00372 {  WWT_SCROLLBAR,    RESIZE_LRB,  COLOUR_MAUVE,  188,  199,   14,  195,  0x0,                      STR_0190_SCROLL_BAR_SCROLLS_LIST }, // AIS_WIDGET_SCROLLBAR
    00373 { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_MAUVE,    0,   93,  196,  207,  STR_AI_CLOSE,             STR_NULL},                          // AIS_WIDGET_ACCEPT
    00374 { WWT_PUSHTXTBTN,    RESIZE_RTB,  COLOUR_MAUVE,   94,  187,  196,  207,  STR_AI_RESET,             STR_NULL},                          // AIS_WIDGET_RESET
    00375 {  WWT_RESIZEBOX,   RESIZE_LRTB,  COLOUR_MAUVE,  188,  199,  196,  207,  STR_NULL,                 STR_RESIZE_BUTTON},                 // AIS_WIDGET_RESIZE
    00376 {   WIDGETS_END},
    00377 };
    00378
    00379 /* Window definition for the AI settings window. */
    00380 static const WindowDesc _ai_settings_desc(
    00381   WDP_CENTER, WDP_CENTER, 200, 208, 500, 208,
    00382   WC_AI_SETTINGS, WC_NONE,
    00383   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
    00384   _ai_settings_widgets
    00385 );
    00386
    00387 void ShowAISettingsWindow(CompanyID slot)
    00388 {
    00389   DeleteWindowByClass(WC_AI_LIST);
    00390   DeleteWindowByClass(WC_AI_SETTINGS);
    00391   new AISettingsWindow(&_ai_settings_desc, slot);
    00392 }
    00393
    00394 /* Widget definition for the configure AI window. */
    00395 static const Widget _ai_config_widgets[] = {
    00396 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_MAUVE,    0,   10,    0,   13,  STR_00C5,               STR_018B_CLOSE_WINDOW},            // AIC_WIDGET_CLOSEBOX
    00397 {    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_MAUVE,   11,  299,    0,   13,  STR_AI_CONFIG_CAPTION,  STR_018C_WINDOW_TITLE_DRAG_THIS},  // AIC_WIDGET_CAPTION
    00398 {      WWT_PANEL,     RESIZE_RB,  COLOUR_MAUVE,    0,  299,   14,  171,  0x0,                    STR_NULL},                         // AIC_WIDGET_BACKGROUND
    00399 {     WWT_MATRIX,     RESIZE_RB,  COLOUR_MAUVE,    0,  287,   30,  141,  0x501,                  STR_AI_LIST_TIP},                  // AIC_WIDGET_LIST
    00400 {  WWT_SCROLLBAR,     RESIZE_LRB, COLOUR_MAUVE,  288,  299,   30,  141,  STR_NULL,               STR_0190_SCROLL_BAR_SCROLLS_LIST}, // AIC_WIDGET_SCROLLBAR
    00401 { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_YELLOW,  10,  102,  151,  162,  STR_AI_CHANGE,          STR_AI_CHANGE_TIP},                // AIC_WIDGET_CHANGE
    00402 { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_YELLOW, 103,  195,  151,  162,  STR_AI_CONFIGURE,       STR_AI_CONFIGURE_TIP},             // AIC_WIDGET_CONFIGURE
    00403 { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_YELLOW, 196,  289,  151,  162,  STR_AI_CLOSE,           STR_NULL},                         // AIC_WIDGET_CLOSE
    00404 {   WIDGETS_END},
    00405 };
    00406
    00407 /* Window definition for the configure AI window. */
    00408 static const WindowDesc _ai_config_desc(
    00409   WDP_CENTER, WDP_CENTER, 300, 172, 300, 172,
    00410   WC_GAME_OPTIONS, WC_NONE,
    00411   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    00412   _ai_config_widgets
    00413 );
    00414
    00418 struct AIConfigWindow : public Window {
    00420   enum AIConfigWindowWidgets {
    00421     AIC_WIDGET_CLOSEBOX = 0,
    00422     AIC_WIDGET_CAPTION,
    00423     AIC_WIDGET_BACKGROUND,
    00424     AIC_WIDGET_LIST,
    00425     AIC_WIDGET_SCROLLBAR,
    00426     AIC_WIDGET_CHANGE,
    00427     AIC_WIDGET_CONFIGURE,
    00428     AIC_WIDGET_CLOSE,
    00429     AIC_WIDGET_RESIZE,
    00430   };
    00431
    00432   CompanyID selected_slot;
    00433   bool clicked_button;
    00434   bool clicked_increase;
    00435   int timeout;
    00436
    00437   AIConfigWindow() : Window(&_ai_config_desc),
    00438     clicked_button(false),
    00439     timeout(0)
    00440   {
    00441     selected_slot = INVALID_COMPANY;
    00442     this->resize.step_height = 14;
    00443     this->vscroll.cap = (this->widget[AIC_WIDGET_LIST].bottom - this->widget[AIC_WIDGET_LIST].top) / 14 + 1;
    00444     this->widget[AIC_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
    00445     SetVScrollCount(this, MAX_COMPANIES);
    00446     this->FindWindowPlacementAndResize(&_ai_config_desc);
    00447   }
    00448
    00449   ~AIConfigWindow()
    00450   {
    00451     DeleteWindowByClass(WC_AI_LIST);
    00452     DeleteWindowByClass(WC_AI_SETTINGS);
    00453   }
    00454
    00455   virtual void OnPaint()
    00456   {
    00457     this->SetWidgetDisabledState(AIC_WIDGET_CHANGE, selected_slot == INVALID_COMPANY);
    00458     this->SetWidgetDisabledState(AIC_WIDGET_CONFIGURE, selected_slot == INVALID_COMPANY);
    00459     this->DrawWidgets();
    00460
    00461     byte max_competitors = _settings_newgame.difficulty.max_no_competitors;
    00462     DrawArrowButtons(10, 18, COLOUR_YELLOW, this->clicked_button ? 1 + !!this->clicked_increase : 0, max_competitors > 0, max_competitors < MAX_COMPANIES - 1);
    00463     SetDParam(0, _settings_newgame.difficulty.max_no_competitors);
    00464     DrawString(36, 18, STR_6805_MAXIMUM_NO_COMPETITORS, TC_FROMSTRING);
    00465
    00466     int y = this->widget[AIC_WIDGET_LIST].top;
    00467     for (int i = this->vscroll.pos; i < this->vscroll.pos + this->vscroll.cap && i < MAX_COMPANIES; i++) {
    00468       StringID text;
    00469
    00470       if (AIConfig::GetConfig((CompanyID)i)->GetInfo() != NULL) {
    00471         SetDParamStr(0, AIConfig::GetConfig((CompanyID)i)->GetInfo()->GetName());
    00472         text = STR_JUST_RAW_STRING;
    00473       } else if (i == 0) {
    00474         text = STR_AI_HUMAN_PLAYER;
    00475       } else {
    00476         text = STR_AI_RANDOM_AI;
    00477       }
    00478       DrawStringTruncated(10, y + 3, text, (this->selected_slot == i) ? TC_WHITE : ((i > _settings_newgame.difficulty.max_no_competitors || i == 0) ? TC_SILVER : TC_ORANGE), this->width - 20);
    00479       y += 14;
    00480     }
    00481   }
    00482
    00483   virtual void OnClick(Point pt, int widget)
    00484   {
    00485     switch (widget) {
    00486       case AIC_WIDGET_BACKGROUND: {
    00487         /* Check if the user clicked on one of the arrows to configure the number of AIs */
    00488         if (IsInsideBS(pt.x, 10, 20) && IsInsideBS(pt.y, 18, 10)) {
    00489           int new_value;
    00490           if (pt.x <= 20) {
    00491             new_value = max(0, _settings_newgame.difficulty.max_no_competitors - 1);
    00492           } else {
    00493             new_value = min(MAX_COMPANIES - 1, _settings_newgame.difficulty.max_no_competitors + 1);
    00494           }
    00495           IConsoleSetSetting("difficulty.max_no_competitors", new_value);
    00496           this->SetDirty();
    00497         }
    00498         break;
    00499       }
    00500
    00501       case AIC_WIDGET_LIST: { // Select a slot
    00502         uint slot = (pt.y - this->widget[AIC_WIDGET_LIST].top) / 14 + this->vscroll.pos;
    00503
    00504         if (slot == 0 || slot > _settings_newgame.difficulty.max_no_competitors) slot = INVALID_COMPANY;
    00505         this->selected_slot = (CompanyID)slot;
    00506         this->SetDirty();
    00507         break;
    00508       }
    00509
    00510       case AIC_WIDGET_CHANGE:  // choose other AI
    00511         ShowAIListWindow((CompanyID)this->selected_slot);
    00512         break;
    00513
    00514       case AIC_WIDGET_CONFIGURE: // change the settings for an AI
    00515         ShowAISettingsWindow((CompanyID)this->selected_slot);
    00516         break;
    00517
    00518       case AIC_WIDGET_CLOSE:
    00519         delete this;
    00520         break;
    00521     }
    00522   }
    00523
    00524   virtual void OnDoubleClick(Point pt, int widget)
    00525   {
    00526     switch (widget) {
    00527       case AIC_WIDGET_LIST:
    00528         this->OnClick(pt, widget);
    00529         if (this->selected_slot != INVALID_COMPANY) ShowAIListWindow((CompanyID)this->selected_slot);
    00530         break;
    00531     }
    00532   }
    00533
    00534   virtual void OnResize(Point new_size, Point delta)
    00535   {
    00536     this->vscroll.cap += delta.y / 14;
    00537     this->widget[AIC_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
    00538   }
    00539
    00540   virtual void OnTick()
    00541   {
    00542     if (--this->timeout == 0) {
    00543       this->clicked_button = false;
    00544       this->SetDirty();
    00545     }
    00546   }
    00547 };
    00548
    00549 void ShowAIConfigWindow()
    00550 {
    00551   DeleteWindowById(WC_GAME_OPTIONS, 0);
    00552   new AIConfigWindow();
    00553 }
    00554
    00555 struct AIDebugWindow : public Window {
    00556   enum AIDebugWindowWidgets {
    00557     AID_WIDGET_CLOSEBOX = 0,
    00558     AID_WIDGET_CAPTION,
    00559     AID_WIDGET_VIEW,
    00560     AID_WIDGET_NAME_TEXT,
    00561     AID_WIDGET_RELOAD_TOGGLE,
    00562     AID_WIDGET_LOG_PANEL,
    00563     AID_WIDGET_SCROLLBAR,
    00564     AID_WIDGET_UNUSED_1,
    00565     AID_WIDGET_UNUSED_2,
    00566     AID_WIDGET_UNUSED_3,
    00567     AID_WIDGET_UNUSED_4,
    00568     AID_WIDGET_UNUSED_5,
    00569     AID_WIDGET_UNUSED_6,
    00570     AID_WIDGET_UNUSED_7,
    00571
    00572     AID_WIDGET_COMPANY_BUTTON_START,
    00573     AID_WIDGET_COMPANY_BUTTON_END = AID_WIDGET_COMPANY_BUTTON_START + 14,
    00574   };
    00575
    00576   static CompanyID ai_debug_company;
    00577   int redraw_timer;
    00578
    00579   AIDebugWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
    00580   {
    00581     /* Disable the companies who are not active or not an AI */
    00582     for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
    00583       this->SetWidgetDisabledState(i + AID_WIDGET_COMPANY_BUTTON_START, !IsValidCompanyID(i) || !GetCompany(i)->is_ai);
    00584     }
    00585     this->DisableWidget(AID_WIDGET_RELOAD_TOGGLE);
    00586
    00587     this->vscroll.cap = 14;
    00588     this->vscroll.pos = 0;
    00589     this->resize.step_height = 12;
    00590
    00591     if (ai_debug_company != INVALID_COMPANY) this->LowerWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
    00592
    00593     this->FindWindowPlacementAndResize(desc);
    00594   }
    00595
    00596   virtual void OnPaint()
    00597   {
    00598     /* Check if the currently selected company is still active. */
    00599     if (ai_debug_company == INVALID_COMPANY || !IsValidCompanyID(ai_debug_company)) {
    00600       if (ai_debug_company != INVALID_COMPANY) {
    00601         /* Raise and disable the widget for the previous selection. */
    00602         this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
    00603         this->DisableWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
    00604
    00605         ai_debug_company = INVALID_COMPANY;
    00606       }
    00607
    00608       for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
    00609         if (IsValidCompanyID(i) && GetCompany(i)->is_ai) {
    00610           /* Lower the widget corresponding to this company. */
    00611           this->LowerWidget(i + AID_WIDGET_COMPANY_BUTTON_START);
    00612
    00613           ai_debug_company = i;
    00614           break;
    00615         }
    00616       }
    00617     }
    00618
    00619     /* Update "Reload AI" button */
    00620     this->SetWidgetDisabledState(AID_WIDGET_RELOAD_TOGGLE, ai_debug_company == INVALID_COMPANY);
    00621
    00622     /* Draw standard stuff */
    00623     this->DrawWidgets();
    00624
    00625     /* If there are no active companies, don't display anything else. */
    00626     if (ai_debug_company == INVALID_COMPANY) return;
    00627
    00628     /* Paint the company icons */
    00629     for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
    00630       if (!IsValidCompanyID(i) || !GetCompany(i)->is_ai) {
    00631         /* Check if we have the company as an active company */
    00632         if (!this->IsWidgetDisabled(i + AID_WIDGET_COMPANY_BUTTON_START)) {
    00633           /* Bah, company gone :( */
    00634           this->DisableWidget(i + AID_WIDGET_COMPANY_BUTTON_START);
    00635
    00636           /* We need a repaint */
    00637           this->SetDirty();
    00638         }
    00639         continue;
    00640       }
    00641
    00642       /* Check if we have the company marked as inactive */
    00643       if (this->IsWidgetDisabled(i + AID_WIDGET_COMPANY_BUTTON_START)) {
    00644         /* New AI! Yippie :p */
    00645         this->EnableWidget(i + AID_WIDGET_COMPANY_BUTTON_START);
    00646
    00647         /* We need a repaint */
    00648         this->SetDirty();
    00649       }
    00650
    00651       byte x = (i == ai_debug_company) ? 1 : 0;
    00652       DrawCompanyIcon(i, (i % 8) * 37 + 13 + x, (i < 8 ? 0 : 13) + 16 + x);
    00653     }
    00654
    00655     /* Draw the AI name */
    00656     AIInfo *info = GetCompany(ai_debug_company)->ai_info;
    00657     assert(info != NULL);
    00658     char name[1024];
    00659     snprintf(name, sizeof(name), "%s (v%d)", info->GetName(), info->GetVersion());
    00660     DoDrawString(name, 7, 47, TC_BLACK);
    00661
    00662     CompanyID old_company = _current_company;
    00663     _current_company = ai_debug_company;
    00664     AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
    00665     _current_company = old_company;
    00666
    00667     SetVScrollCount(this, (log == NULL) ? 0 : log->used);
    00668     this->InvalidateWidget(AID_WIDGET_SCROLLBAR);
    00669     if (log == NULL) return;
    00670
    00671     int y = 6;
    00672     for (int i = this->vscroll.pos; i < (this->vscroll.cap + this->vscroll.pos); i++) {
    00673       uint pos = (log->count + log->pos - i) % log->count;
    00674       if (log->lines[pos] == NULL) break;
    00675
    00676       TextColour colour;
    00677       switch (log->type[pos]) {
    00678         case AILog::LOG_SQ_INFO:  colour = TC_BLACK;  break;
    00679         case AILog::LOG_SQ_ERROR: colour = TC_RED;    break;
    00680         case AILog::LOG_INFO:     colour = TC_BLACK;  break;
    00681         case AILog::LOG_WARNING:  colour = TC_YELLOW; break;
    00682         case AILog::LOG_ERROR:    colour = TC_RED;    break;
    00683         default:                  colour = TC_BLACK;  break;
    00684       }
    00685
    00686       DoDrawStringTruncated(log->lines[pos], 7, this->widget[AID_WIDGET_LOG_PANEL].top + y, colour, this->widget[AID_WIDGET_LOG_PANEL].right - this->widget[AID_WIDGET_LOG_PANEL].left - 14);
    00687       y += 12;
    00688     }
    00689   }
    00690
    00691   void ChangeToAI(CompanyID show_ai)
    00692   {
    00693     this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
    00694     ai_debug_company = show_ai;
    00695     this->LowerWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
    00696     this->SetDirty();
    00697   }
    00698
    00699   virtual void OnClick(Point pt, int widget)
    00700   {
    00701     /* Check which button is clicked */
    00702     if (IsInsideMM(widget, AID_WIDGET_COMPANY_BUTTON_START, AID_WIDGET_COMPANY_BUTTON_END + 1)) {
    00703       /* Is it no on disable? */
    00704       if (!this->IsWidgetDisabled(widget)) {
    00705         ChangeToAI((CompanyID)(widget - AID_WIDGET_COMPANY_BUTTON_START));
    00706       }
    00707     }
    00708     if (widget == AID_WIDGET_RELOAD_TOGGLE && !this->IsWidgetDisabled(widget)) {
    00709       /* First kill the company of the AI, then start a new one. This should start the current AI again */
    00710       DoCommandP(0, 2, ai_debug_company, CMD_COMPANY_CTRL);
    00711       DoCommandP(0, 1, 0, CMD_COMPANY_CTRL);
    00712     }
    00713   }
    00714
    00715   virtual void OnTimeout()
    00716   {
    00717     this->RaiseWidget(AID_WIDGET_RELOAD_TOGGLE);
    00718     this->SetDirty();
    00719   }
    00720
    00721   virtual void OnInvalidateData(int data = 0)
    00722   {
    00723     if (data == -1 || ai_debug_company == data) this->SetDirty();
    00724   }
    00725
    00726   virtual void OnResize(Point new_size, Point delta)
    00727   {
    00728     this->vscroll.cap += delta.y / (int)this->resize.step_height;
    00729   }
    00730 };
    00731
    00732 CompanyID AIDebugWindow::ai_debug_company = INVALID_COMPANY;
    00733
    00734 static const Widget _ai_debug_widgets[] = {
    00735 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},                 // AID_WIDGET_CLOSEBOX
    00736 {    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_GREY,    11,   298,     0,    13, STR_AI_DEBUG,               STR_018C_WINDOW_TITLE_DRAG_THIS},       // AID_WIDGET_CAPTION
    00737 {      WWT_PANEL,  RESIZE_RIGHT,  COLOUR_GREY,     0,   298,    14,    40, 0x0,                        STR_NULL},                              // AID_WIDGET_VIEW
    00738
    00739 {      WWT_PANEL,  RESIZE_RIGHT,  COLOUR_GREY,     0,   149,    41,    60, 0x0,                        STR_AI_DEBUG_NAME_TIP},                 // AID_WIDGET_NAME_TEXT
    00740 { WWT_PUSHTXTBTN,     RESIZE_LR,  COLOUR_GREY,   150,   298,    41,    60, STR_AI_DEBUG_RELOAD,        STR_AI_DEBUG_RELOAD_TIP},               // AID_WIDGET_RELOAD_TOGGLE
    00741 {      WWT_PANEL,     RESIZE_RB,  COLOUR_GREY,     0,   286,    61,   240, 0x0,                        STR_NULL},                              // AID_WIDGET_LOG_PANEL
    00742 {  WWT_SCROLLBAR,    RESIZE_LRB,  COLOUR_GREY,   287,   298,    61,   228, STR_NULL,                   STR_0190_SCROLL_BAR_SCROLLS_LIST},      // AID_WIDGET_SCROLLBAR
    00743 /* As this is WIP, leave the next few so we can work a bit with the GUI */
    00744 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   101,   120, 0x0,                        STR_NULL},                              // AID_WIDGET_UNUSED_1
    00745 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   121,   140, 0x0,                        STR_NULL},                              // AID_WIDGET_UNUSED_2
    00746 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   141,   160, 0x0,                        STR_NULL},                              // AID_WIDGET_UNUSED_3
    00747 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   161,   180, 0x0,                        STR_NULL},                              // AID_WIDGET_UNUSED_4
    00748 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   181,   200, 0x0,                        STR_NULL},                              // AID_WIDGET_UNUSED_5
    00749 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   201,   220, 0x0,                        STR_NULL},                              // AID_WIDGET_UNUSED_6
    00750 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   221,   240, 0x0,                        STR_NULL},                              // AID_WIDGET_UNUSED_7
    00751
    00752 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,    38,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, // AID_WIDGET_COMPANY_BUTTON_START
    00753 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    39,    75,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00754 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    76,   112,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00755 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   113,   149,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00756 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   150,   186,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00757 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   187,   223,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00758 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   224,   260,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00759 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   261,   297,    14,    26, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00760 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,    38,    27,    39, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00761 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    39,    75,    27,    39, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00762 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    76,   112,    27,    39, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00763 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   113,   149,    27,    39, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00764 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   150,   186,    27,    39, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00765 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   187,   223,    27,    39, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00766 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   224,   260,    27,    39, 0x0,                        STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY}, // AID_WIDGET_COMPANY_BUTTON_END
    00767 {  WWT_RESIZEBOX,   RESIZE_LRTB,  COLOUR_GREY,   287,   298,   229,   240, STR_NULL,                   STR_RESIZE_BUTTON},
    00768 {   WIDGETS_END},
    00769 };
    00770
    00771 static const WindowDesc _ai_debug_desc(
    00772   WDP_AUTO, WDP_AUTO, 299, 241, 299, 241,
    00773   WC_AI_DEBUG, WC_NONE,
    00774   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
    00775   _ai_debug_widgets
    00776 );
    00777
    00778 void ShowAIDebugWindow(CompanyID show_company)
    00779 {
    00780   if (!_networking || _network_server) {
    00781     AIDebugWindow *w = (AIDebugWindow *)BringWindowToFrontById(WC_AI_DEBUG, 0);
    00782     if (w == NULL) w = new AIDebugWindow(&_ai_debug_desc, 0);
    00783     if (show_company != INVALID_COMPANY) w->ChangeToAI(show_company);
    00784   } else {
    00785     ShowErrorMessage(INVALID_STRING_ID, STR_AI_DEBUG_SERVER_ONLY, 0, 0);
    00786   }
    00787 }