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;
1303 bool loading =
false;
1309 assert(colour == NULL || (st != NULL && is_loading));
1315 for (
const Vehicle *v = front; v != NULL; v = v->
Next()) {
1318 if (v->
cargo_cap != 0 && colour != NULL) {
1320 loading |= !order_no_load &&
1327 if (colour != NULL) {
1328 if (unloading == 0 && loading) {
1329 *colour = STR_PERCENT_UP;
1330 }
else if (unloading == 0 && !loading) {
1331 *colour = STR_PERCENT_NONE;
1332 }
else if (cars == unloading || !loading) {
1333 *colour = STR_PERCENT_DOWN;
1335 *colour = STR_PERCENT_UP_DOWN;
1340 if (max == 0)
return 100;
1343 if (count * 2 < max) {
1345 return CeilDiv(count * 100, max);
1348 return (count * 100) /
max;
1359 assert(v == v->
First());
1395 default: NOT_REACHED();
1412 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1435 _vehicles_to_autoreplace[v] =
false;
1441 }
else if (cost.
GetCost() != 0) {
1457 _vehicles_to_autoreplace[v] =
false;
1479 UpdateVehicleTileHash(
this,
false);
1496 UpdateVehicleViewportHash(
this, pt.x, pt.y);
1499 this->
coord.left = pt.x;
1500 this->
coord.top = pt.y;
1501 this->
coord.right = pt.x + spr->
width + 2 * ZOOM_LVL_BASE;
1502 this->
coord.bottom = pt.y + spr->
height + 2 * ZOOM_LVL_BASE;
1509 min(old_coord.left, this->coord.left),
1510 min(old_coord.top, this->coord.top),
1511 max(old_coord.right, this->coord.right),
1512 max(old_coord.bottom, this->coord.bottom));
1541 static const int8 _delta_coord[16] = {
1542 -1,-1,-1, 0, 1, 1, 1, 0,
1543 -1, 0, 1, 1, 1, 0,-1,-1,
1557 static const Direction _new_direction_table[] = {
1567 if (y >= v->
y_pos) {
1568 if (y != v->
y_pos) i += 3;
1572 if (x >= v->
x_pos) {
1573 if (x != v->
x_pos) i++;
1610 if (v->
type == type && v->
owner == owner) {
1615 if (this->
maxid == 0)
return;
1620 this->
cache = CallocT<bool>(this->
maxid + 2);
1624 if (v->
type == type && v->
owner == owner) {
1633 if (this->maxid <= this->
curid)
return ++this->
curid;
1635 while (this->
cache[++this->curid]) { }
1654 default: NOT_REACHED();
1687 default: NOT_REACHED();
1694 FOR_ALL_ENGINES_OF_TYPE(e, type) {
1722 default: NOT_REACHED();
1727 engine_type = parent_engine_type;
1732 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1733 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1737 return LS_PASSENGER_WAGON_STEAM;
1739 switch (RailVehInfo(parent_engine_type)->engclass) {
1740 default: NOT_REACHED();
1741 case EC_STEAM:
return LS_PASSENGER_WAGON_STEAM;
1742 case EC_DIESEL:
return LS_PASSENGER_WAGON_DIESEL;
1743 case EC_ELECTRIC:
return LS_PASSENGER_WAGON_ELECTRIC;
1744 case EC_MONORAIL:
return LS_PASSENGER_WAGON_MONORAIL;
1745 case EC_MAGLEV:
return LS_PASSENGER_WAGON_MAGLEV;
1749 return LS_FREIGHT_WAGON;
1754 switch (e->u.rail.engclass) {
1755 default: NOT_REACHED();
1757 case EC_DIESEL:
return is_mu ? LS_DMU : LS_DIESEL;
1758 case EC_ELECTRIC:
return is_mu ? LS_EMU : LS_ELECTRIC;
1767 engine_type = parent_engine_type;
1771 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1772 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1784 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1785 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1789 switch (e->u.air.subtype) {
1790 case AIR_HELI:
return LS_HELICOPTER;
1791 case AIR_CTOL:
return LS_SMALL_PLANE;
1792 case AIR_CTOL | AIR_FAST:
return LS_LARGE_PLANE;
1793 default: NOT_REACHED();
1819 if (!c->livery[scheme].
in_use) scheme = LS_DEFAULT;
1822 return &c->livery[scheme];
1831 if (map != PAL_NONE)
return map;
1840 assert_compile(PAL_NONE == 0);
1841 map =
GB(callback, 0, 14);
1844 if (!
HasBit(callback, 14)) {
1846 if (v != NULL)
const_cast<Vehicle *
>(v)->colourmap = map;
1857 if (!
Company::IsValidID(company)) return map;
1861 map += livery->colour1;
1862 if (twocc) map += livery->colour2 * 16;
1865 if (v != NULL) const_cast<
Vehicle *>(v)->colourmap = map;
1877 return GetEngineColourMap(engine_type, company,
INVALID_ENGINE, NULL);
1911 while (order != NULL) {
1914 if (order->
IsType(OT_IMPLICIT)) {
1920 order = order->
next;
1925 if (order == NULL) {
1962 (in_list == NULL || !in_list->
IsType(OT_IMPLICIT) ||
1967 if (prev_order == NULL ||
1968 (!prev_order->
IsType(OT_IMPLICIT) && !prev_order->
IsType(OT_GOTO_STATION)) ||
1980 if (order == NULL)
break;
1986 if (target_index >= this->
orders.list->GetNumOrders()) {
1997 if (suppress_implicit_orders) {
2005 if (order->
IsType(OT_IMPLICIT)) {
2011 order = order->
next;
2016 if (order == NULL) {
2020 assert(order != NULL);
2023 }
else if (!suppress_implicit_orders &&
2071 DEBUG(misc, 1,
"cancelling cargo reservation");
2113 st->loading_vehicles.remove(
this);
2158 if (order == NULL ||
2159 (!order->
IsType(OT_IMPLICIT) && !order->
IsType(OT_GOTO_STATION)) ||
2166 case OT_DUMMY:
break;
2180 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2183 if (pair == capacities.
End()) {
2184 pair = capacities.
Append();
2193 uint Vehicle::GetConsistTotalCapacity()
const
2196 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2211 if (ret.
Failed())
return ret;
2248 DestinationID destination;
2250 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};
2308 callback =
GB(callback, 0, 8);
2315 visual_effect = callback;
2347 static const int8 _vehicle_smoke_pos[8] = {
2348 1, 1, 1, 0, -1, -1, -1, 0
2360 uint count =
GB(callback, 0, 2);
2361 bool auto_center =
HasBit(callback, 13);
2362 bool auto_rotate = !
HasBit(callback, 14);
2377 int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2378 int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2380 for (uint i = 0; i < count; i++) {
2382 uint type =
GB(reg, 0, 8);
2383 int8 x =
GB(reg, 8, 8);
2384 int8 y =
GB(reg, 16, 8);
2385 int8 z =
GB(reg, 24, 8);
2390 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2391 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2422 this->cur_speed < 2) {
2435 if (
HasBit(t->flags, VRF_REVERSING) ||
2451 if (effect_model >= VESM_END) effect_model =
VESM_NONE;
2478 switch (effect_model) {
2502 int power_weight_effect = 0;
2530 if (evt != EV_END && advanced) {
2533 }
else if (evt != EV_END) {
2541 int x = _vehicle_smoke_pos[v->
direction] * effect_offset;
2542 int y = _vehicle_smoke_pos[(v->
direction + 2) % 8] * effect_offset;
2551 }
while ((v = v->
Next()) != NULL);
2562 assert(
this != next);
2564 if (this->next != NULL) {
2566 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2574 if (this->next != NULL) {
2578 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2619 this->
orders.list->RemoveVehicle(
this);
2629 if (this->
orders.list->GetNumVehicles() == 1) {
2633 }
else if (were_first) {
2643 void VehiclesYearlyLoop()
2650 if (v->
age >= 730 && profit < 0) {
2797 for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2800 set.Include(u->
index);