37 BUILD_VEHICLE_WIDGET_RESIZE, |
38 BUILD_VEHICLE_WIDGET_RESIZE, |
38 }; |
39 }; |
39 |
40 |
40 static const Widget _build_vehicle_widgets[] = { |
41 static const Widget _build_vehicle_widgets[] = { |
41 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW }, |
42 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW }, |
42 { WWT_CAPTION, RESIZE_NONE, 14, 11, 239, 0, 13, STR_A005_NEW_AIRCRAFT, STR_018C_WINDOW_TITLE_DRAG_THIS }, |
43 { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 227, 0, 13, 0x0, STR_018C_WINDOW_TITLE_DRAG_THIS }, |
43 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP}, |
44 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP}, |
44 { WWT_PANEL, RESIZE_NONE, 14, 81, 227, 14, 25, 0x0, STR_SORT_CRITERIA_TIP}, |
45 { WWT_PANEL, RESIZE_RIGHT, 14, 81, 215, 14, 25, 0x0, STR_SORT_CRITERIA_TIP}, |
45 { WWT_TEXTBTN, RESIZE_NONE, 14, 228, 239, 14, 25, STR_0225, STR_SORT_CRITERIA_TIP}, |
46 { WWT_TEXTBTN, RESIZE_LR, 14, 216, 227, 14, 25, STR_0225, STR_SORT_CRITERIA_TIP}, |
46 { WWT_MATRIX, RESIZE_BOTTOM, 14, 0, 227, 26, 121, 0x401, STR_A025_AIRCRAFT_SELECTION_LIST }, |
47 { WWT_MATRIX, RESIZE_RB, 14, 0, 215, 26, 121, 0x0, STR_NULL }, |
47 { WWT_SCROLLBAR, RESIZE_BOTTOM, 14, 228, 239, 26, 121, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST }, |
48 { WWT_SCROLLBAR, RESIZE_LRB, 14, 216, 227, 26, 121, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST }, |
48 { WWT_PANEL, RESIZE_TB, 14, 0, 239, 122, 213, 0x0, STR_NULL }, |
49 { WWT_PANEL, RESIZE_RTB, 14, 0, 227, 122, 213, 0x0, STR_NULL }, |
49 |
50 |
50 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 114, 214, 225, STR_A006_BUILD_AIRCRAFT, STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT }, |
51 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 114, 214, 225, 0x0, STR_NULL }, |
51 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 115, 227, 214, 225, STR_A037_RENAME, STR_A038_RENAME_AIRCRAFT_TYPE }, |
52 { WWT_PUSHTXTBTN, RESIZE_RTB, 14, 115, 215, 214, 225, 0x0, STR_NULL }, |
52 { WWT_RESIZEBOX, RESIZE_TB, 14, 228, 239, 214, 225, 0x0, STR_RESIZE_BUTTON }, |
53 { WWT_RESIZEBOX, RESIZE_LRTB, 14, 216, 227, 214, 225, 0x0, STR_RESIZE_BUTTON }, |
53 { WIDGETS_END}, |
54 { WIDGETS_END}, |
54 }; |
55 }; |
55 |
56 |
|
57 /* Setup widget strings to fit the different types of vehicles */ |
|
58 static void SetupWindowStrings(const Window *w, byte type) |
|
59 { |
|
60 switch (type) { |
|
61 case VEH_Train: |
|
62 w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_JUST_STRING; |
|
63 w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_8843_TRAIN_VEHICLE_SELECTION; |
|
64 w->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_881F_BUILD_VEHICLE; |
|
65 w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN; |
|
66 w->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_8820_RENAME; |
|
67 w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_8845_RENAME_TRAIN_VEHICLE_TYPE; |
|
68 break; |
|
69 case VEH_Aircraft: |
|
70 w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_A005_NEW_AIRCRAFT; |
|
71 w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_A025_AIRCRAFT_SELECTION_LIST; |
|
72 w->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_A006_BUILD_AIRCRAFT; |
|
73 w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT; |
|
74 w->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_A037_RENAME; |
|
75 w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_A038_RENAME_AIRCRAFT_TYPE; |
|
76 break; |
|
77 } |
|
78 } |
|
79 |
56 static bool _internal_sort_order; // descending/ascending |
80 static bool _internal_sort_order; // descending/ascending |
57 static byte _last_sort_criteria = 0; |
81 static byte _last_sort_criteria_train = 0; |
58 static bool _last_sort_order = false; |
82 static bool _last_sort_order_train = false; |
|
83 |
|
84 static byte _last_sort_criteria_aircraft = 0; |
|
85 static bool _last_sort_order_aircraft = false; |
59 |
86 |
60 static int CDECL EngineNumberSorter(const void *a, const void *b) |
87 static int CDECL EngineNumberSorter(const void *a, const void *b) |
61 { |
88 { |
62 const EngineID va = *(const EngineID*)a; |
89 const EngineID va = *(const EngineID*)a; |
63 const EngineID vb = *(const EngineID*)b; |
90 const EngineID vb = *(const EngineID*)b; |
118 return EngineNumberSorter(a, b); |
145 return EngineNumberSorter(a, b); |
119 } |
146 } |
120 return _internal_sort_order ? -r : r; |
147 return _internal_sort_order ? -r : r; |
121 } |
148 } |
122 |
149 |
|
150 /* Train sorting functions */ |
|
151 static int CDECL TrainEngineCostSorter(const void *a, const void *b) |
|
152 { |
|
153 int va = RailVehInfo(*(const EngineID*)a)->base_cost; |
|
154 int vb = RailVehInfo(*(const EngineID*)b)->base_cost; |
|
155 int r = va - vb; |
|
156 |
|
157 return _internal_sort_order ? -r : r; |
|
158 } |
|
159 |
|
160 static int CDECL TrainEngineSpeedSorter(const void *a, const void *b) |
|
161 { |
|
162 int va = RailVehInfo(*(const EngineID*)a)->max_speed; |
|
163 int vb = RailVehInfo(*(const EngineID*)b)->max_speed; |
|
164 int r = va - vb; |
|
165 |
|
166 return _internal_sort_order ? -r : r; |
|
167 } |
|
168 |
|
169 static int CDECL TrainEnginePowerSorter(const void *a, const void *b) |
|
170 { |
|
171 const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a); |
|
172 const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b); |
|
173 |
|
174 int va = rvi_a->power << (rvi_a->flags & RVI_MULTIHEAD ? 1 : 0); |
|
175 int vb = rvi_b->power << (rvi_b->flags & RVI_MULTIHEAD ? 1 : 0); |
|
176 int r = va - vb; |
|
177 |
|
178 return _internal_sort_order ? -r : r; |
|
179 } |
|
180 |
|
181 static int CDECL TrainEngineRunningCostSorter(const void *a, const void *b) |
|
182 { |
|
183 const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a); |
|
184 const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b); |
|
185 |
|
186 int va = rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class] * (rvi_a->flags & RVI_MULTIHEAD ? 2 : 1); |
|
187 int vb = rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class] * (rvi_b->flags & RVI_MULTIHEAD ? 2 : 1); |
|
188 int r = va - vb; |
|
189 |
|
190 return _internal_sort_order ? -r : r; |
|
191 } |
|
192 |
|
193 static int CDECL TrainEnginePowerVsRunningCostSorter(const void *a, const void *b) |
|
194 { |
|
195 const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a); |
|
196 const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b); |
|
197 |
|
198 /* Here we are using a few tricks to get the right sort. |
|
199 * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, |
|
200 * we will actually calculate cunning cost/power (to make it more than 1). |
|
201 * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. |
|
202 * Another thing is that both power and running costs should be doubled for multiheaded engines. |
|
203 * Since it would be multipling with 2 in both numerator and denumerator, it will even themselves out and we skip checking for multiheaded. */ |
|
204 int va = (rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class]) / max((uint16)1, rvi_a->power); |
|
205 int vb = (rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class]) / max((uint16)1, rvi_b->power); |
|
206 int r = vb - va; |
|
207 |
|
208 return _internal_sort_order ? -r : r; |
|
209 } |
|
210 |
|
211 static int CDECL TrainEnginesThenWagonsSorter(const void *a, const void *b) |
|
212 { |
|
213 EngineID va = *(const EngineID*)a; |
|
214 EngineID vb = *(const EngineID*)b; |
|
215 int val_a = ((RailVehInfo(va)->flags & RVI_WAGON) != 0) ? 1 : 0; |
|
216 int val_b = ((RailVehInfo(vb)->flags & RVI_WAGON) != 0) ? 1 : 0; |
|
217 int r = val_a - val_b; |
|
218 |
|
219 /* Use EngineID to sort instead since we want consistent sorting */ |
|
220 if (r == 0) return EngineNumberSorter(a, b); |
|
221 |
|
222 return _internal_sort_order ? -r : r; |
|
223 } |
|
224 |
123 /* Aircraft sorting functions */ |
225 /* Aircraft sorting functions */ |
124 |
226 |
125 static int CDECL AircraftEngineCostSorter(const void *a, const void *b) |
227 static int CDECL AircraftEngineCostSorter(const void *a, const void *b) |
126 { |
228 { |
127 const int va = AircraftVehInfo(*(const EngineID*)a)->base_cost; |
229 const int va = AircraftVehInfo(*(const EngineID*)a)->base_cost; |
167 /* Use EngineID to sort instead since we want consistent sorting */ |
269 /* Use EngineID to sort instead since we want consistent sorting */ |
168 return EngineNumberSorter(a, b); |
270 return EngineNumberSorter(a, b); |
169 } |
271 } |
170 return _internal_sort_order ? -r : r; |
272 return _internal_sort_order ? -r : r; |
171 } |
273 } |
|
274 |
|
275 static EngList_SortTypeFunction * const _train_sorter[] = { |
|
276 &EngineNumberSorter, |
|
277 &TrainEngineCostSorter, |
|
278 &TrainEngineSpeedSorter, |
|
279 &TrainEnginePowerSorter, |
|
280 &EngineIntroDateSorter, |
|
281 &EngineNameSorter, |
|
282 &TrainEngineRunningCostSorter, |
|
283 &TrainEnginePowerVsRunningCostSorter, |
|
284 &EngineReliabilitySorter, |
|
285 }; |
|
286 |
|
287 static const StringID _train_sort_listing[] = { |
|
288 STR_ENGINE_SORT_ENGINE_ID, |
|
289 STR_ENGINE_SORT_COST, |
|
290 STR_SORT_BY_MAX_SPEED, |
|
291 STR_ENGINE_SORT_POWER, |
|
292 STR_ENGINE_SORT_INTRO_DATE, |
|
293 STR_SORT_BY_DROPDOWN_NAME, |
|
294 STR_ENGINE_SORT_RUNNING_COST, |
|
295 STR_ENGINE_SORT_POWER_VS_RUNNING_COST, |
|
296 STR_SORT_BY_RELIABILITY, |
|
297 INVALID_STRING_ID |
|
298 }; |
172 |
299 |
173 static EngList_SortTypeFunction * const _aircraft_sorter[] = { |
300 static EngList_SortTypeFunction * const _aircraft_sorter[] = { |
174 &EngineNumberSorter, |
301 &EngineNumberSorter, |
175 &AircraftEngineCostSorter, |
302 &AircraftEngineCostSorter, |
176 &AircraftEngineSpeedSorter, |
303 &AircraftEngineSpeedSorter, |
192 STR_ENGINE_SORT_CARGO_CAPACITY, |
319 STR_ENGINE_SORT_CARGO_CAPACITY, |
193 INVALID_STRING_ID |
320 INVALID_STRING_ID |
194 }; |
321 }; |
195 |
322 |
196 |
323 |
197 /** |
324 /* Draw rail wagon specific details */ |
198 * Draw the purchase info details of an aircraft at a given location. |
325 static int DrawVehiclePurchaseInfo(int x, int y, EngineID engine_number, const RailVehicleInfo *rvi) |
199 * @param x,y location where to draw the info |
326 { |
200 * @param engine_number the engine of which to draw the info of |
327 /* Purchase cost */ |
201 */ |
328 SetDParam(0, (rvi->base_cost * _price.build_railwagon) >> 8); |
202 void DrawAircraftPurchaseInfo(int x, int y, uint w, EngineID engine_number) |
329 DrawString(x, y, STR_PURCHASE_INFO_COST, 0); |
203 { |
330 y += 10; |
204 const AircraftVehicleInfo *avi = AircraftVehInfo(engine_number); |
331 |
205 const Engine *e = GetEngine(engine_number); |
332 /* Wagon weight - (including cargo) */ |
|
333 SetDParam(0, rvi->weight); |
|
334 SetDParam(1, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight); |
|
335 DrawString(x, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT, 0); |
|
336 y += 10; |
|
337 |
|
338 /* Wagon speed limit, displayed if above zero */ |
|
339 if (rvi->max_speed > 0 && _patches.wagon_speed_limits) { |
|
340 SetDParam(0, rvi->max_speed); |
|
341 DrawString(x,y, STR_PURCHASE_INFO_SPEED, 0); |
|
342 y += 10; |
|
343 } |
|
344 return y; |
|
345 } |
|
346 |
|
347 /* Draw locomotive specific details */ |
|
348 static int DrawVehiclePurchaseInfo(int x, int y, EngineID engine_number, const RailVehicleInfo *rvi, const Engine *e) |
|
349 { |
|
350 int multihead = (rvi->flags&RVI_MULTIHEAD?1:0); |
|
351 |
|
352 /* Purchase Cost - Engine weight */ |
|
353 SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5); |
|
354 SetDParam(1, rvi->weight << multihead); |
|
355 DrawString(x,y, STR_PURCHASE_INFO_COST_WEIGHT, 0); |
|
356 y += 10; |
|
357 |
|
358 /* Max speed - Engine power */ |
|
359 SetDParam(0, rvi->max_speed); |
|
360 SetDParam(1, rvi->power << multihead); |
|
361 DrawString(x,y, STR_PURCHASE_INFO_SPEED_POWER, 0); |
|
362 y += 10; |
|
363 |
|
364 /* Max tractive effort - not applicable if old acceleration or maglev */ |
|
365 if (_patches.realistic_acceleration && e->railtype != RAILTYPE_MAGLEV) { |
|
366 SetDParam(0, ((rvi->weight << multihead) * 10 * rvi->tractive_effort) / 256); |
|
367 DrawString(x, y, STR_PURCHASE_INFO_MAX_TE, 0); |
|
368 y += 10; |
|
369 } |
|
370 |
|
371 /* Running cost */ |
|
372 SetDParam(0, (rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8) << multihead); |
|
373 DrawString(x,y, STR_PURCHASE_INFO_RUNNINGCOST, 0); |
|
374 y += 10; |
|
375 |
|
376 /* Powered wagons power - Powered wagons extra weight */ |
|
377 if (rvi->pow_wag_power != 0) { |
|
378 SetDParam(0, rvi->pow_wag_power); |
|
379 SetDParam(1, rvi->pow_wag_weight); |
|
380 DrawString(x,y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, 0); |
|
381 y += 10; |
|
382 }; |
|
383 |
|
384 return y; |
|
385 } |
|
386 |
|
387 /* Draw aircraft specific details */ |
|
388 static int DrawVehiclePurchaseInfo(int x, int y, EngineID engine_number, const AircraftVehicleInfo *avi) |
|
389 { |
206 CargoID cargo; |
390 CargoID cargo; |
207 YearMonthDay ymd; |
|
208 ConvertDateToYMD(e->intro_date, &ymd); |
|
209 |
391 |
210 /* Purchase cost - Max speed */ |
392 /* Purchase cost - Max speed */ |
211 SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5); |
393 SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5); |
212 SetDParam(1, avi->max_speed * 128 / 10); |
394 SetDParam(1, avi->max_speed * 128 / 10); |
213 DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0); |
395 DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0); |
232 /* Running cost */ |
414 /* Running cost */ |
233 SetDParam(0, avi->running_cost * _price.aircraft_running >> 8); |
415 SetDParam(0, avi->running_cost * _price.aircraft_running >> 8); |
234 DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0); |
416 DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0); |
235 y += 10; |
417 y += 10; |
236 |
418 |
237 /* Design date - Life length */ |
419 return y; |
238 SetDParam(0, ymd.year); |
420 } |
239 SetDParam(1, e->lifelength); |
421 |
240 DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0); |
422 /** |
241 y += 10; |
423 * Draw the purchase info details of a vehicle at a given location. |
242 |
424 * @param x,y location where to draw the info |
243 /* Reliability */ |
425 * @param w how wide are the text allowed to be (size of widget/window to Draw in) |
244 SetDParam(0, e->reliability * 100 >> 16); |
426 * @param engine_number the engine of which to draw the info of |
245 DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0); |
427 */ |
246 y += 10; |
428 void DrawVehiclePurchaseInfo(int x, int y, uint w, EngineID engine_number) |
|
429 { |
|
430 const Engine *e = GetEngine(engine_number); |
|
431 YearMonthDay ymd; |
|
432 ConvertDateToYMD(e->intro_date, &ymd); |
|
433 |
|
434 switch (e->type) { |
|
435 case VEH_Train: { |
|
436 const RailVehicleInfo *rvi = RailVehInfo(engine_number); |
|
437 |
|
438 if (rvi->flags & RVI_WAGON) { |
|
439 y = DrawVehiclePurchaseInfo(x, y, engine_number, rvi); |
|
440 } else { |
|
441 y = DrawVehiclePurchaseInfo(x, y, engine_number, rvi, e); |
|
442 } |
|
443 |
|
444 /* Cargo type + capacity, or N/A */ |
|
445 if (rvi->capacity == 0) { |
|
446 SetDParam(0, CT_INVALID); |
|
447 SetDParam(2, STR_EMPTY); |
|
448 } else { |
|
449 int multihead = (rvi->flags & RVI_MULTIHEAD ? 1 : 0); |
|
450 SetDParam(0, rvi->cargo_type); |
|
451 SetDParam(1, (rvi->capacity * (CountArticulatedParts(engine_number) + 1)) << multihead); |
|
452 SetDParam(2, STR_9842_REFITTABLE); |
|
453 } |
|
454 DrawString(x,y, STR_PURCHASE_INFO_CAPACITY, 0); |
|
455 y += 10; |
|
456 } |
|
457 break; |
|
458 case VEH_Aircraft: |
|
459 y = DrawVehiclePurchaseInfo(x, y, engine_number, AircraftVehInfo(engine_number)); |
|
460 break; |
|
461 default: NOT_REACHED(); |
|
462 } |
|
463 |
|
464 /* Draw details, that applies to all types except rail wagons */ |
|
465 if (e->type != VEH_Train || (RailVehInfo(engine_number)->flags & RVI_WAGON == 0)) { |
|
466 /* Design date - Life length */ |
|
467 SetDParam(0, ymd.year); |
|
468 SetDParam(1, e->lifelength); |
|
469 DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0); |
|
470 y += 10; |
|
471 |
|
472 /* Reliability */ |
|
473 SetDParam(0, e->reliability * 100 >> 16); |
|
474 DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0); |
|
475 y += 10; |
|
476 } |
247 |
477 |
248 /* Additional text from NewGRF */ |
478 /* Additional text from NewGRF */ |
249 y += ShowAdditionalText(x, y, w, engine_number); |
479 y += ShowAdditionalText(x, y, w, engine_number); |
250 y += ShowRefitOptionsList(x, y, w, engine_number); |
480 switch (e->type) { |
|
481 case VEH_Train: { |
|
482 const RailVehicleInfo *rvi = RailVehInfo(engine_number); |
|
483 if (rvi->capacity > 0) y += ShowRefitOptionsList(x, y, w, engine_number); |
|
484 } break; |
|
485 case VEH_Aircraft: |
|
486 y += ShowRefitOptionsList(x, y, w, engine_number); |
|
487 break; |
|
488 } |
251 } |
489 } |
252 |
490 |
253 void DrawAircraftImage(const Vehicle *v, int x, int y, VehicleID selection) |
491 void DrawAircraftImage(const Vehicle *v, int x, int y, VehicleID selection) |
254 { |
492 { |
255 SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); |
493 SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); |
275 } |
513 } |
276 ShowAircraftViewWindow(v); |
514 ShowAircraftViewWindow(v); |
277 } |
515 } |
278 } |
516 } |
279 |
517 |
|
518 /* Figure out what train EngineIDs to put in the list */ |
|
519 static void GenerateBuildTrainList(Window *w) |
|
520 { |
|
521 EngineID eid, sel_id; |
|
522 int num_engines = 0; |
|
523 int num_wagons = 0; |
|
524 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
|
525 |
|
526 bv->filter.railtype = (w->window_number == 0) ? RAILTYPE_END : GetRailType(w->window_number); |
|
527 |
|
528 EngList_RemoveAll(&bv->eng_list); |
|
529 |
|
530 /* Make list of all available train engines and wagons. |
|
531 * Also check to see if the previously selected engine is still available, |
|
532 * and if not, reset selection to INVALID_ENGINE. This could be the case |
|
533 * when engines become obsolete and are removed */ |
|
534 for (sel_id = INVALID_ENGINE, eid = 0; eid < NUM_TRAIN_ENGINES; eid++) { |
|
535 const Engine *e = GetEngine(eid); |
|
536 const RailVehicleInfo *rvi = RailVehInfo(eid); |
|
537 |
|
538 if (bv->filter.railtype != RAILTYPE_END && !HasPowerOnRail(e->railtype, bv->filter.railtype)) continue; |
|
539 if (!IsEngineBuildable(eid, VEH_Train, _local_player)) continue; |
|
540 |
|
541 EngList_Add(&bv->eng_list, eid); |
|
542 if ((rvi->flags & RVI_WAGON) == 0) { |
|
543 num_engines++; |
|
544 } else { |
|
545 num_wagons++; |
|
546 } |
|
547 |
|
548 if (eid == bv->sel_engine) sel_id = eid; |
|
549 } |
|
550 |
|
551 bv->sel_engine = sel_id; |
|
552 |
|
553 // make engines first, and then wagons, sorted by ListPositionOfEngine() |
|
554 _internal_sort_order = false; |
|
555 EngList_Sort(&bv->eng_list, TrainEnginesThenWagonsSorter); |
|
556 |
|
557 // and then sort engines |
|
558 _internal_sort_order = bv->descending_sort_order; |
|
559 EngList_SortPartial(&bv->eng_list, _train_sorter[bv->sort_criteria], 0, num_engines); |
|
560 |
|
561 // and finally sort wagons |
|
562 EngList_SortPartial(&bv->eng_list, _train_sorter[bv->sort_criteria], num_engines, num_wagons); |
|
563 } |
|
564 |
|
565 /* Figure out what aircraft EngineIDs to put in the list */ |
280 static void GenerateBuildAircraftList(Window *w) |
566 static void GenerateBuildAircraftList(Window *w) |
281 { |
567 { |
282 EngineID eid, sel_id; |
568 EngineID eid, sel_id; |
283 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
569 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
284 |
570 |
312 } |
598 } |
313 |
599 |
314 bv->sel_engine = sel_id; |
600 bv->sel_engine = sel_id; |
315 } |
601 } |
316 |
602 |
|
603 /* Generate the list of vehicles */ |
317 static void GenerateBuildList(Window *w) |
604 static void GenerateBuildList(Window *w) |
318 { |
605 { |
319 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
606 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
320 |
607 |
321 switch (bv->vehicle_type) { |
608 switch (bv->vehicle_type) { |
|
609 case VEH_Train: |
|
610 GenerateBuildTrainList(w); |
|
611 break; |
322 case VEH_Aircraft: |
612 case VEH_Aircraft: |
323 GenerateBuildAircraftList(w); |
613 GenerateBuildAircraftList(w); |
324 _internal_sort_order = bv->descending_sort_order; |
614 _internal_sort_order = bv->descending_sort_order; |
325 EngList_Sort(&bv->eng_list, _aircraft_sorter[bv->sort_criteria]); |
615 EngList_Sort(&bv->eng_list, _aircraft_sorter[bv->sort_criteria]); |
326 break; |
616 break; |
327 |
617 } |
328 default: NOT_REACHED(); |
618 } |
329 } |
619 |
330 } |
620 static void DrawBuildVehicleWindow(Window *w) |
331 |
|
332 static void DrawBuildAircraftWindow(Window *w) |
|
333 { |
621 { |
334 const buildvehicle_d *bv = &WP(w, buildvehicle_d); |
622 const buildvehicle_d *bv = &WP(w, buildvehicle_d); |
335 |
623 |
336 SetWindowWidgetDisabledState(w, BUILD_VEHICLE_WIDGET_BUILD, w->window_number == 0); |
624 SetWindowWidgetDisabledState(w, BUILD_VEHICLE_WIDGET_BUILD, w->window_number == 0); |
337 |
625 |
338 SetVScrollCount(w, EngList_Count(&bv->eng_list)); |
626 SetVScrollCount(w, EngList_Count(&bv->eng_list)); |
|
627 SetDParam(0, bv->filter.railtype + STR_881C_NEW_RAIL_VEHICLES); // This should only affect rail vehicles |
339 DrawWindowWidgets(w); |
628 DrawWindowWidgets(w); |
340 |
629 |
341 { |
630 { |
342 int x = 2; |
631 int x = 2; |
343 int y = 27; |
632 int y = 27; |
344 EngineID selected_id = bv->sel_engine; |
633 EngineID selected_id = bv->sel_engine; |
345 EngineID eid = w->vscroll.pos; |
634 uint16 position = w->vscroll.pos; |
346 uint16 max = min(w->vscroll.pos + w->vscroll.cap, EngList_Count(&bv->eng_list)); |
635 uint16 max = min(w->vscroll.pos + w->vscroll.cap, EngList_Count(&bv->eng_list)); |
347 |
636 |
348 for (; eid < max; eid++) { |
637 switch (bv->vehicle_type) { |
349 const EngineID engine = bv->eng_list[eid]; |
638 case VEH_Train: |
350 |
639 for (; position < max; position++, y += 14) { |
351 DrawString(x + 62, y + 7, GetCustomEngineName(engine), engine == selected_id ? 0xC : 0x10); |
640 const EngineID engine = bv->eng_list[position]; |
352 DrawAircraftEngine(x + 29, y + 10, engine, GetEnginePalette(engine, _local_player)); |
641 |
353 y += 24; |
642 DrawString(x + 59, y + 2, GetCustomEngineName(engine), engine == selected_id ? 0xC : 0x10); |
|
643 DrawTrainEngine(x + 29, y + 6, engine, GetEnginePalette(engine, _local_player)); |
|
644 } |
|
645 break; |
|
646 case VEH_Aircraft: |
|
647 for (; position < max; position++, y += 24) { |
|
648 const EngineID engine = bv->eng_list[position]; |
|
649 |
|
650 DrawString(x + 62, y + 7, GetCustomEngineName(engine), engine == selected_id ? 0xC : 0x10); |
|
651 DrawAircraftEngine(x + 29, y + 10, engine, GetEnginePalette(engine, _local_player)); |
|
652 } |
|
653 break; |
354 } |
654 } |
355 |
655 |
356 if (selected_id != INVALID_ENGINE) { |
656 if (selected_id != INVALID_ENGINE) { |
357 const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL]; |
657 const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL]; |
358 DrawAircraftPurchaseInfo(x, wi->top + 1, wi->right - wi->left - 2, selected_id); |
658 DrawVehiclePurchaseInfo(x, wi->top + 1, wi->right - wi->left - 2, selected_id); |
359 } |
659 } |
360 } |
660 } |
361 DrawString(85, 15, _aircraft_sort_listing[bv->sort_criteria], 0x10); |
661 { |
362 DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10); |
662 StringID str = STR_NULL; |
363 } |
663 switch (bv->vehicle_type) { |
364 |
664 case VEH_Train: str = _train_sort_listing[bv->sort_criteria]; break; |
365 static void BuildAircraftClickEvent(Window *w, WindowEvent *e) |
665 case VEH_Aircraft: str = _aircraft_sort_listing[bv->sort_criteria]; break; |
|
666 } |
|
667 |
|
668 DrawString(85, 15, str, 0x10); |
|
669 DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10); |
|
670 } |
|
671 } |
|
672 |
|
673 static void BuildVehicleClickEvent(Window *w, WindowEvent *e) |
366 { |
674 { |
367 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
675 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
368 |
676 |
369 switch (e->we.click.widget) { |
677 switch (e->we.click.widget) { |
370 case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING: |
678 case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING: |
371 bv->descending_sort_order ^= true; |
679 bv->descending_sort_order ^= true; |
372 _last_sort_order = bv->descending_sort_order; |
680 switch (bv->vehicle_type) { |
|
681 case VEH_Train: _last_sort_order_train = bv->descending_sort_order; break; |
|
682 case VEH_Aircraft: _last_sort_order_aircraft = bv->descending_sort_order; break; |
|
683 } |
373 GenerateBuildList(w); |
684 GenerateBuildList(w); |
374 SetWindowDirty(w); |
685 SetWindowDirty(w); |
375 break; |
686 break; |
376 |
687 |
377 case BUILD_VEHICLE_WIDGET_LIST: { |
688 case BUILD_VEHICLE_WIDGET_LIST: { |
378 uint i = (e->we.click.pt.y - 26) / 24 + w->vscroll.pos; |
689 uint i = (e->we.click.pt.y - 26) / GetVehicleListHeight(bv->vehicle_type) + w->vscroll.pos; |
379 uint num_items = EngList_Count(&bv->eng_list); |
690 uint num_items = EngList_Count(&bv->eng_list); |
380 bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE; |
691 bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE; |
381 SetWindowDirty(w); |
692 SetWindowDirty(w); |
382 break; |
693 break; |
383 } |
694 } |
384 |
695 |
385 case BUILD_VEHICLE_WIDGET_SORT_TEXT: case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:/* Select sorting criteria dropdown menu */ |
696 case BUILD_VEHICLE_WIDGET_SORT_TEXT: case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: // Select sorting criteria dropdown menu |
386 ShowDropDownMenu(w, _aircraft_sort_listing, bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0); |
697 switch (bv->vehicle_type) { |
|
698 case VEH_Train: |
|
699 ShowDropDownMenu(w, _train_sort_listing, bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0); |
|
700 break; |
|
701 case VEH_Aircraft: |
|
702 ShowDropDownMenu(w, _aircraft_sort_listing, bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0); |
|
703 break; |
|
704 } |
387 return; |
705 return; |
388 |
706 |
389 case BUILD_VEHICLE_WIDGET_BUILD: { |
707 case BUILD_VEHICLE_WIDGET_BUILD: { |
390 EngineID sel_eng = bv->sel_engine; |
708 EngineID sel_eng = bv->sel_engine; |
391 if (sel_eng != INVALID_ENGINE) { |
709 if (sel_eng != INVALID_ENGINE) { |
392 DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT)); |
710 switch (bv->vehicle_type) { |
|
711 case VEH_Train: |
|
712 DoCommandP(w->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->flags & RVI_WAGON) ? CcBuildWagon : CcBuildLoco, |
|
713 CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE)); |
|
714 break; |
|
715 case VEH_Aircraft: |
|
716 DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT)); |
|
717 break; |
|
718 } |
393 } |
719 } |
394 break; |
720 break; |
395 } |
721 } |
396 |
722 |
397 case BUILD_VEHICLE_WIDGET_RENAME: { |
723 case BUILD_VEHICLE_WIDGET_RENAME: { |
398 EngineID sel_eng = bv->sel_engine; |
724 EngineID sel_eng = bv->sel_engine; |
399 if (sel_eng != INVALID_ENGINE) { |
725 if (sel_eng != INVALID_ENGINE) { |
|
726 StringID str = STR_NULL; |
|
727 |
400 bv->rename_engine = sel_eng; |
728 bv->rename_engine = sel_eng; |
401 ShowQueryString(GetCustomEngineName(sel_eng), STR_A039_RENAME_AIRCRAFT_TYPE, 31, 160, w, CS_ALPHANUMERAL); |
729 switch (bv->vehicle_type) { |
|
730 case VEH_Train: str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break; |
|
731 case VEH_Aircraft: str = STR_A039_RENAME_AIRCRAFT_TYPE; break; |
|
732 } |
|
733 ShowQueryString(GetCustomEngineName(sel_eng), str, 31, 160, w, CS_ALPHANUMERAL); |
402 } |
734 } |
403 break; |
735 break; |
404 } |
736 } |
405 } |
737 } |
406 } |
738 } |
407 |
739 |
408 static void NewAircraftWndProc(Window *w, WindowEvent *e) |
740 static void NewVehicleWndProc(Window *w, WindowEvent *e) |
409 { |
741 { |
410 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
742 buildvehicle_d *bv = &WP(w, buildvehicle_d); |
411 |
743 |
412 switch (e->event) { |
744 switch (e->event) { |
413 case WE_INVALIDATE_DATA: |
745 case WE_INVALIDATE_DATA: |
417 case WE_DESTROY: |
749 case WE_DESTROY: |
418 EngList_Destroy(&bv->eng_list); |
750 EngList_Destroy(&bv->eng_list); |
419 break; |
751 break; |
420 |
752 |
421 case WE_PAINT: |
753 case WE_PAINT: |
422 DrawBuildAircraftWindow(w); |
754 DrawBuildVehicleWindow(w); |
423 break; |
755 break; |
424 |
756 |
425 case WE_CLICK: |
757 case WE_CLICK: |
426 BuildAircraftClickEvent(w, e); |
758 BuildVehicleClickEvent(w, e); |
427 break; |
759 break; |
428 |
760 |
429 case WE_ON_EDIT_TEXT: { |
761 case WE_ON_EDIT_TEXT: { |
430 if (e->we.edittext.str[0] != '\0') { |
762 if (e->we.edittext.str[0] != '\0') { |
|
763 StringID str = STR_NULL; |
431 _cmd_text = e->we.edittext.str; |
764 _cmd_text = e->we.edittext.str; |
432 DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE)); |
765 switch (bv->vehicle_type) { |
|
766 case VEH_Train: str = STR_886B_CAN_T_RENAME_TRAIN_VEHICLE; break; |
|
767 case VEH_Aircraft: str = STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE; break; |
|
768 } |
|
769 DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(str)); |
433 } |
770 } |
434 break; |
771 break; |
435 } |
772 } |
436 |
773 |
437 case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ |
774 case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */ |
438 if (bv->sort_criteria != e->we.dropdown.index) { |
775 if (bv->sort_criteria != e->we.dropdown.index) { |
439 bv->sort_criteria = _last_sort_criteria = e->we.dropdown.index; |
776 bv->sort_criteria = e->we.dropdown.index; |
|
777 switch (bv->vehicle_type) { |
|
778 case VEH_Train: _last_sort_criteria_train = bv->sort_criteria; break; |
|
779 case VEH_Aircraft: _last_sort_criteria_aircraft = bv->sort_criteria; break; |
|
780 } |
440 GenerateBuildList(w); |
781 GenerateBuildList(w); |
441 } |
782 } |
442 SetWindowDirty(w); |
783 SetWindowDirty(w); |
443 break; |
784 break; |
444 |
785 |
445 case WE_RESIZE: |
786 case WE_RESIZE: |
446 w->vscroll.cap += e->we.sizing.diff.y / 24; |
787 if (e->we.sizing.diff.y == 0) break; |
|
788 |
|
789 w->vscroll.cap += e->we.sizing.diff.y / GetVehicleListHeight(bv->vehicle_type); |
447 w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1; |
790 w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1; |
448 break; |
791 break; |
449 } |
792 } |
450 } |
793 } |
451 |
794 |
452 static const WindowDesc _build_vehicle_desc = { |
795 static const WindowDesc _build_vehicle_desc = { |
453 WDP_AUTO, WDP_AUTO, 240, 226, |
796 WDP_AUTO, WDP_AUTO, 228, 226, |
454 WC_BUILD_VEHICLE,0, |
797 WC_BUILD_VEHICLE,0, |
455 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE, |
798 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE, |
456 _build_vehicle_widgets, |
799 _build_vehicle_widgets, |
457 NewAircraftWndProc |
800 NewVehicleWndProc |
458 }; |
801 }; |
459 |
802 |
460 void ShowBuildVehicleWindow(TileIndex tile, byte type) |
803 void ShowBuildVehicleWindow(TileIndex tile, byte type) |
461 { |
804 { |
462 buildvehicle_d *bv; |
805 buildvehicle_d *bv; |
463 Window *w; |
806 Window *w; |
464 |
807 |
|
808 assert(IsPlayerBuildableVehicleType(type)); |
|
809 |
465 DeleteWindowById(WC_BUILD_VEHICLE, tile); |
810 DeleteWindowById(WC_BUILD_VEHICLE, tile); |
|
811 |
466 w = AllocateWindowDescFront(&_build_vehicle_desc, tile); |
812 w = AllocateWindowDescFront(&_build_vehicle_desc, tile); |
|
813 |
467 if (w == NULL) return; |
814 if (w == NULL) return; |
468 |
815 |
469 w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player; |
816 w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player; |
470 w->resize.step_height = GetVehicleListHeight(type); |
817 w->resize.step_height = GetVehicleListHeight(type); |
471 w->vscroll.cap = 4; |
818 w->vscroll.cap = w->resize.step_height == 24 ? 4 : 8; |
472 w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1; |
819 w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1; |
473 |
820 |
474 bv = &WP(w, buildvehicle_d); |
821 bv = &WP(w, buildvehicle_d); |
475 EngList_Create(&bv->eng_list); |
822 EngList_Create(&bv->eng_list); |
476 bv->sel_engine = INVALID_ENGINE; |
823 bv->sel_engine = INVALID_ENGINE; |
477 bv->sort_criteria = _last_sort_criteria; |
|
478 bv->descending_sort_order = _last_sort_order; |
|
479 |
824 |
480 bv->vehicle_type = type; |
825 bv->vehicle_type = type; |
481 |
826 |
482 switch (type) { |
827 switch (type) { |
|
828 case VEH_Train: |
|
829 WP(w,buildvehicle_d).filter.railtype = (tile == 0) ? RAILTYPE_END : GetRailType(tile); |
|
830 ResizeWindow(w, 0, 16); |
|
831 bv->sort_criteria = _last_sort_criteria_train; |
|
832 bv->descending_sort_order = _last_sort_order_train; |
|
833 break; |
483 case VEH_Aircraft: { |
834 case VEH_Aircraft: { |
484 AcceptPlanes acc_planes = (tile == 0) ? ALL : GetAirport(GetStationByTile(tile)->airport_type)->acc_planes; |
835 AcceptPlanes acc_planes = (tile == 0) ? ALL : GetAirport(GetStationByTile(tile)->airport_type)->acc_planes; |
485 bv->filter.acc_planes = acc_planes; |
836 bv->filter.acc_planes = acc_planes; |
486 break; |
837 ResizeWindow(w, 12, 0); |
487 } |
838 bv->sort_criteria = _last_sort_criteria_aircraft; |
488 default: NOT_REACHED(); |
839 bv->descending_sort_order = _last_sort_order_aircraft; |
489 } |
840 break; |
|
841 } |
|
842 } |
|
843 SetupWindowStrings(w, type); |
|
844 |
|
845 w->resize.width = w->width; |
|
846 w->resize.height = w->height; |
490 |
847 |
491 GenerateBuildList(w); |
848 GenerateBuildList(w); |
492 /* Select the first plane in the list as default when opening the window */ |
849 /* Select the first engine in the list as default when opening the window */ |
493 if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0]; |
850 if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0]; |
494 } |
851 } |