39 #include "table/strings.h"
43 static const uint16 _roadveh_images[] = {
44 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
45 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
46 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
47 0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
48 0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
49 0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
50 0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
51 0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
54 static const uint16 _roadveh_full_adder[] = {
55 0, 88, 0, 0, 0, 0, 48, 48,
56 48, 48, 0, 0, 64, 64, 0, 16,
57 16, 0, 88, 0, 0, 0, 0, 48,
58 48, 48, 48, 0, 0, 64, 64, 0,
59 16, 16, 0, 88, 0, 0, 0, 0,
60 48, 48, 48, 48, 0, 0, 64, 64,
61 0, 16, 16, 0, 8, 8, 8, 8,
67 bool IsValidImageIndex<VEH_ROAD>(uint8 image_index)
69 return image_index <
lengthof(_roadveh_images);
107 int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
109 if (offset != NULL) {
121 if (is_custom_sprite(spritenum)) {
122 SpriteID sprite = GetCustomVehicleIcon(engine,
DIR_W, image_type);
123 if (sprite != 0)
return sprite;
128 assert(IsValidImageIndex<VEH_ROAD>(spritenum));
137 if (is_custom_sprite(spritenum)) {
138 sprite = GetCustomVehicleSprite(
this, (
Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type);
139 if (sprite != 0)
return sprite;
144 assert(IsValidImageIndex<VEH_ROAD>(spritenum));
145 sprite = direction + _roadveh_images[
spritenum];
163 SpriteID sprite = GetRoadVehIcon(engine, image_type);
165 preferred_x =
Clamp(preferred_x,
182 const Sprite *spr = GetSprite(GetRoadVehIcon(engine, image_type),
ST_NORMAL);
201 if (e->
GetGRF() != NULL && e->
GetGRF()->grf_version >= 8) {
234 assert(u->First() == v);
244 u->gcache.cached_veh_length = veh_len;
248 u->UpdateVisualEffect();
284 v->
z_pos = GetSlopePixelZ(x, y);
302 _new_vehicle_id = v->
index;
325 u->cargo_cap = u->GetEngine()->DetermineCapacity(u);
328 u->InvalidateNewGRFCache();
350 default: NOT_REACHED();
359 if (location != NULL) *location = rfdd.
tile;
382 if (ret.
Failed())
return ret;
398 if (flags &
DC_EXEC) v->reverse_ctr = 180;
415 static const int8 _delta_xy_table[8][10] = {
417 {3, 3, -1, -1, 0, 0, -1, -1, -1, -1},
418 {3, 7, -1, -3, 0, -1, 0, -1, 0, 0},
419 {3, 3, -1, -1, 0, 0, 1, -1, 1, -1},
420 {7, 3, -3, -1, -1, 0, 0, 0, 1, 0},
421 {3, 3, -1, -1, 0, 0, 1, 1, 1, 1},
422 {3, 7, -1, -3, 0, -1, 0, 0, 0, 1},
423 {3, 3, -1, -1, 0, 0, -1, 1, -1, 1},
424 {7, 3, -3, -1, -1, 0, -1, 0, 0, 0},
430 const int8 *bb = _delta_xy_table[
direction];
431 this->
x_bb_offs = bb[5] + bb[9] * shorten;
432 this->
y_bb_offs = bb[4] + bb[8] * shorten;;
435 this->
x_extent = bb[1] + bb[7] * shorten;
436 this->
y_extent = bb[0] + bb[6] * shorten;
454 }
else if ((u->direction & 1) == 0) {
476 for (; v->
Next() != NULL; v = v->
Next()) u = v;
486 static void RoadVehSetRandomDirection(
RoadVehicle *v)
488 static const DirDiff delta[] = {
497 }
while ((v = v->
Next()) != NULL);
511 if ((v->
tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
513 bool ret = v->
Next() != NULL;
554 uint pass = v->
Crash();
557 Game::NewEvent(
new ScriptEventVehicleCrashed(v->
index, v->
tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
562 STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
567 ModifyStationRatingAround(v->
tile, v->
owner, -160, 22);
603 static void StartRoadVehSound(
const RoadVehicle *v)
607 if (s == SND_19_BUS_START_PULL_AWAY && (v->
tick_counter & 3) == 0) {
608 s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
610 SndPlayVehicleFx(s, v);
625 static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
626 static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
630 short x_diff = v->
x_pos - rvf->x;
631 short y_diff = v->
y_pos - rvf->y;
642 uint diff =
abs(x_diff) +
abs(y_diff);
644 if (diff < rvf->best_diff || (diff == rvf->best_diff && v->
index < rvf->best->
index)) {
646 rvf->best_diff = diff;
658 if (front->reverse_ctr != 0)
return NULL;
664 rvf.best_diff = UINT_MAX;
677 if (rvf.best_diff == UINT_MAX) {
678 front->blocked_ctr = 0;
682 if (update_blocked_ctr && ++front->blocked_ctr > 1480)
return NULL;
696 if (!(st->had_vehicle_of_type &
HVOT_BUS)) {
697 st->had_vehicle_of_type |=
HVOT_BUS;
700 v->roadtype ==
ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
710 if (!(st->had_vehicle_of_type &
HVOT_TRUCK)) {
714 v->roadtype ==
ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
735 default: NOT_REACHED();
746 static const Direction _roadveh_new_dir[] = {
752 x = x - v->
x_pos + 1;
753 y = y - v->
y_pos + 1;
755 if ((uint)x > 2 || (uint)y > 2)
return v->
direction;
756 return _roadveh_new_dir[y * 4 + x];
761 Direction new_dir = RoadVehGetNewDirection(v, x, y);
765 if (new_dir == old_dir)
return old_dir;
777 static Vehicle *EnumFindVehBlockingOvertake(
Vehicle *v,
void *data)
781 return (v->
type ==
VEH_ROAD && v->
First() == v && v != od->u && v != od->v) ? v : NULL;
856 static void RoadZPosAffectSpeed(
RoadVehicle *v,
int old_z)
860 if (old_z < v->z_pos) {
864 if (spd <= v->vcache.cached_max_speed) v->
cur_speed = spd;
868 static int PickRandomBit(uint bits)
873 for (i = 0; !(bits & 1) || (
int)--num >= 0; bits >>= 1, i++) {}
887 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
891 bool path_found =
true;
931 trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
934 return_track(_road_reverse_table[enterdir]);
937 if (v->reverse_ctr != 0) {
944 reverse = ((rb & straight) == straight) ||
949 if (v->
tile != tile) {
950 return_track(_road_reverse_table[enterdir]);
958 return_track(PickRandomBit(trackdirs));
970 default: NOT_REACHED();
987 static bool RoadVehLeaveDepot(
RoadVehicle *v,
bool first)
997 Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
1010 if (RoadVehFindCloseTo(v, x, y, v->
direction,
false) != NULL)
return true;
1014 StartRoadVehSound(v);
1022 v->frame = RVC_DEPOT_START_FRAME;
1036 if (prev->
tile == v->
tile && !already_reversed) {
1039 return _road_reverse_table[entry_dir];
1042 byte prev_state = prev->
state;
1057 if (already_reversed && prev->
tile != tile) {
1087 static const RoadBits required_roadbits[] = {
1091 RoadBits required = required_roadbits[dir & 0x07];
1182 dir = FollowPreviousRoadVehicle(v, prev, tile, (
DiagDirection)(rd.x & 3),
false);
1192 uint start_frame = RVC_DEFAULT_START_FRAME;
1203 default: NOT_REACHED();
1235 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
1255 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1257 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1271 dir = _road_reverse_table[rd.x & 3];
1303 v->
state = (byte)dir;
1304 v->frame = start_frame;
1320 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
1332 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
1333 switch (rd.x & 0x3) {
1334 default: NOT_REACHED();
1345 dir = FollowPreviousRoadVehicle(v, prev, v->
tile, (
DiagDirection)(rd.x & 3),
true);
1359 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1360 if (v->
IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL)
return false;
1369 v->frame = turn_around_start_frame;
1388 RoadVehLeaveDepot(v->
Next(),
false);
1393 int x = (v->
x_pos & ~15) + (rd.x & 15);
1394 int y = (v->
y_pos & ~15) + (rd.y & 15);
1396 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1401 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1406 if (v->
overtaking == 0) RoadVehCheckOvertake(v, u);
1424 if (new_dir != old_dir) {
1447 v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
1494 StartRoadVehSound(v);
1524 if (v->reverse_ctr != 0) v->reverse_ctr--;
1540 if (v->
IsInDepot() && RoadVehLeaveDepot(v,
true))
return true;
1548 bool blocked =
false;
1549 while (j >= adv_spd) {
1554 if (!IndividualRoadVehicleController(u, prev)) {
1565 if (j >= adv_spd && RoadVehCheckTrainCrash(v))
break;
1571 if ((u->vehstatus &
VS_HIDDEN) != 0)
continue;
1573 u->UpdateViewport(
false,
false);
1587 if (e->u.road.running_cost_class == INVALID_PRICE)
return 0;
1590 if (cost_factor == 0)
return 0;
1592 return GetPrice(e->u.road.running_cost_class, cost_factor, e->
GetGRF());
1601 return RoadVehController(
this);
1607 static void CheckIfRoadVehNeedsService(
RoadVehicle *v)
1620 default: NOT_REACHED();
1657 if (this->blocked_ctr == 0) CheckVehicleBreakdown(
this);
1659 CheckIfRoadVehNeedsService(
this);