00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "debug.h"
00008 #include "gui.h"
00009 #include "window_gui.h"
00010 #include "textbuf_gui.h"
00011 #include "command_func.h"
00012 #include "viewport_func.h"
00013 #include "gfx_func.h"
00014 #include "industry.h"
00015 #include "town.h"
00016 #include "variables.h"
00017 #include "cargotype.h"
00018 #include "newgrf.h"
00019 #include "newgrf_callbacks.h"
00020 #include "newgrf_industries.h"
00021 #include "newgrf_text.h"
00022 #include "strings_func.h"
00023 #include "map_func.h"
00024 #include "player_func.h"
00025 #include "settings_type.h"
00026
00027 #include "table/strings.h"
00028 #include "table/sprites.h"
00029
00030 bool _ignore_restrictions;
00031
00033 enum DynamicPlaceIndustriesWidgets {
00034 DPIW_CLOSEBOX = 0,
00035 DPIW_CAPTION,
00036 DPIW_MATRIX_WIDGET,
00037 DPIW_SCROLLBAR,
00038 DPIW_INFOPANEL,
00039 DPIW_FUND_WIDGET,
00040 DPIW_RESIZE_WIDGET,
00041 };
00042
00044 struct fnd_d {
00045 int index;
00046 IndustryType select;
00047 uint16 callback_timer;
00048 bool timer_enabled;
00049 };
00050 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(fnd_d));
00051
00053 static struct IndustryData {
00054 uint16 count;
00055 IndustryType index[NUM_INDUSTRYTYPES + 1];
00056 StringID text[NUM_INDUSTRYTYPES + 1];
00057 bool enabled[NUM_INDUSTRYTYPES + 1];
00058 } _fund_gui;
00059
00060 assert_compile(lengthof(_fund_gui.index) == lengthof(_fund_gui.text));
00061 assert_compile(lengthof(_fund_gui.index) == lengthof(_fund_gui.enabled));
00062
00063 static void SetupFundArrays(Window *w)
00064 {
00065 IndustryType ind;
00066 const IndustrySpec *indsp;
00067
00068 _fund_gui.count = 0;
00069
00070 for (uint i = 0; i < lengthof(_fund_gui.index); i++) {
00071 _fund_gui.index[i] = INVALID_INDUSTRYTYPE;
00072 _fund_gui.text[i] = STR_NULL;
00073 _fund_gui.enabled[i] = false;
00074 }
00075
00076 if (_game_mode == GM_EDITOR) {
00077 _fund_gui.index[_fund_gui.count] = INVALID_INDUSTRYTYPE;
00078 _fund_gui.count++;
00079 WP(w, fnd_d).timer_enabled = false;
00080 }
00081
00082
00083
00084
00085 for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
00086 indsp = GetIndustrySpec(ind);
00087 if (indsp->enabled){
00088
00089
00090
00091 if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) {
00092
00093 if (WP(w, fnd_d).select == ind) WP(w, fnd_d).index = -1;
00094 continue;
00095 }
00096 _fund_gui.index[_fund_gui.count] = ind;
00097 _fund_gui.enabled[_fund_gui.count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
00098
00099 if (WP(w, fnd_d).select == ind) WP(w, fnd_d).index = _fund_gui.count;
00100 _fund_gui.count++;
00101 }
00102 }
00103
00104
00105
00106 if (WP(w, fnd_d).index == -1) {
00107 WP(w, fnd_d).index = 0;
00108 WP(w, fnd_d).select = _fund_gui.index[0];
00109 }
00110 }
00111
00112 static void BuildDynamicIndustryWndProc(Window *w, WindowEvent *e)
00113 {
00114 switch (e->event) {
00115 case WE_CREATE: {
00116
00117
00118
00119 if (!_loaded_newgrf_features.has_newindustries) {
00120 w->widget[DPIW_INFOPANEL].bottom -= 44;
00121 w->widget[DPIW_FUND_WIDGET].bottom -= 44;
00122 w->widget[DPIW_FUND_WIDGET].top -= 44;
00123 w->widget[DPIW_RESIZE_WIDGET].bottom -= 44;
00124 w->widget[DPIW_RESIZE_WIDGET].top -= 44;
00125 w->resize.height = w->height -= 44;
00126 }
00127
00128 WP(w, fnd_d).timer_enabled = _loaded_newgrf_features.has_newindustries;
00129
00130 w->vscroll.cap = 8;
00131 w->resize.step_height = 13;
00132
00133 WP(w, fnd_d).index = -1;
00134 WP(w, fnd_d).select = INVALID_INDUSTRYTYPE;
00135
00136
00137 SetupFundArrays(w);
00138
00139 WP(w, fnd_d).callback_timer = DAY_TICKS;
00140 } break;
00141
00142 case WE_PAINT: {
00143 const IndustrySpec *indsp = (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(WP(w, fnd_d).select);
00144 int x_str = w->widget[DPIW_INFOPANEL].left + 3;
00145 int y_str = w->widget[DPIW_INFOPANEL].top + 3;
00146 const Widget *wi = &w->widget[DPIW_INFOPANEL];
00147 int max_width = wi->right - wi->left - 4;
00148
00149
00150
00151 if (_game_mode == GM_EDITOR) {
00152
00153 if (indsp == NULL) _fund_gui.enabled[WP(w, fnd_d).index] = _opt.diff.number_industries != 0;
00154 w->widget[DPIW_FUND_WIDGET].data = STR_BUILD_NEW_INDUSTRY;
00155 } else {
00156 w->widget[DPIW_FUND_WIDGET].data = (_patches.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_PROSPECT_NEW_INDUSTRY : STR_FUND_NEW_INDUSTRY;
00157 }
00158 w->SetWidgetDisabledState(DPIW_FUND_WIDGET, !_fund_gui.enabled[WP(w, fnd_d).index]);
00159
00160 SetVScrollCount(w, _fund_gui.count);
00161
00162 DrawWindowWidgets(w);
00163
00164
00165 for (byte i = 0; i < w->vscroll.cap && ((i + w->vscroll.pos) < _fund_gui.count); i++) {
00166 int offset = i * 13;
00167 int x = 3;
00168 int y = 16;
00169 bool selected = WP(w, fnd_d).index == i + w->vscroll.pos;
00170
00171 if (_fund_gui.index[i + w->vscroll.pos] == INVALID_INDUSTRYTYPE) {
00172 DrawStringTruncated(20, y + offset, STR_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE, max_width - 25);
00173 continue;
00174 }
00175 const IndustrySpec *indsp = GetIndustrySpec(_fund_gui.index[i + w->vscroll.pos]);
00176
00177
00178 DrawStringTruncated(20, y + offset, indsp->name, selected ? TC_WHITE : TC_ORANGE, max_width - 25);
00179 GfxFillRect(x, y + 1 + offset, x + 10, y + 7 + offset, selected ? 15 : 0);
00180 GfxFillRect(x + 1, y + 2 + offset, x + 9, y + 6 + offset, indsp->map_colour);
00181 }
00182
00183 if (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) {
00184 DrawStringMultiLine(x_str, y_str, STR_RANDOM_INDUSTRIES_TIP, max_width, wi->bottom - wi->top - 40);
00185 break;
00186 }
00187
00188 if (_game_mode != GM_EDITOR) {
00189 SetDParam(0, indsp->GetConstructionCost());
00190 DrawStringTruncated(x_str, y_str, STR_482F_COST, TC_FROMSTRING, max_width);
00191 y_str += 11;
00192 }
00193
00194
00195 StringID str = STR_4827_REQUIRES;
00196 byte p = 0;
00197 SetDParam(0, STR_00D0_NOTHING);
00198 for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) {
00199 if (indsp->accepts_cargo[j] == CT_INVALID) continue;
00200 if (p > 0) str++;
00201 SetDParam(p++, GetCargo(indsp->accepts_cargo[j])->name);
00202 }
00203 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width);
00204 y_str += 11;
00205
00206
00207 str = STR_4827_PRODUCES;
00208 p = 0;
00209 SetDParam(0, STR_00D0_NOTHING);
00210 for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) {
00211 if (indsp->produced_cargo[j] == CT_INVALID) continue;
00212 if (p > 0) str++;
00213 SetDParam(p++, GetCargo(indsp->produced_cargo[j])->name);
00214 }
00215 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width);
00216 y_str += 11;
00217
00218
00219 if (_fund_gui.text[WP(w, fnd_d).index] == STR_NULL) {
00220 if (HasBit(indsp->callback_flags, CBM_IND_FUND_MORE_TEXT)) {
00221 uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, WP(w, fnd_d).select, INVALID_TILE);
00222 if (callback_res != CALLBACK_FAILED) {
00223 StringID newtxt = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res);
00224 _fund_gui.text[WP(w, fnd_d).index] = newtxt;
00225 }
00226 }
00227 }
00228
00229
00230
00231 str = _fund_gui.text[WP(w, fnd_d).index];
00232 if (str != STR_NULL && str != STR_UNDEFINED) {
00233 SetDParam(0, str);
00234 DrawStringMultiLine(x_str, y_str, STR_JUST_STRING, max_width, wi->bottom - wi->top - 40);
00235 }
00236 } break;
00237
00238 case WE_DOUBLE_CLICK:
00239 if (e->we.click.widget != DPIW_MATRIX_WIDGET) break;
00240 e->we.click.widget = DPIW_FUND_WIDGET;
00241
00242
00243 case WE_CLICK:
00244 switch (e->we.click.widget) {
00245 case DPIW_MATRIX_WIDGET: {
00246 const IndustrySpec *indsp;
00247 int y = (e->we.click.pt.y - w->widget[DPIW_MATRIX_WIDGET].top) / 13 + w->vscroll.pos ;
00248
00249 if (y >= 0 && y < _fund_gui.count) {
00250 WP(w, fnd_d).index = y;
00251 WP(w, fnd_d).select = _fund_gui.index[WP(w, fnd_d).index];
00252 indsp = (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(WP(w, fnd_d).select);
00253
00254 SetWindowDirty(w);
00255
00256 if ((_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) ||
00257 WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) {
00258
00259 w->RaiseButtons();
00260 ResetObjectToPlace();
00261 }
00262 }
00263 } break;
00264
00265 case DPIW_FUND_WIDGET: {
00266 if (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) {
00267 w->HandleButtonClick(DPIW_FUND_WIDGET);
00268
00269 if (GetNumTowns() == 0) {
00270 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_CAN_T_GENERATE_INDUSTRIES, 0, 0);
00271 } else {
00272 extern void GenerateIndustries();
00273 _generating_world = true;
00274 GenerateIndustries();
00275 _generating_world = false;
00276 }
00277 } else if (_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && GetIndustrySpec(WP(w, fnd_d).select)->IsRawIndustry()) {
00278 DoCommandP(0, WP(w, fnd_d).select, InteractiveRandom(), NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY));
00279 w->HandleButtonClick(DPIW_FUND_WIDGET);
00280 } else {
00281 HandlePlacePushButton(w, DPIW_FUND_WIDGET, SPR_CURSOR_INDUSTRY, VHM_RECT, NULL);
00282 }
00283 } break;
00284 }
00285 break;
00286
00287 case WE_RESIZE: {
00288
00289 w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
00290 w->widget[DPIW_MATRIX_WIDGET].data = (w->vscroll.cap << 8) + 1;
00291 } break;
00292
00293 case WE_PLACE_OBJ: {
00294 bool success = true;
00295
00296 const IndustrySpec *indsp = GetIndustrySpec(WP(w, fnd_d).select);
00297 uint32 seed = InteractiveRandom();
00298
00299 if (_game_mode == GM_EDITOR) {
00300
00301 if (GetNumTowns() == 0) {
00302 SetDParam(0, indsp->name);
00303 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y);
00304 return;
00305 }
00306
00307 _current_player = OWNER_NONE;
00308 _generating_world = true;
00309 _ignore_restrictions = true;
00310 success = DoCommandP(e->we.place.tile, (InteractiveRandomRange(indsp->num_table) << 16) | WP(w, fnd_d).select, seed, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY));
00311 if (!success) {
00312 SetDParam(0, indsp->name);
00313 ShowErrorMessage(_error_message, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y);
00314 }
00315
00316 _ignore_restrictions = false;
00317 _generating_world = false;
00318 } else {
00319 success = DoCommandP(e->we.place.tile, (InteractiveRandomRange(indsp->num_table) << 16) | WP(w, fnd_d).select, seed, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY));
00320 }
00321
00322
00323 if (success) ResetObjectToPlace();
00324 } break;
00325
00326 case WE_TICK:
00327 if (_pause_game != 0) break;
00328 if (!WP(w, fnd_d).timer_enabled) break;
00329 if (--WP(w, fnd_d).callback_timer == 0) {
00330
00331
00332 WP(w, fnd_d).callback_timer = DAY_TICKS;
00333
00334 const IndustrySpec *indsp = GetIndustrySpec(WP(w, fnd_d).select);
00335
00336 if (indsp->enabled) {
00337 bool call_back_result = CheckIfCallBackAllowsAvailability(WP(w, fnd_d).select, IACT_USERCREATION);
00338
00339
00340 if (call_back_result != _fund_gui.enabled[WP(w, fnd_d).index]) {
00341 _fund_gui.enabled[WP(w, fnd_d).index] = call_back_result;
00342 SetWindowDirty(w);
00343 }
00344 }
00345 }
00346 break;
00347
00348 case WE_TIMEOUT:
00349 case WE_ABORT_PLACE_OBJ:
00350 w->RaiseButtons();
00351 break;
00352
00353 case WE_INVALIDATE_DATA:
00354 SetupFundArrays(w);
00355 SetWindowDirty(w);
00356 }
00357 }
00358
00360 static const Widget _build_dynamic_industry_widgets[] = {
00361 { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00362 { WWT_CAPTION, RESIZE_RIGHT, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
00363 { WWT_MATRIX, RESIZE_RB, 7, 0, 157, 14, 118, 0x801, STR_INDUSTRY_SELECTION_HINT},
00364 { WWT_SCROLLBAR, RESIZE_LRB, 7, 158, 169, 14, 118, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00365 { WWT_PANEL, RESIZE_RTB, 7, 0, 169, 119, 199, 0x0, STR_NULL},
00366 { WWT_TEXTBTN, RESIZE_RTB, 7, 0, 157, 200, 211, STR_FUND_NEW_INDUSTRY, STR_NULL},
00367 { WWT_RESIZEBOX, RESIZE_LRTB, 7, 158, 169, 200, 211, 0x0, STR_RESIZE_BUTTON},
00368 { WIDGETS_END},
00369 };
00370
00372 static const WindowDesc _build_industry_dynamic_desc = {
00373 WDP_AUTO, WDP_AUTO, 170, 212, 170, 212,
00374 WC_BUILD_INDUSTRY, WC_NONE,
00375 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
00376 _build_dynamic_industry_widgets,
00377 BuildDynamicIndustryWndProc,
00378 };
00379
00380 void ShowBuildIndustryWindow()
00381 {
00382 if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return;
00383 AllocateWindowDescFront(&_build_industry_dynamic_desc, 0);
00384 }
00385
00386 static void UpdateIndustryProduction(Industry *i);
00387
00388 static inline bool isProductionMinimum(const Industry *i, int pt)
00389 {
00390 return i->production_rate[pt] == 0;
00391 }
00392
00393 static inline bool isProductionMaximum(const Industry *i, int pt)
00394 {
00395 return i->production_rate[pt] >= 255;
00396 }
00397
00398 static inline bool IsProductionAlterable(const Industry *i)
00399 {
00400 return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) &&
00401 (i->accepts_cargo[0] == CT_INVALID || i->accepts_cargo[0] == CT_VALUABLES));
00402 }
00403
00405 enum IndustryViewWidgets {
00406 IVW_CLOSEBOX = 0,
00407 IVW_CAPTION,
00408 IVW_STICKY,
00409 IVW_BACKGROUND,
00410 IVW_VIEWPORT,
00411 IVW_INFO,
00412 IVW_GOTO,
00413 IVW_SPACER,
00414 IVW_RESIZE_WIDGET,
00415 };
00416
00418 struct indview_d : public vp_d {
00419 byte editbox_line;
00420 byte clicked_line;
00421 byte clicked_button;
00422 byte production_offset_y;
00423 };
00424 assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(indview_d));
00425
00426
00427 static void IndustryViewWndProc(Window *w, WindowEvent *e)
00428 {
00429 switch (e->event) {
00430 case WE_CREATE: {
00431
00432 const Industry *i = GetIndustry(w->window_number);
00433 const IndustrySpec *ind = GetIndustrySpec(i->type);
00434 int lines = -3;
00435 bool first = true;
00436 bool has_accept = false;
00437
00438 if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) {
00439 for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
00440 if (i->accepts_cargo[j] == CT_INVALID) continue;
00441 has_accept = true;
00442 if (first) {
00443 lines++;
00444 first = false;
00445 }
00446 lines++;
00447 }
00448 } else {
00449 for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
00450 if (i->accepts_cargo[j] == CT_INVALID) continue;
00451 has_accept = true;
00452 lines++;
00453 break;
00454 }
00455 }
00456
00457 first = true;
00458 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
00459 if (i->produced_cargo[j] == CT_INVALID) continue;
00460 if (first) {
00461 if (has_accept) lines++;
00462 lines++;
00463 first = false;
00464 }
00465 lines++;
00466 }
00467
00468 if (HasBit(ind->callback_flags, CBM_IND_WINDOW_MORE_TEXT)) {
00469 lines += 2;
00470 } else {
00471
00472 for (byte j = IVW_INFO; j <= IVW_RESIZE_WIDGET; j++) {
00473 w->widget[j].display_flags = RESIZE_NONE;
00474 }
00475
00476 w->HideWidget(IVW_RESIZE_WIDGET);
00477 w->widget[IVW_SPACER].right = w->widget[IVW_RESIZE_WIDGET].right;
00478 }
00479
00480 lines *= 10;
00481
00482
00483 for (byte j = IVW_INFO; j <= IVW_RESIZE_WIDGET; j++) {
00484 if (j != IVW_INFO) w->widget[j].top += lines;
00485 w->widget[j].bottom += lines;
00486 }
00487 w->height += lines;
00488 w->resize.height += lines;
00489 } break;
00490
00491 case WE_PAINT: {
00492 Industry *i = GetIndustry(w->window_number);
00493 const IndustrySpec *ind = GetIndustrySpec(i->type);
00494 int y = 111;
00495 bool first = true;
00496 bool has_accept = false;
00497
00498 SetDParam(0, w->window_number);
00499 DrawWindowWidgets(w);
00500
00501 if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) {
00502 for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
00503 if (i->accepts_cargo[j] == CT_INVALID) continue;
00504 has_accept = true;
00505 if (first) {
00506 DrawString(2, y, STR_INDUSTRY_WINDOW_WAITING_FOR_PROCESSING, TC_FROMSTRING);
00507 y += 10;
00508 first = false;
00509 }
00510 SetDParam(0, i->accepts_cargo[j]);
00511 SetDParam(1, i->incoming_cargo_waiting[j]);
00512 DrawString(4, y, STR_INDUSTRY_WINDOW_WAITING_STOCKPILE_CARGO, TC_FROMSTRING);
00513 y += 10;
00514 }
00515 } else {
00516 StringID str = STR_4827_REQUIRES;
00517 byte p = 0;
00518 for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
00519 if (i->accepts_cargo[j] == CT_INVALID) continue;
00520 has_accept = true;
00521 if (p > 0) str++;
00522 SetDParam(p++, GetCargo(i->accepts_cargo[j])->name);
00523 }
00524 if (has_accept) {
00525 DrawString(2, y, str, TC_FROMSTRING);
00526 y += 10;
00527 }
00528 }
00529
00530 first = true;
00531 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
00532 if (i->produced_cargo[j] == CT_INVALID) continue;
00533 if (first) {
00534 if (has_accept) y += 10;
00535 DrawString(2, y, STR_482A_PRODUCTION_LAST_MONTH, TC_FROMSTRING);
00536 y += 10;
00537 WP(w, indview_d).production_offset_y = y;
00538 first = false;
00539 }
00540
00541 SetDParam(0, i->produced_cargo[j]);
00542 SetDParam(1, i->last_month_production[j]);
00543
00544 SetDParam(2, i->last_month_pct_transported[j] * 100 >> 8);
00545 DrawString(4 + (IsProductionAlterable(i) ? 30 : 0), y, STR_482B_TRANSPORTED, TC_FROMSTRING);
00546
00547 if (IsProductionAlterable(i)) {
00548 DrawArrowButtons(5, y, 3, (WP(w, indview_d).clicked_line == j + 1) ? WP(w, indview_d).clicked_button : 0,
00549 !isProductionMinimum(i, j), !isProductionMaximum(i, j));
00550 }
00551 y += 10;
00552 }
00553
00554
00555 if (HasBit(ind->callback_flags, CBM_IND_WINDOW_MORE_TEXT)) {
00556 uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->xy);
00557 if (callback_res != CALLBACK_FAILED) {
00558 StringID message = GetGRFStringID(ind->grf_prop.grffile->grfid, 0xD000 + callback_res);
00559 if (message != STR_NULL && message != STR_UNDEFINED) {
00560 const Widget *wi = &w->widget[IVW_INFO];
00561 y += 10;
00562
00563 PrepareTextRefStackUsage(6);
00564
00565 DrawStringMultiLine(2, y, message, wi->right - wi->left - 4, wi->bottom - y);
00566 StopTextRefStackUsage();
00567 }
00568 }
00569 }
00570
00571 DrawWindowViewport(w);
00572 } break;
00573
00574 case WE_CLICK: {
00575 Industry *i;
00576
00577 switch (e->we.click.widget) {
00578 case IVW_INFO: {
00579 int line, x;
00580
00581 i = GetIndustry(w->window_number);
00582
00583
00584 if (!IsProductionAlterable(i)) return;
00585 x = e->we.click.pt.x;
00586 line = (e->we.click.pt.y - WP(w, indview_d).production_offset_y) / 10;
00587 if (e->we.click.pt.y >= WP(w, indview_d).production_offset_y && IsInsideMM(line, 0, 2) && i->produced_cargo[line] != CT_INVALID) {
00588 if (IsInsideMM(x, 5, 25) ) {
00589
00590 if (x < 15) {
00591 if (isProductionMinimum(i, line)) return;
00592 i->production_rate[line] = max(i->production_rate[line] / 2, 0);
00593 } else {
00594
00595 int new_prod = i->production_rate[line] == 0 ? 1 : i->production_rate[line] * 2;
00596 if (isProductionMaximum(i, line)) return;
00597 i->production_rate[line] = minu(new_prod, 255);
00598 }
00599
00600 UpdateIndustryProduction(i);
00601 SetWindowDirty(w);
00602 w->flags4 |= 5 << WF_TIMEOUT_SHL;
00603 WP(w, indview_d).clicked_line = line + 1;
00604 WP(w, indview_d).clicked_button = (x < 15 ? 1 : 2);
00605 } else if (IsInsideMM(x, 34, 160)) {
00606
00607 WP(w, indview_d).editbox_line = line;
00608 SetDParam(0, i->production_rate[line] * 8);
00609 ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_GAME_PRODUCTION, 10, 100, w, CS_ALPHANUMERAL);
00610 }
00611 }
00612 } break;
00613 case IVW_GOTO:
00614 i = GetIndustry(w->window_number);
00615 ScrollMainWindowToTile(i->xy + TileDiffXY(1, 1));
00616 } break;
00617
00618 }
00619 break;
00620 case WE_TIMEOUT:
00621 WP(w, indview_d).clicked_line = 0;
00622 WP(w, indview_d).clicked_button = 0;
00623 SetWindowDirty(w);
00624 break;
00625
00626 case WE_ON_EDIT_TEXT:
00627 if (e->we.edittext.str[0] != '\0') {
00628 Industry* i = GetIndustry(w->window_number);
00629 int line = WP(w, indview_d).editbox_line;
00630
00631 i->production_rate[line] = ClampU(atoi(e->we.edittext.str), 0, 255);
00632 UpdateIndustryProduction(i);
00633 SetWindowDirty(w);
00634 }
00635 }
00636 }
00637
00638 static void UpdateIndustryProduction(Industry *i)
00639 {
00640 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
00641 if (i->produced_cargo[j] != CT_INVALID) {
00642 i->last_month_production[j] = 8 * i->production_rate[j];
00643 }
00644 }
00645 }
00646
00648 static const Widget _industry_view_widgets[] = {
00649 { WWT_CLOSEBOX, RESIZE_NONE, 9, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00650 { WWT_CAPTION, RESIZE_NONE, 9, 11, 247, 0, 13, STR_4801, STR_018C_WINDOW_TITLE_DRAG_THIS},
00651 { WWT_STICKYBOX, RESIZE_NONE, 9, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
00652 { WWT_PANEL, RESIZE_NONE, 9, 0, 259, 14, 105, 0x0, STR_NULL},
00653 { WWT_INSET, RESIZE_NONE, 9, 2, 257, 16, 103, 0x0, STR_NULL},
00654 { WWT_PANEL, RESIZE_BOTTOM, 9, 0, 259, 106, 147, 0x0, STR_NULL},
00655 { WWT_PUSHTXTBTN, RESIZE_TB, 9, 0, 129, 148, 159, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON},
00656 { WWT_PANEL, RESIZE_TB, 9, 130, 247, 148, 159, 0x0, STR_NULL},
00657 { WWT_RESIZEBOX, RESIZE_TB, 9, 248, 259, 148, 159, 0x0, STR_RESIZE_BUTTON},
00658 { WIDGETS_END},
00659 };
00660
00662 static const WindowDesc _industry_view_desc = {
00663 WDP_AUTO, WDP_AUTO, 260, 160, 260, 160,
00664 WC_INDUSTRY_VIEW, WC_NONE,
00665 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00666 _industry_view_widgets,
00667 IndustryViewWndProc
00668 };
00669
00670 void ShowIndustryViewWindow(int industry)
00671 {
00672 Window *w = AllocateWindowDescFront(&_industry_view_desc, industry);
00673
00674 if (w != NULL) {
00675 w->flags4 |= WF_DISABLE_VP_SCROLL;
00676 WP(w, indview_d).editbox_line = 0;
00677 WP(w, indview_d).clicked_line = 0;
00678 WP(w, indview_d).clicked_button = 0;
00679 AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetIndustry(w->window_number)->xy + TileDiffXY(1, 1), ZOOM_LVL_INDUSTRY);
00680 }
00681 }
00682
00684 enum IndustryDirectoryWidgets {
00685 IDW_CLOSEBOX = 0,
00686 IDW_CAPTION,
00687 IDW_STICKY,
00688 IDW_SORTBYNAME,
00689 IDW_SORTBYTYPE,
00690 IDW_SORTBYPROD,
00691 IDW_SORTBYTRANSPORT,
00692 IDW_SPACER,
00693 IDW_INDUSRTY_LIST,
00694 IDW_SCROLLBAR,
00695 IDW_RESIZE,
00696 };
00697
00699 static const Widget _industry_directory_widgets[] = {
00700 { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00701 { WWT_CAPTION, RESIZE_NONE, 13, 11, 495, 0, 13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
00702 { WWT_STICKYBOX, RESIZE_NONE, 13, 496, 507, 0, 13, 0x0, STR_STICKY_BUTTON},
00703 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 0, 100, 14, 25, STR_SORT_BY_NAME, STR_SORT_ORDER_TIP},
00704 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 101, 200, 14, 25, STR_SORT_BY_TYPE, STR_SORT_ORDER_TIP},
00705 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 201, 300, 14, 25, STR_SORT_BY_PRODUCTION, STR_SORT_ORDER_TIP},
00706 { WWT_PUSHTXTBTN, RESIZE_NONE, 13, 301, 400, 14, 25, STR_SORT_BY_TRANSPORTED, STR_SORT_ORDER_TIP},
00707 { WWT_PANEL, RESIZE_NONE, 13, 401, 495, 14, 25, 0x0, STR_NULL},
00708 { WWT_PANEL, RESIZE_BOTTOM, 13, 0, 495, 26, 189, 0x0, STR_INDUSTRYDIR_LIST_CAPTION},
00709 { WWT_SCROLLBAR, RESIZE_BOTTOM, 13, 496, 507, 14, 177, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00710 { WWT_RESIZEBOX, RESIZE_TB, 13, 496, 507, 178, 189, 0x0, STR_RESIZE_BUTTON},
00711 { WIDGETS_END},
00712 };
00713
00714 static uint _num_industry_sort;
00715
00716 static char _bufcache[96];
00717 static const Industry* _last_industry;
00718
00719 static byte _industry_sort_order;
00720
00721 static int CDECL GeneralIndustrySorter(const void *a, const void *b)
00722 {
00723 const Industry* i = *(const Industry**)a;
00724 const Industry* j = *(const Industry**)b;
00725 int r;
00726
00727 switch (_industry_sort_order >> 1) {
00728 default: NOT_REACHED();
00729 case 0:
00730 r = 0;
00731 break;
00732
00733 case 1:
00734 r = i->type - j->type;
00735 break;
00736
00737 case 2:
00738 if (i->produced_cargo[0] == CT_INVALID) {
00739 r = (j->produced_cargo[0] == CT_INVALID ? 0 : -1);
00740 } else {
00741 if (j->produced_cargo[0] == CT_INVALID) {
00742 r = 1;
00743 } else {
00744 r =
00745 (i->last_month_production[0] + i->last_month_production[1]) -
00746 (j->last_month_production[0] + j->last_month_production[1]);
00747 }
00748 }
00749 break;
00750
00751 case 3:
00752 if (i->produced_cargo[0] == CT_INVALID) {
00753 r = (j->produced_cargo[0] == CT_INVALID ? 0 : -1);
00754 } else {
00755 if (j->produced_cargo[0] == CT_INVALID) {
00756 r = 1;
00757 } else {
00758 int pi;
00759 int pj;
00760
00761 pi = i->last_month_pct_transported[0] * 100 >> 8;
00762 if (i->produced_cargo[1] != CT_INVALID) {
00763 int p = i->last_month_pct_transported[1] * 100 >> 8;
00764 if (p < pi) pi = p;
00765 }
00766
00767 pj = j->last_month_pct_transported[0] * 100 >> 8;
00768 if (j->produced_cargo[1] != CT_INVALID) {
00769 int p = j->last_month_pct_transported[1] * 100 >> 8;
00770 if (p < pj) pj = p;
00771 }
00772
00773 r = pi - pj;
00774 }
00775 }
00776 break;
00777 }
00778
00779
00780 if (r == 0) {
00781 char buf1[96];
00782
00783 SetDParam(0, i->town->index);
00784 GetString(buf1, STR_TOWN, lastof(buf1));
00785
00786 if (j != _last_industry) {
00787 _last_industry = j;
00788 SetDParam(0, j->town->index);
00789 GetString(_bufcache, STR_TOWN, lastof(_bufcache));
00790 }
00791 r = strcmp(buf1, _bufcache);
00792 }
00793
00794 if (_industry_sort_order & 1) r = -r;
00795 return r;
00796 }
00797
00804 static void MakeSortedIndustryList()
00805 {
00806 const Industry* i;
00807 int n = 0;
00808
00809
00810 _industry_sort = ReallocT(_industry_sort, GetMaxIndustryIndex() + 1);
00811
00812
00813 if (GetNumIndustries() != 0) {
00814 FOR_ALL_INDUSTRIES(i) _industry_sort[n++] = i;
00815 qsort((void*)_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter);
00816 }
00817
00818 _num_industry_sort = n;
00819 _last_industry = NULL;
00820
00821 DEBUG(misc, 3, "Resorting industries list");
00822 }
00823
00824
00825 static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
00826 {
00827 switch (e->event) {
00828 case WE_PAINT: {
00829 if (_industry_sort_dirty) {
00830 _industry_sort_dirty = false;
00831 MakeSortedIndustryList();
00832 }
00833
00834 SetVScrollCount(w, _num_industry_sort);
00835
00836 DrawWindowWidgets(w);
00837 DrawSortButtonState(w, IDW_SORTBYNAME + (_industry_sort_order >> 1), _industry_sort_order & 1 ? SBS_DOWN : SBS_UP);
00838
00839 uint p = w->vscroll.pos;
00840 int n = 0;
00841
00842 while (p < _num_industry_sort) {
00843 const Industry* i = _industry_sort[p];
00844
00845 SetDParam(0, i->index);
00846 if (i->produced_cargo[0] != CT_INVALID) {
00847 SetDParam(1, i->produced_cargo[0]);
00848 SetDParam(2, i->last_month_production[0]);
00849
00850 if (i->produced_cargo[1] != CT_INVALID) {
00851 SetDParam(3, i->produced_cargo[1]);
00852 SetDParam(4, i->last_month_production[1]);
00853 SetDParam(5, i->last_month_pct_transported[0] * 100 >> 8);
00854 SetDParam(6, i->last_month_pct_transported[1] * 100 >> 8);
00855 DrawString(4, 28 + n * 10, STR_INDUSTRYDIR_ITEM_TWO, TC_FROMSTRING);
00856 } else {
00857 SetDParam(3, i->last_month_pct_transported[0] * 100 >> 8);
00858 DrawString(4, 28 + n * 10, STR_INDUSTRYDIR_ITEM, TC_FROMSTRING);
00859 }
00860 } else {
00861 DrawString(4, 28 + n * 10, STR_INDUSTRYDIR_ITEM_NOPROD, TC_FROMSTRING);
00862 }
00863 p++;
00864 if (++n == w->vscroll.cap) break;
00865 }
00866 } break;
00867
00868 case WE_CLICK:
00869 switch (e->we.click.widget) {
00870 case IDW_SORTBYNAME: {
00871 _industry_sort_order = _industry_sort_order == 0 ? 1 : 0;
00872 _industry_sort_dirty = true;
00873 SetWindowDirty(w);
00874 } break;
00875
00876 case IDW_SORTBYTYPE: {
00877 _industry_sort_order = _industry_sort_order == 2 ? 3 : 2;
00878 _industry_sort_dirty = true;
00879 SetWindowDirty(w);
00880 } break;
00881
00882 case IDW_SORTBYPROD: {
00883 _industry_sort_order = _industry_sort_order == 4 ? 5 : 4;
00884 _industry_sort_dirty = true;
00885 SetWindowDirty(w);
00886 } break;
00887
00888 case IDW_SORTBYTRANSPORT: {
00889 _industry_sort_order = _industry_sort_order == 6 ? 7 : 6;
00890 _industry_sort_dirty = true;
00891 SetWindowDirty(w);
00892 } break;
00893
00894 case IDW_INDUSRTY_LIST: {
00895 int y = (e->we.click.pt.y - 28) / 10;
00896 uint16 p;
00897
00898 if (!IsInsideMM(y, 0, w->vscroll.cap)) return;
00899 p = y + w->vscroll.pos;
00900 if (p < _num_industry_sort) {
00901 ScrollMainWindowToTile(_industry_sort[p]->xy);
00902 }
00903 } break;
00904 }
00905 break;
00906
00907 case WE_4:
00908 SetWindowDirty(w);
00909 break;
00910
00911 case WE_RESIZE:
00912 w->vscroll.cap += e->we.sizing.diff.y / 10;
00913 break;
00914 }
00915 }
00916
00918 static const WindowDesc _industry_directory_desc = {
00919 WDP_AUTO, WDP_AUTO, 508, 190, 508, 190,
00920 WC_INDUSTRY_DIRECTORY, WC_NONE,
00921 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00922 _industry_directory_widgets,
00923 IndustryDirectoryWndProc
00924 };
00925
00926 void ShowIndustryDirectory()
00927 {
00928 Window *w = AllocateWindowDescFront(&_industry_directory_desc, 0);
00929
00930 if (w != NULL) {
00931 w->vscroll.cap = 16;
00932 w->resize.height = w->height - 6 * 10;
00933 w->resize.step_height = 10;
00934 SetWindowDirty(w);
00935 }
00936 }