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))
77 bool
Vehicle::NeedsAutorenewing(const
Company *c,
bool use_renew_setting)
const
85 if (use_renew_setting && !c->settings.engine_renew)
return false;
86 if (this->age - this->max_age < (c->settings.engine_renew_months * 30))
return false;
128 if (this->ServiceIntervalIsPercent() ?
144 bool pending_replace =
false;
146 if (needed_money > c->
money)
return false;
149 bool replace_when_old =
false;
155 if (replace_when_old && !v->NeedsAutorenewing(c,
false))
continue;
158 uint32 available_cargo_types, union_mask;
161 if (union_mask != 0) {
169 if (!
HasBit(available_cargo_types, cargo_type))
continue;
175 pending_replace =
true;
176 needed_money += 2 *
Engine::Get(new_engine)->GetCost();
177 if (needed_money > c->
money)
return false;
180 return pending_replace;
205 for (
Vehicle *v =
this; v != NULL; v = v->
Next()) {
209 v->MarkAllViewportsDirty();
239 if (grfconfig == NULL)
return;
253 GetString(buffer, part1,
lastof(buffer));
254 DEBUG(grf, 0,
"%s", buffer + 3);
257 GetString(buffer, part2,
lastof(buffer));
258 DEBUG(grf, 0,
"%s", buffer + 3);
300 return GB(Random(), 0, 8);
305 const int HASH_BITS = 7;
306 const int HASH_SIZE = 1 << HASH_BITS;
307 const int HASH_MASK = HASH_SIZE - 1;
308 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
309 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
313 const int HASH_RES = 0;
315 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
317 static Vehicle *VehicleFromTileHash(
int xl,
int yl,
int xu,
int yu,
void *data, VehicleFromPosProc *proc,
bool find_first)
319 for (
int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
320 for (
int x = xl; ; x = (x + 1) & HASH_MASK) {
321 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
324 if (find_first && a != NULL)
return a;
348 const int COLL_DIST = 6;
351 int xl =
GB((x - COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS);
352 int xu =
GB((x + COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS);
353 int yl =
GB((y - COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
354 int yu =
GB((y + COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
356 return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
406 int x =
GB(
TileX(tile), HASH_RES, HASH_BITS);
407 int y =
GB(
TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
409 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
411 if (v->
tile != tile)
continue;
414 if (find_first && a != NULL)
return a;
464 if (v->
z_pos > z)
return NULL;
491 if (v == (
const Vehicle *)data)
return NULL;
523 if ((t->track != rail_bits) && !
TracksOverlap(t->track | rail_bits))
return NULL;
547 static void UpdateVehicleTileHash(
Vehicle *v,
bool remove)
556 int y =
GB(
TileY(v->
tile), HASH_RES, HASH_BITS) << HASH_BITS;
557 new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
560 if (old_hash == new_hash)
return;
563 if (old_hash != NULL) {
569 if (new_hash != NULL) {
580 static Vehicle *_vehicle_viewport_hash[0x1000];
582 static void UpdateVehicleViewportHash(
Vehicle *v,
int x,
int y)
584 Vehicle **old_hash, **new_hash;
585 int old_x = v->
coord.left;
586 int old_y = v->
coord.top;
588 new_hash = (x ==
INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
589 old_hash = (old_x ==
INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
591 if (old_hash == new_hash)
return;
594 if (old_hash != NULL) {
600 if (new_hash != NULL) {
608 void ResetVehicleHash()
612 memset(_vehicle_viewport_hash, 0,
sizeof(_vehicle_viewport_hash));
613 memset(_vehicle_tile_hash, 0,
sizeof(_vehicle_tile_hash));
616 void ResetVehicleColourMap()
627 static AutoreplaceMap _vehicles_to_autoreplace;
629 void InitializeVehicles()
631 _vehicles_to_autoreplace.
Reset();
635 uint CountVehiclesInChain(
const Vehicle *v)
638 do count++;
while ((v = v->
Next()) != NULL);
648 switch (this->
type) {
655 default:
return false;
665 switch (this->
type) {
670 default:
return false;
744 st->loading_vehicles.remove(
this);
797 extern void StopGlobalFollowVehicle(
const Vehicle *v);
798 StopGlobalFollowVehicle(
this);
819 UpdateVehicleTileHash(
this,
true);
849 if (_game_mode != GM_NORMAL)
return;
854 if (v == NULL)
continue;
860 if (
HasBit(callback, 0)) {
861 TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32);
877 void CallVehicleTicks()
879 _vehicles_to_autoreplace.
Clear();
905 if (v->vcache.cached_cargo_age_period != 0) {
907 if (--v->cargo_age_counter == 0) {
909 v->cargo_age_counter = v->vcache.cached_cargo_age_period;
945 if (
GB(v->tick_counter, 0, 4) == 0) {
960 cur_company.Change(v->owner);
985 if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message ==
INVALID_STRING_ID)
continue;
987 if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
990 if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
991 message = error_message;
993 message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1001 cur_company.Restore();
1036 const int l = dpi->left;
1037 const int r = dpi->left + dpi->width;
1038 const int t = dpi->top;
1039 const int b = dpi->top + dpi->height;
1044 if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
1045 xl =
GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
1046 xu =
GB(r, 7 + ZOOM_LVL_SHIFT, 6);
1053 if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
1054 yl =
GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
1055 yu =
GB(b, 6 + ZOOM_LVL_SHIFT, 6) << 6;
1062 for (
int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
1063 for (
int x = xl;; x = (x + 1) & 0x3F) {
1064 const Vehicle *v = _vehicle_viewport_hash[x + y];
1068 l <= v->
coord.right &&
1069 t <= v->
coord.bottom &&
1070 r >= v->
coord.left &&
1071 b >= v->
coord.top) {
1094 uint dist, best_dist = UINT_MAX;
1096 if ((uint)(x -= vp->
left) >= (uint)vp->
width || (uint)(y -= vp->
top) >= (uint)vp->
height)
return NULL;
1103 x >= v->coord.left && x <= v->coord.right &&
1104 y >= v->coord.top && y <= v->coord.bottom) {
1107 abs(((v->coord.left + v->coord.right) >> 1) - x),
1108 abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1111 if (dist < best_dist) {
1131 static const byte _breakdown_chance[64] = {
1132 3, 3, 3, 3, 3, 3, 3, 3,
1133 4, 4, 5, 5, 6, 6, 7, 7,
1134 8, 8, 9, 9, 10, 10, 11, 11,
1135 12, 13, 13, 13, 13, 14, 15, 16,
1136 17, 19, 21, 25, 28, 31, 34, 37,
1137 40, 44, 48, 52, 56, 60, 64, 68,
1138 72, 80, 90, 100, 110, 120, 130, 140,
1139 150, 170, 190, 210, 230, 250, 250, 250,
1142 void CheckVehicleBreakdown(
Vehicle *v)
1152 v->
cur_speed < 5 || _game_mode == GM_MENU) {
1156 uint32 r = Random();
1211 (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
1212 (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN),
this);
1275 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1276 }
else if (age == 0) {
1277 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1279 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1300 bool loading =
false;
1306 assert(colour == NULL || (st != NULL && is_loading));
1312 for (
const Vehicle *v = front; v != NULL; v = v->
Next()) {
1315 if (v->
cargo_cap != 0 && colour != NULL) {
1317 loading |= !order_no_load &&
1324 if (colour != NULL) {
1325 if (unloading == 0 && loading) {
1326 *colour = STR_PERCENT_UP;
1327 }
else if (unloading == 0 && !loading) {
1328 *colour = STR_PERCENT_NONE;
1329 }
else if (cars == unloading || !loading) {
1330 *colour = STR_PERCENT_DOWN;
1332 *colour = STR_PERCENT_UP_DOWN;
1337 if (max == 0)
return 100;
1340 return (count * 100) /
max;
1350 assert(v == v->
First());
1386 default: NOT_REACHED();
1403 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1426 _vehicles_to_autoreplace[v] =
false;
1432 }
else if (cost.
GetCost() != 0) {
1448 _vehicles_to_autoreplace[v] =
false;
1470 UpdateVehicleTileHash(
this,
false);
1487 UpdateVehicleViewportHash(
this, pt.x, pt.y);
1490 this->
coord.left = pt.x;
1491 this->
coord.top = pt.y;
1492 this->
coord.right = pt.x + spr->
width + 2 * ZOOM_LVL_BASE;
1493 this->
coord.bottom = pt.y + spr->
height + 2 * ZOOM_LVL_BASE;
1500 min(old_coord.left, this->coord.left),
1501 min(old_coord.top, this->coord.top),
1502 max(old_coord.right, this->coord.right),
1503 max(old_coord.bottom, this->coord.bottom));
1532 static const int8 _delta_coord[16] = {
1533 -1,-1,-1, 0, 1, 1, 1, 0,
1534 -1, 0, 1, 1, 1, 0,-1,-1,
1548 static const Direction _new_direction_table[] = {
1558 if (y >= v->
y_pos) {
1559 if (y != v->
y_pos) i += 3;
1563 if (x >= v->
x_pos) {
1564 if (x != v->
x_pos) i++;
1601 if (v->
type == type && v->
owner == owner) {
1606 if (this->
maxid == 0)
return;
1611 this->
cache = CallocT<bool>(this->
maxid + 2);
1615 if (v->
type == type && v->
owner == owner) {
1624 if (this->maxid <= this->
curid)
return ++this->
curid;
1626 while (this->
cache[++this->curid]) { }
1645 default: NOT_REACHED();
1678 default: NOT_REACHED();
1685 FOR_ALL_ENGINES_OF_TYPE(e, type) {
1713 default: NOT_REACHED();
1718 engine_type = parent_engine_type;
1723 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1724 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1728 return LS_PASSENGER_WAGON_STEAM;
1730 switch (RailVehInfo(parent_engine_type)->engclass) {
1731 default: NOT_REACHED();
1732 case EC_STEAM:
return LS_PASSENGER_WAGON_STEAM;
1733 case EC_DIESEL:
return LS_PASSENGER_WAGON_DIESEL;
1734 case EC_ELECTRIC:
return LS_PASSENGER_WAGON_ELECTRIC;
1735 case EC_MONORAIL:
return LS_PASSENGER_WAGON_MONORAIL;
1736 case EC_MAGLEV:
return LS_PASSENGER_WAGON_MAGLEV;
1740 return LS_FREIGHT_WAGON;
1745 switch (e->u.rail.engclass) {
1746 default: NOT_REACHED();
1748 case EC_DIESEL:
return is_mu ? LS_DMU : LS_DIESEL;
1749 case EC_ELECTRIC:
return is_mu ? LS_EMU : LS_ELECTRIC;
1758 engine_type = parent_engine_type;
1762 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1763 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1775 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1776 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1780 switch (e->u.air.subtype) {
1781 case AIR_HELI:
return LS_HELICOPTER;
1782 case AIR_CTOL:
return LS_SMALL_PLANE;
1783 case AIR_CTOL | AIR_FAST:
return LS_LARGE_PLANE;
1784 default: NOT_REACHED();
1810 if (!c->livery[scheme].
in_use) scheme = LS_DEFAULT;
1813 return &c->livery[scheme];
1822 if (map != PAL_NONE)
return map;
1831 assert_compile(PAL_NONE == 0);
1832 map =
GB(callback, 0, 14);
1835 if (!
HasBit(callback, 14)) {
1837 if (v != NULL)
const_cast<Vehicle *
>(v)->colourmap = map;
1848 if (!
Company::IsValidID(company)) return map;
1852 map += livery->colour1;
1853 if (twocc) map += livery->colour2 * 16;
1856 if (v != NULL) const_cast<
Vehicle *>(v)->colourmap = map;
1868 return GetEngineColourMap(engine_type, company,
INVALID_ENGINE, NULL);
1902 while (order != NULL) {
1905 if (order->
IsType(OT_IMPLICIT)) {
1911 order = order->
next;
1916 if (order == NULL) {
1953 (in_list == NULL || !in_list->
IsType(OT_IMPLICIT) ||
1958 if (prev_order == NULL ||
1959 (!prev_order->
IsType(OT_IMPLICIT) && !prev_order->
IsType(OT_GOTO_STATION)) ||
1971 if (order == NULL)
break;
1977 if (target_index >= this->
orders.list->GetNumOrders()) {
1988 if (suppress_implicit_orders) {
1996 if (order->
IsType(OT_IMPLICIT)) {
2002 order = order->
next;
2007 if (order == NULL) {
2011 assert(order != NULL);
2014 }
else if (!suppress_implicit_orders &&
2062 DEBUG(misc, 1,
"cancelling cargo reservation");
2104 st->loading_vehicles.remove(
this);
2149 if (order == NULL ||
2150 (!order->
IsType(OT_IMPLICIT) && !order->
IsType(OT_GOTO_STATION)) ||
2157 case OT_DUMMY:
break;
2171 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2174 if (pair == capacities.
End()) {
2175 pair = capacities.
Append();
2184 uint Vehicle::GetConsistTotalCapacity()
const
2187 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2202 if (ret.
Failed())
return ret;
2239 DestinationID destination;
2241 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};
2299 callback =
GB(callback, 0, 8);
2306 visual_effect = callback;
2338 static const int8 _vehicle_smoke_pos[8] = {
2339 1, 1, 1, 0, -1, -1, -1, 0
2351 uint count =
GB(callback, 0, 2);
2352 bool auto_center =
HasBit(callback, 13);
2353 bool auto_rotate = !
HasBit(callback, 14);
2368 int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2369 int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2371 for (uint i = 0; i < count; i++) {
2373 uint type =
GB(reg, 0, 8);
2374 int8 x =
GB(reg, 8, 8);
2375 int8 y =
GB(reg, 16, 8);
2376 int8 z =
GB(reg, 24, 8);
2381 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2382 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2413 this->cur_speed < 2) {
2424 if (
HasBit(t->flags, VRF_REVERSING) ||
2426 t->
cur_speed >= t->Train::GetCurrentMaxSpeed())) {
2444 if (effect_model >= VESM_END) effect_model =
VESM_NONE;
2471 switch (effect_model) {
2495 int power_weight_effect = 0;
2513 if (
GB(v->tick_counter, 0, 2) == 0 &&
2523 if (evt != EV_END && advanced) {
2526 }
else if (evt != EV_END) {
2534 int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2535 int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2544 }
while ((v = v->Next()) != NULL);
2555 assert(
this != next);
2557 if (this->next != NULL) {
2559 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2567 if (this->next != NULL) {
2571 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2612 this->
orders.list->RemoveVehicle(
this);
2622 if (this->
orders.list->GetNumVehicles() == 1) {
2626 }
else if (were_first) {
2636 void VehiclesYearlyLoop()
2643 if (v->
age >= 730 && profit < 0) {
2790 for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2793 set.Include(u->
index);