392 } |
392 } |
393 |
393 |
394 return true; |
394 return true; |
395 } |
395 } |
396 |
396 |
|
397 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash |
|
398 * lookup times at the expense of memory usage. */ |
|
399 const int HASH_BITS = 7; |
|
400 const int HASH_SIZE = 1 << HASH_BITS; |
|
401 const int HASH_MASK = HASH_SIZE - 1; |
|
402 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2); |
|
403 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1; |
|
404 |
|
405 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc. |
|
406 * Profiling results show that 0 is fastest. */ |
|
407 const int HASH_RES = 0; |
|
408 |
|
409 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE]; |
|
410 |
|
411 static void *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc) |
|
412 { |
|
413 for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) { |
|
414 for (int x = xl; ; x = (x + 1) & HASH_MASK) { |
|
415 Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK]; |
|
416 for (; v != NULL; v = v->next_new_hash) { |
|
417 void *a = proc(v, data); |
|
418 if (a != NULL) return a; |
|
419 } |
|
420 if (x == xu) break; |
|
421 } |
|
422 if (y == yu) break; |
|
423 } |
|
424 |
|
425 return NULL; |
|
426 } |
|
427 |
|
428 |
|
429 void *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc) |
|
430 { |
|
431 const int COLL_DIST = 6; |
|
432 |
|
433 /* Hash area to scan is from xl,yl to xu,yu */ |
|
434 int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS); |
|
435 int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS); |
|
436 int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS; |
|
437 int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS; |
|
438 |
|
439 return VehicleFromHash(xl, yl, xu, yu, data, proc); |
|
440 } |
|
441 |
|
442 |
|
443 void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc) |
|
444 { |
|
445 int x = GB(TileX(tile), HASH_RES, HASH_BITS); |
|
446 int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS; |
|
447 |
|
448 Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK]; |
|
449 for (; v != NULL; v = v->next_new_hash) { |
|
450 if (v->tile != tile) continue; |
|
451 |
|
452 void *a = proc(v, data); |
|
453 if (a != NULL) return a; |
|
454 } |
|
455 |
|
456 return NULL; |
|
457 } |
|
458 |
|
459 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove) |
|
460 { |
|
461 Vehicle **old_hash = v->old_new_hash; |
|
462 Vehicle **new_hash; |
|
463 |
|
464 if (remove) { |
|
465 new_hash = NULL; |
|
466 } else { |
|
467 int x = GB(TileX(v->tile), HASH_RES, HASH_BITS); |
|
468 int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS; |
|
469 new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK]; |
|
470 } |
|
471 |
|
472 if (old_hash == new_hash) return; |
|
473 |
|
474 /* Remove from the old position in the hash table */ |
|
475 if (old_hash != NULL) { |
|
476 Vehicle *last = NULL; |
|
477 Vehicle *u = *old_hash; |
|
478 while (u != v) { |
|
479 last = u; |
|
480 u = u->next_new_hash; |
|
481 assert(u != NULL); |
|
482 } |
|
483 |
|
484 if (last == NULL) { |
|
485 *old_hash = v->next_new_hash; |
|
486 } else { |
|
487 last->next_new_hash = v->next_new_hash; |
|
488 } |
|
489 } |
|
490 |
|
491 /* Insert vehicle at beginning of the new position in the hash table */ |
|
492 if (new_hash != NULL) { |
|
493 v->next_new_hash = *new_hash; |
|
494 *new_hash = v; |
|
495 assert(v != v->next_new_hash); |
|
496 } |
|
497 |
|
498 /* Remember current hash position */ |
|
499 v->old_new_hash = new_hash; |
|
500 } |
397 |
501 |
398 static Vehicle *_vehicle_position_hash[0x1000]; |
502 static Vehicle *_vehicle_position_hash[0x1000]; |
399 |
503 |
400 void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc) |
|
401 { |
|
402 Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, 0); |
|
403 |
|
404 /* The hash area to scan */ |
|
405 const int xl = GB(pt.x - 174, 7, 6); |
|
406 const int xu = GB(pt.x + 104, 7, 6); |
|
407 const int yl = GB(pt.y - 294, 6, 6) << 6; |
|
408 const int yu = GB(pt.y + 56, 6, 6) << 6; |
|
409 |
|
410 int x; |
|
411 int y; |
|
412 |
|
413 for (y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) { |
|
414 for (x = xl;; x = (x + 1) & 0x3F) { |
|
415 Vehicle *v = _vehicle_position_hash[(x + y) & 0xFFFF]; |
|
416 |
|
417 while (v != NULL) { |
|
418 void* a = proc(v, data); |
|
419 |
|
420 if (a != NULL) return a; |
|
421 v = v->next_hash; |
|
422 } |
|
423 |
|
424 if (x == xu) break; |
|
425 } |
|
426 |
|
427 if (y == yu) break; |
|
428 } |
|
429 return NULL; |
|
430 } |
|
431 |
|
432 |
|
433 static void UpdateVehiclePosHash(Vehicle* v, int x, int y) |
504 static void UpdateVehiclePosHash(Vehicle* v, int x, int y) |
434 { |
505 { |
|
506 UpdateNewVehiclePosHash(v, x == INVALID_COORD); |
|
507 |
435 Vehicle **old_hash, **new_hash; |
508 Vehicle **old_hash, **new_hash; |
436 int old_x = v->left_coord; |
509 int old_x = v->left_coord; |
437 int old_y = v->top_coord; |
510 int old_y = v->top_coord; |
438 |
511 |
439 new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)]; |
512 new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)]; |
810 const int r = dpi->left + dpi->width; |
887 const int r = dpi->left + dpi->width; |
811 const int t = dpi->top; |
888 const int t = dpi->top; |
812 const int b = dpi->top + dpi->height; |
889 const int b = dpi->top + dpi->height; |
813 |
890 |
814 /* The hash area to scan */ |
891 /* The hash area to scan */ |
815 const int xl = GB(l - 70, 7, 6); |
892 int xl, xu, yl, yu; |
816 const int xu = GB(r, 7, 6); |
893 |
817 const int yl = GB(t - 70, 6, 6) << 6; |
894 if (dpi->width + 70 < (1 << (7 + 6))) { |
818 const int yu = GB(b, 6, 6) << 6; |
895 xl = GB(l - 70, 7, 6); |
819 |
896 xu = GB(r, 7, 6); |
820 int x; |
897 } else { |
821 int y; |
898 /* scan whole hash row */ |
822 |
899 xl = 0; |
823 for (y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) { |
900 xu = 0x3F; |
824 for (x = xl;; x = (x + 1) & 0x3F) { |
901 } |
825 const Vehicle *v = _vehicle_position_hash[(x + y) & 0xFFFF]; |
902 |
|
903 if (dpi->height + 70 < (1 << (6 + 6))) { |
|
904 yl = GB(t - 70, 6, 6) << 6; |
|
905 yu = GB(b, 6, 6) << 6; |
|
906 } else { |
|
907 /* scan whole column */ |
|
908 yl = 0; |
|
909 yu = 0x3F << 6; |
|
910 } |
|
911 |
|
912 for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) { |
|
913 for (int x = xl;; x = (x + 1) & 0x3F) { |
|
914 const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF |
826 |
915 |
827 while (v != NULL) { |
916 while (v != NULL) { |
828 if (!(v->vehstatus & VS_HIDDEN) && |
917 if (!(v->vehstatus & VS_HIDDEN) && |
829 l <= v->right_coord && |
918 l <= v->right_coord && |
830 t <= v->bottom_coord && |
919 t <= v->bottom_coord && |
1588 * - bit 0-4 Vehicle type |
1677 * - bit 0-4 Vehicle type |
1589 * - bit 5 false = start vehicles, true = stop vehicles |
1678 * - bit 5 false = start vehicles, true = stop vehicles |
1590 * - bit 6 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case |
1679 * - bit 6 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case |
1591 * - bit 8-11 Vehicle List Window type (ignored unless bit 1 is set) |
1680 * - bit 8-11 Vehicle List Window type (ignored unless bit 1 is set) |
1592 */ |
1681 */ |
1593 int32 CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1682 CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1594 { |
1683 { |
1595 Vehicle **vl = NULL; |
1684 Vehicle **vl = NULL; |
1596 uint16 engine_list_length = 0; |
1685 uint16 engine_list_length = 0; |
1597 uint16 engine_count = 0; |
1686 uint16 engine_count = 0; |
1598 int32 return_value = CMD_ERROR; |
1687 CommandCost return_value = CMD_ERROR; |
1599 uint i; |
1688 uint i; |
1600 uint stop_command; |
1689 uint stop_command; |
1601 VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5); |
1690 VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5); |
1602 bool start_stop = HASBIT(p2, 5); |
1691 bool start_stop = HASBIT(p2, 5); |
1603 bool vehicle_list_window = HASBIT(p2, 6); |
1692 bool vehicle_list_window = HASBIT(p2, 6); |
1652 * @param tile Tile of the depot where the depot is |
1741 * @param tile Tile of the depot where the depot is |
1653 * @param flags type of operation |
1742 * @param flags type of operation |
1654 * @param p1 Vehicle type |
1743 * @param p1 Vehicle type |
1655 * @param p2 unused |
1744 * @param p2 unused |
1656 */ |
1745 */ |
1657 int32 CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1746 CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1658 { |
1747 { |
1659 Vehicle **engines = NULL; |
1748 Vehicle **engines = NULL; |
1660 Vehicle **wagons = NULL; |
1749 Vehicle **wagons = NULL; |
1661 uint16 engine_list_length = 0; |
1750 uint16 engine_list_length = 0; |
1662 uint16 engine_count = 0; |
1751 uint16 engine_count = 0; |
1663 uint16 wagon_list_length = 0; |
1752 uint16 wagon_list_length = 0; |
1664 uint16 wagon_count = 0; |
1753 uint16 wagon_count = 0; |
1665 |
1754 |
1666 int32 cost = 0; |
1755 CommandCost cost = 0; |
1667 uint i, sell_command, total_number_vehicles; |
1756 uint i, sell_command, total_number_vehicles; |
1668 VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8); |
1757 VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8); |
1669 |
1758 |
1670 switch (vehicle_type) { |
1759 switch (vehicle_type) { |
1671 case VEH_TRAIN: sell_command = CMD_SELL_RAIL_WAGON; break; |
1760 case VEH_TRAIN: sell_command = CMD_SELL_RAIL_WAGON; break; |
1705 * @param tile Tile of the depot where the vehicles are |
1794 * @param tile Tile of the depot where the vehicles are |
1706 * @param flags type of operation |
1795 * @param flags type of operation |
1707 * @param p1 Type of vehicle |
1796 * @param p1 Type of vehicle |
1708 * @param p2 Unused |
1797 * @param p2 Unused |
1709 */ |
1798 */ |
1710 int32 CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1799 CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1711 { |
1800 { |
1712 Vehicle **vl = NULL; |
1801 Vehicle **vl = NULL; |
1713 uint16 engine_list_length = 0; |
1802 uint16 engine_list_length = 0; |
1714 uint16 engine_count = 0; |
1803 uint16 engine_count = 0; |
1715 uint i, x = 0, y = 0, z = 0; |
1804 uint i, x = 0, y = 0, z = 0; |
1716 int32 cost = 0; |
1805 CommandCost cost = 0; |
1717 VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8); |
1806 VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8); |
1718 |
1807 |
1719 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
1808 if (!IsTileOwner(tile, _current_player)) return CMD_ERROR; |
1720 |
1809 |
1721 /* Get the list of vehicles in the depot */ |
1810 /* Get the list of vehicles in the depot */ |
1771 * @param tile tile of the depot where the cloned vehicle is build |
1860 * @param tile tile of the depot where the cloned vehicle is build |
1772 * @param flags type of operation |
1861 * @param flags type of operation |
1773 * @param p1 the original vehicle's index |
1862 * @param p1 the original vehicle's index |
1774 * @param p2 1 = shared orders, else copied orders |
1863 * @param p2 1 = shared orders, else copied orders |
1775 */ |
1864 */ |
1776 int32 CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1865 CommandCost CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1777 { |
1866 { |
1778 Vehicle *v_front, *v; |
1867 Vehicle *v_front, *v; |
1779 Vehicle *w_front, *w, *w_rear; |
1868 Vehicle *w_front, *w, *w_rear; |
1780 int32 cost, total_cost = 0; |
1869 CommandCost cost, total_cost = 0; |
1781 uint32 build_argument = 2; |
1870 uint32 build_argument = 2; |
1782 |
1871 |
1783 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1872 if (!IsValidVehicleID(p1)) return CMD_ERROR; |
1784 v = GetVehicle(p1); |
1873 v = GetVehicle(p1); |
1785 v_front = v; |
1874 v_front = v; |
1835 } |
1924 } |
1836 |
1925 |
1837 if (v->type == VEH_TRAIN && !IsFrontEngine(v)) { |
1926 if (v->type == VEH_TRAIN && !IsFrontEngine(v)) { |
1838 /* this s a train car |
1927 /* this s a train car |
1839 * add this unit to the end of the train */ |
1928 * add this unit to the end of the train */ |
1840 int32 result = DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE); |
1929 CommandCost result = DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE); |
1841 if (CmdFailed(result)) { |
1930 if (CmdFailed(result)) { |
1842 /* The train can't be joined to make the same consist as the original. |
1931 /* The train can't be joined to make the same consist as the original. |
1843 * Sell what we already made (clean up) and return an error. */ |
1932 * Sell what we already made (clean up) and return an error. */ |
1844 DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front)); |
1933 DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front)); |
1845 DoCommand(w_front->tile, w->index, 1, flags, GetCmdSellVeh(w)); |
1934 DoCommand(w_front->tile, w->index, 1, flags, GetCmdSellVeh(w)); |
2132 * @param service should the vehicles only get service in the depots |
2221 * @param service should the vehicles only get service in the depots |
2133 * @param owner PlayerID of owner of the vehicles to send |
2222 * @param owner PlayerID of owner of the vehicles to send |
2134 * @param vlw_flag tells what kind of list requested the goto depot |
2223 * @param vlw_flag tells what kind of list requested the goto depot |
2135 * @return 0 for success and CMD_ERROR if no vehicle is able to go to depot |
2224 * @return 0 for success and CMD_ERROR if no vehicle is able to go to depot |
2136 */ |
2225 */ |
2137 int32 SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id) |
2226 CommandCost SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id) |
2138 { |
2227 { |
2139 const Vehicle **sort_list = NULL; |
2228 const Vehicle **sort_list = NULL; |
2140 uint n, i; |
2229 uint n, i; |
2141 uint16 array_length = 0; |
2230 uint16 array_length = 0; |
2142 |
2231 |
2143 n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, vlw_flag); |
2232 n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, vlw_flag); |
2144 |
2233 |
2145 /* Send all the vehicles to a depot */ |
2234 /* Send all the vehicles to a depot */ |
2146 for (i = 0; i < n; i++) { |
2235 for (i = 0; i < n; i++) { |
2147 const Vehicle *v = sort_list[i]; |
2236 const Vehicle *v = sort_list[i]; |
2148 int32 ret = DoCommand(v->tile, v->index, (service ? 1 : 0) | DEPOT_DONT_CANCEL, flags, GetCmdSendToDepot(type)); |
2237 CommandCost ret = DoCommand(v->tile, v->index, (service ? 1 : 0) | DEPOT_DONT_CANCEL, flags, GetCmdSendToDepot(type)); |
2149 |
2238 |
2150 /* Return 0 if DC_EXEC is not set this is a valid goto depot command) |
2239 /* Return 0 if DC_EXEC is not set this is a valid goto depot command) |
2151 * In this case we know that at least one vehicle can be sent to a depot |
2240 * In this case we know that at least one vehicle can be sent to a depot |
2152 * and we will issue the command. We can now safely quit the loop, knowing |
2241 * and we will issue the command. We can now safely quit the loop, knowing |
2153 * it will succeed at least once. With DC_EXEC we really need to send them to the depot */ |
2242 * it will succeed at least once. With DC_EXEC we really need to send them to the depot */ |
2154 if (!CmdFailed(ret) && !(flags & DC_EXEC)) { |
2243 if (CmdSucceeded(ret) && !(flags & DC_EXEC)) { |
2155 free((void*)sort_list); |
2244 free((void*)sort_list); |
2156 return 0; |
2245 return 0; |
2157 } |
2246 } |
2158 } |
2247 } |
2159 |
2248 |