138 order->type = data.type; |
138 order->type = data.type; |
139 order->flags = data.flags; |
139 order->flags = data.flags; |
140 order->station = data.station; |
140 order->station = data.station; |
141 } |
141 } |
142 |
142 |
143 /** |
143 /** Add an order to the orderlist of a vehicle. |
144 * |
144 * @param x,y unused |
145 * Add an order to the orderlist of a vehicle |
145 * @param p1 various bitstuffed elements |
146 * |
146 * - p1 = (bit 0 - 15) - ID of the vehicle (p1 & 0xFFFF) |
147 * @param veh_sel First 16 bits are the ID of the vehicle. The next 16 are the selected order (if any) |
147 * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given, |
148 * If the lastone is given, order will be inserted above thatone |
148 * the order will be inserted before that one (p1 & 0xFFFF0000)>>16 |
149 * @param packed_order Packed order to insert |
149 * only the first 8 bytes used currently (bit 16 - 23) (max 255) |
150 * |
150 * @param p2 packed order to insert |
151 */ |
151 */ |
152 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 veh_sel, uint32 packed_order) |
152 int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
153 { |
153 { |
154 Vehicle *v; |
154 Vehicle *v; |
155 int sel = veh_sel >> 16; |
155 VehicleID veh = p1 & 0xFFFF; |
156 Order new_order = UnpackOrder(packed_order); |
156 OrderID sel_ord = p1 >> 16; |
157 |
157 Order new_order = UnpackOrder(p2); |
158 if (!IsVehicleIndex(veh_sel & 0xFFFF)) return CMD_ERROR; |
158 |
159 v = GetVehicle(veh_sel & 0xFFFF); |
159 if (!IsVehicleIndex(veh)) return CMD_ERROR; |
|
160 v = GetVehicle(veh); |
160 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
161 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
161 |
162 |
|
163 /* Check if the inserted order is to the correct destination (owner, type), |
|
164 * and has the correct flags if any */ |
162 switch (new_order.type) { |
165 switch (new_order.type) { |
163 case OT_GOTO_STATION: { |
166 case OT_GOTO_STATION: { |
164 const Station* st; |
167 const Station *st; |
165 |
168 |
166 if (!IsStationIndex(new_order.station)) return CMD_ERROR; |
169 if (!IsStationIndex(new_order.station)) return CMD_ERROR; |
167 st = GetStation(new_order.station); |
170 st = GetStation(new_order.station); |
168 |
171 |
169 if (!IsValidStation(st) || |
172 if (!IsValidStation(st) || |
279 switch (new_order.flags) { |
278 switch (new_order.flags) { |
280 case 0: |
279 case 0: |
281 case OF_NON_STOP: |
280 case OF_NON_STOP: |
282 break; |
281 break; |
283 |
282 |
284 default: |
283 default: return CMD_ERROR; |
285 return CMD_ERROR; |
|
286 } |
284 } |
287 break; |
285 break; |
288 } |
286 } |
289 |
287 |
290 default: |
288 default: return CMD_ERROR; |
291 return CMD_ERROR; |
289 } |
292 } |
290 |
293 |
291 if (sel_ord > v->num_orders) return CMD_ERROR; |
294 if (sel > v->num_orders) |
292 |
295 return_cmd_error(STR_EMPTY); |
293 if (IsOrderPoolFull()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS); |
296 |
|
297 if (IsOrderPoolFull()) |
|
298 return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS); |
|
299 |
294 |
300 /* XXX - This limit is only here because the backuppedorders can't |
295 /* XXX - This limit is only here because the backuppedorders can't |
301 handle any more then this.. */ |
296 * handle any more then this.. */ |
302 if (v->num_orders >= 40) |
297 if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS); |
303 return_cmd_error(STR_8832_TOO_MANY_ORDERS); |
|
304 |
298 |
305 /* For ships, make sure that the station is not too far away from the |
299 /* For ships, make sure that the station is not too far away from the |
306 * previous destination, for human players with new pathfinding disabled */ |
300 * previous destination, for human players with new pathfinding disabled */ |
307 if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) && |
301 if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) && |
308 sel != 0 && GetVehicleOrder(v, sel - 1)->type == OT_GOTO_STATION |
302 sel_ord != 0 && GetVehicleOrder(v, sel_ord - 1)->type == OT_GOTO_STATION |
309 && !_patches.new_pathfinding_all) { |
303 && !_patches.new_pathfinding_all) { |
310 |
304 |
311 int dist = DistanceManhattan( |
305 int dist = DistanceManhattan( |
312 GetStation(GetVehicleOrder(v, sel - 1)->station)->xy, |
306 GetStation(GetVehicleOrder(v, sel_ord - 1)->station)->xy, |
313 GetStation(new_order.station)->xy // XXX type != OT_GOTO_STATION? |
307 GetStation(new_order.station)->xy // XXX type != OT_GOTO_STATION? |
314 ); |
308 ); |
315 if (dist >= 130) |
309 if (dist >= 130) |
316 return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO); |
310 return_cmd_error(STR_0210_TOO_FAR_FROM_PREVIOUS_DESTINATIO); |
317 } |
311 } |
318 |
312 |
319 if (flags & DC_EXEC) { |
313 if (flags & DC_EXEC) { |
320 Order *new; |
|
321 Vehicle *u; |
314 Vehicle *u; |
322 |
315 Order *new = AllocateOrder(); |
323 new = AllocateOrder(); |
|
324 AssignOrder(new, new_order); |
316 AssignOrder(new, new_order); |
325 |
317 |
326 /* Create new order and link in list */ |
318 /* Create new order and link in list */ |
327 if (v->orders == NULL) { |
319 if (v->orders == NULL) { |
328 v->orders = new; |
320 v->orders = new; |
329 } else { |
321 } else { |
330 /* Try to get the previous item (we are inserting above the |
322 /* Try to get the previous item (we are inserting above the |
331 selected) */ |
323 selected) */ |
332 Order *order = GetVehicleOrder(v, sel - 1); |
324 Order *order = GetVehicleOrder(v, sel_ord - 1); |
333 |
325 |
334 if (order == NULL && GetVehicleOrder(v, sel) != NULL) { |
326 if (order == NULL && GetVehicleOrder(v, sel_ord) != NULL) { |
335 /* There is no previous item, so we are altering v->orders itself |
327 /* There is no previous item, so we are altering v->orders itself |
336 But because the orders can be shared, we copy the info over |
328 But because the orders can be shared, we copy the info over |
337 the v->orders, so we don't have to change the pointers of |
329 the v->orders, so we don't have to change the pointers of |
338 all vehicles */ |
330 all vehicles */ |
339 SwapOrders(v->orders, new); |
331 SwapOrders(v->orders, new); |
354 while (u != NULL) { |
346 while (u != NULL) { |
355 /* Increase amount of orders */ |
347 /* Increase amount of orders */ |
356 u->num_orders++; |
348 u->num_orders++; |
357 |
349 |
358 /* If the orderlist was empty, assign it */ |
350 /* If the orderlist was empty, assign it */ |
359 if (u->orders == NULL) |
351 if (u->orders == NULL) u->orders = v->orders; |
360 u->orders = v->orders; |
|
361 |
352 |
362 assert(v->orders == u->orders); |
353 assert(v->orders == u->orders); |
363 |
354 |
364 /* If there is added an order before the current one, we need |
355 /* If there is added an order before the current one, we need |
365 to update the selected order */ |
356 to update the selected order */ |
366 if (sel <= u->cur_order_index) { |
357 if (sel_ord <= u->cur_order_index) { |
367 uint cur = u->cur_order_index + 1; |
358 uint cur = u->cur_order_index + 1; |
368 /* Check if we don't go out of bound */ |
359 /* Check if we don't go out of bound */ |
369 if (cur < u->num_orders) |
360 if (cur < u->num_orders) |
370 u->cur_order_index = cur; |
361 u->cur_order_index = cur; |
371 } |
362 } |
397 RebuildVehicleLists(); |
387 RebuildVehicleLists(); |
398 } |
388 } |
399 return 0; |
389 return 0; |
400 } |
390 } |
401 |
391 |
402 /** |
392 /** Delete an order from the orderlist of a vehicle. |
403 * |
393 * @param x,y unused |
404 * Delete an order from the orderlist of a vehicle |
394 * @param p1 the ID of the vehicle |
405 * |
395 * @param p2 the order to delete (max 255) |
406 * @param vehicle_id The ID of the vehicle |
396 */ |
407 * @param selected The order to delete |
397 int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
408 * |
398 { |
409 */ |
399 Vehicle *v, *u; |
410 int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 vehicle_id, uint32 selected) |
400 VehicleID veh_id = p1; |
411 { |
401 OrderID sel_ord = p2; |
412 Vehicle *v; |
|
413 Vehicle *u; |
|
414 uint sel = selected; |
|
415 Order *order; |
402 Order *order; |
416 |
403 |
417 if (!IsVehicleIndex(vehicle_id)) return CMD_ERROR; |
404 if (!IsVehicleIndex(veh_id)) return CMD_ERROR; |
418 v = GetVehicle(vehicle_id); |
405 v = GetVehicle(veh_id); |
419 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
406 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
420 |
407 |
421 /* XXX -- Why is this here? :s */ |
|
422 _error_message = STR_EMPTY; |
|
423 |
|
424 /* If we did not select an order, we maybe want to de-clone the orders */ |
408 /* If we did not select an order, we maybe want to de-clone the orders */ |
425 if (sel >= v->num_orders) |
409 if (sel_ord >= v->num_orders) |
426 return DecloneOrder(v, flags); |
410 return DecloneOrder(v, flags); |
427 |
411 |
428 order = GetVehicleOrder(v, sel); |
412 order = GetVehicleOrder(v, sel_ord); |
429 if (order == NULL) |
413 if (order == NULL) return CMD_ERROR; |
430 return CMD_ERROR; |
|
431 |
414 |
432 if (flags & DC_EXEC) { |
415 if (flags & DC_EXEC) { |
433 if (GetVehicleOrder(v, sel - 1) == NULL) { |
416 if (GetVehicleOrder(v, sel_ord - 1) == NULL) { |
434 if (GetVehicleOrder(v, sel + 1) != NULL) { |
417 if (GetVehicleOrder(v, sel_ord + 1) != NULL) { |
435 /* First item, but not the last, so we need to alter v->orders |
418 /* First item, but not the last, so we need to alter v->orders |
436 Because we can have shared order, we copy the data |
419 Because we can have shared order, we copy the data |
437 from the next item over the deleted */ |
420 from the next item over the deleted */ |
438 order = GetVehicleOrder(v, sel + 1); |
421 order = GetVehicleOrder(v, sel_ord + 1); |
439 SwapOrders(v->orders, order); |
422 SwapOrders(v->orders, order); |
440 } else { |
423 } else { |
441 /* Last item, so clean the list */ |
424 /* Last item, so clean the list */ |
442 v->orders = NULL; |
425 v->orders = NULL; |
443 } |
426 } |
444 } else { |
427 } else { |
445 GetVehicleOrder(v, sel - 1)->next = order->next; |
428 GetVehicleOrder(v, sel_ord - 1)->next = order->next; |
446 } |
429 } |
447 |
430 |
448 /* Give the item free */ |
431 /* Give the item free */ |
449 order->type = OT_NOTHING; |
432 order->type = OT_NOTHING; |
450 order->next = NULL; |
433 order->next = NULL; |
451 |
434 |
452 u = GetFirstVehicleFromSharedList(v); |
435 u = GetFirstVehicleFromSharedList(v); |
453 while (u != NULL) { |
436 while (u != NULL) { |
454 u->num_orders--; |
437 u->num_orders--; |
455 |
438 |
456 if (sel < u->cur_order_index) |
439 if (sel_ord < u->cur_order_index) |
457 u->cur_order_index--; |
440 u->cur_order_index--; |
458 |
441 |
459 /* If we removed the last order, make sure the shared vehicles |
442 /* If we removed the last order, make sure the shared vehicles |
460 also set their orders to NULL */ |
443 * also set their orders to NULL */ |
461 if (v->orders == NULL) |
444 if (v->orders == NULL) u->orders = NULL; |
462 u->orders = NULL; |
|
463 |
445 |
464 assert(v->orders == u->orders); |
446 assert(v->orders == u->orders); |
465 |
447 |
466 /* NON-stop flag is misused to see if a train is in a station that is |
448 /* NON-stop flag is misused to see if a train is in a station that is |
467 on his order list or not */ |
449 * on his order list or not */ |
468 if (sel == u->cur_order_index && |
450 if (sel_ord == u->cur_order_index && u->current_order.type == OT_LOADING && |
469 u->current_order.type == OT_LOADING && |
|
470 HASBIT(u->current_order.flags, OFB_NON_STOP)) { |
451 HASBIT(u->current_order.flags, OFB_NON_STOP)) { |
471 u->current_order.flags = 0; |
452 u->current_order.flags = 0; |
472 } |
453 } |
473 |
454 |
474 /* Update any possible open window of the vehicle */ |
455 /* Update any possible open window of the vehicle */ |
481 } |
462 } |
482 |
463 |
483 return 0; |
464 return 0; |
484 } |
465 } |
485 |
466 |
486 /** |
467 /** Goto next order of order-list. |
487 * |
468 * @param x,y unused |
488 * Goto next order of order-list |
469 * @param p1 The ID of the vehicle which order is skipped |
489 * |
470 * @param p2 unused |
490 * @param vehicle_id The ID of the vehicle |
471 */ |
491 * |
472 int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
492 */ |
|
493 int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 vehicle_id, uint32 not_used) |
|
494 { |
473 { |
495 Vehicle *v; |
474 Vehicle *v; |
496 |
475 VehicleID veh_id = p1; |
497 if (!IsVehicleIndex(vehicle_id)) return CMD_ERROR; |
476 |
498 v = GetVehicle(vehicle_id); |
477 if (!IsVehicleIndex(veh_id)) return CMD_ERROR; |
|
478 v = GetVehicle(veh_id); |
499 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
479 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
500 |
480 |
501 if (flags & DC_EXEC) { |
481 if (flags & DC_EXEC) { |
502 /* Goto next order */ |
482 /* Goto next order */ |
503 { |
483 OrderID b = v->cur_order_index + 1; |
504 byte b = v->cur_order_index + 1; |
484 if (b >= v->num_orders) b = 0; |
505 if (b >= v->num_orders) |
485 |
506 b = 0; |
486 v->cur_order_index = b; |
507 |
487 |
508 v->cur_order_index = b; |
488 if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0; |
509 |
489 |
510 if (v->type == VEH_Train) |
490 if (v->type == VEH_Road) ClearSlot(v, v->u.road.slot); |
511 v->u.rail.days_since_order_progr = 0; |
|
512 |
|
513 if (v->type == VEH_Road) |
|
514 ClearSlot(v, v->u.road.slot); |
|
515 } |
|
516 |
491 |
517 /* NON-stop flag is misused to see if a train is in a station that is |
492 /* NON-stop flag is misused to see if a train is in a station that is |
518 on his order list or not */ |
493 * on his order list or not */ |
519 if (v->current_order.type == OT_LOADING && |
494 if (v->current_order.type == OT_LOADING && HASBIT(v->current_order.flags, OFB_NON_STOP)) |
520 HASBIT(v->current_order.flags, OFB_NON_STOP)) { |
|
521 v->current_order.flags = 0; |
495 v->current_order.flags = 0; |
522 } |
|
523 |
496 |
524 InvalidateVehicleOrder(v); |
497 InvalidateVehicleOrder(v); |
525 } |
498 } |
526 |
499 |
527 /* We have an aircraft/ship, they have a mini-schedule, so update them all */ |
500 /* We have an aircraft/ship, they have a mini-schedule, so update them all */ |
530 |
503 |
531 return 0; |
504 return 0; |
532 } |
505 } |
533 |
506 |
534 |
507 |
535 /** |
508 /** Modify an order in the orderlist of a vehicle. |
536 * |
509 * @param x,y unused |
537 * Modify an order in the orderlist of a vehicle |
510 * @param p1 various bitstuffed elements |
538 * |
511 * - p1 = (bit 0 - 15) - ID of the vehicle (p1 & 0xFFFF) |
539 * @param veh_sel First 16 bits are the ID of the vehicle. The next 16 are the selected order (if any) |
512 * - p1 = (bit 16 - 31) - the selected order (if any). If the last order is given, |
540 * If the lastone is given, order will be inserted above thatone |
513 * the order will be inserted before that one (p1 & 0xFFFF0000)>>16 |
541 * @param mode Mode to change the order to |
514 * only the first 8 bytes used currently (bit 16 - 23) (max 255) |
542 * |
515 * @param p2 mode to change the order to (always set) |
543 */ |
516 */ |
544 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 veh_sel, uint32 mode) |
517 int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2) |
545 { |
518 { |
546 Vehicle *v; |
519 Vehicle *v; |
547 byte sel = veh_sel >> 16; |
|
548 Order *order; |
520 Order *order; |
549 |
521 OrderID sel_ord = p1 >> 16; // XXX - automatically truncated to 8 bits. |
550 if (!IsVehicleIndex(veh_sel & 0xFFFF)) return CMD_ERROR; |
522 VehicleID veh = p1 & 0xFFFF; |
551 v = GetVehicle(veh_sel & 0xFFFF); |
523 |
|
524 if (!IsVehicleIndex(veh)) return CMD_ERROR; |
|
525 if (p2 != OFB_FULL_LOAD || p2 != OFB_UNLOAD || p2 != OFB_NON_STOP) return CMD_ERROR; |
|
526 |
|
527 v = GetVehicle(veh); |
552 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
528 if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR; |
553 |
529 |
554 /* Is it a valid order? */ |
530 /* Is it a valid order? */ |
555 if (sel >= v->num_orders) |
531 if (sel_ord >= v->num_orders) return CMD_ERROR; |
|
532 |
|
533 order = GetVehicleOrder(v, sel_ord); |
|
534 if (order->type != OT_GOTO_STATION && |
|
535 (order->type != OT_GOTO_DEPOT || p2 == OFB_UNLOAD) && |
|
536 (order->type != OT_GOTO_WAYPOINT || p2 != OFB_NON_STOP)) |
556 return CMD_ERROR; |
537 return CMD_ERROR; |
557 |
538 |
558 order = GetVehicleOrder(v, sel); |
|
559 if (order->type != OT_GOTO_STATION && |
|
560 (order->type != OT_GOTO_DEPOT || mode == OFB_UNLOAD) && |
|
561 (order->type != OT_GOTO_WAYPOINT || mode != OFB_NON_STOP)) |
|
562 return CMD_ERROR; |
|
563 |
|
564 if (flags & DC_EXEC) { |
539 if (flags & DC_EXEC) { |
565 switch (mode) { |
540 switch (p2) { |
566 case OFB_FULL_LOAD: |
541 case OFB_FULL_LOAD: |
567 TOGGLEBIT(order->flags, OFB_FULL_LOAD); |
542 TOGGLEBIT(order->flags, OFB_FULL_LOAD); |
568 if (order->type != OT_GOTO_DEPOT) |
543 if (order->type != OT_GOTO_DEPOT) |
569 CLRBIT(order->flags, OFB_UNLOAD); |
544 CLRBIT(order->flags, OFB_UNLOAD); |
570 break; |
545 break; |
573 CLRBIT(order->flags, OFB_FULL_LOAD); |
548 CLRBIT(order->flags, OFB_FULL_LOAD); |
574 break; |
549 break; |
575 case OFB_NON_STOP: |
550 case OFB_NON_STOP: |
576 TOGGLEBIT(order->flags, OFB_NON_STOP); |
551 TOGGLEBIT(order->flags, OFB_NON_STOP); |
577 break; |
552 break; |
578 |
553 default: NOT_REACHED(); |
579 default: |
|
580 return CMD_ERROR; |
|
581 } |
554 } |
582 |
555 |
583 /* Update the windows and full load flags, also for vehicles that share the same order list */ |
556 /* Update the windows and full load flags, also for vehicles that share the same order list */ |
584 { |
557 { |
585 Vehicle *u = GetFirstVehicleFromSharedList(v); |
558 Vehicle *u = GetFirstVehicleFromSharedList(v); |
586 while (u != NULL) { |
559 while (u != NULL) { |
587 /* toggle u->current_order "Full load" flag if it changed */ |
560 /* toggle u->current_order "Full load" flag if it changed */ |
588 if (sel == u->cur_order_index && |
561 if (sel_ord == u->cur_order_index && |
589 HASBIT(u->current_order.flags, OFB_FULL_LOAD) != HASBIT(order->flags, OFB_FULL_LOAD)) |
562 HASBIT(u->current_order.flags, OFB_FULL_LOAD) != HASBIT(order->flags, OFB_FULL_LOAD)) |
590 TOGGLEBIT(u->current_order.flags, OFB_FULL_LOAD); |
563 TOGGLEBIT(u->current_order.flags, OFB_FULL_LOAD); |
591 InvalidateVehicleOrder(u); |
564 InvalidateVehicleOrder(u); |
592 u = u->next_shared; |
565 u = u->next_shared; |
593 } |
566 } |