13 */ |
13 */ |
14 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
14 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
15 { |
15 { |
16 Vehicle *v = &_vehicles[p1 & 0xFFFF]; |
16 Vehicle *v = &_vehicles[p1 & 0xFFFF]; |
17 int sel = p1 >> 16; |
17 int sel = p1 >> 16; |
18 int t; |
18 Order new_order = UnpackOrder(p2); |
19 |
19 |
20 if (sel > v->num_orders) return_cmd_error(STR_EMPTY); |
20 if (sel > v->num_orders) return_cmd_error(STR_EMPTY); |
21 if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS); |
21 if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS); |
22 if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS); |
22 if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS); |
23 |
23 |
24 // for ships, make sure that the station is not too far away from the previous destination. |
24 // for ships, make sure that the station is not too far away from the previous destination. |
25 if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) && |
25 if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) && |
26 sel != 0 && ((t=v->schedule_ptr[sel-1])&OT_MASK) == OT_GOTO_STATION) { |
26 sel != 0 && v->schedule_ptr[sel - 1].type == OT_GOTO_STATION) { |
27 |
27 |
28 int dist = GetTileDist(DEREF_STATION(t >> 8)->xy, DEREF_STATION(p2 >> 8)->xy); |
28 int dist = GetTileDist( |
|
29 DEREF_STATION(v->schedule_ptr[sel - 1].station)->xy, |
|
30 DEREF_STATION(new_order.station)->xy |
|
31 ); |
29 if (dist >= 130) |
32 if (dist >= 130) |
30 return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO); |
33 return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO); |
31 } |
34 } |
32 |
35 |
33 if (flags & DC_EXEC) { |
36 if (flags & DC_EXEC) { |
34 uint16 *s1, *s2; |
37 Order *s1; |
|
38 Order *s2; |
35 Vehicle *u; |
39 Vehicle *u; |
36 |
40 |
37 s1 = &v->schedule_ptr[sel]; |
41 s1 = &v->schedule_ptr[sel]; |
38 s2 = _ptr_to_next_order++; |
42 s2 = _ptr_to_next_order++; |
39 do s2[1] = s2[0]; while (--s2 >= s1); |
43 do s2[1] = s2[0]; while (--s2 >= s1); |
40 s1[0] = (uint16)p2; |
44 *s1 = new_order; |
41 |
45 |
42 s1 = v->schedule_ptr; |
46 s1 = v->schedule_ptr; |
43 |
47 |
44 FOR_ALL_VEHICLES(u) { |
48 FOR_ALL_VEHICLES(u) { |
45 if (u->type != 0 && u->schedule_ptr != NULL) { |
49 if (u->type != 0 && u->schedule_ptr != NULL) { |
90 _error_message = STR_EMPTY; |
96 _error_message = STR_EMPTY; |
91 if (sel >= v->num_orders) |
97 if (sel >= v->num_orders) |
92 return DecloneOrder(v, flags); |
98 return DecloneOrder(v, flags); |
93 |
99 |
94 if (flags & DC_EXEC) { |
100 if (flags & DC_EXEC) { |
95 uint16 *s1; |
101 Order *s1 = &v->schedule_ptr[sel]; |
96 |
|
97 s1 = &v->schedule_ptr[sel]; |
|
98 |
102 |
99 // copy all orders to get rid of the hole |
103 // copy all orders to get rid of the hole |
100 do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order); |
104 do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order); |
101 _ptr_to_next_order--; |
105 _ptr_to_next_order--; |
102 |
106 |
109 } else if (s1 == u->schedule_ptr) {// handle shared orders |
113 } else if (s1 == u->schedule_ptr) {// handle shared orders |
110 u->num_orders--; |
114 u->num_orders--; |
111 if ((byte)sel < u->cur_order_index) |
115 if ((byte)sel < u->cur_order_index) |
112 u->cur_order_index--; |
116 u->cur_order_index--; |
113 |
117 |
114 if ((byte)sel == u->cur_order_index && (u->next_order&(OT_MASK|OF_NON_STOP)) == (OT_LOADING|OF_NON_STOP)) |
118 if ((byte)sel == u->cur_order_index && |
115 u->next_order = OT_LOADING; |
119 u->current_order.type == OT_LOADING && |
|
120 u->current_order.flags & OF_NON_STOP) { |
|
121 u->current_order.flags = 0; |
|
122 } |
116 |
123 |
117 InvalidateWindow(WC_VEHICLE_VIEW, u->index); |
124 InvalidateWindow(WC_VEHICLE_VIEW, u->index); |
118 InvalidateWindow(WC_VEHICLE_ORDERS, u->index); |
125 InvalidateWindow(WC_VEHICLE_ORDERS, u->index); |
119 } |
126 } |
120 } |
127 } |
153 */ |
162 */ |
154 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
163 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
155 { |
164 { |
156 Vehicle *v = &_vehicles[p1]; |
165 Vehicle *v = &_vehicles[p1]; |
157 byte sel = (byte)p2; |
166 byte sel = (byte)p2; |
158 uint16 *sched; |
167 Order *sched; |
159 |
168 |
160 if (sel >= v->num_orders) |
169 if (sel >= v->num_orders) |
161 return CMD_ERROR; |
170 return CMD_ERROR; |
162 |
171 |
163 sched = &v->schedule_ptr[sel]; |
172 sched = &v->schedule_ptr[sel]; |
164 if (!((*sched & OT_MASK) == OT_GOTO_STATION || |
173 if (sched->type != OT_GOTO_STATION && |
165 ((*sched & OT_MASK) == OT_GOTO_DEPOT && (p2>>8) != 1))) |
174 (sched->type != OT_GOTO_DEPOT || (p2 >> 8) == 1)) |
166 return CMD_ERROR; |
175 return CMD_ERROR; |
167 |
176 |
168 if (flags & DC_EXEC) { |
177 if (flags & DC_EXEC) { |
169 switch(p2 >> 8) { |
178 switch (p2 >> 8) { |
170 case 0: // full load |
179 case 0: // full load |
171 *sched ^= OF_FULL_LOAD; |
180 sched->flags ^= OF_FULL_LOAD; |
172 if ((*sched & OT_MASK) != OT_GOTO_DEPOT) |
181 if (sched->type != OT_GOTO_DEPOT) sched->flags &= ~OF_UNLOAD; |
173 *sched &= ~OF_UNLOAD; |
|
174 break; |
182 break; |
175 case 1: // unload |
183 case 1: // unload |
176 *sched ^= OF_UNLOAD; |
184 sched->flags ^= OF_UNLOAD; |
177 *sched &= ~OF_FULL_LOAD; |
185 sched->flags &= ~OF_FULL_LOAD; |
178 break; |
186 break; |
179 case 2: // non stop |
187 case 2: // non stop |
180 *sched ^= OF_NON_STOP; |
188 sched->flags ^= OF_NON_STOP; |
181 break; |
189 break; |
182 } |
190 } |
183 sched = v->schedule_ptr; |
191 sched = v->schedule_ptr; |
184 |
192 |
185 FOR_ALL_VEHICLES(v) { |
193 FOR_ALL_VEHICLES(v) { |
245 if (!(src->owner == _current_player && dst->type == src->type && dst != src)) |
253 if (!(src->owner == _current_player && dst->type == src->type && dst != src)) |
246 return CMD_ERROR; |
254 return CMD_ERROR; |
247 |
255 |
248 // let's see what happens with road vehicles |
256 // let's see what happens with road vehicles |
249 if (src->type == VEH_Road) { |
257 if (src->type == VEH_Road) { |
250 uint16 ord; |
258 const Order *i; |
251 int i; |
|
252 Station *st; |
|
253 TileIndex required_dst; |
259 TileIndex required_dst; |
254 |
260 |
255 for (i=0; (ord = src->schedule_ptr[i]) != 0; i++) { |
261 for (i = src->schedule_ptr; i->type != OT_NOTHING; ++i) { |
256 if ( ( ord & OT_MASK ) == OT_GOTO_STATION ) { |
262 if (i->type == OT_GOTO_STATION) { |
257 st = DEREF_STATION(ord >> 8); |
263 const Station *st = DEREF_STATION(i->station); |
258 required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile; |
264 required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile; |
259 if ( !required_dst ) |
265 if ( !required_dst ) |
260 return CMD_ERROR; |
266 return CMD_ERROR; |
261 } |
267 } |
262 } |
268 } |
287 } |
293 } |
288 |
294 |
289 void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak) |
295 void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak) |
290 { |
296 { |
291 Vehicle *u = IsScheduleShared(v); |
297 Vehicle *u = IsScheduleShared(v); |
292 uint16 *sched, ord, *os; |
|
293 |
298 |
294 bak->orderindex = v->cur_order_index; |
299 bak->orderindex = v->cur_order_index; |
295 bak->service_interval = v->service_interval; |
300 bak->service_interval = v->service_interval; |
296 |
301 |
297 if ((v->string_id & 0xF800) != 0x7800) { |
302 if ((v->string_id & 0xF800) != 0x7800) { |
298 bak->name[0] = 0; |
303 bak->name[0] = 0; |
299 } else { |
304 } else { |
300 GetName(v->string_id & 0x7FF, bak->name); |
305 GetName(v->string_id & 0x7FF, bak->name); |
301 } |
306 } |
302 |
307 |
303 os = bak->order; |
|
304 // stored shared orders in this special way? |
308 // stored shared orders in this special way? |
305 if (u) { |
309 if (u != NULL) { |
306 os[0] = 0xFFFF; |
310 bak->clone = u->index; |
307 os[1] = u->index; |
311 } else { |
308 return; |
312 Order *sched = v->schedule_ptr; |
309 } |
313 Order *os = bak->order; |
310 |
314 |
311 sched = v->schedule_ptr; |
315 bak->clone = INVALID_VEHICLE; |
312 do { |
316 |
313 ord = *sched++; |
317 do { |
314 *os++ = ord; |
318 *os++ = *sched++; |
315 } while (ord != 0); |
319 } while (sched->type != OT_NOTHING); |
|
320 } |
316 } |
321 } |
317 |
322 |
318 void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak) |
323 void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak) |
319 { |
324 { |
320 uint16 ord, *os; |
325 int i; |
321 int ind; |
|
322 |
326 |
323 if (bak->name[0]) { |
327 if (bak->name[0]) { |
324 strcpy((char*)_decode_parameters, bak->name); |
328 strcpy((char*)_decode_parameters, bak->name); |
325 DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE); |
329 DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE); |
326 } |
330 } |
327 |
331 |
328 DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX); |
332 DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX); |
329 |
333 |
330 os = bak->order; |
334 if (bak->clone != INVALID_VEHICLE) { |
331 if (os[0] == 0xFFFF) { |
335 DoCommandP(0, v->index | bak->clone << 16, 0, NULL, CMD_CLONE_ORDER); |
332 DoCommandP(0, v->index | os[1]<<16, 0, NULL, CMD_CLONE_ORDER); |
|
333 return; |
336 return; |
334 } |
337 } |
335 |
338 |
336 // CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the |
339 // CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the |
337 // order number is one more then the current amount of orders, and because |
340 // order number is one more then the current amount of orders, and because |
338 // in network the commands are queued before send, the second insert always |
341 // in network the commands are queued before send, the second insert always |
339 // fails in test mode. By bypassing the test-mode, that no longer is a problem. |
342 // fails in test mode. By bypassing the test-mode, that no longer is a problem. |
340 ind = 0; |
343 for (i = 0; bak->order[i].type != OT_NOTHING; ++i) |
341 while ((ord = *os++) != 0) { |
344 if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) |
342 if (!DoCommandP(0, v->index + (ind << 16), ord, NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) |
|
343 break; |
345 break; |
344 ind++; |
|
345 } |
|
346 } |
346 } |
347 |
347 |
348 /* p1 = vehicle |
348 /* p1 = vehicle |
349 * upper 16 bits p2 = service_interval |
349 * upper 16 bits p2 = service_interval |
350 * lower 16 bits p2 = cur_order_index |
350 * lower 16 bits p2 = cur_order_index |
368 if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) ) |
368 if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) ) |
369 return 0; |
369 return 0; |
370 |
370 |
371 /* only check every 20 days, so that we don't flood the message log */ |
371 /* only check every 20 days, so that we don't flood the message log */ |
372 if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) { |
372 if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) { |
373 |
373 Order order; |
374 uint16 order, old_order; |
374 Order old_order; |
375 int i, n_st, problem_type = -1; |
375 int i, n_st, problem_type = -1; |
376 Station *st; |
376 Station *st; |
377 int message=0; |
377 int message=0; |
378 TileIndex required_tile=-1; |
378 TileIndex required_tile=-1; |
379 |
379 |
380 /* check the order list */ |
380 /* check the order list */ |
381 order = v->schedule_ptr[0]; |
381 order = v->schedule_ptr[0]; |
382 n_st = 0; |
382 n_st = 0; |
383 |
383 |
384 for (old_order = i = 0; order!=0; i++ ) { |
384 old_order.type = OT_NOTHING; |
|
385 old_order.flags = 0; |
|
386 for (i = 0; order.type != OT_NOTHING; i++) { |
385 order = v->schedule_ptr[i]; |
387 order = v->schedule_ptr[i]; |
386 if (order == old_order) { |
388 if (order.type == old_order.type && |
|
389 order.flags == old_order.flags && |
|
390 order.station == old_order.station) { |
387 problem_type = 2; |
391 problem_type = 2; |
388 break; |
392 break; |
389 } |
393 } |
390 if ( (order & OT_MASK) == OT_DUMMY ) { |
394 if (order.type == OT_DUMMY) { |
391 problem_type = 1; |
395 problem_type = 1; |
392 break; |
396 break; |
393 } |
397 } |
394 if ( ( (order & OT_MASK) == OT_GOTO_STATION ) /*&& (order != old_order) */) { |
398 if (order.type == OT_GOTO_STATION /*&& (order != old_order) */) { |
395 //I uncommented this in order not to get two error messages |
399 //I uncommented this in order not to get two error messages |
396 //when two identical entries are in the list |
400 //when two identical entries are in the list |
397 n_st++; |
401 n_st++; |
398 st = DEREF_STATION(order >> 8); |
402 st = DEREF_STATION(order.station); |
399 required_tile = GetStationTileForVehicle(v,st); |
403 required_tile = GetStationTileForVehicle(v,st); |
400 if (!required_tile) problem_type = 3; |
404 if (!required_tile) problem_type = 3; |
401 } |
405 } |
402 old_order = order; //store the old order |
406 old_order = order; //store the old order |
403 } |
407 } |
404 |
408 |
405 //Now, check the last and the first order |
409 //Now, check the last and the first order |
406 //as the last order is the end of order marker, jump back 2 |
410 //as the last order is the end of order marker, jump back 2 |
407 if ( (v->schedule_ptr[0] == v->schedule_ptr[i-2]) && ( i-2 != 0 ) ) { |
411 if (i > 2 && |
|
412 v->schedule_ptr[0].type == v->schedule_ptr[i - 2].type && |
|
413 v->schedule_ptr[0].flags == v->schedule_ptr[i - 2].flags && |
|
414 v->schedule_ptr[0].station == v->schedule_ptr[i - 2].station) |
408 problem_type = 2; |
415 problem_type = 2; |
409 } |
|
410 |
416 |
411 if ( (n_st < 2) && (problem_type == -1) ) problem_type = 0; |
417 if ( (n_st < 2) && (problem_type == -1) ) problem_type = 0; |
412 |
418 |
413 SetDParam(0, v->unitnumber); |
419 SetDParam(0, v->unitnumber); |
414 |
420 |