28 void InitializeVehiclesGuiList(void) |
31 void InitializeVehiclesGuiList(void) |
29 { |
32 { |
30 _railtype_selected_in_replace_gui = RAILTYPE_RAIL; |
33 _railtype_selected_in_replace_gui = RAILTYPE_RAIL; |
31 } |
34 } |
32 |
35 |
33 // this define is to match engine.c, but engine.c keeps it to itself |
36 /** Rebuild the left autoreplace list if an engine is removed or added |
34 // ENGINE_AVAILABLE is used in ReplaceVehicleWndProc |
37 * @param e Engine to check if it is removed or added |
35 #define ENGINE_AVAILABLE ((e->flags & 1 && HASBIT(info->climates, _opt.landscape)) || HASBIT(e->player_avail, _local_player)) |
38 * Note: this function only works if it is called either |
36 |
39 * - when a new vehicle is build, but before it's counted in num_engines |
37 /* if show_outdated is selected, it do not sort psudo engines properly but it draws all engines |
40 * - when a vehicle is deleted and after it's substracted from num_engines |
38 * if used compined with show_cars set to false, it will work as intended. Replace window do it like that |
41 * - when not changing the count (used when changing replace orders) |
39 * this was a big hack even before show_outdated was added. Stupid newgrf :p |
42 */ |
40 */ |
43 void InvalidateAutoreplaceWindow(EngineID e) |
41 static void train_engine_drawing_loop(int *x, int *y, int *pos, int *sel, EngineID *selected_id, RailType railtype, |
44 { |
42 uint8 lines_drawn, bool is_engine, bool show_cars, bool show_outdated, bool show_compatible) |
45 Player *p = GetPlayer(_local_player); |
43 { |
46 byte type = GetEngine(e)->type; |
44 EngineID j; |
47 |
45 byte colour; |
48 if (p->num_engines[e] == 0) { |
46 const Player *p = GetPlayer(_local_player); |
49 /* We don't have any of this engine type. |
47 |
50 * Either we just sold the last one, we build a new one or we stopped replacing it. |
48 for (j = 0; j < NUM_TRAIN_ENGINES; j++) { |
51 * In all cases, we need to update the left list */ |
49 EngineID i = GetRailVehAtPosition(j); |
52 _rebuild_left_list = true; |
50 const Engine *e = GetEngine(i); |
53 } else { |
51 const RailVehicleInfo *rvi = RailVehInfo(i); |
54 _rebuild_left_list = false; |
52 const EngineInfo *info = EngInfo(i); |
55 } |
53 |
56 _rebuild_right_list = false; |
54 if (!EngineHasReplacementForPlayer(p, i) && p->num_engines[i] == 0 && show_outdated) continue; |
57 InvalidateWindowData(WC_REPLACE_VEHICLE, type); |
55 |
58 } |
56 if ((rvi->power == 0 && !show_cars) || (rvi->power != 0 && show_cars)) // show wagons or engines (works since wagons do not have power) |
59 |
57 continue; |
60 /** When an engine is made buildable or is removed from being buildable, add/remove it from the build/autoreplace lists |
58 |
61 * @param type The type of engine |
59 if (*sel == 0) *selected_id = j; |
62 */ |
60 |
63 void AddRemoveEngineFromAutoreplaceAndBuildWindows(byte type) |
61 |
64 { |
62 colour = *sel == 0 ? 0xC : 0x10; |
65 _rebuild_left_list = false; // left list is only for the vehicles the player owns and is not related to being buildable |
63 if (!(ENGINE_AVAILABLE && show_outdated && RailVehInfo(i)->power && IsCompatibleRail(rvi->railtype, railtype))) { |
66 _rebuild_right_list = true; |
64 if ((!IsCompatibleRail(rvi->railtype, railtype) && show_compatible) |
67 InvalidateWindowData(WC_REPLACE_VEHICLE, type); // Update the autoreplace window |
65 || (rvi->railtype != railtype && !show_compatible) |
68 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well |
66 || (rvi->railveh_type != RAILVEH_WAGON) != is_engine || |
69 } |
67 !HASBIT(e->player_avail, _local_player)) |
70 |
68 continue; |
71 /** Get the default cargo type for an engine |
69 #if 0 |
72 * @param engine the EngineID to get the cargo for |
|
73 * @return the cargo type carried by the engine (CT_INVALID if engine got no cargo capacity) |
|
74 */ |
|
75 static CargoID EngineCargo(EngineID engine) |
|
76 { |
|
77 if (engine == INVALID_ENGINE) return CT_INVALID; // surely INVALID_ENGINE can't carry anything but CT_INVALID |
|
78 |
|
79 switch (GetEngine(engine)->type) { |
|
80 default: NOT_REACHED(); |
|
81 case VEH_Train: |
|
82 if (RailVehInfo(engine)->capacity == 0) return CT_INVALID; // no capacity -> can't carry cargo |
|
83 return RailVehInfo(engine)->cargo_type; |
|
84 case VEH_Road: return RoadVehInfo(engine)->cargo_type; |
|
85 case VEH_Ship: return ShipVehInfo(engine)->cargo_type; |
|
86 case VEH_Aircraft: return CT_PASSENGERS; // all planes are build with passengers by default |
|
87 } |
|
88 } |
|
89 |
|
90 /** Figure out if an engine should be added to a list |
|
91 * @param e The EngineID |
|
92 * @param draw_left If true, then the left list is drawn (the engines specific to the railtype you selected) |
|
93 * @param show_engines if truem then locomotives are drawn, else wagons (never both) |
|
94 * @return true if the engine should be in the list (based on this check) |
|
95 */ |
|
96 static bool GenerateReplaceRailList(EngineID e, bool draw_left, bool show_engines) |
|
97 { |
|
98 const RailVehicleInfo *rvi = RailVehInfo(e); |
|
99 |
|
100 /* Ensure that the wagon/engine selection fits the engine. */ |
|
101 if ((rvi->railveh_type == RAILVEH_WAGON) == show_engines) return false; |
|
102 |
|
103 if (draw_left && show_engines) { |
|
104 /* Ensure that the railtype is specific to the selected one */ |
|
105 if (rvi->railtype != _railtype_selected_in_replace_gui) return false; |
|
106 } else { |
|
107 /* Ensure that it's a compatible railtype to the selected one (like electric <-> diesel) |
|
108 * The vehicle do not have to have power on the railtype in question, only able to drive (pulled if needed) */ |
|
109 if (!IsCompatibleRail(rvi->railtype, _railtype_selected_in_replace_gui)) return false; |
|
110 } |
|
111 return true; |
|
112 } |
|
113 |
|
114 /** Figure out if two engines got at least one type of cargo in common (refitting if needed) |
|
115 * @param engine_a one of the EngineIDs |
|
116 * @param engine_b the other EngineID |
|
117 * @return true if they can both carry the same type of cargo (or at least one of them got no capacity at all) |
|
118 */ |
|
119 static bool EnginesGotCargoInCommon(EngineID engine_a, EngineID engine_b) |
|
120 { |
|
121 CargoID a = EngineCargo(engine_a); |
|
122 CargoID b = EngineCargo(engine_b); |
|
123 |
|
124 /* we should always be able to refit to/from locomotives without capacity |
|
125 * Because of that, CT_INVALID shoudl always return true */ |
|
126 if (a == CT_INVALID || b == CT_INVALID || a == b) return true; // they carry no ro the same type by default |
|
127 if (EngInfo(engine_a)->refit_mask & EngInfo(engine_b)->refit_mask) return true; // both can refit to the same |
|
128 if (CanRefitTo(engine_a, b) || CanRefitTo(engine_b, a)) return true; // one can refit to what the other one carries |
|
129 return false; |
|
130 } |
|
131 |
|
132 /** Generate a list |
|
133 * @param w Window, that contains the list |
|
134 * @param draw_left true if generating the left list, otherwise false |
|
135 */ |
|
136 static void GenerateReplaceVehList(Window *w, bool draw_left) |
|
137 { |
|
138 Player *p = GetPlayer(_local_player); |
|
139 EngineID e; |
|
140 EngineID selected_engine = INVALID_ENGINE; |
|
141 byte type = w->window_number; |
|
142 byte i = draw_left ? 0 : 1; |
|
143 |
|
144 EngineList *list = &WP(w, replaceveh_d).list[i]; |
|
145 EngList_RemoveAll(list); |
|
146 |
|
147 FOR_ALL_ENGINEIDS_OF_TYPE(e, type) { |
|
148 if (type == VEH_Train && !GenerateReplaceRailList(e, draw_left, WP(w, replaceveh_d).wagon_btnstate)) continue; // special rules for trains |
|
149 |
|
150 if (draw_left) { |
|
151 /* Skip drawing the engines we don't have any of and haven't set for replacement */ |
|
152 if (p->num_engines[e] == 0 && EngineReplacementForPlayer(GetPlayer(_local_player), e) == INVALID_ENGINE) continue; |
70 } else { |
153 } else { |
71 // TODO find a nice red colour for vehicles being replaced |
154 /* This is for engines we can replace to and they should depend on what we selected to replace from */ |
72 if ( _autoreplace_array[i] != i ) |
155 if (!IsEngineBuildable(e, type, _local_player)) continue; // we need to be able to build the engine |
73 colour = *sel == 0 ? 0x44 : 0x45; |
156 if (!EnginesGotCargoInCommon(e, WP(w, replaceveh_d).sel_engine[0])) continue; // the engines needs to be able to carry the same cargo |
74 #endif |
157 if (e == WP(w, replaceveh_d).sel_engine[0]) continue; // we can't replace an engine into itself (that would be autorenew) |
75 } |
158 } |
76 |
159 |
77 if (IS_INT_INSIDE(--*pos, -lines_drawn, 0)) { |
160 EngList_Add(list, e); |
78 DrawString(*x + 59, *y + 2, GetCustomEngineName(i), |
161 if (e == WP(w, replaceveh_d).sel_engine[i]) selected_engine = e; // The selected engine is still in the list |
79 colour); |
162 } |
80 // show_outdated is true only for left side, which is where we show old replacements |
163 WP(w, replaceveh_d).sel_engine[i] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore) |
81 DrawTrainEngine(*x + 29, *y + 6, i, (p->num_engines[i] == 0 && show_outdated) ? |
164 } |
82 PALETTE_CRASH : GetEnginePalette(i, _local_player)); |
165 |
83 if ( show_outdated ) { |
166 /** Generate the lists |
84 SetDParam(0, p->num_engines[i]); |
167 * @param w Window containing the lists |
85 DrawStringRightAligned(213, *y+5, STR_TINY_BLACK, 0); |
168 */ |
|
169 static void GenerateLists(Window *w) |
|
170 { |
|
171 EngineID e = WP(w, replaceveh_d).sel_engine[0]; |
|
172 |
|
173 if (WP(w, replaceveh_d).update_left == true) { |
|
174 /* We need to rebuild the left list */ |
|
175 GenerateReplaceVehList(w, true); |
|
176 SetVScrollCount(w, EngList_Count(&WP(w, replaceveh_d).list[0])); |
|
177 if (WP(w, replaceveh_d).init_lists && WP(w, replaceveh_d).sel_engine[0] == INVALID_ENGINE && EngList_Count(&WP(w, replaceveh_d).list[0]) != 0) { |
|
178 WP(w, replaceveh_d).sel_engine[0] = WP(w, replaceveh_d).list[0][0]; |
|
179 } |
|
180 } |
|
181 |
|
182 if (WP(w, replaceveh_d).update_right || e != WP(w, replaceveh_d).sel_engine[0]) { |
|
183 /* Either we got a request to rebuild the right list or the left list selected a different engine */ |
|
184 if (WP(w, replaceveh_d).sel_engine[0] == INVALID_ENGINE) { |
|
185 /* Always empty the right list when nothing is selected in the left list */ |
|
186 EngList_RemoveAll(&WP(w, replaceveh_d).list[1]); |
|
187 WP(w, replaceveh_d).sel_engine[1] = INVALID_ENGINE; |
|
188 } else { |
|
189 GenerateReplaceVehList(w, false); |
|
190 SetVScroll2Count(w, EngList_Count(&WP(w, replaceveh_d).list[1])); |
|
191 if (WP(w, replaceveh_d).init_lists && WP(w, replaceveh_d).sel_engine[1] == INVALID_ENGINE && EngList_Count(&WP(w, replaceveh_d).list[1]) != 0) { |
|
192 WP(w, replaceveh_d).sel_engine[1] = WP(w, replaceveh_d).list[1][0]; |
86 } |
193 } |
87 *y += 14; |
|
88 } |
194 } |
89 --*sel; |
195 } |
90 } |
196 /* Reset the flags about needed updates */ |
91 } |
197 WP(w, replaceveh_d).update_left = false; |
92 |
198 WP(w, replaceveh_d).update_right = false; |
93 |
199 WP(w, replaceveh_d).init_lists = false; |
94 static void SetupScrollStuffForReplaceWindow(Window *w) |
200 } |
95 { |
201 |
96 EngineID selected_id[2] = { INVALID_ENGINE, INVALID_ENGINE }; |
202 |
97 const Player* p = GetPlayer(_local_player); |
203 void DrawEngineList(byte type, int x, int y, const EngineList eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count); |
98 uint sel[2]; |
|
99 uint count = 0; |
|
100 uint count2 = 0; |
|
101 EngineID i; |
|
102 |
|
103 sel[0] = WP(w,replaceveh_d).sel_index[0]; |
|
104 sel[1] = WP(w,replaceveh_d).sel_index[1]; |
|
105 |
|
106 switch (WP(w,replaceveh_d).vehicletype) { |
|
107 case VEH_Train: { |
|
108 RailType railtype = _railtype_selected_in_replace_gui; |
|
109 |
|
110 w->widget[13].color = _player_colors[_local_player]; // sets the colour of that art thing |
|
111 w->widget[16].color = _player_colors[_local_player]; // sets the colour of that art thing |
|
112 |
|
113 for (i = 0; i < NUM_TRAIN_ENGINES; i++) { |
|
114 EngineID eid = GetRailVehAtPosition(i); |
|
115 const Engine* e = GetEngine(eid); |
|
116 const RailVehicleInfo *rvi = RailVehInfo(eid); |
|
117 const EngineInfo* info = EngInfo(eid); |
|
118 |
|
119 // left window contains compatible engines while right window only contains engines of the selected type |
|
120 if (ENGINE_AVAILABLE && |
|
121 (rvi->power != 0) == (WP(w, replaceveh_d).wagon_btnstate != 0)) { |
|
122 if (IsCompatibleRail(rvi->railtype, railtype) && (p->num_engines[eid] > 0 || EngineHasReplacementForPlayer(p, eid))) { |
|
123 if (sel[0] == count) selected_id[0] = eid; |
|
124 count++; |
|
125 } |
|
126 if (rvi->railtype == railtype && HASBIT(e->player_avail, _local_player)) { |
|
127 if (sel[1] == count2) selected_id[1] = eid; |
|
128 count2++; |
|
129 } |
|
130 } |
|
131 } |
|
132 break; |
|
133 } |
|
134 |
|
135 case VEH_Road: { |
|
136 for (i = ROAD_ENGINES_INDEX; i < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; i++) { |
|
137 if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { |
|
138 if (sel[0] == count) selected_id[0] = i; |
|
139 count++; |
|
140 } |
|
141 } |
|
142 |
|
143 if (selected_id[0] != INVALID_ENGINE) { // only draw right array if we have anything in the left one |
|
144 CargoID cargo = RoadVehInfo(selected_id[0])->cargo_type; |
|
145 |
|
146 for (i = ROAD_ENGINES_INDEX; i < ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES; i++) { |
|
147 if (cargo == RoadVehInfo(i)->cargo_type && |
|
148 HASBIT(GetEngine(i)->player_avail, _local_player)) { |
|
149 if (sel[1] == count2) selected_id[1] = i; |
|
150 count2++; |
|
151 } |
|
152 } |
|
153 } |
|
154 break; |
|
155 } |
|
156 |
|
157 case VEH_Ship: { |
|
158 for (i = SHIP_ENGINES_INDEX; i < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; i++) { |
|
159 if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { |
|
160 if (sel[0] == count) selected_id[0] = i; |
|
161 count++; |
|
162 } |
|
163 } |
|
164 |
|
165 if (selected_id[0] != INVALID_ENGINE) { |
|
166 const ShipVehicleInfo* svi = ShipVehInfo(selected_id[0]); |
|
167 CargoID cargo = svi->cargo_type; |
|
168 bool refittable = svi->refittable; |
|
169 |
|
170 for (i = SHIP_ENGINES_INDEX; i < SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES; i++) { |
|
171 if (HASBIT(GetEngine(i)->player_avail, _local_player) && ( |
|
172 ShipVehInfo(i)->cargo_type == cargo || |
|
173 ShipVehInfo(i)->refittable && refittable |
|
174 )) { |
|
175 if (sel[1] == count2) selected_id[1] = i; |
|
176 count2++; |
|
177 } |
|
178 } |
|
179 } |
|
180 break; |
|
181 } |
|
182 |
|
183 case VEH_Aircraft: { |
|
184 for (i = AIRCRAFT_ENGINES_INDEX; i < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) { |
|
185 if (p->num_engines[i] > 0 || EngineHasReplacementForPlayer(p, i)) { |
|
186 if (sel[0] == count) selected_id[0] = i; |
|
187 count++; |
|
188 } |
|
189 } |
|
190 |
|
191 if (selected_id[0] != INVALID_ENGINE) { |
|
192 byte subtype = AircraftVehInfo(selected_id[0])->subtype; |
|
193 |
|
194 for (i = AIRCRAFT_ENGINES_INDEX; i < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; i++) { |
|
195 if (HASBIT(GetEngine(i)->player_avail, _local_player) && |
|
196 (subtype & AIR_CTOL) == (AircraftVehInfo(i)->subtype & AIR_CTOL)) { |
|
197 if (sel[1] == count2) selected_id[1] = i; |
|
198 count2++; |
|
199 } |
|
200 } |
|
201 } |
|
202 break; |
|
203 } |
|
204 } |
|
205 // sets up the number of items in each list |
|
206 SetVScrollCount(w, count); |
|
207 SetVScroll2Count(w, count2); |
|
208 WP(w,replaceveh_d).sel_engine[0] = selected_id[0]; |
|
209 WP(w,replaceveh_d).sel_engine[1] = selected_id[1]; |
|
210 |
|
211 WP(w,replaceveh_d).count[0] = count; |
|
212 WP(w,replaceveh_d).count[1] = count2; |
|
213 return; |
|
214 } |
|
215 |
|
216 |
|
217 static void DrawEngineArrayInReplaceWindow(Window *w, int x, int y, int x2, int y2, int pos, int pos2, |
|
218 int sel1, int sel2, EngineID selected_id1, EngineID selected_id2) |
|
219 { |
|
220 int sel[2]; |
|
221 EngineID selected_id[2]; |
|
222 const Player *p = GetPlayer(_local_player); |
|
223 |
|
224 sel[0] = sel1; |
|
225 sel[1] = sel2; |
|
226 |
|
227 selected_id[0] = selected_id1; |
|
228 selected_id[1] = selected_id2; |
|
229 |
|
230 switch (WP(w,replaceveh_d).vehicletype) { |
|
231 case VEH_Train: { |
|
232 RailType railtype = _railtype_selected_in_replace_gui; |
|
233 DrawString(157, w->widget[14].top + 1, _rail_types_list[railtype], 0x10); |
|
234 /* draw sorting criteria string */ |
|
235 |
|
236 /* Ensure that custom engines which substituted wagons |
|
237 * are sorted correctly. |
|
238 * XXX - DO NOT EVER DO THIS EVER AGAIN! GRRR hacking in wagons as |
|
239 * engines to get more types.. Stays here until we have our own format |
|
240 * then it is exit!!! */ |
|
241 if (WP(w,replaceveh_d).wagon_btnstate) { |
|
242 train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, true, false, true, true); // True engines |
|
243 train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, true, false, false, false); // True engines |
|
244 train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, false, false, false); // Feeble wagons |
|
245 } else { |
|
246 train_engine_drawing_loop(&x, &y, &pos, &sel[0], &selected_id[0], railtype, w->vscroll.cap, false, true, true, true); |
|
247 train_engine_drawing_loop(&x2, &y2, &pos2, &sel[1], &selected_id[1], railtype, w->vscroll.cap, false, true, false, true); |
|
248 } |
|
249 break; |
|
250 } |
|
251 |
|
252 case VEH_Road: { |
|
253 int num = NUM_ROAD_ENGINES; |
|
254 const Engine* e = GetEngine(ROAD_ENGINES_INDEX); |
|
255 EngineID engine_id = ROAD_ENGINES_INDEX; |
|
256 |
|
257 do { |
|
258 if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { |
|
259 if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { |
|
260 DrawString(x+59, y+2, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); |
|
261 DrawRoadVehEngine(x+29, y+6, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); |
|
262 SetDParam(0, p->num_engines[engine_id]); |
|
263 DrawStringRightAligned(213, y+5, STR_TINY_BLACK, 0); |
|
264 y += 14; |
|
265 } |
|
266 sel[0]--; |
|
267 } |
|
268 |
|
269 if (selected_id[0] != INVALID_ENGINE) { |
|
270 byte cargo = RoadVehInfo(selected_id[0])->cargo_type; |
|
271 |
|
272 if (RoadVehInfo(engine_id)->cargo_type == cargo && HASBIT(e->player_avail, _local_player)) { |
|
273 if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0) && RoadVehInfo(engine_id)->cargo_type == cargo) { |
|
274 DrawString(x2+59, y2+2, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10); |
|
275 DrawRoadVehEngine(x2+29, y2+6, engine_id, GetEnginePalette(engine_id, _local_player)); |
|
276 y2 += 14; |
|
277 } |
|
278 sel[1]--; |
|
279 } |
|
280 } |
|
281 } while (++engine_id, ++e,--num); |
|
282 break; |
|
283 } |
|
284 |
|
285 case VEH_Ship: { |
|
286 int num = NUM_SHIP_ENGINES; |
|
287 const Engine* e = GetEngine(SHIP_ENGINES_INDEX); |
|
288 EngineID engine_id = SHIP_ENGINES_INDEX; |
|
289 |
|
290 do { |
|
291 if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { |
|
292 if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { |
|
293 DrawString(x+75, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); |
|
294 DrawShipEngine(x+35, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); |
|
295 SetDParam(0, p->num_engines[engine_id]); |
|
296 DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0); |
|
297 y += 24; |
|
298 } |
|
299 sel[0]--; |
|
300 } |
|
301 |
|
302 if (selected_id[0] != INVALID_ENGINE) { |
|
303 CargoID cargo = ShipVehInfo(selected_id[0])->cargo_type; |
|
304 bool refittable = ShipVehInfo(selected_id[0])->refittable; |
|
305 |
|
306 if (HASBIT(e->player_avail, _local_player) && ( cargo == ShipVehInfo(engine_id)->cargo_type || refittable & ShipVehInfo(engine_id)->refittable)) { |
|
307 if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) { |
|
308 DrawString(x2+75, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10); |
|
309 DrawShipEngine(x2+35, y2+10, engine_id, GetEnginePalette(engine_id, _local_player)); |
|
310 y2 += 24; |
|
311 } |
|
312 sel[1]--; |
|
313 } |
|
314 } |
|
315 } while (++engine_id, ++e, --num); |
|
316 break; |
|
317 } //end of ship |
|
318 |
|
319 case VEH_Aircraft: { |
|
320 int num = NUM_AIRCRAFT_ENGINES; |
|
321 const Engine* e = GetEngine(AIRCRAFT_ENGINES_INDEX); |
|
322 EngineID engine_id = AIRCRAFT_ENGINES_INDEX; |
|
323 |
|
324 do { |
|
325 if (p->num_engines[engine_id] > 0 || EngineHasReplacementForPlayer(p, engine_id)) { |
|
326 if (sel[0] == 0) selected_id[0] = engine_id; |
|
327 if (IS_INT_INSIDE(--pos, -w->vscroll.cap, 0)) { |
|
328 DrawString(x+62, y+7, GetCustomEngineName(engine_id), sel[0]==0 ? 0xC : 0x10); |
|
329 DrawAircraftEngine(x+29, y+10, engine_id, p->num_engines[engine_id] > 0 ? GetEnginePalette(engine_id, _local_player) : PALETTE_CRASH); |
|
330 SetDParam(0, p->num_engines[engine_id]); |
|
331 DrawStringRightAligned(213, y+15, STR_TINY_BLACK, 0); |
|
332 y += 24; |
|
333 } |
|
334 sel[0]--; |
|
335 } |
|
336 |
|
337 if (selected_id[0] != INVALID_ENGINE) { |
|
338 byte subtype = AircraftVehInfo(selected_id[0])->subtype; |
|
339 |
|
340 if ((subtype & AIR_CTOL) == (AircraftVehInfo(engine_id)->subtype & AIR_CTOL) && |
|
341 HASBIT(e->player_avail, _local_player)) { |
|
342 if (sel[1] == 0) selected_id[1] = engine_id; |
|
343 if (IS_INT_INSIDE(--pos2, -w->vscroll.cap, 0)) { |
|
344 DrawString(x2+62, y2+7, GetCustomEngineName(engine_id), sel[1]==0 ? 0xC : 0x10); |
|
345 DrawAircraftEngine(x2+29, y2+10, engine_id, GetEnginePalette(engine_id, _local_player)); |
|
346 y2 += 24; |
|
347 } |
|
348 sel[1]--; |
|
349 } |
|
350 } |
|
351 } while (++engine_id, ++e,--num); |
|
352 break; |
|
353 } // end of aircraft |
|
354 } |
|
355 } |
|
356 |
204 |
357 static void ReplaceVehicleWndProc(Window *w, WindowEvent *e) |
205 static void ReplaceVehicleWndProc(Window *w, WindowEvent *e) |
358 { |
206 { |
|
207 /* Strings for the pulldown menu */ |
359 static const StringID _vehicle_type_names[] = { |
208 static const StringID _vehicle_type_names[] = { |
360 STR_019F_TRAIN, |
209 STR_019F_TRAIN, |
361 STR_019C_ROAD_VEHICLE, |
210 STR_019C_ROAD_VEHICLE, |
362 STR_019E_SHIP, |
211 STR_019E_SHIP, |
363 STR_019D_AIRCRAFT |
212 STR_019D_AIRCRAFT |
364 }; |
213 }; |
365 |
214 |
366 switch (e->event) { |
215 switch (e->event) { |
|
216 case WE_CREATE: |
|
217 WP(w, replaceveh_d).wagon_btnstate = true; // start with locomotives (all other vehicles will not read this bool) |
|
218 EngList_Create(&WP(w, replaceveh_d).list[0]); |
|
219 EngList_Create(&WP(w, replaceveh_d).list[1]); |
|
220 WP(w, replaceveh_d).update_left = true; |
|
221 WP(w, replaceveh_d).update_right = true; |
|
222 WP(w, replaceveh_d).init_lists = true; |
|
223 WP(w, replaceveh_d).sel_engine[0] = INVALID_ENGINE; |
|
224 WP(w, replaceveh_d).sel_engine[1] = INVALID_ENGINE; |
|
225 break; |
|
226 |
367 case WE_PAINT: { |
227 case WE_PAINT: { |
368 Player *p = GetPlayer(_local_player); |
228 if (WP(w, replaceveh_d).update_left || WP(w, replaceveh_d).update_right) GenerateLists(w); |
369 int pos = w->vscroll.pos; |
229 |
370 EngineID selected_id[2] = { INVALID_ENGINE, INVALID_ENGINE }; |
230 Player *p = GetPlayer(_local_player); |
371 int x = 1; |
231 EngineID selected_id[2]; |
372 int y = 15; |
232 |
373 int pos2 = w->vscroll2.pos; |
233 selected_id[0] = WP(w, replaceveh_d).sel_engine[0]; |
374 int x2 = 1 + 228; |
234 selected_id[1] = WP(w, replaceveh_d).sel_engine[1]; |
375 int y2 = 15; |
235 |
376 int sel[2]; |
236 /* Disable the "Start Replacing" button if: |
377 byte i; |
237 * Either list is empty |
378 sel[0] = WP(w,replaceveh_d).sel_index[0]; |
238 * or The selected replacement engine has a replacement (to prevent loops) |
379 sel[1] = WP(w,replaceveh_d).sel_index[1]; |
239 * or The right list (new replacement) has the existing replacement vehicle selected */ |
380 |
240 SetWindowWidgetDisabledState(w, 4, |
381 SetupScrollStuffForReplaceWindow(w); |
241 selected_id[0] == INVALID_ENGINE || |
382 |
242 selected_id[1] == INVALID_ENGINE || |
383 selected_id[0] = WP(w,replaceveh_d).sel_engine[0]; |
243 EngineReplacementForPlayer(p, selected_id[1]) != INVALID_ENGINE || |
384 selected_id[1] = WP(w,replaceveh_d).sel_engine[1]; |
244 EngineReplacementForPlayer(p, selected_id[0]) == selected_id[1]); |
385 |
245 |
386 // Disable the "Start Replacing" button if: |
246 /* Disable the "Stop Replacing" button if: |
387 // Either list is empty |
247 * The left list (existing vehicle) is empty |
388 // or Both lists have the same vehicle selected |
248 * or The selected vehicle has no replacement set up */ |
389 // or The selected replacement engine has a replacement (to prevent loops) |
249 SetWindowWidgetDisabledState(w, 6, |
390 // or The right list (new replacement) has the existing replacement vehicle selected |
250 selected_id[0] == INVALID_ENGINE || |
391 SetWindowWidgetDisabledState(w, 4, |
251 !EngineHasReplacementForPlayer(p, selected_id[0])); |
392 selected_id[0] == INVALID_ENGINE || |
252 |
393 selected_id[1] == INVALID_ENGINE || |
253 /* now the actual drawing of the window itself takes place */ |
394 selected_id[0] == selected_id[1] || |
254 SetDParam(0, _vehicle_type_names[VehTypeToIndex(w->window_number)]); |
395 EngineReplacementForPlayer(p, selected_id[1]) != INVALID_ENGINE || |
255 |
396 EngineReplacementForPlayer(p, selected_id[0]) == selected_id[1]); |
256 if (w->window_number == VEH_Train) { |
397 |
257 /* set on/off for renew_keep_length */ |
398 // Disable the "Stop Replacing" button if: |
258 SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF); |
399 // The left list (existing vehicle) is empty |
259 |
400 // or The selected vehicle has no replacement set up |
260 /* set wagon/engine button */ |
401 SetWindowWidgetDisabledState(w, 6, |
261 SetDParam(2, WP(w, replaceveh_d).wagon_btnstate ? STR_ENGINES : STR_WAGONS); |
402 selected_id[0] == INVALID_ENGINE || |
262 } |
403 !EngineHasReplacementForPlayer(p, selected_id[0])); |
263 |
404 |
264 w->widget[13].color = _player_colors[_local_player]; // sets the colour of that art thing |
405 // now the actual drawing of the window itself takes place |
265 w->widget[16].color = _player_colors[_local_player]; // sets the colour of that art thing |
406 SetDParam(0, _vehicle_type_names[WP(w, replaceveh_d).vehicletype - VEH_Train]); |
266 |
407 |
267 DrawWindowWidgets(w); |
408 if (WP(w, replaceveh_d).vehicletype == VEH_Train) { |
268 |
409 // set on/off for renew_keep_length |
269 |
410 SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF); |
270 if (w->window_number == VEH_Train) { |
411 |
271 /* Draw the selected railtype in the pulldown menu */ |
412 // set wagon/engine button |
272 RailType railtype = _railtype_selected_in_replace_gui; |
413 SetDParam(2, WP(w, replaceveh_d).wagon_btnstate ? STR_ENGINES : STR_WAGONS); |
273 DrawString(157, w->widget[14].top + 1, _rail_types_list[railtype], 0x10); |
|
274 } |
|
275 |
|
276 /* sets up the string for the vehicle that is being replaced to */ |
|
277 if (selected_id[0] != INVALID_ENGINE) { |
|
278 if (!EngineHasReplacementForPlayer(p, selected_id[0])) { |
|
279 SetDParam(0, STR_NOT_REPLACING); |
|
280 } else { |
|
281 SetDParam(0, GetCustomEngineName(EngineReplacementForPlayer(p, selected_id[0]))); |
414 } |
282 } |
415 |
283 } else { |
416 DrawWindowWidgets(w); |
284 SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED); |
417 |
285 } |
418 // sets up the string for the vehicle that is being replaced to |
286 |
419 if (selected_id[0] != INVALID_ENGINE) { |
287 DrawString(145, w->widget[5].top + 1, STR_02BD, 0x10); |
420 if (!EngineHasReplacementForPlayer(p, selected_id[0])) { |
288 |
421 SetDParam(0, STR_NOT_REPLACING); |
289 /* Draw the lists */ |
422 } else { |
290 for(byte i = 0; i < 2; i++) { |
423 SetDParam(0, GetCustomEngineName(EngineReplacementForPlayer(p, selected_id[0]))); |
291 uint16 x = i == 0 ? 2 : 230; // at what X offset |
424 } |
292 EngineList list = WP(w, replaceveh_d).list[i]; // which list to draw |
425 } else { |
293 EngineID start = i == 0 ? w->vscroll.pos : w->vscroll2.pos; // what is the offset for the start (scrolling) |
426 SetDParam(0, STR_NOT_REPLACING_VEHICLE_SELECTED); |
294 EngineID end = min((i == 0 ? w->vscroll.cap : w->vscroll2.cap) + start, EngList_Count(&list)); |
|
295 |
|
296 /* Do the actual drawing */ |
|
297 DrawEngineList(w->window_number, x, 15, list, start, end, WP(w, replaceveh_d).sel_engine[i], i == 0); |
|
298 |
|
299 /* Also draw the details if an engine is selected */ |
|
300 if (WP(w, replaceveh_d).sel_engine[i] != INVALID_ENGINE) { |
|
301 const Widget *wi = &w->widget[i == 0 ? 3 : 11]; |
|
302 DrawVehiclePurchaseInfo(wi->left + 2, wi->top + 1, wi->right - wi->left - 2, WP(w, replaceveh_d).sel_engine[i]); |
427 } |
303 } |
428 |
304 } |
429 DrawString(145, w->widget[5].top + 1, STR_02BD, 0x10); |
305 |
430 |
306 } break; // end of paint |
431 /* now we draw the two arrays according to what we just counted */ |
|
432 DrawEngineArrayInReplaceWindow(w, x, y, x2, y2, pos, pos2, sel[0], sel[1], selected_id[0], selected_id[1]); |
|
433 |
|
434 WP(w,replaceveh_d).sel_engine[0] = selected_id[0]; |
|
435 WP(w,replaceveh_d).sel_engine[1] = selected_id[1]; |
|
436 /* now we draw the info about the vehicles we selected */ |
|
437 for (i = 0 ; i < 2 ; i++) { |
|
438 if (selected_id[i] != INVALID_ENGINE) { |
|
439 const Widget *wi = &w->widget[i == 0 ? 3 : 11]; |
|
440 DrawVehiclePurchaseInfo(wi->left + 2 , wi->top + 1, wi->right - wi->left - 2, selected_id[i]); |
|
441 } |
|
442 } |
|
443 } break; // end of paint |
|
444 |
307 |
445 case WE_CLICK: { |
308 case WE_CLICK: { |
446 // these 3 variables is used if any of the lists is clicked |
|
447 uint16 click_scroll_pos = w->vscroll2.pos; |
|
448 uint16 click_scroll_cap = w->vscroll2.cap; |
|
449 byte click_side = 1; |
|
450 |
|
451 switch (e->we.click.widget) { |
309 switch (e->we.click.widget) { |
452 case 12: |
310 case 12: |
453 WP(w, replaceveh_d).wagon_btnstate = !(WP(w, replaceveh_d).wagon_btnstate); |
311 WP(w, replaceveh_d).wagon_btnstate = !(WP(w, replaceveh_d).wagon_btnstate); |
|
312 WP(w, replaceveh_d).update_left = true; |
|
313 WP(w, replaceveh_d).init_lists = true; |
454 SetWindowDirty(w); |
314 SetWindowDirty(w); |
455 break; |
315 break; |
456 |
316 |
457 case 14: |
317 case 14: |
458 case 15: /* Railtype selection dropdown menu */ |
318 case 15: /* Railtype selection dropdown menu */ |