56 #include "table/strings.h"
60 #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6))
78 bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
79 for (uint i = 0; i < this->count; ++i) {
82 bounds->left = spr->
x_offs;
87 if (spr->
x_offs < bounds->left) bounds->left = spr->
x_offs;
88 if (spr->
y_offs < bounds->top) bounds->top = spr->
y_offs;
91 if (right > bounds->right) bounds->right = right;
92 if (bottom > bounds->bottom) bounds->bottom = bottom;
106 for (uint i = 0; i < this->count; ++i) {
107 PaletteID pal = force_pal || !this->seq[i].
pal ? default_pal : this->seq[i].
pal;
169 if (this->ServiceIntervalIsPercent() ?
185 bool pending_replace =
false;
187 if (needed_money > c->
money)
return false;
190 bool replace_when_old =
false;
196 if (replace_when_old && !v->NeedsAutorenewing(c,
false))
continue;
199 uint32 available_cargo_types, union_mask;
202 if (union_mask != 0) {
210 if (!
HasBit(available_cargo_types, cargo_type))
continue;
216 pending_replace =
true;
217 needed_money += 2 *
Engine::Get(new_engine)->GetCost();
218 if (needed_money > c->
money)
return false;
221 return pending_replace;
246 for (
Vehicle *v =
this; v != NULL; v = v->
Next()) {
250 v->MarkAllViewportsDirty();
280 if (grfconfig == NULL)
return;
294 GetString(buffer, part1,
lastof(buffer));
295 DEBUG(grf, 0,
"%s", buffer + 3);
298 GetString(buffer, part2,
lastof(buffer));
299 DEBUG(grf, 0,
"%s", buffer + 3);
341 return GB(Random(), 0, 8);
346 const int HASH_BITS = 7;
347 const int HASH_SIZE = 1 << HASH_BITS;
348 const int HASH_MASK = HASH_SIZE - 1;
349 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
350 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
354 const int HASH_RES = 0;
356 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
358 static Vehicle *VehicleFromTileHash(
int xl,
int yl,
int xu,
int yu,
void *data, VehicleFromPosProc *proc,
bool find_first)
360 for (
int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
361 for (
int x = xl; ; x = (x + 1) & HASH_MASK) {
362 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
365 if (find_first && a != NULL)
return a;
389 const int COLL_DIST = 6;
392 int xl =
GB((x - COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS);
393 int xu =
GB((x + COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS);
394 int yl =
GB((y - COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
395 int yu =
GB((y + COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
397 return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
447 int x =
GB(
TileX(tile), HASH_RES, HASH_BITS);
448 int y =
GB(
TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
450 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
452 if (v->
tile != tile)
continue;
455 if (find_first && a != NULL)
return a;
505 if (v->
z_pos > z)
return NULL;
532 if (v == (
const Vehicle *)data)
return NULL;
564 if ((t->track != rail_bits) && !
TracksOverlap(t->track | rail_bits))
return NULL;
588 static void UpdateVehicleTileHash(
Vehicle *v,
bool remove)
597 int y =
GB(
TileY(v->
tile), HASH_RES, HASH_BITS) << HASH_BITS;
598 new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
601 if (old_hash == new_hash)
return;
604 if (old_hash != NULL) {
610 if (new_hash != NULL) {
621 static Vehicle *_vehicle_viewport_hash[0x1000];
623 static void UpdateVehicleViewportHash(
Vehicle *v,
int x,
int y)
625 Vehicle **old_hash, **new_hash;
626 int old_x = v->
coord.left;
627 int old_y = v->
coord.top;
629 new_hash = (x ==
INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
630 old_hash = (old_x ==
INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
632 if (old_hash == new_hash)
return;
635 if (old_hash != NULL) {
641 if (new_hash != NULL) {
649 void ResetVehicleHash()
653 memset(_vehicle_viewport_hash, 0,
sizeof(_vehicle_viewport_hash));
654 memset(_vehicle_tile_hash, 0,
sizeof(_vehicle_tile_hash));
657 void ResetVehicleColourMap()
668 static AutoreplaceMap _vehicles_to_autoreplace;
670 void InitializeVehicles()
672 _vehicles_to_autoreplace.
Reset();
676 uint CountVehiclesInChain(
const Vehicle *v)
679 do count++;
while ((v = v->
Next()) != NULL);
689 switch (this->
type) {
696 default:
return false;
706 switch (this->
type) {
711 default:
return false;
785 st->loading_vehicles.remove(
this);
839 extern void StopGlobalFollowVehicle(
const Vehicle *v);
840 StopGlobalFollowVehicle(
this);
861 UpdateVehicleTileHash(
this,
true);
891 if (_game_mode != GM_NORMAL)
return;
896 if (v == NULL)
continue;
902 if (
HasBit(callback, 0)) {
903 TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32);
919 void CallVehicleTicks()
921 _vehicles_to_autoreplace.
Clear();
947 if (v->vcache.cached_cargo_age_period != 0) {
949 if (--v->cargo_age_counter == 0) {
951 v->cargo_age_counter = v->vcache.cached_cargo_age_period;
987 if (
GB(v->tick_counter, 0, 4) == 0) {
1002 cur_company.Change(v->owner);
1027 if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message ==
INVALID_STRING_ID)
continue;
1029 if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1032 if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1033 message = error_message;
1035 message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1043 cur_company.Restore();
1067 for (uint i = 0; i < v->
sprite_seq.count; ++i) {
1083 const int l = dpi->left;
1084 const int r = dpi->left + dpi->width;
1085 const int t = dpi->top;
1086 const int b = dpi->top + dpi->height;
1091 if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
1092 xl =
GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
1093 xu =
GB(r, 7 + ZOOM_LVL_SHIFT, 6);
1100 if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
1101 yl =
GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
1102 yu =
GB(b, 6 + ZOOM_LVL_SHIFT, 6) << 6;
1109 for (
int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
1110 for (
int x = xl;; x = (x + 1) & 0x3F) {
1111 const Vehicle *v = _vehicle_viewport_hash[x + y];
1115 l <= v->
coord.right &&
1116 t <= v->
coord.bottom &&
1117 r >= v->
coord.left &&
1118 b >= v->
coord.top) {
1141 uint dist, best_dist = UINT_MAX;
1143 if ((uint)(x -= vp->
left) >= (uint)vp->
width || (uint)(y -= vp->
top) >= (uint)vp->
height)
return NULL;
1150 x >= v->coord.left && x <= v->coord.right &&
1151 y >= v->coord.top && y <= v->coord.bottom) {
1154 abs(((v->coord.left + v->coord.right) >> 1) - x),
1155 abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1158 if (dist < best_dist) {
1178 static const byte _breakdown_chance[64] = {
1179 3, 3, 3, 3, 3, 3, 3, 3,
1180 4, 4, 5, 5, 6, 6, 7, 7,
1181 8, 8, 9, 9, 10, 10, 11, 11,
1182 12, 13, 13, 13, 13, 14, 15, 16,
1183 17, 19, 21, 25, 28, 31, 34, 37,
1184 40, 44, 48, 52, 56, 60, 64, 68,
1185 72, 80, 90, 100, 110, 120, 130, 140,
1186 150, 170, 190, 210, 230, 250, 250, 250,
1189 void CheckVehicleBreakdown(
Vehicle *v)
1199 v->
cur_speed < 5 || _game_mode == GM_MENU) {
1203 uint32 r = Random();
1258 (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
1259 (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN),
this);
1322 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1323 }
else if (age == 0) {
1324 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1326 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1350 bool loading =
false;
1356 assert(colour == NULL || (st != NULL && is_loading));
1362 for (
const Vehicle *v = front; v != NULL; v = v->
Next()) {
1365 if (v->
cargo_cap != 0 && colour != NULL) {
1367 loading |= !order_no_load &&
1374 if (colour != NULL) {
1375 if (unloading == 0 && loading) {
1376 *colour = STR_PERCENT_UP;
1377 }
else if (unloading == 0 && !loading) {
1378 *colour = STR_PERCENT_NONE;
1379 }
else if (cars == unloading || !loading) {
1380 *colour = STR_PERCENT_DOWN;
1382 *colour = STR_PERCENT_UP_DOWN;
1387 if (max == 0)
return 100;
1390 if (count * 2 < max) {
1392 return CeilDiv(count * 100, max);
1395 return (count * 100) /
max;
1406 assert(v == v->
First());
1442 default: NOT_REACHED();
1459 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1482 _vehicles_to_autoreplace[v] =
false;
1488 }
else if (cost.
GetCost() != 0) {
1504 _vehicles_to_autoreplace[v] =
false;
1526 UpdateVehicleTileHash(
this,
false);
1540 new_coord.left += pt.x;
1541 new_coord.top += pt.y;
1542 new_coord.right += pt.x + 2 * ZOOM_LVL_BASE;
1543 new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE;
1545 UpdateVehicleViewportHash(
this, new_coord.left, new_coord.top);
1548 this->
coord = new_coord;
1555 min(old_coord.left, this->coord.left),
1556 min(old_coord.top, this->coord.top),
1557 max(old_coord.right, this->coord.right),
1558 max(old_coord.bottom, this->coord.bottom));
1587 static const int8 _delta_coord[16] = {
1588 -1,-1,-1, 0, 1, 1, 1, 0,
1589 -1, 0, 1, 1, 1, 0,-1,-1,
1603 static const Direction _new_direction_table[] = {
1613 if (y >= v->
y_pos) {
1614 if (y != v->
y_pos) i += 3;
1618 if (x >= v->
x_pos) {
1619 if (x != v->
x_pos) i++;
1656 if (v->
type == type && v->
owner == owner) {
1661 if (this->
maxid == 0)
return;
1666 this->
cache = CallocT<bool>(this->
maxid + 2);
1670 if (v->
type == type && v->
owner == owner) {
1679 if (this->maxid <= this->
curid)
return ++this->
curid;
1681 while (this->
cache[++this->curid]) { }
1700 default: NOT_REACHED();
1733 default: NOT_REACHED();
1740 FOR_ALL_ENGINES_OF_TYPE(e, type) {
1768 default: NOT_REACHED();
1773 engine_type = parent_engine_type;
1778 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1779 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1783 return LS_PASSENGER_WAGON_STEAM;
1785 switch (RailVehInfo(parent_engine_type)->engclass) {
1786 default: NOT_REACHED();
1787 case EC_STEAM:
return LS_PASSENGER_WAGON_STEAM;
1788 case EC_DIESEL:
return LS_PASSENGER_WAGON_DIESEL;
1789 case EC_ELECTRIC:
return LS_PASSENGER_WAGON_ELECTRIC;
1790 case EC_MONORAIL:
return LS_PASSENGER_WAGON_MONORAIL;
1791 case EC_MAGLEV:
return LS_PASSENGER_WAGON_MAGLEV;
1795 return LS_FREIGHT_WAGON;
1800 switch (e->u.rail.engclass) {
1801 default: NOT_REACHED();
1803 case EC_DIESEL:
return is_mu ? LS_DMU : LS_DIESEL;
1804 case EC_ELECTRIC:
return is_mu ? LS_EMU : LS_ELECTRIC;
1813 engine_type = parent_engine_type;
1817 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1818 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1830 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1831 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1835 switch (e->u.air.subtype) {
1836 case AIR_HELI:
return LS_HELICOPTER;
1837 case AIR_CTOL:
return LS_SMALL_PLANE;
1838 case AIR_CTOL | AIR_FAST:
return LS_LARGE_PLANE;
1839 default: NOT_REACHED();
1865 if (!c->livery[scheme].
in_use) scheme = LS_DEFAULT;
1868 return &c->livery[scheme];
1877 if (map != PAL_NONE)
return map;
1886 assert_compile(PAL_NONE == 0);
1887 map =
GB(callback, 0, 14);
1890 if (!
HasBit(callback, 14)) {
1892 if (v != NULL)
const_cast<Vehicle *
>(v)->colourmap = map;
1903 if (!
Company::IsValidID(company)) return map;
1907 map += livery->colour1;
1908 if (twocc) map += livery->colour2 * 16;
1911 if (v != NULL) const_cast<
Vehicle *>(v)->colourmap = map;
1923 return GetEngineColourMap(engine_type, company,
INVALID_ENGINE, NULL);
1957 while (order != NULL) {
1960 if (order->
IsType(OT_IMPLICIT)) {
1966 order = order->
next;
1971 if (order == NULL) {
2008 (in_list == NULL || !in_list->
IsType(OT_IMPLICIT) ||
2013 if (prev_order == NULL ||
2014 (!prev_order->
IsType(OT_IMPLICIT) && !prev_order->
IsType(OT_GOTO_STATION)) ||
2026 if (order == NULL)
break;
2032 if (target_index >= this->
orders.list->GetNumOrders()) {
2043 if (suppress_implicit_orders) {
2051 if (order->
IsType(OT_IMPLICIT)) {
2057 order = order->
next;
2062 if (order == NULL) {
2066 assert(order != NULL);
2069 }
else if (!suppress_implicit_orders &&
2117 DEBUG(misc, 1,
"cancelling cargo reservation");
2134 assert(this->cargo_payment == NULL);
2160 st->loading_vehicles.remove(
this);
2205 if (order == NULL ||
2206 (!order->
IsType(OT_IMPLICIT) && !order->
IsType(OT_GOTO_STATION)) ||
2213 case OT_DUMMY:
break;
2227 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2230 if (pair == capacities.
End()) {
2231 pair = capacities.
Append();
2240 uint Vehicle::GetConsistTotalCapacity()
const
2243 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2258 if (ret.
Failed())
return ret;
2295 DestinationID destination;
2297 static const StringID no_depot[] = {STR_ERROR_UNABLE_TO_FIND_ROUTE_TO, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR};
2355 callback =
GB(callback, 0, 8);
2362 visual_effect = callback;
2394 static const int8 _vehicle_smoke_pos[8] = {
2395 1, 1, 1, 0, -1, -1, -1, 0
2407 uint count =
GB(callback, 0, 2);
2408 bool auto_center =
HasBit(callback, 13);
2409 bool auto_rotate = !
HasBit(callback, 14);
2424 int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2425 int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2427 for (uint i = 0; i < count; i++) {
2429 uint type =
GB(reg, 0, 8);
2430 int8 x =
GB(reg, 8, 8);
2431 int8 y =
GB(reg, 16, 8);
2432 int8 z =
GB(reg, 24, 8);
2437 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2438 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2469 this->cur_speed < 2) {
2482 if (
HasBit(t->flags, VRF_REVERSING) ||
2498 if (effect_model >= VESM_END) effect_model =
VESM_NONE;
2525 switch (effect_model) {
2549 int power_weight_effect = 0;
2577 if (evt != EV_END && advanced) {
2580 }
else if (evt != EV_END) {
2588 int x = _vehicle_smoke_pos[v->
direction] * effect_offset;
2589 int y = _vehicle_smoke_pos[(v->
direction + 2) % 8] * effect_offset;
2598 }
while ((v = v->
Next()) != NULL);
2609 assert(
this != next);
2611 if (this->next != NULL) {
2613 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2621 if (this->next != NULL) {
2625 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2666 this->
orders.list->RemoveVehicle(
this);
2676 if (this->
orders.list->GetNumVehicles() == 1) {
2680 }
else if (were_first) {
2690 void VehiclesYearlyLoop()
2697 if (v->
age >= 730 && profit < 0) {
2844 for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2847 set.Include(u->
index);