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);
798 extern void StopGlobalFollowVehicle(
const Vehicle *v);
799 StopGlobalFollowVehicle(
this);
820 UpdateVehicleTileHash(
this,
true);
850 if (_game_mode != GM_NORMAL)
return;
855 if (v == NULL)
continue;
861 if (
HasBit(callback, 0)) {
862 TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32);
878 void CallVehicleTicks()
880 _vehicles_to_autoreplace.
Clear();
906 if (v->vcache.cached_cargo_age_period != 0) {
908 if (--v->cargo_age_counter == 0) {
910 v->cargo_age_counter = v->vcache.cached_cargo_age_period;
946 if (
GB(v->tick_counter, 0, 4) == 0) {
961 cur_company.Change(v->owner);
986 if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message ==
INVALID_STRING_ID)
continue;
988 if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
991 if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
992 message = error_message;
994 message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1002 cur_company.Restore();
1037 const int l = dpi->left;
1038 const int r = dpi->left + dpi->width;
1039 const int t = dpi->top;
1040 const int b = dpi->top + dpi->height;
1045 if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
1046 xl =
GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
1047 xu =
GB(r, 7 + ZOOM_LVL_SHIFT, 6);
1054 if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
1055 yl =
GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
1056 yu =
GB(b, 6 + ZOOM_LVL_SHIFT, 6) << 6;
1063 for (
int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
1064 for (
int x = xl;; x = (x + 1) & 0x3F) {
1065 const Vehicle *v = _vehicle_viewport_hash[x + y];
1069 l <= v->
coord.right &&
1070 t <= v->
coord.bottom &&
1071 r >= v->
coord.left &&
1072 b >= v->
coord.top) {
1095 uint dist, best_dist = UINT_MAX;
1097 if ((uint)(x -= vp->
left) >= (uint)vp->
width || (uint)(y -= vp->
top) >= (uint)vp->
height)
return NULL;
1104 x >= v->coord.left && x <= v->coord.right &&
1105 y >= v->coord.top && y <= v->coord.bottom) {
1108 abs(((v->coord.left + v->coord.right) >> 1) - x),
1109 abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1112 if (dist < best_dist) {
1132 static const byte _breakdown_chance[64] = {
1133 3, 3, 3, 3, 3, 3, 3, 3,
1134 4, 4, 5, 5, 6, 6, 7, 7,
1135 8, 8, 9, 9, 10, 10, 11, 11,
1136 12, 13, 13, 13, 13, 14, 15, 16,
1137 17, 19, 21, 25, 28, 31, 34, 37,
1138 40, 44, 48, 52, 56, 60, 64, 68,
1139 72, 80, 90, 100, 110, 120, 130, 140,
1140 150, 170, 190, 210, 230, 250, 250, 250,
1143 void CheckVehicleBreakdown(
Vehicle *v)
1153 v->
cur_speed < 5 || _game_mode == GM_MENU) {
1157 uint32 r = Random();
1212 (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
1213 (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN),
this);
1276 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1277 }
else if (age == 0) {
1278 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1280 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1304 bool loading =
false;
1310 assert(colour == NULL || (st != NULL && is_loading));
1316 for (
const Vehicle *v = front; v != NULL; v = v->
Next()) {
1319 if (v->
cargo_cap != 0 && colour != NULL) {
1321 loading |= !order_no_load &&
1328 if (colour != NULL) {
1329 if (unloading == 0 && loading) {
1330 *colour = STR_PERCENT_UP;
1331 }
else if (unloading == 0 && !loading) {
1332 *colour = STR_PERCENT_NONE;
1333 }
else if (cars == unloading || !loading) {
1334 *colour = STR_PERCENT_DOWN;
1336 *colour = STR_PERCENT_UP_DOWN;
1341 if (max == 0)
return 100;
1344 if (count * 2 < max) {
1346 return CeilDiv(count * 100, max);
1349 return (count * 100) /
max;
1360 assert(v == v->
First());
1396 default: NOT_REACHED();
1413 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1436 _vehicles_to_autoreplace[v] =
false;
1442 }
else if (cost.
GetCost() != 0) {
1458 _vehicles_to_autoreplace[v] =
false;
1480 UpdateVehicleTileHash(
this,
false);
1497 UpdateVehicleViewportHash(
this, pt.x, pt.y);
1500 this->
coord.left = pt.x;
1501 this->
coord.top = pt.y;
1502 this->
coord.right = pt.x + spr->
width + 2 * ZOOM_LVL_BASE;
1503 this->
coord.bottom = pt.y + spr->
height + 2 * ZOOM_LVL_BASE;
1510 min(old_coord.left, this->coord.left),
1511 min(old_coord.top, this->coord.top),
1512 max(old_coord.right, this->coord.right),
1513 max(old_coord.bottom, this->coord.bottom));
1542 static const int8 _delta_coord[16] = {
1543 -1,-1,-1, 0, 1, 1, 1, 0,
1544 -1, 0, 1, 1, 1, 0,-1,-1,
1558 static const Direction _new_direction_table[] = {
1568 if (y >= v->
y_pos) {
1569 if (y != v->
y_pos) i += 3;
1573 if (x >= v->
x_pos) {
1574 if (x != v->
x_pos) i++;
1611 if (v->
type == type && v->
owner == owner) {
1616 if (this->
maxid == 0)
return;
1621 this->
cache = CallocT<bool>(this->
maxid + 2);
1625 if (v->
type == type && v->
owner == owner) {
1634 if (this->maxid <= this->
curid)
return ++this->
curid;
1636 while (this->
cache[++this->curid]) { }
1655 default: NOT_REACHED();
1688 default: NOT_REACHED();
1695 FOR_ALL_ENGINES_OF_TYPE(e, type) {
1723 default: NOT_REACHED();
1728 engine_type = parent_engine_type;
1733 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1734 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1738 return LS_PASSENGER_WAGON_STEAM;
1740 switch (RailVehInfo(parent_engine_type)->engclass) {
1741 default: NOT_REACHED();
1742 case EC_STEAM:
return LS_PASSENGER_WAGON_STEAM;
1743 case EC_DIESEL:
return LS_PASSENGER_WAGON_DIESEL;
1744 case EC_ELECTRIC:
return LS_PASSENGER_WAGON_ELECTRIC;
1745 case EC_MONORAIL:
return LS_PASSENGER_WAGON_MONORAIL;
1746 case EC_MAGLEV:
return LS_PASSENGER_WAGON_MAGLEV;
1750 return LS_FREIGHT_WAGON;
1755 switch (e->u.rail.engclass) {
1756 default: NOT_REACHED();
1758 case EC_DIESEL:
return is_mu ? LS_DMU : LS_DIESEL;
1759 case EC_ELECTRIC:
return is_mu ? LS_EMU : LS_ELECTRIC;
1768 engine_type = parent_engine_type;
1772 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1773 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1785 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1786 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1790 switch (e->u.air.subtype) {
1791 case AIR_HELI:
return LS_HELICOPTER;
1792 case AIR_CTOL:
return LS_SMALL_PLANE;
1793 case AIR_CTOL | AIR_FAST:
return LS_LARGE_PLANE;
1794 default: NOT_REACHED();
1820 if (!c->livery[scheme].
in_use) scheme = LS_DEFAULT;
1823 return &c->livery[scheme];
1832 if (map != PAL_NONE)
return map;
1841 assert_compile(PAL_NONE == 0);
1842 map =
GB(callback, 0, 14);
1845 if (!
HasBit(callback, 14)) {
1847 if (v != NULL)
const_cast<Vehicle *
>(v)->colourmap = map;
1858 if (!
Company::IsValidID(company)) return map;
1862 map += livery->colour1;
1863 if (twocc) map += livery->colour2 * 16;
1866 if (v != NULL) const_cast<
Vehicle *>(v)->colourmap = map;
1878 return GetEngineColourMap(engine_type, company,
INVALID_ENGINE, NULL);
1912 while (order != NULL) {
1915 if (order->
IsType(OT_IMPLICIT)) {
1921 order = order->
next;
1926 if (order == NULL) {
1963 (in_list == NULL || !in_list->
IsType(OT_IMPLICIT) ||
1968 if (prev_order == NULL ||
1969 (!prev_order->
IsType(OT_IMPLICIT) && !prev_order->
IsType(OT_GOTO_STATION)) ||
1981 if (order == NULL)
break;
1987 if (target_index >= this->
orders.list->GetNumOrders()) {
1998 if (suppress_implicit_orders) {
2006 if (order->
IsType(OT_IMPLICIT)) {
2012 order = order->
next;
2017 if (order == NULL) {
2021 assert(order != NULL);
2024 }
else if (!suppress_implicit_orders &&
2072 DEBUG(misc, 1,
"cancelling cargo reservation");
2089 assert(this->cargo_payment == NULL);
2115 st->loading_vehicles.remove(
this);
2160 if (order == NULL ||
2161 (!order->
IsType(OT_IMPLICIT) && !order->
IsType(OT_GOTO_STATION)) ||
2168 case OT_DUMMY:
break;
2182 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2185 if (pair == capacities.
End()) {
2186 pair = capacities.
Append();
2195 uint Vehicle::GetConsistTotalCapacity()
const
2198 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2213 if (ret.
Failed())
return ret;
2250 DestinationID destination;
2252 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};
2310 callback =
GB(callback, 0, 8);
2317 visual_effect = callback;
2349 static const int8 _vehicle_smoke_pos[8] = {
2350 1, 1, 1, 0, -1, -1, -1, 0
2362 uint count =
GB(callback, 0, 2);
2363 bool auto_center =
HasBit(callback, 13);
2364 bool auto_rotate = !
HasBit(callback, 14);
2379 int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2380 int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2382 for (uint i = 0; i < count; i++) {
2384 uint type =
GB(reg, 0, 8);
2385 int8 x =
GB(reg, 8, 8);
2386 int8 y =
GB(reg, 16, 8);
2387 int8 z =
GB(reg, 24, 8);
2392 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2393 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2424 this->cur_speed < 2) {
2437 if (
HasBit(t->flags, VRF_REVERSING) ||
2453 if (effect_model >= VESM_END) effect_model =
VESM_NONE;
2480 switch (effect_model) {
2504 int power_weight_effect = 0;
2532 if (evt != EV_END && advanced) {
2535 }
else if (evt != EV_END) {
2543 int x = _vehicle_smoke_pos[v->
direction] * effect_offset;
2544 int y = _vehicle_smoke_pos[(v->
direction + 2) % 8] * effect_offset;
2553 }
while ((v = v->
Next()) != NULL);
2564 assert(
this != next);
2566 if (this->next != NULL) {
2568 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2576 if (this->next != NULL) {
2580 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2621 this->
orders.list->RemoveVehicle(
this);
2631 if (this->
orders.list->GetNumVehicles() == 1) {
2635 }
else if (were_first) {
2645 void VehiclesYearlyLoop()
2652 if (v->
age >= 730 && profit < 0) {
2799 for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2802 set.Include(u->
index);