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);
93 int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
107 if (is_custom_sprite(spritenum)) {
108 GetCustomVehicleIcon(engine,
DIR_W, image_type, result);
114 assert(IsValidImageIndex<VEH_ROAD>(spritenum));
115 result->
Set(
DIR_W + _roadveh_images[spritenum]);
122 if (is_custom_sprite(spritenum)) {
123 GetCustomVehicleSprite(
this, (
Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
129 assert(IsValidImageIndex<VEH_ROAD>(spritenum));
149 GetRoadVehIcon(engine, image_type, &seq);
153 preferred_x =
Clamp(preferred_x,
172 GetRoadVehIcon(engine, image_type, &seq);
177 width =
UnScaleGUI(rect.right - rect.left + 1);
178 height =
UnScaleGUI(rect.bottom - rect.top + 1);
194 if (e->
GetGRF() != NULL && e->
GetGRF()->grf_version >= 8) {
227 assert(u->First() == v);
237 u->gcache.cached_veh_length = veh_len;
241 u->UpdateVisualEffect();
277 v->
z_pos = GetSlopePixelZ(x, y);
295 _new_vehicle_id = v->
index;
318 u->cargo_cap = u->GetEngine()->DetermineCapacity(u);
321 u->InvalidateNewGRFCache();
343 default: NOT_REACHED();
352 if (location != NULL) *location = rfdd.
tile;
375 if (ret.
Failed())
return ret;
391 if (flags &
DC_EXEC) v->reverse_ctr = 180;
408 static const int8 _delta_xy_table[8][10] = {
410 {3, 3, -1, -1, 0, 0, -1, -1, -1, -1},
411 {3, 7, -1, -3, 0, -1, 0, -1, 0, 0},
412 {3, 3, -1, -1, 0, 0, 1, -1, 1, -1},
413 {7, 3, -3, -1, -1, 0, 0, 0, 1, 0},
414 {3, 3, -1, -1, 0, 0, 1, 1, 1, 1},
415 {3, 7, -1, -3, 0, -1, 0, 0, 0, 1},
416 {3, 3, -1, -1, 0, 0, -1, 1, -1, 1},
417 {7, 3, -3, -1, -1, 0, -1, 0, 0, 0},
423 const int8 *bb = _delta_xy_table[
direction];
424 this->
x_bb_offs = bb[5] + bb[9] * shorten;
425 this->
y_bb_offs = bb[4] + bb[8] * shorten;;
428 this->
x_extent = bb[1] + bb[7] * shorten;
429 this->
y_extent = bb[0] + bb[6] * shorten;
447 }
else if ((u->direction & 1) == 0) {
469 for (; v->
Next() != NULL; v = v->
Next()) u = v;
479 static void RoadVehSetRandomDirection(
RoadVehicle *v)
481 static const DirDiff delta[] = {
490 }
while ((v = v->
Next()) != NULL);
504 if ((v->
tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
506 bool ret = v->
Next() != NULL;
547 uint pass = v->
Crash();
550 Game::NewEvent(
new ScriptEventVehicleCrashed(v->
index, v->
tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
555 STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
560 ModifyStationRatingAround(v->
tile, v->
owner, -160, 22);
596 static void StartRoadVehSound(
const RoadVehicle *v)
600 if (s == SND_19_BUS_START_PULL_AWAY && (v->
tick_counter & 3) == 0) {
601 s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
603 SndPlayVehicleFx(s, v);
618 static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
619 static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
623 short x_diff = v->
x_pos - rvf->x;
624 short y_diff = v->
y_pos - rvf->y;
635 uint diff =
abs(x_diff) +
abs(y_diff);
637 if (diff < rvf->best_diff || (diff == rvf->best_diff && v->
index < rvf->best->
index)) {
639 rvf->best_diff = diff;
651 if (front->reverse_ctr != 0)
return NULL;
657 rvf.best_diff = UINT_MAX;
670 if (rvf.best_diff == UINT_MAX) {
671 front->blocked_ctr = 0;
675 if (update_blocked_ctr && ++front->blocked_ctr > 1480)
return NULL;
689 if (!(st->had_vehicle_of_type &
HVOT_BUS)) {
690 st->had_vehicle_of_type |=
HVOT_BUS;
693 v->roadtype ==
ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
703 if (!(st->had_vehicle_of_type &
HVOT_TRUCK)) {
707 v->roadtype ==
ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
728 default: NOT_REACHED();
739 static const Direction _roadveh_new_dir[] = {
745 x = x - v->
x_pos + 1;
746 y = y - v->
y_pos + 1;
748 if ((uint)x > 2 || (uint)y > 2)
return v->
direction;
749 return _roadveh_new_dir[y * 4 + x];
754 Direction new_dir = RoadVehGetNewDirection(v, x, y);
758 if (new_dir == old_dir)
return old_dir;
770 static Vehicle *EnumFindVehBlockingOvertake(
Vehicle *v,
void *data)
774 return (v->
type ==
VEH_ROAD && v->
First() == v && v != od->u && v != od->v) ? v : NULL;
849 static void RoadZPosAffectSpeed(
RoadVehicle *v,
int old_z)
853 if (old_z < v->z_pos) {
857 if (spd <= v->vcache.cached_max_speed) v->
cur_speed = spd;
861 static int PickRandomBit(uint bits)
866 for (i = 0; !(bits & 1) || (
int)--num >= 0; bits >>= 1, i++) {}
880 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
884 bool path_found =
true;
927 return_track(_road_reverse_table[enterdir]);
930 if (v->reverse_ctr != 0) {
937 reverse = ((rb & straight) == straight) ||
942 if (v->
tile != tile) {
943 return_track(_road_reverse_table[enterdir]);
951 return_track(PickRandomBit(trackdirs));
963 default: NOT_REACHED();
980 static bool RoadVehLeaveDepot(
RoadVehicle *v,
bool first)
1003 if (RoadVehFindCloseTo(v, x, y, v->
direction,
false) != NULL)
return true;
1007 StartRoadVehSound(v);
1015 v->frame = RVC_DEPOT_START_FRAME;
1029 if (prev->
tile == v->
tile && !already_reversed) {
1032 return _road_reverse_table[entry_dir];
1035 byte prev_state = prev->
state;
1050 if (already_reversed && prev->
tile != tile) {
1080 static const RoadBits required_roadbits[] = {
1084 RoadBits required = required_roadbits[dir & 0x07];
1175 dir = FollowPreviousRoadVehicle(v, prev, tile, (
DiagDirection)(rd.x & 3),
false);
1185 uint start_frame = RVC_DEFAULT_START_FRAME;
1196 default: NOT_REACHED();
1228 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
1248 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1250 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1264 dir = _road_reverse_table[rd.x & 3];
1296 v->
state = (byte)dir;
1297 v->frame = start_frame;
1313 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
1325 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
1326 switch (rd.x & 0x3) {
1327 default: NOT_REACHED();
1338 dir = FollowPreviousRoadVehicle(v, prev, v->
tile, (
DiagDirection)(rd.x & 3),
true);
1352 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1353 if (v->
IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL)
return false;
1362 v->frame = turn_around_start_frame;
1381 RoadVehLeaveDepot(v->
Next(),
false);
1386 int x = (v->
x_pos & ~15) + (rd.x & 15);
1387 int y = (v->
y_pos & ~15) + (rd.y & 15);
1389 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1394 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1399 if (v->
overtaking == 0) RoadVehCheckOvertake(v, u);
1417 if (new_dir != old_dir) {
1440 v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
1487 StartRoadVehSound(v);
1517 if (v->reverse_ctr != 0) v->reverse_ctr--;
1533 if (v->
IsInDepot() && RoadVehLeaveDepot(v,
true))
return true;
1541 bool blocked =
false;
1542 while (j >= adv_spd) {
1547 if (!IndividualRoadVehicleController(u, prev)) {
1558 if (j >= adv_spd && RoadVehCheckTrainCrash(v))
break;
1564 if ((u->vehstatus &
VS_HIDDEN) != 0)
continue;
1566 u->UpdateViewport(
false,
false);
1580 if (e->u.road.running_cost_class == INVALID_PRICE)
return 0;
1583 if (cost_factor == 0)
return 0;
1585 return GetPrice(e->u.road.running_cost_class, cost_factor, e->
GetGRF());
1594 return RoadVehController(
this);
1600 static void CheckIfRoadVehNeedsService(
RoadVehicle *v)
1613 default: NOT_REACHED();
1650 if (this->blocked_ctr == 0) CheckVehicleBreakdown(
this);
1652 CheckIfRoadVehNeedsService(
this);