90 if (GB(callback, 0, 8) != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback); |
59 if (GB(callback, 0, 8) != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback); |
91 } |
60 } |
92 return STR_EMPTY; |
61 return STR_EMPTY; |
93 } |
62 } |
94 |
63 |
95 static void BuildDynamicIndustryWndProc(Window *w, WindowEvent *e) |
64 /** Names of the widgets of the dynamic place industries gui */ |
96 { |
65 enum DynamicPlaceIndustriesWidgets { |
97 switch (e->event) { |
66 DPIW_CLOSEBOX = 0, |
98 case WE_CREATE: { |
67 DPIW_CAPTION, |
99 IndustryType ind; |
68 DPIW_MATRIX_WIDGET, |
100 const IndustrySpec *indsp; |
69 DPIW_SCROLLBAR, |
101 |
70 DPIW_INFOPANEL, |
102 /* Shorten the window to the equivalant of the additionnal purchase |
71 DPIW_FUND_WIDGET, |
103 * info coming from the callback. SO it will only be available to tis full |
72 DPIW_RESIZE_WIDGET, |
104 * height when newindistries are loaded */ |
73 }; |
105 if (!_loaded_newgrf_features.has_newindustries) { |
|
106 w->widget[DPIW_INFOPANEL].bottom -= 44; |
|
107 w->widget[DPIW_FUND_WIDGET].bottom -= 44; |
|
108 w->widget[DPIW_FUND_WIDGET].top -= 44; |
|
109 w->widget[DPIW_RESIZE_WIDGET].bottom -= 44; |
|
110 w->widget[DPIW_RESIZE_WIDGET].top -= 44; |
|
111 w->resize.height = w->height -= 44; |
|
112 } |
|
113 |
|
114 WP(w, fnd_d).timer_enabled = _loaded_newgrf_features.has_newindustries; |
|
115 |
|
116 /* Initilialize structures */ |
|
117 _fund_gui.count = 0; |
|
118 |
|
119 for (uint i = 0; i < lengthof(_fund_gui.index); i++) { |
|
120 _fund_gui.index[i] = 0xFF; |
|
121 _fund_gui.text[i] = STR_NULL; |
|
122 _fund_gui.enabled[i] = false; |
|
123 } |
|
124 |
|
125 w->vscroll.cap = 8; // rows in grid, same in scroller |
|
126 w->resize.step_height = 13; |
|
127 |
|
128 if (_game_mode == GM_EDITOR) { // give room for the Many Random "button" |
|
129 _fund_gui.index[_fund_gui.count] = INVALID_INDUSTRYTYPE; |
|
130 _fund_gui.count++; |
|
131 WP(w, fnd_d).timer_enabled = false; |
|
132 } |
|
133 |
|
134 /* Fill the _fund_gui structure with industries. |
|
135 * The tests performed after the enabled allow to load the industries |
|
136 * In the same way they are inserted by grf (if any) |
|
137 */ |
|
138 for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) { |
|
139 indsp = GetIndustrySpec(ind); |
|
140 if (indsp->enabled){ |
|
141 /* Rule is that editor mode loads all industries. |
|
142 * In game mode, all non raw industries are loaded too |
|
143 * and raw ones are loaded only when setting allows it */ |
|
144 if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) continue; |
|
145 _fund_gui.index[_fund_gui.count] = ind; |
|
146 _fund_gui.enabled[_fund_gui.count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION); |
|
147 _fund_gui.count++; |
|
148 } |
|
149 } |
|
150 |
|
151 /* first indutry type is selected. |
|
152 * I'll be damned if there are none available ;) */ |
|
153 WP(w, fnd_d).index = 0; |
|
154 WP(w, fnd_d).select = _fund_gui.index[0]; |
|
155 WP(w, fnd_d).callback_timer = DAY_TICKS; |
|
156 } break; |
|
157 |
|
158 case WE_PAINT: { |
|
159 const IndustrySpec *indsp = (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(WP(w, fnd_d).select); |
|
160 int x_str = w->widget[DPIW_INFOPANEL].left + 3; |
|
161 int y_str = w->widget[DPIW_INFOPANEL].top + 3; |
|
162 const Widget *wi = &w->widget[DPIW_INFOPANEL]; |
|
163 int max_width = wi->right - wi->left - 4; |
|
164 |
|
165 /* Raw industries might be prospected. Show this fact by changing the string |
|
166 * In Editor, you just build, while ingame, or you fund or you prospect */ |
|
167 if (_game_mode == GM_EDITOR) { |
|
168 /* We've chosen many random industries but no industries have been specified */ |
|
169 if (indsp == NULL) _fund_gui.enabled[WP(w, fnd_d).index] = _opt.diff.number_industries != 0; |
|
170 w->widget[DPIW_FUND_WIDGET].data = STR_BUILD_NEW_INDUSTRY; |
|
171 } else { |
|
172 w->widget[DPIW_FUND_WIDGET].data = (_patches.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_PROSPECT_NEW_INDUSTRY : STR_FUND_NEW_INDUSTRY; |
|
173 } |
|
174 w->SetWidgetDisabledState(DPIW_FUND_WIDGET, !_fund_gui.enabled[WP(w, fnd_d).index]); |
|
175 |
|
176 SetVScrollCount(w, _fund_gui.count); |
|
177 |
|
178 DrawWindowWidgets(w); |
|
179 |
|
180 /* and now with the matrix painting */ |
|
181 for (byte i = 0; i < w->vscroll.cap && ((i + w->vscroll.pos) < _fund_gui.count); i++) { |
|
182 int offset = i * 13; |
|
183 int x = 3; |
|
184 int y = 16; |
|
185 bool selected = WP(w, fnd_d).index == i + w->vscroll.pos; |
|
186 |
|
187 if (_fund_gui.index[i + w->vscroll.pos] == INVALID_INDUSTRYTYPE) { |
|
188 DrawStringTruncated(20, y + offset, STR_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE, max_width - 25); |
|
189 continue; |
|
190 } |
|
191 const IndustrySpec *indsp = GetIndustrySpec(_fund_gui.index[i + w->vscroll.pos]); |
|
192 |
|
193 /* Draw the name of the industry in white is selected, otherwise, in orange */ |
|
194 DrawStringTruncated(20, y + offset, indsp->name, selected ? TC_WHITE : TC_ORANGE, max_width - 25); |
|
195 GfxFillRect(x, y + 1 + offset, x + 10, y + 7 + offset, selected ? 15 : 0); |
|
196 GfxFillRect(x + 1, y + 2 + offset, x + 9, y + 6 + offset, indsp->map_colour); |
|
197 } |
|
198 |
|
199 if (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) { |
|
200 DrawStringMultiLine(x_str, y_str, STR_RANDOM_INDUSTRIES_TIP, max_width, wi->bottom - wi->top - 40); |
|
201 break; |
|
202 } |
|
203 |
|
204 if (_game_mode != GM_EDITOR) { |
|
205 SetDParam(0, indsp->GetConstructionCost()); |
|
206 DrawStringTruncated(x_str, y_str, STR_482F_COST, TC_FROMSTRING, max_width); |
|
207 y_str += 11; |
|
208 } |
|
209 |
|
210 /* Draw the accepted cargos, if any. Otherwhise, will print "Nothing" */ |
|
211 StringID str = STR_4827_REQUIRES; |
|
212 byte p = 0; |
|
213 SetDParam(0, STR_00D0_NOTHING); |
|
214 SetDParam(1, STR_EMPTY); |
|
215 for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { |
|
216 if (indsp->accepts_cargo[j] == CT_INVALID) continue; |
|
217 if (p > 0) str++; |
|
218 SetDParam(p++, GetCargo(indsp->accepts_cargo[j])->name); |
|
219 SetDParam(p++, GetCargoSuffix(j, CST_FUND, NULL, WP(w, fnd_d).select, indsp)); |
|
220 } |
|
221 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width); |
|
222 y_str += 11; |
|
223 |
|
224 /* Draw the produced cargos, if any. Otherwhise, will print "Nothing" */ |
|
225 str = STR_4827_PRODUCES; |
|
226 p = 0; |
|
227 SetDParam(0, STR_00D0_NOTHING); |
|
228 SetDParam(1, STR_EMPTY); |
|
229 for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { |
|
230 if (indsp->produced_cargo[j] == CT_INVALID) continue; |
|
231 if (p > 0) str++; |
|
232 SetDParam(p++, GetCargo(indsp->produced_cargo[j])->name); |
|
233 SetDParam(p++, GetCargoSuffix(j + 3, CST_FUND, NULL, WP(w, fnd_d).select, indsp)); |
|
234 } |
|
235 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width); |
|
236 y_str += 11; |
|
237 |
|
238 /* Get the additional purchase info text, if it has not already been */ |
|
239 if (_fund_gui.text[WP(w, fnd_d).index] == STR_NULL) { // Have i been called already? |
|
240 if (HasBit(indsp->callback_flags, CBM_IND_FUND_MORE_TEXT)) { // No. Can it be called? |
|
241 uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, WP(w, fnd_d).select, INVALID_TILE); |
|
242 if (callback_res != CALLBACK_FAILED) { // Did it failed? |
|
243 StringID newtxt = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string |
|
244 _fund_gui.text[WP(w, fnd_d).index] = newtxt; // Store it for further usage |
|
245 } |
|
246 } |
|
247 } |
|
248 |
|
249 /* Draw the Additional purchase text, provided by newgrf callback, if any. |
|
250 * Otherwhise, will print Nothing */ |
|
251 str = _fund_gui.text[WP(w, fnd_d).index]; |
|
252 if (str != STR_NULL && str != STR_UNDEFINED) { |
|
253 SetDParam(0, str); |
|
254 DrawStringMultiLine(x_str, y_str, STR_JUST_STRING, max_width, wi->bottom - wi->top - 40); |
|
255 } |
|
256 } break; |
|
257 |
|
258 case WE_DOUBLE_CLICK: |
|
259 if (e->we.click.widget != DPIW_MATRIX_WIDGET) break; |
|
260 e->we.click.widget = DPIW_FUND_WIDGET; |
|
261 /* Fall through */ |
|
262 |
|
263 case WE_CLICK: |
|
264 switch (e->we.click.widget) { |
|
265 case DPIW_MATRIX_WIDGET: { |
|
266 const IndustrySpec *indsp; |
|
267 int y = (e->we.click.pt.y - w->widget[DPIW_MATRIX_WIDGET].top) / 13 + w->vscroll.pos ; |
|
268 |
|
269 if (y >= 0 && y < _fund_gui.count) { // Is it within the boundaries of available data? |
|
270 WP(w, fnd_d).index = y; |
|
271 WP(w, fnd_d).select = _fund_gui.index[WP(w, fnd_d).index]; |
|
272 indsp = (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(WP(w, fnd_d).select); |
|
273 |
|
274 w->SetDirty(); |
|
275 |
|
276 if ((_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) || |
|
277 WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) { |
|
278 /* Reset the button state if going to prospecting or "build many industries" */ |
|
279 w->RaiseButtons(); |
|
280 ResetObjectToPlace(); |
|
281 } |
|
282 } |
|
283 } break; |
|
284 |
|
285 case DPIW_FUND_WIDGET: { |
|
286 if (WP(w, fnd_d).select == INVALID_INDUSTRYTYPE) { |
|
287 w->HandleButtonClick(DPIW_FUND_WIDGET); |
|
288 |
|
289 if (GetNumTowns() == 0) { |
|
290 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_CAN_T_GENERATE_INDUSTRIES, 0, 0); |
|
291 } else { |
|
292 extern void GenerateIndustries(); |
|
293 _generating_world = true; |
|
294 GenerateIndustries(); |
|
295 _generating_world = false; |
|
296 } |
|
297 } else if (_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && GetIndustrySpec(WP(w, fnd_d).select)->IsRawIndustry()) { |
|
298 DoCommandP(0, WP(w, fnd_d).select, InteractiveRandom(), NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)); |
|
299 w->HandleButtonClick(DPIW_FUND_WIDGET); |
|
300 } else { |
|
301 HandlePlacePushButton(w, DPIW_FUND_WIDGET, SPR_CURSOR_INDUSTRY, VHM_RECT, NULL); |
|
302 } |
|
303 } break; |
|
304 } |
|
305 break; |
|
306 |
|
307 case WE_RESIZE: { |
|
308 /* Adjust the number of items in the matrix depending of the rezise */ |
|
309 w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height; |
|
310 w->widget[DPIW_MATRIX_WIDGET].data = (w->vscroll.cap << 8) + 1; |
|
311 } break; |
|
312 |
|
313 case WE_PLACE_OBJ: { |
|
314 bool success = true; |
|
315 /* We do not need to protect ourselves against "Random Many Industries" in this mode */ |
|
316 const IndustrySpec *indsp = GetIndustrySpec(WP(w, fnd_d).select); |
|
317 uint32 seed = InteractiveRandom(); |
|
318 |
|
319 if (_game_mode == GM_EDITOR) { |
|
320 /* Show error if no town exists at all */ |
|
321 if (GetNumTowns() == 0) { |
|
322 SetDParam(0, indsp->name); |
|
323 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y); |
|
324 return; |
|
325 } |
|
326 |
|
327 _current_player = OWNER_NONE; |
|
328 _generating_world = true; |
|
329 _ignore_restrictions = true; |
|
330 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)); |
|
331 if (!success) { |
|
332 SetDParam(0, indsp->name); |
|
333 ShowErrorMessage(_error_message, STR_0285_CAN_T_BUILD_HERE, e->we.place.pt.x, e->we.place.pt.y); |
|
334 } |
|
335 |
|
336 _ignore_restrictions = false; |
|
337 _generating_world = false; |
|
338 } else { |
|
339 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)); |
|
340 } |
|
341 |
|
342 /* If an industry has been built, just reset the cursor and the system */ |
|
343 if (success) ResetObjectToPlace(); |
|
344 } break; |
|
345 |
|
346 case WE_TICK: |
|
347 if (_pause_game != 0) break; |
|
348 if (!WP(w, fnd_d).timer_enabled) break; |
|
349 if (--WP(w, fnd_d).callback_timer == 0) { |
|
350 /* We have just passed another day. |
|
351 * See if we need to update availability of currently selected industry */ |
|
352 WP(w, fnd_d).callback_timer = DAY_TICKS; //restart counter |
|
353 |
|
354 const IndustrySpec *indsp = GetIndustrySpec(WP(w, fnd_d).select); |
|
355 |
|
356 if (indsp->enabled) { |
|
357 bool call_back_result = CheckIfCallBackAllowsAvailability(WP(w, fnd_d).select, IACT_USERCREATION); |
|
358 |
|
359 /* Only if result does match the previous state would it require a redraw. */ |
|
360 if (call_back_result != _fund_gui.enabled[WP(w, fnd_d).index]) { |
|
361 _fund_gui.enabled[WP(w, fnd_d).index] = call_back_result; |
|
362 w->SetDirty(); |
|
363 } |
|
364 } |
|
365 } |
|
366 break; |
|
367 |
|
368 case WE_TIMEOUT: |
|
369 case WE_ABORT_PLACE_OBJ: |
|
370 w->RaiseButtons(); |
|
371 break; |
|
372 } |
|
373 } |
|
374 |
74 |
375 /** Widget definition of the dynamic place industries gui */ |
75 /** Widget definition of the dynamic place industries gui */ |
376 static const Widget _build_dynamic_industry_widgets[] = { |
76 static const Widget _build_industry_widgets[] = { |
377 { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // DPIW_CLOSEBOX |
77 { WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // DPIW_CLOSEBOX |
378 { WWT_CAPTION, RESIZE_RIGHT, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, // DPIW_CAPTION |
78 { WWT_CAPTION, RESIZE_RIGHT, 7, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, // DPIW_CAPTION |
379 { WWT_MATRIX, RESIZE_RB, 7, 0, 157, 14, 118, 0x801, STR_INDUSTRY_SELECTION_HINT}, // DPIW_MATRIX_WIDGET |
79 { WWT_MATRIX, RESIZE_RB, 7, 0, 157, 14, 118, 0x801, STR_INDUSTRY_SELECTION_HINT}, // DPIW_MATRIX_WIDGET |
380 { WWT_SCROLLBAR, RESIZE_LRB, 7, 158, 169, 14, 118, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DPIW_SCROLLBAR |
80 { WWT_SCROLLBAR, RESIZE_LRB, 7, 158, 169, 14, 118, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DPIW_SCROLLBAR |
381 { WWT_PANEL, RESIZE_RTB, 7, 0, 169, 119, 199, 0x0, STR_NULL}, // DPIW_INFOPANEL |
81 { WWT_PANEL, RESIZE_RTB, 7, 0, 169, 119, 199, 0x0, STR_NULL}, // DPIW_INFOPANEL |
383 { WWT_RESIZEBOX, RESIZE_LRTB, 7, 158, 169, 200, 211, 0x0, STR_RESIZE_BUTTON}, // DPIW_RESIZE_WIDGET |
83 { WWT_RESIZEBOX, RESIZE_LRTB, 7, 158, 169, 200, 211, 0x0, STR_RESIZE_BUTTON}, // DPIW_RESIZE_WIDGET |
384 { WIDGETS_END}, |
84 { WIDGETS_END}, |
385 }; |
85 }; |
386 |
86 |
387 /** Window definition of the dynamic place industries gui */ |
87 /** Window definition of the dynamic place industries gui */ |
388 static const WindowDesc _build_industry_dynamic_desc = { |
88 static const WindowDesc _build_industry_desc = { |
389 WDP_AUTO, WDP_AUTO, 170, 212, 170, 212, |
89 WDP_AUTO, WDP_AUTO, 170, 212, 170, 212, |
390 WC_BUILD_INDUSTRY, WC_NONE, |
90 WC_BUILD_INDUSTRY, WC_NONE, |
391 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE, |
91 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE, |
392 _build_dynamic_industry_widgets, |
92 _build_industry_widgets, |
393 BuildDynamicIndustryWndProc, |
93 NULL, |
|
94 }; |
|
95 |
|
96 class BuildIndustryWindow : public Window { |
|
97 int selected_index; ///< index of the element in the matrix |
|
98 IndustryType selected_type; ///< industry corresponding to the above index |
|
99 uint16 callback_timer; ///< timer counter for callback eventual verification |
|
100 bool timer_enabled; ///< timer can be used |
|
101 uint16 count; ///< How many industries are loaded |
|
102 IndustryType index[NUM_INDUSTRYTYPES + 1]; ///< Type of industry, in the order it was loaded |
|
103 StringID text[NUM_INDUSTRYTYPES + 1]; ///< Text coming from CBM_IND_FUND_MORE_TEXT (if ever) |
|
104 bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_AVAILABLE (if ever) |
|
105 |
|
106 public: |
|
107 BuildIndustryWindow() : Window(&_build_industry_desc) |
|
108 { |
|
109 IndustryType ind; |
|
110 const IndustrySpec *indsp; |
|
111 |
|
112 /* Shorten the window to the equivalant of the additionnal purchase |
|
113 * info coming from the callback. SO it will only be available to tis full |
|
114 * height when newindistries are loaded */ |
|
115 if (!_loaded_newgrf_features.has_newindustries) { |
|
116 this->widget[DPIW_INFOPANEL].bottom -= 44; |
|
117 this->widget[DPIW_FUND_WIDGET].bottom -= 44; |
|
118 this->widget[DPIW_FUND_WIDGET].top -= 44; |
|
119 this->widget[DPIW_RESIZE_WIDGET].bottom -= 44; |
|
120 this->widget[DPIW_RESIZE_WIDGET].top -= 44; |
|
121 this->resize.height = this->height -= 44; |
|
122 } |
|
123 |
|
124 this->timer_enabled = _loaded_newgrf_features.has_newindustries; |
|
125 |
|
126 /* Initialize structures */ |
|
127 this->count = 0; |
|
128 |
|
129 for (uint i = 0; i < lengthof(this->index); i++) { |
|
130 this->index[i] = 0xFF; |
|
131 this->text[i] = STR_NULL; |
|
132 this->enabled[i] = false; |
|
133 } |
|
134 |
|
135 this->vscroll.cap = 8; // rows in grid, same in scroller |
|
136 this->resize.step_height = 13; |
|
137 |
|
138 if (_game_mode == GM_EDITOR) { // give room for the Many Random "button" |
|
139 this->index[this->count] = INVALID_INDUSTRYTYPE; |
|
140 this->count++; |
|
141 this->timer_enabled = false; |
|
142 } |
|
143 |
|
144 /* Fill the _fund_gui structure with industries. |
|
145 * The tests performed after the enabled allow to load the industries |
|
146 * In the same way they are inserted by grf (if any) |
|
147 */ |
|
148 for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) { |
|
149 indsp = GetIndustrySpec(ind); |
|
150 if (indsp->enabled){ |
|
151 /* Rule is that editor mode loads all industries. |
|
152 * In game mode, all non raw industries are loaded too |
|
153 * and raw ones are loaded only when setting allows it */ |
|
154 if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) continue; |
|
155 this->index[this->count] = ind; |
|
156 this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION); |
|
157 this->count++; |
|
158 } |
|
159 } |
|
160 |
|
161 /* first indutry type is selected. |
|
162 * I'll be damned if there are none available ;) */ |
|
163 this->selected_index = 0; |
|
164 this->selected_type = this->index[0]; |
|
165 this->callback_timer = DAY_TICKS; |
|
166 } |
|
167 |
|
168 virtual void OnPaint() |
|
169 { |
|
170 const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); |
|
171 int x_str = this->widget[DPIW_INFOPANEL].left + 3; |
|
172 int y_str = this->widget[DPIW_INFOPANEL].top + 3; |
|
173 const Widget *wi = &this->widget[DPIW_INFOPANEL]; |
|
174 int max_width = wi->right - wi->left - 4; |
|
175 |
|
176 /* Raw industries might be prospected. Show this fact by changing the string |
|
177 * In Editor, you just build, while ingame, or you fund or you prospect */ |
|
178 if (_game_mode == GM_EDITOR) { |
|
179 /* We've chosen many random industries but no industries have been specified */ |
|
180 if (indsp == NULL) this->enabled[this->selected_index] = _opt.diff.number_industries != 0; |
|
181 this->widget[DPIW_FUND_WIDGET].data = STR_BUILD_NEW_INDUSTRY; |
|
182 } else { |
|
183 this->widget[DPIW_FUND_WIDGET].data = (_patches.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_PROSPECT_NEW_INDUSTRY : STR_FUND_NEW_INDUSTRY; |
|
184 } |
|
185 this->SetWidgetDisabledState(DPIW_FUND_WIDGET, !this->enabled[this->selected_index]); |
|
186 |
|
187 SetVScrollCount(this, this->count); |
|
188 |
|
189 DrawWindowWidgets(this); |
|
190 |
|
191 /* and now with the matrix painting */ |
|
192 for (byte i = 0; i < this->vscroll.cap && ((i + this->vscroll.pos) < this->count); i++) { |
|
193 int offset = i * 13; |
|
194 int x = 3; |
|
195 int y = 16; |
|
196 bool selected = this->selected_index == i + this->vscroll.pos; |
|
197 |
|
198 if (this->index[i + this->vscroll.pos] == INVALID_INDUSTRYTYPE) { |
|
199 DrawStringTruncated(20, y + offset, STR_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE, max_width - 25); |
|
200 continue; |
|
201 } |
|
202 const IndustrySpec *indsp = GetIndustrySpec(this->index[i + this->vscroll.pos]); |
|
203 |
|
204 /* Draw the name of the industry in white is selected, otherwise, in orange */ |
|
205 DrawStringTruncated(20, y + offset, indsp->name, selected ? TC_WHITE : TC_ORANGE, max_width - 25); |
|
206 GfxFillRect(x, y + 1 + offset, x + 10, y + 7 + offset, selected ? 15 : 0); |
|
207 GfxFillRect(x + 1, y + 2 + offset, x + 9, y + 6 + offset, indsp->map_colour); |
|
208 } |
|
209 |
|
210 if (this->selected_type == INVALID_INDUSTRYTYPE) { |
|
211 DrawStringMultiLine(x_str, y_str, STR_RANDOM_INDUSTRIES_TIP, max_width, wi->bottom - wi->top - 40); |
|
212 return; |
|
213 } |
|
214 |
|
215 if (_game_mode != GM_EDITOR) { |
|
216 SetDParam(0, indsp->GetConstructionCost()); |
|
217 DrawStringTruncated(x_str, y_str, STR_482F_COST, TC_FROMSTRING, max_width); |
|
218 y_str += 11; |
|
219 } |
|
220 |
|
221 /* Draw the accepted cargos, if any. Otherwhise, will print "Nothing" */ |
|
222 StringID str = STR_4827_REQUIRES; |
|
223 byte p = 0; |
|
224 SetDParam(0, STR_00D0_NOTHING); |
|
225 SetDParam(1, STR_EMPTY); |
|
226 for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { |
|
227 if (indsp->accepts_cargo[j] == CT_INVALID) continue; |
|
228 if (p > 0) str++; |
|
229 SetDParam(p++, GetCargo(indsp->accepts_cargo[j])->name); |
|
230 SetDParam(p++, GetCargoSuffix(j, CST_FUND, NULL, this->selected_type, indsp)); |
|
231 } |
|
232 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width); |
|
233 y_str += 11; |
|
234 |
|
235 /* Draw the produced cargos, if any. Otherwhise, will print "Nothing" */ |
|
236 str = STR_4827_PRODUCES; |
|
237 p = 0; |
|
238 SetDParam(0, STR_00D0_NOTHING); |
|
239 SetDParam(1, STR_EMPTY); |
|
240 for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { |
|
241 if (indsp->produced_cargo[j] == CT_INVALID) continue; |
|
242 if (p > 0) str++; |
|
243 SetDParam(p++, GetCargo(indsp->produced_cargo[j])->name); |
|
244 SetDParam(p++, GetCargoSuffix(j + 3, CST_FUND, NULL, this->selected_type, indsp)); |
|
245 } |
|
246 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width); |
|
247 y_str += 11; |
|
248 |
|
249 /* Get the additional purchase info text, if it has not already been */ |
|
250 if (this->text[this->selected_index] == STR_NULL) { // Have i been called already? |
|
251 if (HasBit(indsp->callback_flags, CBM_IND_FUND_MORE_TEXT)) { // No. Can it be called? |
|
252 uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE); |
|
253 if (callback_res != CALLBACK_FAILED) { // Did it failed? |
|
254 StringID newtxt = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string |
|
255 this->text[this->selected_index] = newtxt; // Store it for further usage |
|
256 } |
|
257 } |
|
258 } |
|
259 |
|
260 /* Draw the Additional purchase text, provided by newgrf callback, if any. |
|
261 * Otherwhise, will print Nothing */ |
|
262 str = this->text[this->selected_index]; |
|
263 if (str != STR_NULL && str != STR_UNDEFINED) { |
|
264 SetDParam(0, str); |
|
265 DrawStringMultiLine(x_str, y_str, STR_JUST_STRING, max_width, wi->bottom - wi->top - 40); |
|
266 } |
|
267 } |
|
268 |
|
269 virtual void OnDoubleClick(Point pt, int widget) |
|
270 { |
|
271 if (widget != DPIW_MATRIX_WIDGET) return; |
|
272 this->OnClick(pt, DPIW_FUND_WIDGET); |
|
273 } |
|
274 |
|
275 virtual void OnClick(Point pt, int widget) |
|
276 { |
|
277 switch (widget) { |
|
278 case DPIW_MATRIX_WIDGET: { |
|
279 const IndustrySpec *indsp; |
|
280 int y = (pt.y - this->widget[DPIW_MATRIX_WIDGET].top) / 13 + this->vscroll.pos ; |
|
281 |
|
282 if (y >= 0 && y < count) { // Is it within the boundaries of available data? |
|
283 this->selected_index = y; |
|
284 this->selected_type = this->index[y]; |
|
285 indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); |
|
286 |
|
287 this->SetDirty(); |
|
288 |
|
289 if ((_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) || |
|
290 this->selected_type == INVALID_INDUSTRYTYPE) { |
|
291 /* Reset the button state if going to prospecting or "build many industries" */ |
|
292 this->RaiseButtons(); |
|
293 ResetObjectToPlace(); |
|
294 } |
|
295 } |
|
296 } break; |
|
297 |
|
298 case DPIW_FUND_WIDGET: { |
|
299 if (this->selected_type == INVALID_INDUSTRYTYPE) { |
|
300 this->HandleButtonClick(DPIW_FUND_WIDGET); |
|
301 |
|
302 if (GetNumTowns() == 0) { |
|
303 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_CAN_T_GENERATE_INDUSTRIES, 0, 0); |
|
304 } else { |
|
305 extern void GenerateIndustries(); |
|
306 _generating_world = true; |
|
307 GenerateIndustries(); |
|
308 _generating_world = false; |
|
309 } |
|
310 } else if (_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && GetIndustrySpec(this->selected_type)->IsRawIndustry()) { |
|
311 DoCommandP(0, this->selected_type, InteractiveRandom(), NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)); |
|
312 this->HandleButtonClick(DPIW_FUND_WIDGET); |
|
313 } else { |
|
314 HandlePlacePushButton(this, DPIW_FUND_WIDGET, SPR_CURSOR_INDUSTRY, VHM_RECT, NULL); |
|
315 } |
|
316 } break; |
|
317 } |
|
318 } |
|
319 |
|
320 virtual void OnResize(Point new_size, Point delta) |
|
321 { |
|
322 /* Adjust the number of items in the matrix depending of the rezise */ |
|
323 this->vscroll.cap += delta.y / (int)this->resize.step_height; |
|
324 this->widget[DPIW_MATRIX_WIDGET].data = (this->vscroll.cap << 8) + 1; |
|
325 } |
|
326 |
|
327 virtual void OnPlaceObject(Point pt, TileIndex tile) |
|
328 { |
|
329 bool success = true; |
|
330 /* We do not need to protect ourselves against "Random Many Industries" in this mode */ |
|
331 const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); |
|
332 uint32 seed = InteractiveRandom(); |
|
333 |
|
334 if (_game_mode == GM_EDITOR) { |
|
335 /* Show error if no town exists at all */ |
|
336 if (GetNumTowns() == 0) { |
|
337 SetDParam(0, indsp->name); |
|
338 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_0285_CAN_T_BUILD_HERE, pt.x, pt.y); |
|
339 return; |
|
340 } |
|
341 |
|
342 _current_player = OWNER_NONE; |
|
343 _generating_world = true; |
|
344 _ignore_restrictions = true; |
|
345 success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 16) | this->selected_type, seed, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)); |
|
346 if (!success) { |
|
347 SetDParam(0, indsp->name); |
|
348 ShowErrorMessage(_error_message, STR_0285_CAN_T_BUILD_HERE, pt.x, pt.y); |
|
349 } |
|
350 |
|
351 _ignore_restrictions = false; |
|
352 _generating_world = false; |
|
353 } else { |
|
354 success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 16) | this->selected_type, seed, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)); |
|
355 } |
|
356 |
|
357 /* If an industry has been built, just reset the cursor and the system */ |
|
358 if (success) ResetObjectToPlace(); |
|
359 } |
|
360 |
|
361 virtual void OnTick() |
|
362 { |
|
363 if (_pause_game != 0) return; |
|
364 if (!this->timer_enabled) return; |
|
365 if (--this->callback_timer == 0) { |
|
366 /* We have just passed another day. |
|
367 * See if we need to update availability of currently selected industry */ |
|
368 this->callback_timer = DAY_TICKS; //restart counter |
|
369 |
|
370 const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); |
|
371 |
|
372 if (indsp->enabled) { |
|
373 bool call_back_result = CheckIfCallBackAllowsAvailability(this->selected_type, IACT_USERCREATION); |
|
374 |
|
375 /* Only if result does match the previous state would it require a redraw. */ |
|
376 if (call_back_result != this->enabled[this->selected_index]) { |
|
377 this->enabled[this->selected_index] = call_back_result; |
|
378 this->SetDirty(); |
|
379 } |
|
380 } |
|
381 } |
|
382 } |
|
383 |
|
384 virtual void OnTimeout() |
|
385 { |
|
386 this->RaiseButtons(); |
|
387 } |
|
388 |
|
389 virtual void OnPlaceObjectAbort() |
|
390 { |
|
391 this->RaiseButtons(); |
|
392 } |
394 }; |
393 }; |
395 |
394 |
396 void ShowBuildIndustryWindow() |
395 void ShowBuildIndustryWindow() |
397 { |
396 { |
398 if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return; |
397 if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return; |
399 AllocateWindowDescFront<Window>(&_build_industry_dynamic_desc, 0); |
398 if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return; |
|
399 new BuildIndustryWindow(); |
400 } |
400 } |
401 |
401 |
402 static void UpdateIndustryProduction(Industry *i); |
402 static void UpdateIndustryProduction(Industry *i); |
403 |
403 |
404 static inline bool IsProductionMinimum(const Industry *i, int pt) |
404 static inline bool IsProductionMinimum(const Industry *i, int pt) |