diff --git a/simconvoi.cc b/simconvoi.cc index 6781ecea6..c7bdc0f6f 100644 --- a/simconvoi.cc +++ b/simconvoi.cc @@ -2549,8 +2549,10 @@ void convoi_t::rdwr(loadsave_t *file) set_tiles_overtaking( 0 ); } else { - file->rdwr_byte(tiles_overtaking); - set_tiles_overtaking( tiles_overtaking ); + overtaker_t* ot = front()->get_overtaker(); + sint8 tiles = ot==NULL ? 0 : ot->get_tiles_overtaking(); + file->rdwr_byte(tiles); + set_tiles_overtaking(tiles); } // no_load, withdraw if(file->is_version_less(102, 1)) { @@ -3076,8 +3078,8 @@ void convoi_t::calc_speedbonus_kmh() speedbonus_kmh = speed_to_kmh( calc_max_speed(sum_gear_and_power, total_max_weight, min_top_speed) ); // convoi overtakers use current actual weight for achievable speed - if( front()->get_overtaker() ) { - max_power_speed = calc_max_speed(sum_gear_and_power, total_weight, min_top_speed); + if( overtaker_t* ot = front()->get_overtaker() ) { + ot->set_max_power_speed(calc_max_speed(sum_gear_and_power, total_weight, min_top_speed)); } } } @@ -3559,235 +3561,6 @@ void convoi_t::set_withdraw(bool new_withdraw) } -/** - * conditions for a city car to overtake another overtaker. - * The city car is not overtaking/being overtaken. - */ -bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) -{ - if(fahr[0]->get_waytype()!=road_wt) { - return false; - } - - if (!other_overtaker->can_be_overtaken()) { - return false; - } - - if( other_speed == 0 ) { - /* overtaking a loading convoi - * => we can do a lazy check, since halts are always straight - */ - grund_t *gr = welt->lookup(get_pos()); - if( gr==NULL ) { - // should never happen, since there is a vehicle in front of us ... - return false; - } - weg_t *str = gr->get_weg(road_wt); - if( str==0 ) { - // also this is not possible, since a car loads in front of is!?! - return false; - } - - uint16 idx = fahr[0]->get_route_index(); - const sint32 tiles = other_speed == 0 ? 2 : (steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT) + get_tile_length() + 1; - if( tiles > 0 && idx+(uint32)tiles >= route.get_count() ) { - // needs more space than there - return false; - } - - for( sint32 i=0; ilookup( route.at( idx+i ) ); - if( gr==NULL ) { - return false; - } - weg_t *str = gr->get_weg(road_wt); - if( str==0 ) { - return false; - } - // not overtaking on railroad crossings or normal crossings ... - if( str->is_crossing() ) { - return false; - } - if( ribi_t::is_threeway(str->get_ribi()) ) { - return false; - } - // Check for other vehicles on the next tile - const uint8 top = gr->get_top(); - for( uint8 j=1; j(gr->obj_bei(j)) ) { - // check for other traffic on the road - const overtaker_t *ov = v->get_overtaker(); - if(ov) { - if(this!=ov && other_overtaker!=ov) { - return false; - } - } - else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { - return false; - } - } - } - } - set_tiles_overtaking( tiles ); - return true; - } - - int diff_speed = akt_speed - other_speed; - if( diff_speed < kmh_to_speed(5) ) { - return false; - } - - // Number of tiles overtaking will take - int n_tiles = 0; - - // Distance it takes overtaking (unit: vehicle_steps) = my_speed * time_overtaking - // time_overtaking = tiles_to_overtake/diff_speed - // tiles_to_overtake = convoi_length + current pos within tile + (pos_other_convoi within tile + length of other convoi) - one tile - sint32 distance = akt_speed*(fahr[0]->get_steps()+get_length_in_steps()+steps_other-VEHICLE_STEPS_PER_TILE)/diff_speed; - sint32 time_overtaking = 0; - - // Conditions for overtaking: - // Flat tiles, with no stops, no crossings, no signs, no change of road speed limit - // First phase: no traffic except me and my overtaken car in the dangerous zone - unsigned int route_index = fahr[0]->get_route_index()+1; - koord3d pos = fahr[0]->get_pos(); - koord3d pos_prev = route_index > 2 ? route.at(route_index-2) : pos; - koord3d pos_next; - - while( distance > 0 ) { - - if( route_index >= route.get_count() ) { - return false; - } - - pos_next = route.at(route_index++); - grund_t *gr = welt->lookup(pos); - // no ground, or slope => about - if( gr==NULL || gr->get_weg_hang()!=slope_t::flat ) { - return false; - } - - weg_t *str = gr->get_weg(road_wt); - if( str==NULL ) { - return false; - } - // the only roadsign we must account for are choose points and traffic lights - if( str->has_sign() ) { - const roadsign_t *rs = gr->find(1); - if(rs) { - const roadsign_desc_t *rb = rs->get_desc(); - if(rb->is_choose_sign() || rb->is_traffic_light() ) { - // because we may need to stop here ... - return false; - } - } - } - // not overtaking on railroad crossings or on normal crossings ... - if( str->is_crossing() || ribi_t::is_threeway(str->get_ribi()) ) { - return false; - } - // street gets too slow (TODO: should be able to be correctly accounted for) - if( akt_speed > kmh_to_speed(str->get_max_speed()) ) { - return false; - } - - int d = ribi_t::is_straight(str->get_ribi()) ? VEHICLE_STEPS_PER_TILE : vehicle_base_t::get_diagonal_vehicle_steps_per_tile(); - distance -= d; - time_overtaking += d; - - // Check for other vehicles - const uint8 top = gr->get_top(); - for( uint8 j=1; j(gr->obj_bei(j))) { - // check for other traffic on the road - const overtaker_t *ov = v->get_overtaker(); - if(ov) { - if(this!=ov && other_overtaker!=ov) { - return false; - } - } - else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { - // sheeps etc. - return false; - } - } - } - n_tiles++; - pos_prev = pos; - pos = pos_next; - } - - // Second phase: only facing traffic is forbidden - - // the original routine was checking using the maximum road speed. - // However, we can tolerate slower vehicles if they are closer - - // Furthermore, if we reach the end of the route for a vehcile as fast as us, - // we simply assume it to be ok too - sint32 overtaking_distance = time_overtaking; - distance = 0; // distance to needed traveled to crash int us from this point - time_overtaking = (time_overtaking << 16)/akt_speed; - while( time_overtaking > 0 ) { - - if( route_index >= route.get_count() ) { - return distance>=time_overtaking; // we assume ok, if there is enough distance when we would face ourselves - } - - pos_next = route.at(route_index++); - grund_t *gr= welt->lookup(pos); - if( gr==NULL ) { - // will cause a route search, but is ok - break; - } - - weg_t *str = gr->get_weg(road_wt); - if( str==NULL ) { - break; - } - // cannot check for oncoming traffic over crossings - if( ribi_t::is_threeway(str->get_ribi()) ) { - return false; - } - - if( ribi_t::is_straight(str->get_ribi()) ) { - time_overtaking -= (VEHICLE_STEPS_PER_TILE<<16) / kmh_to_speed(str->get_max_speed()); - distance -= VEHICLE_STEPS_PER_TILE; - } - else { - time_overtaking -= (vehicle_base_t::get_diagonal_vehicle_steps_per_tile()<<16) / kmh_to_speed(str->get_max_speed()); - distance -= vehicle_base_t::get_diagonal_vehicle_steps_per_tile(); - } - - // Check for other vehicles in facing direction - ribi_t::ribi their_direction = ribi_t::backward( fahr[0]->calc_direction(pos_prev, pos_next) ); - const uint8 top = gr->get_top(); - for( uint8 j=1; j(gr->obj_bei(j)); - if( v && v->get_direction() == their_direction && v->get_overtaker() ) { - // tolerated distance us>them: total_distance*akt_speed > current_distance*other_speed - if( road_vehicle_t const* const car = obj_cast(v) ) { - convoi_t* const ocnv = car->get_convoi(); - if( ocnv && ocnv->get_max_power_speed()*distance > akt_speed*overtaking_distance ) { - return false; - } - } - else if( private_car_t* const caut = obj_cast(v) ) { - if( caut->get_desc()->get_topspeed()*distance > akt_speed*overtaking_distance ) { - return false; - } - } - } - } - pos_prev = pos; - pos = pos_next; - } - - set_tiles_overtaking( 1+n_tiles ); - other_overtaker->set_tiles_overtaking( -1-(n_tiles*(akt_speed-diff_speed))/akt_speed ); - return true; -} - - sint64 convoi_t::get_stat_converted(int month, int cost_type) const { sint64 value = financial_history[month][cost_type]; @@ -3853,3 +3626,10 @@ const char* convoi_t::send_to_depot(bool local) return txt; } + + +void convoi_t::set_tiles_overtaking(sint8 v) { + if( overtaker_t* ot = front()->get_overtaker() ) { + ot->set_tiles_overtaking(v); + } +} diff --git a/simconvoi.h b/simconvoi.h index 553d32f67..af39f2946 100644 --- a/simconvoi.h +++ b/simconvoi.h @@ -36,7 +36,7 @@ class cbuffer_t; /** * Base class for all vehicle consists. Convoys can be referenced by handles, see halthandle_t. */ -class convoi_t : public sync_steppable, public overtaker_t +class convoi_t : public sync_steppable { public: enum { @@ -792,9 +792,9 @@ public: // just a guess of the speed uint32 get_average_kmh() const; - - // Overtaking for convois - bool can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) OVERRIDE; + + // calls set_tiles_overtaking() of overtaker_t + void set_tiles_overtaking(sint8); }; #endif diff --git a/vehicle/overtaker.h b/vehicle/overtaker.h index ba7f50c26..a97b346b4 100644 --- a/vehicle/overtaker.h +++ b/vehicle/overtaker.h @@ -44,6 +44,8 @@ public: diff ++; } } + + sint8 get_tiles_overtaking() const { return tiles_overtaking; } // change counter for overtaking void update_tiles_overtaking() { @@ -57,6 +59,7 @@ public: virtual bool can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) = 0; sint32 get_max_power_speed() const { return max_power_speed; } + void set_max_power_speed(sint32 m) { max_power_speed = m; } }; #endif diff --git a/vehicle/simroadtraffic.cc b/vehicle/simroadtraffic.cc index ef33739cc..6dddfe01e 100644 --- a/vehicle/simroadtraffic.cc +++ b/vehicle/simroadtraffic.cc @@ -533,7 +533,7 @@ bool private_car_t::ist_weg_frei(grund_t *gr) // otherwise the overtaken car would stop for us ... if( road_vehicle_t const* const car = obj_cast(dt) ) { convoi_t* const ocnv = car->get_convoi(); - if( ocnv==NULL || !can_overtake( ocnv, (ocnv->get_state()==convoi_t::LOADING ? 0 : over->get_max_power_speed()), ocnv->get_length_in_steps()+ocnv->get_vehikel(0)->get_steps()) ) { + if( ocnv==NULL || !can_overtake( over, (ocnv->get_state()==convoi_t::LOADING ? 0 : over->get_max_power_speed()), ocnv->get_length_in_steps()+ocnv->get_vehikel(0)->get_steps()) ) { frei = false; } } else if( private_car_t* const caut = obj_cast(dt) ) { diff --git a/vehicle/simvehicle.cc b/vehicle/simvehicle.cc index c2b240bc2..4300e7d78 100644 --- a/vehicle/simvehicle.cc +++ b/vehicle/simvehicle.cc @@ -1976,11 +1976,11 @@ void road_vehicle_t::get_screen_offset( int &xoff, int &yoff, const sint16 raste // eventually shift position to take care of overtaking if(cnv) { - if( cnv->is_overtaking() ) { + if( is_overtaking() ) { xoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width); yoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width); } - else if( cnv->is_overtaken() ) { + else if( is_overtaken() ) { xoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width)/5; yoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width)/5; } @@ -2119,7 +2119,7 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui uint32 test_index = route_index + 1u; // way should be clear for overtaking: we checked previously - if( !cnv->is_overtaking() ) { + if( !is_overtaking() ) { // calculate new direction route_t const& r = *cnv->get_route(); koord3d next = route_index < r.get_count() - 1u ? r.at(route_index + 1u) : pos_next; @@ -2235,7 +2235,7 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui if( obj->is_stuck() ) { // end of traffic jam, but no stuck message, because previous vehicle is stuck too restart_speed = 0; - cnv->set_tiles_overtaking(0); + set_tiles_overtaking(0); cnv->reset_waiting(); } else { @@ -2250,12 +2250,12 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui // not overtaking/being overtake: we need to make a more thought test! if( road_vehicle_t const* const car = obj_cast(obj) ) { convoi_t* const ocnv = car->get_convoi(); - if( cnv->can_overtake( ocnv, (ocnv->get_state()==convoi_t::LOADING ? 0 : over->get_max_power_speed()), ocnv->get_length_in_steps()+ocnv->get_vehikel(0)->get_steps()) ) { + if( ocnv && can_overtake( over, (ocnv->get_state()==convoi_t::LOADING ? 0 : over->get_max_power_speed()), ocnv->get_length_in_steps()+ocnv->get_vehikel(0)->get_steps()) ) { return true; } } else if( private_car_t* const caut = obj_cast(obj) ) { - if( cnv->can_overtake(caut, caut->get_desc()->get_topspeed(), VEHICLE_STEPS_PER_TILE) ) { + if( can_overtake(caut, caut->get_desc()->get_topspeed(), VEHICLE_STEPS_PER_TILE) ) { return true; } } @@ -2263,7 +2263,7 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui } // we have to wait ... restart_speed = (cnv->get_akt_speed()*3)/4; - cnv->set_tiles_overtaking(0); + set_tiles_overtaking(0); } } @@ -2276,7 +2276,7 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui overtaker_t* road_vehicle_t::get_overtaker() { - return cnv; + return this; } @@ -2294,7 +2294,7 @@ void road_vehicle_t::enter_tile(grund_t* gr) } } if (leading) { - cnv->update_tiles_overtaking(); + update_tiles_overtaking(); } } @@ -2335,6 +2335,231 @@ void road_vehicle_t::set_convoi(convoi_t *c) } +/** + * conditions for a city car to overtake another overtaker. + * The city car is not overtaking/being overtaken. + */ +bool road_vehicle_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) +{ + if (!other_overtaker->can_be_overtaken()) { + return false; + } + + if( other_speed == 0 ) { + /* overtaking a loading convoi + * => we can do a lazy check, since halts are always straight + */ + grund_t *gr = welt->lookup(get_pos()); + if( gr==NULL ) { + // should never happen, since there is a vehicle in front of us ... + return false; + } + weg_t *str = gr->get_weg(road_wt); + if( str==0 ) { + // also this is not possible, since a car loads in front of is!?! + return false; + } + + uint16 idx = get_route_index(); + const sint32 tiles = other_speed == 0 ? 2 : (steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT) + cnv->get_tile_length() + 1; + if( tiles > 0 && idx+(uint32)tiles >= cnv->get_route()->get_count() ) { + // needs more space than there + return false; + } + + for( sint32 i=0; ilookup( cnv->get_route()->at( idx+i ) ); + if( gr==NULL ) { + return false; + } + weg_t *str = gr->get_weg(road_wt); + if( str==0 ) { + return false; + } + // not overtaking on railroad crossings or normal crossings ... + if( str->is_crossing() ) { + return false; + } + if( ribi_t::is_threeway(str->get_ribi()) ) { + return false; + } + // Check for other vehicles on the next tile + const uint8 top = gr->get_top(); + for( uint8 j=1; j(gr->obj_bei(j)) ) { + // check for other traffic on the road + const overtaker_t *ov = v->get_overtaker(); + if(ov) { + if(this!=ov && other_overtaker!=ov) { + return false; + } + } + else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { + return false; + } + } + } + } + set_tiles_overtaking( tiles ); + return true; + } + + const uint32 akt_speed = cnv->get_akt_speed(); + int diff_speed = akt_speed - other_speed; + if( diff_speed < kmh_to_speed(5) ) { + return false; + } + + // Number of tiles overtaking will take + int n_tiles = 0; + + // Distance it takes overtaking (unit: vehicle_steps) = my_speed * time_overtaking + // time_overtaking = tiles_to_overtake/diff_speed + // tiles_to_overtake = convoi_length + current pos within tile + (pos_other_convoi within tile + length of other convoi) - one tile + sint32 distance = akt_speed*(get_steps()+cnv->get_length_in_steps()+steps_other-VEHICLE_STEPS_PER_TILE)/diff_speed; + sint32 time_overtaking = 0; + + // Conditions for overtaking: + // Flat tiles, with no stops, no crossings, no signs, no change of road speed limit + // First phase: no traffic except me and my overtaken car in the dangerous zone + unsigned int route_index = get_route_index()+1; + koord3d pos = get_pos(); + koord3d pos_prev = route_index > 2 ? cnv->get_route()->at(route_index-2) : pos; + koord3d pos_next; + + while( distance > 0 ) { + + if( route_index >= cnv->get_route()->get_count() ) { + return false; + } + + pos_next = cnv->get_route()->at(route_index++); + grund_t *gr = welt->lookup(pos); + // no ground, or slope => about + if( gr==NULL || gr->get_weg_hang()!=slope_t::flat ) { + return false; + } + + weg_t *str = gr->get_weg(road_wt); + if( str==NULL ) { + return false; + } + // the only roadsign we must account for are choose points and traffic lights + if( str->has_sign() ) { + const roadsign_t *rs = gr->find(1); + if(rs) { + const roadsign_desc_t *rb = rs->get_desc(); + if(rb->is_choose_sign() || rb->is_traffic_light() ) { + // because we may need to stop here ... + return false; + } + } + } + // not overtaking on railroad crossings or on normal crossings ... + if( str->is_crossing() || ribi_t::is_threeway(str->get_ribi()) ) { + return false; + } + // street gets too slow (TODO: should be able to be correctly accounted for) + if( akt_speed > kmh_to_speed(str->get_max_speed()) ) { + return false; + } + + int d = ribi_t::is_straight(str->get_ribi()) ? VEHICLE_STEPS_PER_TILE : vehicle_base_t::get_diagonal_vehicle_steps_per_tile(); + distance -= d; + time_overtaking += d; + + // Check for other vehicles + const uint8 top = gr->get_top(); + for( uint8 j=1; j(gr->obj_bei(j))) { + // check for other traffic on the road + const overtaker_t *ov = v->get_overtaker(); + if(ov) { + if(this!=ov && other_overtaker!=ov) { + return false; + } + } + else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { + // sheeps etc. + return false; + } + } + } + n_tiles++; + pos_prev = pos; + pos = pos_next; + } + + // Second phase: only facing traffic is forbidden + + // the original routine was checking using the maximum road speed. + // However, we can tolerate slower vehicles if they are closer + + // Furthermore, if we reach the end of the route for a vehcile as fast as us, + // we simply assume it to be ok too + sint32 overtaking_distance = time_overtaking; + distance = 0; // distance to needed traveled to crash int us from this point + time_overtaking = (time_overtaking << 16)/akt_speed; + while( time_overtaking > 0 ) { + + if( route_index >= cnv->get_route()->get_count() ) { + return distance>=time_overtaking; // we assume ok, if there is enough distance when we would face ourselves + } + + pos_next = cnv->get_route()->at(route_index++); + grund_t *gr= welt->lookup(pos); + if( gr==NULL ) { + // will cause a route search, but is ok + break; + } + + weg_t *str = gr->get_weg(road_wt); + if( str==NULL ) { + break; + } + // cannot check for oncoming traffic over crossings + if( ribi_t::is_threeway(str->get_ribi()) ) { + return false; + } + + if( ribi_t::is_straight(str->get_ribi()) ) { + time_overtaking -= (VEHICLE_STEPS_PER_TILE<<16) / kmh_to_speed(str->get_max_speed()); + distance -= VEHICLE_STEPS_PER_TILE; + } + else { + time_overtaking -= (vehicle_base_t::get_diagonal_vehicle_steps_per_tile()<<16) / kmh_to_speed(str->get_max_speed()); + distance -= vehicle_base_t::get_diagonal_vehicle_steps_per_tile(); + } + + // Check for other vehicles in facing direction + ribi_t::ribi their_direction = ribi_t::backward( calc_direction(pos_prev, pos_next) ); + const uint8 top = gr->get_top(); + for( uint8 j=1; j(gr->obj_bei(j)); + if( v && v->get_direction() == their_direction && v->get_overtaker() ) { + // tolerated distance us>them: total_distance*akt_speed > current_distance*other_speed + if( road_vehicle_t const* const car = obj_cast(v) ) { + if( car->get_max_power_speed()*distance > akt_speed*overtaking_distance ) { + return false; + } + } + else if( private_car_t* const caut = obj_cast(v) ) { + if( caut->get_desc()->get_topspeed()*distance > akt_speed*overtaking_distance ) { + return false; + } + } + } + } + pos_prev = pos; + pos = pos_next; + } + + set_tiles_overtaking( 1+n_tiles ); + other_overtaker->set_tiles_overtaking( -1-(n_tiles*(akt_speed-diff_speed))/akt_speed ); + return true; +} + + /* from now on rail vehicles (and other vehicles using blocks) */ rail_vehicle_t::rail_vehicle_t(loadsave_t *file, bool is_first, bool is_last) : vehicle_t() { diff --git a/vehicle/simvehicle.h b/vehicle/simvehicle.h index 69ee0e6b3..a0a9d5773 100644 --- a/vehicle/simvehicle.h +++ b/vehicle/simvehicle.h @@ -456,7 +456,7 @@ template<> inline vehicle_t* obj_cast(obj_t* const d) * and the navigability of tiles. * @see vehicle_t */ -class road_vehicle_t : public vehicle_t +class road_vehicle_t : public vehicle_t, public overtaker_t { private: // called internally only from ist_weg_frei() @@ -465,6 +465,8 @@ private: protected: bool check_next_tile(const grund_t *bd) const OVERRIDE; + // Overtaking for convois + bool can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) OVERRIDE; public: void enter_tile(grund_t*) OVERRIDE;