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 GetCustomVehicleIcon(engine,
DIR_W, image_type, result);
128 assert(IsValidImageIndex<VEH_ROAD>(spritenum));
129 result->
Set(
DIR_W + _roadveh_images[spritenum]);
136 if (is_custom_sprite(spritenum)) {
137 GetCustomVehicleSprite(
this, (
Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
143 assert(IsValidImageIndex<VEH_ROAD>(spritenum));
163 GetRoadVehIcon(engine, image_type, &seq);
167 preferred_x =
Clamp(preferred_x,
186 GetRoadVehIcon(engine, image_type, &seq);
191 width =
UnScaleGUI(rect.right - rect.left + 1);
192 height =
UnScaleGUI(rect.bottom - rect.top + 1);
208 if (e->
GetGRF() != NULL && e->
GetGRF()->grf_version >= 8) {
241 assert(u->First() == v);
251 u->gcache.cached_veh_length = veh_len;
255 u->UpdateVisualEffect();
291 v->
z_pos = GetSlopePixelZ(x, y);
309 _new_vehicle_id = v->
index;
332 u->cargo_cap = u->GetEngine()->DetermineCapacity(u);
335 u->InvalidateNewGRFCache();
357 default: NOT_REACHED();
366 if (location != NULL) *location = rfdd.
tile;
389 if (ret.
Failed())
return ret;
405 if (flags &
DC_EXEC) v->reverse_ctr = 180;
422 static const int8 _delta_xy_table[8][10] = {
424 {3, 3, -1, -1, 0, 0, -1, -1, -1, -1},
425 {3, 7, -1, -3, 0, -1, 0, -1, 0, 0},
426 {3, 3, -1, -1, 0, 0, 1, -1, 1, -1},
427 {7, 3, -3, -1, -1, 0, 0, 0, 1, 0},
428 {3, 3, -1, -1, 0, 0, 1, 1, 1, 1},
429 {3, 7, -1, -3, 0, -1, 0, 0, 0, 1},
430 {3, 3, -1, -1, 0, 0, -1, 1, -1, 1},
431 {7, 3, -3, -1, -1, 0, -1, 0, 0, 0},
437 const int8 *bb = _delta_xy_table[
direction];
438 this->
x_bb_offs = bb[5] + bb[9] * shorten;
439 this->
y_bb_offs = bb[4] + bb[8] * shorten;;
442 this->
x_extent = bb[1] + bb[7] * shorten;
443 this->
y_extent = bb[0] + bb[6] * shorten;
461 }
else if ((u->direction & 1) == 0) {
483 for (; v->
Next() != NULL; v = v->
Next()) u = v;
493 static void RoadVehSetRandomDirection(
RoadVehicle *v)
495 static const DirDiff delta[] = {
504 }
while ((v = v->
Next()) != NULL);
518 if ((v->
tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
520 bool ret = v->
Next() != NULL;
561 uint pass = v->
Crash();
564 Game::NewEvent(
new ScriptEventVehicleCrashed(v->
index, v->
tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
569 STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
574 ModifyStationRatingAround(v->
tile, v->
owner, -160, 22);
610 static void StartRoadVehSound(
const RoadVehicle *v)
614 if (s == SND_19_BUS_START_PULL_AWAY && (v->
tick_counter & 3) == 0) {
615 s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
617 SndPlayVehicleFx(s, v);
632 static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
633 static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
637 short x_diff = v->
x_pos - rvf->x;
638 short y_diff = v->
y_pos - rvf->y;
649 uint diff =
abs(x_diff) +
abs(y_diff);
651 if (diff < rvf->best_diff || (diff == rvf->best_diff && v->
index < rvf->best->
index)) {
653 rvf->best_diff = diff;
665 if (front->reverse_ctr != 0)
return NULL;
671 rvf.best_diff = UINT_MAX;
684 if (rvf.best_diff == UINT_MAX) {
685 front->blocked_ctr = 0;
689 if (update_blocked_ctr && ++front->blocked_ctr > 1480)
return NULL;
703 if (!(st->had_vehicle_of_type &
HVOT_BUS)) {
704 st->had_vehicle_of_type |=
HVOT_BUS;
707 v->roadtype ==
ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
717 if (!(st->had_vehicle_of_type &
HVOT_TRUCK)) {
721 v->roadtype ==
ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
742 default: NOT_REACHED();
753 static const Direction _roadveh_new_dir[] = {
759 x = x - v->
x_pos + 1;
760 y = y - v->
y_pos + 1;
762 if ((uint)x > 2 || (uint)y > 2)
return v->
direction;
763 return _roadveh_new_dir[y * 4 + x];
768 Direction new_dir = RoadVehGetNewDirection(v, x, y);
772 if (new_dir == old_dir)
return old_dir;
784 static Vehicle *EnumFindVehBlockingOvertake(
Vehicle *v,
void *data)
788 return (v->
type ==
VEH_ROAD && v->
First() == v && v != od->u && v != od->v) ? v : NULL;
863 static void RoadZPosAffectSpeed(
RoadVehicle *v,
int old_z)
867 if (old_z < v->z_pos) {
871 if (spd <= v->vcache.cached_max_speed) v->
cur_speed = spd;
875 static int PickRandomBit(uint bits)
880 for (i = 0; !(bits & 1) || (
int)--num >= 0; bits >>= 1, i++) {}
894 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
898 bool path_found =
true;
938 trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
941 return_track(_road_reverse_table[enterdir]);
944 if (v->reverse_ctr != 0) {
951 reverse = ((rb & straight) == straight) ||
956 if (v->
tile != tile) {
957 return_track(_road_reverse_table[enterdir]);
965 return_track(PickRandomBit(trackdirs));
977 default: NOT_REACHED();
994 static bool RoadVehLeaveDepot(
RoadVehicle *v,
bool first)
1004 Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
1017 if (RoadVehFindCloseTo(v, x, y, v->
direction,
false) != NULL)
return true;
1021 StartRoadVehSound(v);
1029 v->frame = RVC_DEPOT_START_FRAME;
1043 if (prev->
tile == v->
tile && !already_reversed) {
1046 return _road_reverse_table[entry_dir];
1049 byte prev_state = prev->
state;
1064 if (already_reversed && prev->
tile != tile) {
1094 static const RoadBits required_roadbits[] = {
1098 RoadBits required = required_roadbits[dir & 0x07];
1189 dir = FollowPreviousRoadVehicle(v, prev, tile, (
DiagDirection)(rd.x & 3),
false);
1199 uint start_frame = RVC_DEFAULT_START_FRAME;
1210 default: NOT_REACHED();
1242 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
1262 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1264 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1278 dir = _road_reverse_table[rd.x & 3];
1310 v->
state = (byte)dir;
1311 v->frame = start_frame;
1327 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
1339 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
1340 switch (rd.x & 0x3) {
1341 default: NOT_REACHED();
1352 dir = FollowPreviousRoadVehicle(v, prev, v->
tile, (
DiagDirection)(rd.x & 3),
true);
1366 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1367 if (v->
IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL)
return false;
1376 v->frame = turn_around_start_frame;
1395 RoadVehLeaveDepot(v->
Next(),
false);
1400 int x = (v->
x_pos & ~15) + (rd.x & 15);
1401 int y = (v->
y_pos & ~15) + (rd.y & 15);
1403 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1408 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1413 if (v->
overtaking == 0) RoadVehCheckOvertake(v, u);
1431 if (new_dir != old_dir) {
1454 v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
1501 StartRoadVehSound(v);
1531 if (v->reverse_ctr != 0) v->reverse_ctr--;
1547 if (v->
IsInDepot() && RoadVehLeaveDepot(v,
true))
return true;
1555 bool blocked =
false;
1556 while (j >= adv_spd) {
1561 if (!IndividualRoadVehicleController(u, prev)) {
1572 if (j >= adv_spd && RoadVehCheckTrainCrash(v))
break;
1578 if ((u->vehstatus &
VS_HIDDEN) != 0)
continue;
1580 u->UpdateViewport(
false,
false);
1594 if (e->u.road.running_cost_class == INVALID_PRICE)
return 0;
1597 if (cost_factor == 0)
return 0;
1599 return GetPrice(e->u.road.running_cost_class, cost_factor, e->
GetGRF());
1608 return RoadVehController(
this);
1614 static void CheckIfRoadVehNeedsService(
RoadVehicle *v)
1627 default: NOT_REACHED();
1664 if (this->blocked_ctr == 0) CheckVehicleBreakdown(
this);
1666 CheckIfRoadVehNeedsService(
this);