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) + 1 * ZOOM_LVL_BASE,
1503 max(old_coord.bottom, this->coord.bottom) + 1 * ZOOM_LVL_BASE
1523 ::MarkAllViewportsDirty(this->
coord.left, this->coord.top, this->coord.right + 1 * ZOOM_LVL_BASE, this->coord.bottom + 1 * ZOOM_LVL_BASE);
1533 static const int8 _delta_coord[16] = {
1534 -1,-1,-1, 0, 1, 1, 1, 0,
1535 -1, 0, 1, 1, 1, 0,-1,-1,
1549 static const Direction _new_direction_table[] = {
1559 if (y >= v->
y_pos) {
1560 if (y != v->
y_pos) i += 3;
1564 if (x >= v->
x_pos) {
1565 if (x != v->
x_pos) i++;
1602 if (v->
type == type && v->
owner == owner) {
1607 if (this->
maxid == 0)
return;
1612 this->
cache = CallocT<bool>(this->
maxid + 2);
1616 if (v->
type == type && v->
owner == owner) {
1625 if (this->maxid <= this->
curid)
return ++this->
curid;
1627 while (this->
cache[++this->curid]) { }
1646 default: NOT_REACHED();
1679 default: NOT_REACHED();
1686 FOR_ALL_ENGINES_OF_TYPE(e, type) {
1714 default: NOT_REACHED();
1719 engine_type = parent_engine_type;
1724 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1725 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1729 return LS_PASSENGER_WAGON_STEAM;
1731 switch (RailVehInfo(parent_engine_type)->engclass) {
1732 default: NOT_REACHED();
1733 case EC_STEAM:
return LS_PASSENGER_WAGON_STEAM;
1734 case EC_DIESEL:
return LS_PASSENGER_WAGON_DIESEL;
1735 case EC_ELECTRIC:
return LS_PASSENGER_WAGON_ELECTRIC;
1736 case EC_MONORAIL:
return LS_PASSENGER_WAGON_MONORAIL;
1737 case EC_MAGLEV:
return LS_PASSENGER_WAGON_MAGLEV;
1741 return LS_FREIGHT_WAGON;
1746 switch (e->u.rail.engclass) {
1747 default: NOT_REACHED();
1749 case EC_DIESEL:
return is_mu ? LS_DMU : LS_DIESEL;
1750 case EC_ELECTRIC:
return is_mu ? LS_EMU : LS_ELECTRIC;
1759 engine_type = parent_engine_type;
1763 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1764 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1776 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1777 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1781 switch (e->u.air.subtype) {
1782 case AIR_HELI:
return LS_HELICOPTER;
1783 case AIR_CTOL:
return LS_SMALL_PLANE;
1784 case AIR_CTOL | AIR_FAST:
return LS_LARGE_PLANE;
1785 default: NOT_REACHED();
1811 if (!c->livery[scheme].
in_use) scheme = LS_DEFAULT;
1814 return &c->livery[scheme];
1823 if (map != PAL_NONE)
return map;
1832 assert_compile(PAL_NONE == 0);
1833 map =
GB(callback, 0, 14);
1836 if (!
HasBit(callback, 14)) {
1838 if (v != NULL)
const_cast<Vehicle *
>(v)->colourmap = map;
1849 if (!
Company::IsValidID(company)) return map;
1853 map += livery->colour1;
1854 if (twocc) map += livery->colour2 * 16;
1857 if (v != NULL) const_cast<
Vehicle *>(v)->colourmap = map;
1869 return GetEngineColourMap(engine_type, company,
INVALID_ENGINE, NULL);
1903 while (order != NULL) {
1906 if (order->
IsType(OT_IMPLICIT)) {
1912 order = order->
next;
1917 if (order == NULL) {
1954 (in_list == NULL || !in_list->
IsType(OT_IMPLICIT) ||
1959 if (prev_order == NULL ||
1960 (!prev_order->
IsType(OT_IMPLICIT) && !prev_order->
IsType(OT_GOTO_STATION)) ||
1972 if (order == NULL)
break;
1978 if (target_index >= this->
orders.list->GetNumOrders()) {
1989 if (suppress_implicit_orders) {
1997 if (order->
IsType(OT_IMPLICIT)) {
2003 order = order->
next;
2008 if (order == NULL) {
2012 assert(order != NULL);
2015 }
else if (!suppress_implicit_orders &&
2063 DEBUG(misc, 1,
"cancelling cargo reservation");
2105 st->loading_vehicles.remove(
this);
2150 if (order == NULL ||
2151 (!order->
IsType(OT_IMPLICIT) && !order->
IsType(OT_GOTO_STATION)) ||
2158 case OT_DUMMY:
break;
2172 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2175 if (pair == capacities.
End()) {
2176 pair = capacities.
Append();
2185 uint Vehicle::GetConsistTotalCapacity()
const
2188 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2203 if (ret.
Failed())
return ret;
2240 DestinationID destination;
2242 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};
2300 callback =
GB(callback, 0, 8);
2307 visual_effect = callback;
2339 static const int8 _vehicle_smoke_pos[8] = {
2340 1, 1, 1, 0, -1, -1, -1, 0
2352 uint count =
GB(callback, 0, 2);
2353 bool auto_center =
HasBit(callback, 13);
2354 bool auto_rotate = !
HasBit(callback, 14);
2369 int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2370 int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2372 for (uint i = 0; i < count; i++) {
2374 uint type =
GB(reg, 0, 8);
2375 int8 x =
GB(reg, 8, 8);
2376 int8 y =
GB(reg, 16, 8);
2377 int8 z =
GB(reg, 24, 8);
2382 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2383 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2414 this->cur_speed < 2) {
2425 if (
HasBit(t->flags, VRF_REVERSING) ||
2427 t->
cur_speed >= t->Train::GetCurrentMaxSpeed())) {
2445 if (effect_model >= VESM_END) effect_model =
VESM_NONE;
2472 switch (effect_model) {
2496 int power_weight_effect = 0;
2514 if (
GB(v->tick_counter, 0, 2) == 0 &&
2524 if (evt != EV_END && advanced) {
2527 }
else if (evt != EV_END) {
2535 int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2536 int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2545 }
while ((v = v->Next()) != NULL);
2556 assert(
this != next);
2558 if (this->next != NULL) {
2560 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2568 if (this->next != NULL) {
2572 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2613 this->
orders.list->RemoveVehicle(
this);
2623 if (this->
orders.list->GetNumVehicles() == 1) {
2627 }
else if (were_first) {
2637 void VehiclesYearlyLoop()
2644 if (v->
age >= 730 && profit < 0) {
2791 for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2794 set.Include(u->
index);