56 #include "table/strings.h"
61 static const uint GEN_HASHX_BITS = 6;
62 static const uint GEN_HASHY_BITS = 6;
65 static const uint GEN_HASHX_BUCKET_BITS = 7;
66 static const uint GEN_HASHY_BUCKET_BITS = 6;
69 #define GEN_HASHX(x) GB((x), GEN_HASHX_BUCKET_BITS + ZOOM_LVL_SHIFT, GEN_HASHX_BITS)
70 #define GEN_HASHY(y) (GB((y), GEN_HASHY_BUCKET_BITS + ZOOM_LVL_SHIFT, GEN_HASHY_BITS) << GEN_HASHX_BITS)
71 #define GEN_HASH(x, y) (GEN_HASHY(y) + GEN_HASHX(x))
74 static const int GEN_HASHX_SIZE = 1 << (GEN_HASHX_BUCKET_BITS + GEN_HASHX_BITS + ZOOM_LVL_SHIFT);
75 static const int GEN_HASHY_SIZE = 1 << (GEN_HASHY_BUCKET_BITS + GEN_HASHY_BITS + ZOOM_LVL_SHIFT);
78 static const int GEN_HASHX_INC = 1;
79 static const int GEN_HASHY_INC = 1 << GEN_HASHX_BITS;
82 static const uint GEN_HASHX_MASK = (1 << GEN_HASHX_BITS) - 1;
83 static const uint GEN_HASHY_MASK = ((1 << GEN_HASHY_BITS) - 1) << GEN_HASHX_BITS;
101 bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
102 for (uint i = 0; i < this->count; ++i) {
105 bounds->left = spr->
x_offs;
106 bounds->top = spr->
y_offs;
110 if (spr->
x_offs < bounds->left) bounds->left = spr->
x_offs;
111 if (spr->
y_offs < bounds->top) bounds->top = spr->
y_offs;
114 if (right > bounds->right) bounds->right = right;
115 if (bottom > bounds->bottom) bounds->bottom = bottom;
129 for (uint i = 0; i < this->count; ++i) {
130 PaletteID pal = force_pal || !this->seq[i].
pal ? default_pal : this->seq[i].
pal;
192 if (this->ServiceIntervalIsPercent() ?
208 bool pending_replace =
false;
210 if (needed_money > c->
money)
return false;
213 bool replace_when_old =
false;
219 if (replace_when_old && !v->NeedsAutorenewing(c,
false))
continue;
222 uint32 available_cargo_types, union_mask;
225 if (union_mask != 0) {
233 if (!
HasBit(available_cargo_types, cargo_type))
continue;
239 pending_replace =
true;
240 needed_money += 2 *
Engine::Get(new_engine)->GetCost();
241 if (needed_money > c->
money)
return false;
244 return pending_replace;
269 for (
Vehicle *v =
this; v != NULL; v = v->
Next()) {
273 v->MarkAllViewportsDirty();
303 if (grfconfig == NULL)
return;
317 GetString(buffer, part1,
lastof(buffer));
318 DEBUG(grf, 0,
"%s", buffer + 3);
321 GetString(buffer, part2,
lastof(buffer));
322 DEBUG(grf, 0,
"%s", buffer + 3);
364 return GB(Random(), 0, 8);
369 const int HASH_BITS = 7;
370 const int HASH_SIZE = 1 << HASH_BITS;
371 const int HASH_MASK = HASH_SIZE - 1;
372 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
373 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
377 const int HASH_RES = 0;
379 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
381 static Vehicle *VehicleFromTileHash(
int xl,
int yl,
int xu,
int yu,
void *data, VehicleFromPosProc *proc,
bool find_first)
383 for (
int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
384 for (
int x = xl; ; x = (x + 1) & HASH_MASK) {
385 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
388 if (find_first && a != NULL)
return a;
412 const int COLL_DIST = 6;
415 int xl =
GB((x - COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS);
416 int xu =
GB((x + COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS);
417 int yl =
GB((y - COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
418 int yu =
GB((y + COLL_DIST) /
TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
420 return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
470 int x =
GB(
TileX(tile), HASH_RES, HASH_BITS);
471 int y =
GB(
TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
473 Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
475 if (v->
tile != tile)
continue;
478 if (find_first && a != NULL)
return a;
528 if (v->
z_pos > z)
return NULL;
555 if (v == (
const Vehicle *)data)
return NULL;
587 if ((t->track != rail_bits) && !
TracksOverlap(t->track | rail_bits))
return NULL;
611 static void UpdateVehicleTileHash(
Vehicle *v,
bool remove)
620 int y =
GB(
TileY(v->
tile), HASH_RES, HASH_BITS) << HASH_BITS;
621 new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
624 if (old_hash == new_hash)
return;
627 if (old_hash != NULL) {
633 if (new_hash != NULL) {
644 static Vehicle *_vehicle_viewport_hash[1 << (GEN_HASHX_BITS + GEN_HASHY_BITS)];
646 static void UpdateVehicleViewportHash(
Vehicle *v,
int x,
int y)
648 Vehicle **old_hash, **new_hash;
649 int old_x = v->
coord.left;
650 int old_y = v->
coord.top;
652 new_hash = (x ==
INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
653 old_hash = (old_x ==
INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
655 if (old_hash == new_hash)
return;
658 if (old_hash != NULL) {
664 if (new_hash != NULL) {
672 void ResetVehicleHash()
676 memset(_vehicle_viewport_hash, 0,
sizeof(_vehicle_viewport_hash));
677 memset(_vehicle_tile_hash, 0,
sizeof(_vehicle_tile_hash));
680 void ResetVehicleColourMap()
691 static AutoreplaceMap _vehicles_to_autoreplace;
693 void InitializeVehicles()
695 _vehicles_to_autoreplace.
Reset();
699 uint CountVehiclesInChain(
const Vehicle *v)
702 do count++;
while ((v = v->
Next()) != NULL);
712 switch (this->
type) {
719 default:
return false;
729 switch (this->
type) {
734 default:
return false;
808 st->loading_vehicles.remove(
this);
862 extern void StopGlobalFollowVehicle(
const Vehicle *v);
863 StopGlobalFollowVehicle(
this);
884 UpdateVehicleTileHash(
this,
true);
914 if (_game_mode != GM_NORMAL)
return;
919 if (v == NULL)
continue;
925 if (
HasBit(callback, 0)) {
926 TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32);
942 void CallVehicleTicks()
944 _vehicles_to_autoreplace.
Clear();
970 if (v->vcache.cached_cargo_age_period != 0) {
972 if (--v->cargo_age_counter == 0) {
974 v->cargo_age_counter = v->vcache.cached_cargo_age_period;
1010 if (
GB(v->tick_counter, 0, 4) == 0) {
1025 cur_company.Change(v->owner);
1050 if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message ==
INVALID_STRING_ID)
continue;
1052 if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
1055 if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
1056 message = error_message;
1058 message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
1066 cur_company.Restore();
1090 for (uint i = 0; i < v->
sprite_seq.count; ++i) {
1106 const int l = dpi->left;
1107 const int r = dpi->left + dpi->width;
1108 const int t = dpi->top;
1109 const int b = dpi->top + dpi->height;
1120 xu = GEN_HASHX_MASK;
1129 yu = GEN_HASHY_MASK;
1132 for (
int y = yl;; y = (y + GEN_HASHY_INC) & GEN_HASHY_MASK) {
1133 for (
int x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) {
1134 const Vehicle *v = _vehicle_viewport_hash[x + y];
1138 l <= v->
coord.right &&
1139 t <= v->
coord.bottom &&
1140 r >= v->
coord.left &&
1141 b >= v->
coord.top) {
1164 uint dist, best_dist = UINT_MAX;
1166 if ((uint)(x -= vp->
left) >= (uint)vp->
width || (uint)(y -= vp->
top) >= (uint)vp->
height)
return NULL;
1173 x >= v->coord.left && x <= v->coord.right &&
1174 y >= v->coord.top && y <= v->coord.bottom) {
1177 abs(((v->coord.left + v->coord.right) >> 1) - x),
1178 abs(((v->coord.top + v->coord.bottom) >> 1) - y)
1181 if (dist < best_dist) {
1201 static const byte _breakdown_chance[64] = {
1202 3, 3, 3, 3, 3, 3, 3, 3,
1203 4, 4, 5, 5, 6, 6, 7, 7,
1204 8, 8, 9, 9, 10, 10, 11, 11,
1205 12, 13, 13, 13, 13, 14, 15, 16,
1206 17, 19, 21, 25, 28, 31, 34, 37,
1207 40, 44, 48, 52, 56, 60, 64, 68,
1208 72, 80, 90, 100, 110, 120, 130, 140,
1209 150, 170, 190, 210, 230, 250, 250, 250,
1212 void CheckVehicleBreakdown(
Vehicle *v)
1222 v->
cur_speed < 5 || _game_mode == GM_MENU) {
1226 uint32 r = Random();
1281 (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
1282 (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN),
this);
1345 str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
1346 }
else if (age == 0) {
1347 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
1349 str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
1373 bool loading =
false;
1379 assert(colour == NULL || (st != NULL && is_loading));
1385 for (
const Vehicle *v = front; v != NULL; v = v->
Next()) {
1388 if (v->
cargo_cap != 0 && colour != NULL) {
1390 loading |= !order_no_load &&
1397 if (colour != NULL) {
1398 if (unloading == 0 && loading) {
1399 *colour = STR_PERCENT_UP;
1400 }
else if (unloading == 0 && !loading) {
1401 *colour = STR_PERCENT_NONE;
1402 }
else if (cars == unloading || !loading) {
1403 *colour = STR_PERCENT_DOWN;
1405 *colour = STR_PERCENT_UP_DOWN;
1410 if (max == 0)
return 100;
1413 if (count * 2 < max) {
1415 return CeilDiv(count * 100, max);
1418 return (count * 100) /
max;
1429 assert(v == v->
First());
1465 default: NOT_REACHED();
1482 TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1505 _vehicles_to_autoreplace[v] =
false;
1511 }
else if (cost.
GetCost() != 0) {
1527 _vehicles_to_autoreplace[v] =
false;
1549 UpdateVehicleTileHash(
this,
false);
1563 new_coord.left += pt.x;
1564 new_coord.top += pt.y;
1565 new_coord.right += pt.x + 2 * ZOOM_LVL_BASE;
1566 new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE;
1568 UpdateVehicleViewportHash(
this, new_coord.left, new_coord.top);
1571 this->
coord = new_coord;
1578 min(old_coord.left, this->coord.left),
1579 min(old_coord.top, this->coord.top),
1580 max(old_coord.right, this->coord.right),
1581 max(old_coord.bottom, this->coord.bottom));
1610 static const int8 _delta_coord[16] = {
1611 -1,-1,-1, 0, 1, 1, 1, 0,
1612 -1, 0, 1, 1, 1, 0,-1,-1,
1626 static const Direction _new_direction_table[] = {
1636 if (y >= v->
y_pos) {
1637 if (y != v->
y_pos) i += 3;
1641 if (x >= v->
x_pos) {
1642 if (x != v->
x_pos) i++;
1679 if (v->
type == type && v->
owner == owner) {
1684 if (this->
maxid == 0)
return;
1689 this->
cache = CallocT<bool>(this->
maxid + 2);
1693 if (v->
type == type && v->
owner == owner) {
1702 if (this->maxid <= this->
curid)
return ++this->
curid;
1704 while (this->
cache[++this->curid]) { }
1723 default: NOT_REACHED();
1756 default: NOT_REACHED();
1763 FOR_ALL_ENGINES_OF_TYPE(e, type) {
1791 default: NOT_REACHED();
1796 engine_type = parent_engine_type;
1801 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1802 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1806 return LS_PASSENGER_WAGON_STEAM;
1808 switch (RailVehInfo(parent_engine_type)->engclass) {
1809 default: NOT_REACHED();
1810 case EC_STEAM:
return LS_PASSENGER_WAGON_STEAM;
1811 case EC_DIESEL:
return LS_PASSENGER_WAGON_DIESEL;
1812 case EC_ELECTRIC:
return LS_PASSENGER_WAGON_ELECTRIC;
1813 case EC_MONORAIL:
return LS_PASSENGER_WAGON_MONORAIL;
1814 case EC_MAGLEV:
return LS_PASSENGER_WAGON_MAGLEV;
1818 return LS_FREIGHT_WAGON;
1823 switch (e->u.rail.engclass) {
1824 default: NOT_REACHED();
1826 case EC_DIESEL:
return is_mu ? LS_DMU : LS_DIESEL;
1827 case EC_ELECTRIC:
return is_mu ? LS_EMU : LS_ELECTRIC;
1836 engine_type = parent_engine_type;
1840 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1841 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1853 if (cargo_type ==
CT_INVALID) cargo_type = e->GetDefaultCargoType();
1854 if (cargo_type ==
CT_INVALID) cargo_type = CT_GOODS;
1858 switch (e->u.air.subtype) {
1859 case AIR_HELI:
return LS_HELICOPTER;
1860 case AIR_CTOL:
return LS_SMALL_PLANE;
1861 case AIR_CTOL | AIR_FAST:
return LS_LARGE_PLANE;
1862 default: NOT_REACHED();
1888 if (!c->livery[scheme].
in_use) scheme = LS_DEFAULT;
1891 return &c->livery[scheme];
1900 if (map != PAL_NONE)
return map;
1909 assert_compile(PAL_NONE == 0);
1910 map =
GB(callback, 0, 14);
1913 if (!
HasBit(callback, 14)) {
1915 if (v != NULL)
const_cast<Vehicle *
>(v)->colourmap = map;
1926 if (!
Company::IsValidID(company)) return map;
1930 map += livery->colour1;
1931 if (twocc) map += livery->colour2 * 16;
1934 if (v != NULL) const_cast<
Vehicle *>(v)->colourmap = map;
1946 return GetEngineColourMap(engine_type, company,
INVALID_ENGINE, NULL);
1980 while (order != NULL) {
1983 if (order->
IsType(OT_IMPLICIT)) {
1989 order = order->
next;
1994 if (order == NULL) {
2031 (in_list == NULL || !in_list->
IsType(OT_IMPLICIT) ||
2036 if (prev_order == NULL ||
2037 (!prev_order->
IsType(OT_IMPLICIT) && !prev_order->
IsType(OT_GOTO_STATION)) ||
2049 if (order == NULL)
break;
2055 if (target_index >= this->
orders.list->GetNumOrders()) {
2066 if (suppress_implicit_orders) {
2074 if (order->
IsType(OT_IMPLICIT)) {
2080 order = order->
next;
2085 if (order == NULL) {
2089 assert(order != NULL);
2092 }
else if (!suppress_implicit_orders &&
2140 DEBUG(misc, 1,
"cancelling cargo reservation");
2157 assert(this->cargo_payment == NULL);
2183 st->loading_vehicles.remove(
this);
2229 if (order == NULL ||
2230 (!order->
IsType(OT_IMPLICIT) && !order->
IsType(OT_GOTO_STATION)) ||
2237 case OT_DUMMY:
break;
2251 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2254 if (pair == capacities.
End()) {
2255 pair = capacities.
Append();
2264 uint Vehicle::GetConsistTotalCapacity()
const
2267 for (
const Vehicle *v =
this; v != NULL; v = v->
Next()) {
2282 if (ret.
Failed())
return ret;
2319 DestinationID destination;
2321 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};
2379 callback =
GB(callback, 0, 8);
2386 visual_effect = callback;
2418 static const int8 _vehicle_smoke_pos[8] = {
2419 1, 1, 1, 0, -1, -1, -1, 0
2431 uint count =
GB(callback, 0, 2);
2432 bool auto_center =
HasBit(callback, 13);
2433 bool auto_rotate = !
HasBit(callback, 14);
2448 int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2449 int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2451 for (uint i = 0; i < count; i++) {
2453 uint type =
GB(reg, 0, 8);
2454 int8 x =
GB(reg, 8, 8);
2455 int8 y =
GB(reg, 16, 8);
2456 int8 z =
GB(reg, 24, 8);
2461 x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2462 y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2493 this->cur_speed < 2) {
2506 if (
HasBit(t->flags, VRF_REVERSING) ||
2522 if (effect_model >= VESM_END) effect_model =
VESM_NONE;
2549 switch (effect_model) {
2573 int power_weight_effect = 0;
2601 if (evt != EV_END && advanced) {
2604 }
else if (evt != EV_END) {
2612 int x = _vehicle_smoke_pos[v->
direction] * effect_offset;
2613 int y = _vehicle_smoke_pos[(v->
direction + 2) % 8] * effect_offset;
2622 }
while ((v = v->
Next()) != NULL);
2633 assert(
this != next);
2635 if (this->next != NULL) {
2637 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2645 if (this->next != NULL) {
2649 for (
Vehicle *v = this->next; v != NULL; v = v->
Next()) {
2690 this->
orders.list->RemoveVehicle(
this);
2700 if (this->
orders.list->GetNumVehicles() == 1) {
2704 }
else if (were_first) {
2714 void VehiclesYearlyLoop()
2721 if (v->
age >= 730 && profit < 0) {
2868 for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2871 set.Include(u->
index);